This plugs another small loophole in the front-end which fails to
generate a range check for a scalar In/Out parameter when -gnatVa is
specified. This also fixes a few more leaks of the Do_Range_Check flag
on actual parameters, both in regular and -gnatVa modes, as well as a
leak specific to expression function in -gnatp mode.
Tested on x86_64-pc-linux-gnu, committed on trunk
2019-08-12 Eric Botcazou <ebotca...@adacore.com>
gcc/ada/
* checks.adb (Insert_Valid_Check): Reset the Do_Range_Check flag
on the validated object.
* exp_ch6.adb (Add_Call_By_Copy_Code): Reset the Do_Range_Check
flag on the actual here, as well as on the Expression if the
actual is a N_Type_Conversion node.
(Add_Validation_Call_By_Copy_Code): Generate the incoming range
check if needed and reset the Do_Range_Check flag on the
Expression if the actual is a N_Type_Conversion node.
(Expand_Actuals): Do not reset the Do_Range_Check flag here.
Generate the incoming range check for In parameters here instead
of...
(Expand_Call_Helper): ...here. Remove redudant condition.
* sem_res.adb (Resolve_Actuals): Use local variable A_Typ and
remove obsolete comments.
(Resolve_Type_Conversion): Do not force the Do_Range_Check flag
on the operand if range checks are suppressed.
gcc/testsuite/
* gnat.dg/range_check6.adb: New testcase.
--- gcc/ada/checks.adb
+++ gcc/ada/checks.adb
@@ -7588,8 +7588,12 @@ package body Checks is
Suppress => Validity_Check);
Set_Validated_Object (Var_Id, New_Copy_Tree (Exp));
+
+ -- Reset the Do_Range_Check flag so it doesn't leak elsewhere
+
+ Set_Do_Range_Check (Validated_Object (Var_Id), False);
+
Rewrite (Exp, New_Occurrence_Of (Var_Id, Loc));
- PV := New_Occurrence_Of (Var_Id, Loc);
-- Copy the Do_Range_Check flag over to the new Exp, so it doesn't
-- get lost. Floating point types are handled elsewhere.
@@ -7598,6 +7602,8 @@ package body Checks is
Set_Do_Range_Check (Exp, Do_Range_Check (Original_Node (Exp)));
end if;
+ PV := New_Occurrence_Of (Var_Id, Loc);
+
-- Otherwise the expression does not denote a variable. Force its
-- evaluation by capturing its value in a constant. Generate:
--- gcc/ada/exp_ch6.adb
+++ gcc/ada/exp_ch6.adb
@@ -1295,7 +1295,14 @@ package body Exp_Ch6 is
Indic := New_Occurrence_Of (F_Typ, Loc);
end if;
+ -- The new code will be properly analyzed below and the setting of
+ -- the Do_Range_Check flag recomputed so remove the obsolete one.
+
+ Set_Do_Range_Check (Actual, False);
+
if Nkind (Actual) = N_Type_Conversion then
+ Set_Do_Range_Check (Expression (Actual), False);
+
V_Typ := Etype (Expression (Actual));
-- If the formal is an (in-)out parameter, capture the name
@@ -1689,6 +1696,20 @@ package body Exp_Ch6 is
Var_Id : Entity_Id;
begin
+ -- Generate range check if required
+
+ if Do_Range_Check (Actual) then
+ Generate_Range_Check (Actual, E_Formal, CE_Range_Check_Failed);
+ end if;
+
+ -- If there is a type conversion in the actual, it will be reinstated
+ -- below, the new instance will be properly analyzed and the setting
+ -- of the Do_Range_Check flag recomputed so remove the obsolete one.
+
+ if Nkind (Actual) = N_Type_Conversion then
+ Set_Do_Range_Check (Expression (Actual), False);
+ end if;
+
-- Copy the value of the validation variable back into the object
-- being validated.
@@ -2073,14 +2094,6 @@ package body Exp_Ch6 is
(Ekind (Formal) = E_In_Out_Parameter
and then not In_Subrange_Of (E_Actual, E_Formal)))
then
- -- Perhaps the setting back to False should be done within
- -- Add_Call_By_Copy_Code, since it could get set on other
- -- cases occurring above???
-
- if Do_Range_Check (Actual) then
- Set_Do_Range_Check (Actual, False);
- end if;
-
Add_Call_By_Copy_Code;
end if;
@@ -2194,6 +2207,12 @@ package body Exp_Ch6 is
-- Processing for IN parameters
else
+ -- Generate range check if required
+
+ if Do_Range_Check (Actual) then
+ Generate_Range_Check (Actual, E_Formal, CE_Range_Check_Failed);
+ end if;
+
-- For IN parameters in the bit-packed array case, we expand an
-- indexed component (the circuit in Exp_Ch4 deliberately left
-- indexed components appearing as actuals untouched, so that
@@ -3054,16 +3073,6 @@ package body Exp_Ch6 is
Actual := First_Actual (Call_Node);
Param_Count := 1;
while Present (Formal) loop
-
- -- Generate range check if required
-
- if Do_Range_Check (Actual)
- and then Ekind (Formal) = E_In_Parameter
- then
- Generate_Range_Check
- (Actual, Etype (Formal), CE_Range_Check_Failed);
- end if;
-
-- Prepare to examine current entry
Prev := Actual;
@@ -3582,9 +3591,7 @@ package body Exp_Ch6 is
-- or IN OUT parameter. We do reset the Is_Known_Valid flag
-- since the subprogram could have returned in invalid value.
- if Ekind_In (Formal, E_Out_Parameter, E_In_Out_Parameter)
- and then Is_Assignable (Ent)
- then
+ if Is_Assignable (Ent) then
Sav := Last_Assignment (Ent);
Kill_Current_Values (Ent);
Set_Last_Assignment (Ent, Sav);
--- gcc/ada/sem_res.adb
+++ gcc/ada/sem_res.adb
@@ -4517,7 +4517,7 @@ package body Sem_Res is
end if;
end if;
- if Etype (A) = Any_Type then
+ if A_Typ = Any_Type then
Set_Etype (N, Any_Type);
return;
end if;
@@ -4539,18 +4539,10 @@ package body Sem_Res is
-- Apply required constraint checks
- -- Gigi looks at the check flag and uses the appropriate types.
- -- For now since one flag is used there is an optimization
- -- which might not be done in the IN OUT case since Gigi does
- -- not do any analysis. More thought required about this ???
-
- -- In fact is this comment obsolete??? doesn't the expander now
- -- generate all these tests anyway???
-
- if Is_Scalar_Type (Etype (A)) then
+ if Is_Scalar_Type (A_Typ) then
Apply_Scalar_Range_Check (A, F_Typ);
- elsif Is_Array_Type (Etype (A)) then
+ elsif Is_Array_Type (A_Typ) then
Apply_Length_Check (A, F_Typ);
elsif Is_Record_Type (F_Typ)
@@ -4624,9 +4616,8 @@ package body Sem_Res is
Apply_Scalar_Range_Check
(Expression (A), Etype (Expression (A)), A_Typ);
- -- In addition, the returned value of the parameter must
- -- satisfy the bounds of the object type (see comment
- -- below).
+ -- In addition the return value must meet the constraints
+ -- of the object type (see the comment below).
Apply_Scalar_Range_Check (A, A_Typ, F_Typ);
@@ -4650,6 +4641,7 @@ package body Sem_Res is
and then Ekind (F) = E_Out_Parameter
then
Apply_Length_Check (A, F_Typ);
+
else
Apply_Range_Check (A, A_Typ, F_Typ);
end if;
@@ -11757,6 +11749,8 @@ package body Sem_Res is
and then (Is_Fixed_Point_Type (Operand_Typ)
or else (not GNATprove_Mode
and then Is_Floating_Point_Type (Operand_Typ)))
+ and then not Range_Checks_Suppressed (Target_Typ)
+ and then not Range_Checks_Suppressed (Operand_Typ)
then
Set_Do_Range_Check (Operand);
end if;
--- /dev/null
new file mode 100644
+++ gcc/testsuite/gnat.dg/range_check6.adb
@@ -0,0 +1,28 @@
+-- { dg-do run }
+-- { dg-options "-O0 -gnatVa" }
+
+procedure Range_Check6 is
+
+ type Byte is range -2**7 .. 2**7-1;
+ for Byte'Size use 8;
+
+ subtype Hour is Byte range 0 .. 23;
+
+ type Rec is record
+ B : Byte;
+ end record;
+
+ procedure Encode (H : in out Hour) is
+ begin
+ null;
+ end;
+
+ R : Rec;
+
+begin
+ R.B := 24;
+ Encode (R.B);
+ raise Program_Error;
+exception
+ when Constraint_Error => null;
+end;