This patch fixes a compiler abort (or an infinite loop in a compiler whose
internal assertions are not enabled) when the subtype indication in an object
declaration does not denote a type. Syntactically this may happen when the
subtype indication is missing altogether and the expression in the declaration
is analyzed as if it were one.

Compiling aida-ling_float_random.adb must yield:

   aida-long_float_random.adb:51:23: subtype mark required in this context
   aida-long_float_random.adb:53:07: assignment to "in" mode parameter
      not allowed
   aida-long_float_random.adb:59:07: "Temp" is undefined
      (more references follow)
   aida-long_float_random.adb:66:07: "Ni" is undefined (more references follow)
   aida-long_float_random.adb:71:07: "Nj" is undefined (more references follow)
   aida-long_float_random.adb:76:30: no selector "Cd" for type "T" defined
      at aida-long_float_random.ads:57
   aida-long_float_random.adb:77:10: "C" is undefined (more references follow)
   aida-long_float_random.ads:27:06: warning: postcondition does not mention
      function result

---
package body Aida.Long_Float_Random with SPARK_Mode is

   function Make (New_I : Seed_Range_1 := Default_I;
                  New_J : Seed_Range_1 := Default_J;
                  New_K : Seed_Range_1 := Default_K;
                  New_L : Seed_Range_2 := Default_L
                 ) return T
   is
      S : Real;
      R : Real;
      M : Range_1;
   begin -- Set_Seed
      return This : T do
         This.I := New_I;
         This.J := New_J;
         This.K := New_K;
         This.L := New_L;
         This.Ni := Range_3'Last;
         This.Nj := Range_3'Last / 3 + 1;
         This.C := Init_C;

         Fill_U : for Ii in Range_3'Range loop
            S := 0.0;
            R := 0.5;

            pragma Loop_Invariant (S = 0.0 and R = 0.5);

            Calc_S : for Jj in 1 .. 24 loop
               M := (This.J * This.I) mod M1;
               M := (M * This.K) mod M1;
               This.I := This.J;
               This.J := This.K;
               This.K := M;
               This.L := (53 * This.L + 1) mod M2;

               pragma Loop_Invariant (R <= 0.5 and R >= 0.0);

               if (This.L * M) mod 64 >= 32 then
                  S  := S + R;
               end if;

               R := 0.5 * R;
            end loop Calc_S;

            This.U (Ii) := S;
         end loop Fill_U;
      end return;
   end Make;

   function Random (This : T) return Real is
      Temp : This.Temp.Value;
   begin
      This.Temp := (Exists => False);
      return Temp;
   end Random;

   procedure Calculate (This : in out T) is
   begin
      Temp := This.U (This.Ni) - This.U (This.Nj);
      if Temp < 0.0 then
         Temp := Temp + 1.0;
      end if;

      This.U (This.Ni) := Temp;

      Ni := Ni - 1;
      if Ni = 0 then
         Ni := Range_3'Last;
      end if;

      Nj := Nj - 1;
      if Nj = 0 then
         Nj := Range_3'Last;
      end if;

      This.C := This.C - This.Cd;
      if C < 0.0 then
         C := C + Cm;
      end if;

      Temp := Temp - C;
      if Temp < 0.0 then
         Temp := Temp + 1.0;
      end if;
   end Calculate;

end Aida.Long_Float_Random;
---
package Aida.Long_Float_Random with SPARK_Mode is

   type T (<>) is tagged limited private;

   subtype Real is Long_Float;

   M1 : constant := 179;
   M2 : constant := M1 - 10;

   subtype Seed_Range_1 is Integer range 2 .. M1 - 1;
   subtype Seed_Range_2 is Integer range 0 .. M2 - 1;

   Default_I : constant Seed_Range_1 := 12;
   Default_J : constant Seed_Range_1 := 34;
   Default_K : constant Seed_Range_1 := 56;
   Default_L : constant Seed_Range_2 := 78;

   function Make (New_I : Seed_Range_1 := Default_I;
                  New_J : Seed_Range_1 := Default_J;
                  New_K : Seed_Range_1 := Default_K;
                  New_L : Seed_Range_2 := Default_L
                 ) return T;

   function Random (This : T) return Real with
     Global => null,
     Pre    => This.Is_Calculated,
     Post   => not This.Is_Calculated;

   function Is_Calculated (This : T) return Boolean with
     Global => null;

   procedure Calculate (This : in out T) with
     Global => null,
     Post   => This.Is_Calculated;

private

   M3      : constant :=       97;
   Divisor : constant := 16777216.0;
   Init_C  : constant :=   362436.0 / Divisor;
   Cd      : constant :=  7654321.0 / Divisor;
   Cm      : constant := 16777213.0 / Divisor;

   subtype Range_1 is Integer range 0 .. M1 - 1;
   subtype Range_2 is Integer range 0 .. M2 - 1;
   subtype Range_3 is Integer range 1 .. M3;

   type U_Array_T is array (Range_3) of Real;

   type Optional_Temp_T (Exists : Boolean := False) is record
      case Exists is
         when True  => Value : Real;
         when False => null;
      end case;
   end record;

   type T is tagged limited record
      I    : Range_1;
      J    : Range_1;
      K    : Range_1;
      Ni   : Integer;
      Nj   : Integer;
      L    : Range_2;
      C    : Real;
      U    : U_Array_T;
      Temp : Optional_Temp_T;
   end record;

   function Is_Calculated (This : T) return Boolean is (This.Temp.Exists);

end Aida.Long_Float_Random;
--
package Aida is
end Aida;

Tested on x86_64-pc-linux-gnu, committed on trunk

2017-11-16  Ed Schonberg  <schonb...@adacore.com>

        * sem_ch3.adb (Process_Subtype): If the subtype indication does not
        syntactically denote a type, return Any_Type to prevent subsequent
        compiler crashes or infinite loops.

Index: sem_ch3.adb
===================================================================
--- sem_ch3.adb (revision 254802)
+++ sem_ch3.adb (working copy)
@@ -21338,6 +21338,16 @@
 
       if Nkind (S) /= N_Subtype_Indication then
          Find_Type (S);
+
+         --  No way to proceed if the subtype indication is malformed.
+         --  This will happen for example when the subtype indication in
+         --  an object declaration is missing altogether and the expression
+         --  is analyzed as if it were that indication.
+
+         if not Is_Entity_Name (S) then
+            return Any_Type;
+         end if;
+
          Check_Incomplete (S);
          P := Parent (S);
 

Reply via email to