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 <[email protected]>
* 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);