===================================================================
@@ -107,6 +107,9 @@ package body Exp_Ch5 is
-- Expand loop over arrays and containers that uses the form "for X of C"
-- with an optional subtype mark, or "for Y in C".
+ procedure Expand_Predicated_Loop (N : Node_Id);
+ -- Expand for loop over predicated subtype
+
function Make_Tag_Ctrl_Assignment (N : Node_Id) return List_Id;
-- Generate the necessary code for controlled and tagged assignment, that
-- is to say, finalization of the target before, adjustment of the target
@@ -1623,16 +1626,21 @@ package body Exp_Ch5 is
end;
end if;
- -- First deal with generation of range check if required
+ -- Deal with assignment checks unless suppressed
- if Do_Range_Check (Rhs) then
- Set_Do_Range_Check (Rhs, False);
- Generate_Range_Check (Rhs, Typ, CE_Range_Check_Failed);
- end if;
+ if not Suppress_Assignment_Checks (N) then
+
+ -- First deal with generation of range check if required
- -- Generate predicate check if required
+ if Do_Range_Check (Rhs) then
+ Set_Do_Range_Check (Rhs, False);
+ Generate_Range_Check (Rhs, Typ, CE_Range_Check_Failed);
+ end if;
+
+ -- Then generate predicate check if required
- Apply_Predicate_Check (Rhs, Typ);
+ Apply_Predicate_Check (Rhs, Typ);
+ end if;
-- Check for a special case where a high level transformation is
-- required. If we have either of:
@@ -2960,8 +2968,9 @@ package body Exp_Ch5 is
-- 2. Deal with while condition for C/Fortran boolean
-- 3. Deal with loops with a non-standard enumeration type range
-- 4. Deal with while loops where Condition_Actions is set
- -- 5. Deal with loops with iterators over arrays and containers
- -- 6. Insert polling call if required
+ -- 5. Deal with loops over predicated subtypes
+ -- 6. Deal with loops with iterators over arrays and containers
+ -- 7. Insert polling call if required
procedure Expand_N_Loop_Statement (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
@@ -2990,33 +2999,15 @@ package body Exp_Ch5 is
-- Nothing more to do for plain loop with no iteration scheme
if No (Isc) then
- return;
- end if;
+ null;
+
+ -- Case of for loop (Loop_Parameter_Specfication present)
-- Note: we do not have to worry about validity checking of the for loop
-- range bounds here, since they were frozen with constant declarations
-- and it is during that process that the validity checking is done.
- -- Handle the case where we have a for loop with the range type being an
- -- enumeration type with non-standard representation. In this case we
- -- expand:
-
- -- for x in [reverse] a .. b loop
- -- ...
- -- end loop;
-
- -- to
-
- -- for xP in [reverse] integer
- -- range etype'Pos (a) .. etype'Pos (b) loop
- -- declare
- -- x : constant etype := Pos_To_Rep (xP);
- -- begin
- -- ...
- -- end;
- -- end loop;
-
- if Present (Loop_Parameter_Specification (Isc)) then
+ elsif Present (Loop_Parameter_Specification (Isc)) then
declare
LPS : constant Node_Id := Loop_Parameter_Specification (Isc);
Loop_Id : constant Entity_Id := Defining_Identifier (LPS);
@@ -3026,95 +3017,129 @@ package body Exp_Ch5 is
New_Id : Entity_Id;
begin
- if not Is_Enumeration_Type (Btype)
- or else No (Enum_Pos_To_Rep (Btype))
+ -- Deal with loop over predicates
+
+ if Is_Discrete_Type (Ltype)
+ and then Present (Predicate_Function (Ltype))
then
- return;
- end if;
+ Expand_Predicated_Loop (N);
- New_Id :=
- Make_Defining_Identifier (Loc,
- Chars => New_External_Name (Chars (Loop_Id), 'P'));
+ -- Handle the case where we have a for loop with the range type
+ -- being an enumeration type with non-standard representation.
+ -- In this case we expand:
+
+ -- for x in [reverse] a .. b loop
+ -- ...
+ -- end loop;
+
+ -- to
+
+ -- for xP in [reverse] integer
+ -- range etype'Pos (a) .. etype'Pos (b)
+ -- loop
+ -- declare
+ -- x : constant etype := Pos_To_Rep (xP);
+ -- begin
+ -- ...
+ -- end;
+ -- end loop;
- -- If the type has a contiguous representation, successive values
- -- can be generated as offsets from the first literal.
+ elsif Is_Enumeration_Type (Btype)
+ and then Present (Enum_Pos_To_Rep (Btype))
+ then
+ New_Id :=
+ Make_Defining_Identifier (Loc,
+ Chars => New_External_Name (Chars (Loop_Id), 'P'));
- if Has_Contiguous_Rep (Btype) then
- Expr :=
- Unchecked_Convert_To (Btype,
- Make_Op_Add (Loc,
- Left_Opnd =>
- Make_Integer_Literal (Loc,
- Enumeration_Rep (First_Literal (Btype))),
- Right_Opnd => New_Reference_To (New_Id, Loc)));
- else
- -- Use the constructed array Enum_Pos_To_Rep
+ -- If the type has a contiguous representation, successive
+ -- values can be generated as offsets from the first literal.
- Expr :=
- Make_Indexed_Component (Loc,
- Prefix => New_Reference_To (Enum_Pos_To_Rep (Btype), Loc),
- Expressions => New_List (New_Reference_To (New_Id, Loc)));
- end if;
+ if Has_Contiguous_Rep (Btype) then
+ Expr :=
+ Unchecked_Convert_To (Btype,
+ Make_Op_Add (Loc,
+ Left_Opnd =>
+ Make_Integer_Literal (Loc,
+ Enumeration_Rep (First_Literal (Btype))),
+ Right_Opnd => New_Reference_To (New_Id, Loc)));
+ else
+ -- Use the constructed array Enum_Pos_To_Rep
- Rewrite (N,
- Make_Loop_Statement (Loc,
- Identifier => Identifier (N),
+ Expr :=
+ Make_Indexed_Component (Loc,
+ Prefix =>
+ New_Reference_To (Enum_Pos_To_Rep (Btype), Loc),
+ Expressions =>
+ New_List (New_Reference_To (New_Id, Loc)));
+ end if;
- Iteration_Scheme =>
- Make_Iteration_Scheme (Loc,
- Loop_Parameter_Specification =>
- Make_Loop_Parameter_Specification (Loc,
- Defining_Identifier => New_Id,
- Reverse_Present => Reverse_Present (LPS),
+ Rewrite (N,
+ Make_Loop_Statement (Loc,
+ Identifier => Identifier (N),
- Discrete_Subtype_Definition =>
- Make_Subtype_Indication (Loc,
+ Iteration_Scheme =>
+ Make_Iteration_Scheme (Loc,
+ Loop_Parameter_Specification =>
+ Make_Loop_Parameter_Specification (Loc,
+ Defining_Identifier => New_Id,
+ Reverse_Present => Reverse_Present (LPS),
- Subtype_Mark =>
- New_Reference_To (Standard_Natural, Loc),
+ Discrete_Subtype_Definition =>
+ Make_Subtype_Indication (Loc,
- Constraint =>
- Make_Range_Constraint (Loc,
- Range_Expression =>
- Make_Range (Loc,
-
- Low_Bound =>
- Make_Attribute_Reference (Loc,
- Prefix =>
- New_Reference_To (Btype, Loc),
-
- Attribute_Name => Name_Pos,
-
- Expressions => New_List (
- Relocate_Node
- (Type_Low_Bound (Ltype)))),
-
- High_Bound =>
- Make_Attribute_Reference (Loc,
- Prefix =>
- New_Reference_To (Btype, Loc),
-
- Attribute_Name => Name_Pos,
-
- Expressions => New_List (
- Relocate_Node
- (Type_High_Bound (Ltype))))))))),
-
- Statements => New_List (
- Make_Block_Statement (Loc,
- Declarations => New_List (
- Make_Object_Declaration (Loc,
- Defining_Identifier => Loop_Id,
- Constant_Present => True,
- Object_Definition => New_Reference_To (Ltype, Loc),
- Expression => Expr)),
+ Subtype_Mark =>
+ New_Reference_To (Standard_Natural, Loc),
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => Statements (N)))),
+ Constraint =>
+ Make_Range_Constraint (Loc,
+ Range_Expression =>
+ Make_Range (Loc,
+
+ Low_Bound =>
+ Make_Attribute_Reference (Loc,
+ Prefix =>
+ New_Reference_To (Btype, Loc),
+
+ Attribute_Name => Name_Pos,
+
+ Expressions => New_List (
+ Relocate_Node
+ (Type_Low_Bound (Ltype)))),
+
+ High_Bound =>
+ Make_Attribute_Reference (Loc,
+ Prefix =>
+ New_Reference_To (Btype, Loc),
+
+ Attribute_Name => Name_Pos,
+
+ Expressions => New_List (
+ Relocate_Node
+ (Type_High_Bound
+ (Ltype))))))))),
+
+ Statements => New_List (
+ Make_Block_Statement (Loc,
+ Declarations => New_List (
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => Loop_Id,
+ Constant_Present => True,
+ Object_Definition =>
+ New_Reference_To (Ltype, Loc),
+ Expression => Expr)),
+
+ Handled_Statement_Sequence =>
+ Make_Handled_Sequence_Of_Statements (Loc,
+ Statements => Statements (N)))),
- End_Label => End_Label (N)));
- Analyze (N);
+ End_Label => End_Label (N)));
+ Analyze (N);
+
+ -- Nothing to do with other cases of for loops
+
+ else
+ null;
+ end if;
end;
-- Second case, if we have a while loop with Condition_Actions set, then
@@ -3162,6 +3187,8 @@ package body Exp_Ch5 is
Analyze (N);
end;
+ -- Here to deal with iterator case
+
elsif Present (Isc)
and then Present (Iterator_Specification (Isc))
then
@@ -3169,6 +3196,215 @@ package body Exp_Ch5 is
end if;
end Expand_N_Loop_Statement;
+ ----------------------------
+ -- Expand_Predicated_Loop --
+ ----------------------------
+
+ -- Note: the expander can handle generation of loops over predicated
+ -- subtypes for both the dynamic and static cases. Depending on what
+ -- we decide is allowed in Ada 2012 mode and/or extentions allowed
+ -- mode, the semantic analyzer may disallow one or both forms.
+
+ procedure Expand_Predicated_Loop (N : Node_Id) is
+ Loc : constant Source_Ptr := Sloc (N);
+ Isc : constant Node_Id := Iteration_Scheme (N);
+ LPS : constant Node_Id := Loop_Parameter_Specification (Isc);
+ Loop_Id : constant Entity_Id := Defining_Identifier (LPS);
+ Ltype : constant Entity_Id := Etype (Loop_Id);
+ Stat : constant List_Id := Static_Predicate (Ltype);
+ Stmts : constant List_Id := Statements (N);
+
+ begin
+ -- Case of iteration over non-static predicate. In this case we
+ -- generate the sequence:
+
+ -- for J in Ltype'First .. Ltype'Last loop
+ -- if Ltype_Predicate_Function (J) then
+ -- body;
+ -- end if;
+ -- end loop;
+
+ if No (Stat) then
+
+ -- The analyzer already expanded the First/Last, so all we have
+ -- to do is wrap the body within the predicate function test.
+
+ Set_Statements (N, New_List (
+ Make_If_Statement (Loc,
+ Condition =>
+ Make_Predicate_Call (Ltype, New_Occurrence_Of (Loop_Id, Loc)),
+ Then_Statements => Stmts)));
+ Analyze (First (Statements (N)));
+
+ -- For expansion over a static predicate we generate the following
+
+ -- declare
+ -- J : Ltype := min-val;
+ -- begin
+ -- loop
+ -- body
+ -- case J is
+ -- when endpoint => J := startpoint;
+ -- when endpoint => J := startpoint;
+ -- ...
+ -- when max-val => exit;
+ -- when others => J := Lval'Succ (J);
+ -- end case;
+ -- end loop;
+ -- end;
+
+ -- To make this a little clearer, let's take a specific example:
+
+ -- type Int is range 1 .. 10;
+ -- subtype L is Int with
+ -- predicate => L in 3 | 10 | 5 .. 7;
+ -- ...
+ -- for L in StaticP loop
+ -- Put_Line ("static:" & J'Img);
+ -- end loop;
+
+ -- In this case, the loop is transformed into
+
+ -- begin
+ -- J : L := 3;
+ -- loop
+ -- body
+ -- case J is
+ -- when 3 => J := 5;
+ -- when 7 => J := 10;
+ -- when 10 => exit;
+ -- when others => J := L'Succ (J);
+ -- end case;
+ -- end loop;
+ -- end;
+
+ else
+ Static_Predicate : declare
+ S : Node_Id;
+ D : Node_Id;
+ P : Node_Id;
+ Alts : List_Id;
+ Cstm : Node_Id;
+
+ function Lo_Val (N : Node_Id) return Node_Id;
+ -- Given static expression or static range, returns an identifier
+ -- whose value is the low bound of the expression value or range.
+
+ function Hi_Val (N : Node_Id) return Node_Id;
+ -- Given static expression or static range, returns an identifier
+ -- whose value is the high bound of the expression value or range.
+
+ ------------
+ -- Hi_Val --
+ ------------
+
+ function Hi_Val (N : Node_Id) return Node_Id is
+ begin
+ if Is_Static_Expression (N) then
+ return New_Copy (N);
+ else
+ pragma Assert (Nkind (N) = N_Range);
+ return New_Copy (High_Bound (N));
+ end if;
+ end Hi_Val;
+
+ ------------
+ -- Lo_Val --
+ ------------
+
+ function Lo_Val (N : Node_Id) return Node_Id is
+ begin
+ if Is_Static_Expression (N) then
+ return New_Copy (N);
+ else
+ pragma Assert (Nkind (N) = N_Range);
+ return New_Copy (Low_Bound (N));
+ end if;
+ end Lo_Val;
+
+ -- Start of processing for Static_Predicate
+
+ begin
+ -- Convert loop identifier to normal variable and reanalyze it so
+ -- that this conversion works. We have to use the same defining
+ -- identifier, since there may be references in the loop body.
+
+ Set_Analyzed (Loop_Id, False);
+ Set_Ekind (Loop_Id, E_Variable);
+
+ -- Loop to create branches of case statement
+
+ Alts := New_List;
+ P := First (Stat);
+ while Present (P) loop
+ if No (Next (P)) then
+ S := Make_Exit_Statement (Loc);
+ else
+ S :=
+ Make_Assignment_Statement (Loc,
+ Name => New_Occurrence_Of (Loop_Id, Loc),
+ Expression => Lo_Val (Next (P)));
+ Set_Suppress_Assignment_Checks (S);
+ end if;
+
+ Append_To (Alts,
+ Make_Case_Statement_Alternative (Loc,
+ Statements => New_List (S),
+ Discrete_Choices => New_List (Hi_Val (P))));
+
+ Next (P);
+ end loop;
+
+ -- Add others choice
+
+ S :=
+ Make_Assignment_Statement (Loc,
+ Name => New_Occurrence_Of (Loop_Id, Loc),
+ Expression =>
+ Make_Attribute_Reference (Loc,
+ Prefix => New_Occurrence_Of (Ltype, Loc),
+ Attribute_Name => Name_Succ,
+ Expressions => New_List (
+ New_Occurrence_Of (Loop_Id, Loc))));
+ Set_Suppress_Assignment_Checks (S);
+
+ Append_To (Alts,
+ Make_Case_Statement_Alternative (Loc,
+ Discrete_Choices => New_List (Make_Others_Choice (Loc)),
+ Statements => New_List (S)));
+
+ -- Construct case statement and append to body statements
+
+ Cstm :=
+ Make_Case_Statement (Loc,
+ Expression => New_Occurrence_Of (Loop_Id, Loc),
+ Alternatives => Alts);
+ Append_To (Stmts, Cstm);
+
+ -- Rewrite the loop
+
+ D :=
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => Loop_Id,
+ Object_Definition => New_Occurrence_Of (Ltype, Loc),
+ Expression => Lo_Val (First (Stat)));
+ Set_Suppress_Assignment_Checks (D);
+
+ Rewrite (N,
+ Make_Block_Statement (Loc,
+ Declarations => New_List (D),
+ Handled_Statement_Sequence =>
+ Make_Handled_Sequence_Of_Statements (Loc,
+ Statements => New_List (
+ Make_Loop_Statement (Loc,
+ Statements => Stmts,
+ End_Label => Empty)))));
+
+ Analyze (N);
+ end Static_Predicate;
+ end if;
+ end Expand_Predicated_Loop;
+
------------------------------
-- Make_Tag_Ctrl_Assignment --
------------------------------
===================================================================
@@ -1832,18 +1832,34 @@ package body Sem_Ch5 is
return;
end if;
- -- The subtype indication may denote the completion of an
- -- incomplete type declaration.
+ -- Some additional checks if we are iterating through a type
if Is_Entity_Name (DS)
and then Present (Entity (DS))
and then Is_Type (Entity (DS))
- and then Ekind (Entity (DS)) = E_Incomplete_Type
then
- Set_Entity (DS, Get_Full_View (Entity (DS)));
- Set_Etype (DS, Entity (DS));
+ -- The subtype indication may denote the completion of an
+ -- incomplete type declaration.
+
+ if Ekind (Entity (DS)) = E_Incomplete_Type then
+ Set_Entity (DS, Get_Full_View (Entity (DS)));
+ Set_Etype (DS, Entity (DS));
+ end if;
+
+ -- Attempt to iterate through non-static predicate
+
+ if Is_Discrete_Type (Entity (DS))
+ and then Present (Predicate_Function (Entity (DS)))
+ and then No (Static_Predicate (Entity (DS)))
+ then
+ Bad_Predicated_Subtype_Use
+ ("cannot use subtype& with non-static "
+ & "predicate for loop iteration", DS, Entity (DS));
+ end if;
end if;
+ -- Error if not discrete type
+
if not Is_Discrete_Type (Etype (DS)) then
Wrong_Type (DS, Any_Discrete);
Set_Etype (DS, Any_Type);
===================================================================
@@ -5407,9 +5407,13 @@ package body Exp_Attr is
-- These checks are not generated for modular types, since the proper
-- semantics for Succ and Pred on modular types is to wrap, not raise CE.
+ -- We also suppress these checks if we are the right side of an assignment
+ -- statement or the expression of an object declaration, where the flag
+ -- Suppress_Assignment_Checks is set for the assignment/declaration.
procedure Expand_Pred_Succ (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
+ P : constant Node_Id := Parent (N);
Cnam : Name_Id;
begin
@@ -5419,18 +5423,22 @@ package body Exp_Attr is
Cnam := Name_Last;
end if;
- Insert_Action (N,
- Make_Raise_Constraint_Error (Loc,
- Condition =>
- Make_Op_Eq (Loc,
- Left_Opnd =>
- Duplicate_Subexpr_Move_Checks (First (Expressions (N))),
- Right_Opnd =>
- Make_Attribute_Reference (Loc,
- Prefix =>
- New_Reference_To (Base_Type (Etype (Prefix (N))), Loc),
- Attribute_Name => Cnam)),
- Reason => CE_Overflow_Check_Failed));
+ if not Nkind_In (P, N_Assignment_Statement, N_Object_Declaration)
+ or else not Suppress_Assignment_Checks (P)
+ then
+ Insert_Action (N,
+ Make_Raise_Constraint_Error (Loc,
+ Condition =>
+ Make_Op_Eq (Loc,
+ Left_Opnd =>
+ Duplicate_Subexpr_Move_Checks (First (Expressions (N))),
+ Right_Opnd =>
+ Make_Attribute_Reference (Loc,
+ Prefix =>
+ New_Reference_To (Base_Type (Etype (Prefix (N))), Loc),
+ Attribute_Name => Cnam)),
+ Reason => CE_Overflow_Check_Failed));
+ end if;
end Expand_Pred_Succ;
-------------------
===================================================================
@@ -2851,6 +2851,15 @@ package body Sinfo is
return Node5 (N);
end Subtype_Indication;
+ function Suppress_Assignment_Checks
+ (N : Node_Id) return Boolean is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Assignment_Statement
+ or else NT (N).Nkind = N_Object_Declaration);
+ return Flag18 (N);
+ end Suppress_Assignment_Checks;
+
function Suppress_Loop_Warnings
(N : Node_Id) return Boolean is
begin
@@ -5886,6 +5895,15 @@ package body Sinfo is
Set_List2_With_Parent (N, Val);
end Set_Subtype_Marks;
+ procedure Set_Suppress_Assignment_Checks
+ (N : Node_Id; Val : Boolean := True) is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Assignment_Statement
+ or else NT (N).Nkind = N_Object_Declaration);
+ Set_Flag18 (N, Val);
+ end Set_Suppress_Assignment_Checks;
+
procedure Set_Suppress_Loop_Warnings
(N : Node_Id; Val : Boolean := True) is
begin
===================================================================
@@ -1733,6 +1733,13 @@ package Sinfo is
-- value of a type whose size is not known at compile time on the
-- secondary stack.
+ -- Suppress_Assignment_Checks (Flag18-Sem)
+ -- Used in genererated N_Assignment_Statement nodes to suppress predicate
+ -- and range checks in cases where the generated code knows that the
+ -- value being assigned is in range and satisifies any predicate. Also
+ -- can be set in N_Object_Declaration nodes, to similarly suppress any
+ -- checks on the initializing value.
+
-- Suppress_Loop_Warnings (Flag17-Sem)
-- Used in N_Loop_Statement node to indicate that warnings within the
-- body of the loop should be suppressed. This is set when the range
@@ -2331,6 +2338,7 @@ package Sinfo is
-- Exception_Junk (Flag8-Sem)
-- Is_Subprogram_Descriptor (Flag16-Sem)
-- Has_Init_Expression (Flag14)
+ -- Suppress_Assignment_Checks (Flag18-Sem)
-------------------------------------
-- 3.3.1 Defining Identifier List --
@@ -4052,9 +4060,10 @@ package Sinfo is
-- Backwards_OK (Flag6-Sem)
-- No_Ctrl_Actions (Flag7-Sem)
-- Componentwise_Assignment (Flag14-Sem)
+ -- Suppress_Assignment_Checks (Flag18-Sem)
-- Note: if a range check is required, then the Do_Range_Check flag
- -- is set in the Expression (right hand side), with the check being
+ -- is set in the Expression (right hand side), with the check b6ing
-- done against the type of the Name (left hand side).
-- Note: the back end places some restrictions on the form of the
@@ -8844,6 +8853,9 @@ package Sinfo is
function Subtype_Marks
(N : Node_Id) return List_Id; -- List2
+ function Suppress_Assignment_Checks
+ (N : Node_Id) return Boolean; -- Flag18
+
function Suppress_Loop_Warnings
(N : Node_Id) return Boolean; -- Flag17
@@ -9804,6 +9816,9 @@ package Sinfo is
procedure Set_Subtype_Marks
(N : Node_Id; Val : List_Id); -- List2
+ procedure Set_Suppress_Assignment_Checks
+ (N : Node_Id; Val : Boolean := True); -- Flag18
+
procedure Set_Suppress_Loop_Warnings
(N : Node_Id; Val : Boolean := True); -- Flag17
@@ -11899,6 +11914,7 @@ package Sinfo is
pragma Inline (Subtype_Indication);
pragma Inline (Subtype_Mark);
pragma Inline (Subtype_Marks);
+ pragma Inline (Suppress_Assignment_Checks);
pragma Inline (Suppress_Loop_Warnings);
pragma Inline (Synchronized_Present);
pragma Inline (Tagged_Present);
@@ -12215,6 +12231,7 @@ package Sinfo is
pragma Inline (Set_Subtype_Indication);
pragma Inline (Set_Subtype_Mark);
pragma Inline (Set_Subtype_Marks);
+ pragma Inline (Set_Suppress_Assignment_Checks);
pragma Inline (Set_Suppress_Loop_Warnings);
pragma Inline (Set_Synchronized_Present);
pragma Inline (Set_Tagged_Present);
===================================================================
@@ -3749,6 +3749,15 @@ package body Checks is
return;
end if;
+ -- Do not set range check flag if parent is assignment statement or
+ -- object declaration with Suppress_Assignment_Checks flag set
+
+ if Nkind_In (Parent (N), N_Assignment_Statement, N_Object_Declaration)
+ and then Suppress_Assignment_Checks (Parent (N))
+ then
+ return;
+ end if;
+
-- Check for various cases where we should suppress the range check
-- No check if range checks suppressed for type of node
===================================================================
@@ -866,8 +866,8 @@ package body Sem_Case is
or else No (Static_Predicate (E))
then
Bad_Predicated_Subtype_Use
- ("cannot use subtype& with non-static "
- & "predicate as case alternative", N, E);
+ ("cannot use subtype& with non-static "
+ & "predicate as case alternative", Choice, E);
-- Static predicate case
===================================================================
@@ -4398,23 +4398,17 @@ package body Exp_Ch4 is
procedure Substitute_Valid_Check is
begin
- -- Don't do this for type with predicates, since we don't care in
- -- this case if it gets optimized away, the critical test is the
- -- call to the predicate function
-
- if not Has_Predicates (Ltyp) then
- Rewrite (N,
- Make_Attribute_Reference (Loc,
- Prefix => Relocate_Node (Lop),
- Attribute_Name => Name_Valid));
-
- Analyze_And_Resolve (N, Restyp);
-
- Error_Msg_N ("?explicit membership test may be optimized away", N);
- Error_Msg_N -- CODEFIX
- ("\?use ''Valid attribute instead", N);
- return;
- end if;
+ Rewrite (N,
+ Make_Attribute_Reference (Loc,
+ Prefix => Relocate_Node (Lop),
+ Attribute_Name => Name_Valid));
+
+ Analyze_And_Resolve (N, Restyp);
+
+ Error_Msg_N ("?explicit membership test may be optimized away", N);
+ Error_Msg_N -- CODEFIX
+ ("\?use ''Valid attribute instead", N);
+ return;
end Substitute_Valid_Check;
-- Start of processing for Expand_N_In
@@ -4437,7 +4431,9 @@ package body Exp_Ch4 is
-- subtype. This is suspicious usage and we replace it with a 'Valid
-- test and give a warning. For floating point types however, this is a
-- standard way to check for finite numbers, and using 'Valid would
- -- typically be a pessimization.
+ -- typically be a pessimization. Also skip this test for predicated
+ -- types, since it is perfectly reasonable to check if a value meets
+ -- its predicate.
if Is_Scalar_Type (Ltyp)
and then not Is_Floating_Point_Type (Ltyp)
@@ -4445,7 +4441,8 @@ package body Exp_Ch4 is
and then Ltyp = Entity (Rop)
and then Comes_From_Source (N)
and then VM_Target = No_VM
- and then No (Predicate_Function (Rtyp))
+ and then not (Is_Discrete_Type (Ltyp)
+ and then Present (Predicate_Function (Ltyp)))
then
Substitute_Valid_Check;
return;
@@ -4688,22 +4685,25 @@ package body Exp_Ch4 is
-- type if they come from the original type definition. Also this
-- way we get all the processing above for an explicit range.
- -- Don't do this for a type with predicates, since we would lose
- -- the predicate from this rewriting (test goes to base type).
+ -- Don't do this for predicated types, since in this case we
+ -- want to check the predicate!
+
+ elsif Is_Scalar_Type (Typ) then
+ if No (Predicate_Function (Typ)) then
+ Rewrite (Rop,
+ Make_Range (Loc,
+ Low_Bound =>
+ Make_Attribute_Reference (Loc,
+ Attribute_Name => Name_First,
+ Prefix => New_Reference_To (Typ, Loc)),
+
+ High_Bound =>
+ Make_Attribute_Reference (Loc,
+ Attribute_Name => Name_Last,
+ Prefix => New_Reference_To (Typ, Loc))));
+ Analyze_And_Resolve (N, Restyp);
+ end if;
- elsif Is_Scalar_Type (Typ) and then not Has_Predicates (Typ) then
- Rewrite (Rop,
- Make_Range (Loc,
- Low_Bound =>
- Make_Attribute_Reference (Loc,
- Attribute_Name => Name_First,
- Prefix => New_Reference_To (Typ, Loc)),
-
- High_Bound =>
- Make_Attribute_Reference (Loc,
- Attribute_Name => Name_Last,
- Prefix => New_Reference_To (Typ, Loc))));
- Analyze_And_Resolve (N, Restyp);
goto Leave;
-- Ada 2005 (AI-216): Program_Error is raised when evaluating
@@ -4843,24 +4843,33 @@ package body Exp_Ch4 is
<<Leave>>
- -- If a predicate is present, then we do the predicate test
+ -- If a predicate is present, then we do the predicate test, but we
+ -- most certainly want to omit this if we are within the predicate
+ -- function itself, since otherwise we have an infinite recursion!
- if Present (Predicate_Function (Rtyp)) then
- Rewrite (N,
- Make_And_Then (Loc,
- Left_Opnd => Relocate_Node (N),
- Right_Opnd => Make_Predicate_Call (Rtyp, Lop)));
+ declare
+ PFunc : constant Entity_Id := Predicate_Function (Rtyp);
- -- Analyze new expression, mark left operand as analyzed to
- -- avoid infinite recursion adding predicate calls.
+ begin
+ if Present (PFunc)
+ and then Current_Scope /= PFunc
+ then
+ Rewrite (N,
+ Make_And_Then (Loc,
+ Left_Opnd => Relocate_Node (N),
+ Right_Opnd => Make_Predicate_Call (Rtyp, Lop)));
- Set_Analyzed (Left_Opnd (N));
- Analyze_And_Resolve (N, Standard_Boolean);
+ -- Analyze new expression, mark left operand as analyzed to
+ -- avoid infinite recursion adding predicate calls.
- -- All done, skip attempt at compile time determination of result
+ Set_Analyzed (Left_Opnd (N));
+ Analyze_And_Resolve (N, Standard_Boolean);
- return;
- end if;
+ -- All done, skip attempt at compile time determination of result
+
+ return;
+ end if;
+ end;
end Expand_N_In;
--------------------------------
===================================================================
@@ -3890,10 +3890,12 @@ package body Sem_Ch13 is
-- Output info message on inheritance if required. Note we do not
-- give this information for generic actual types, since it is
- -- unwelcome noise in that case in instantiations.
+ -- unwelcome noise in that case in instantiations. We also
+ -- generally suppress the message in instantiations.
if Opt.List_Inherited_Aspects
and then not Is_Generic_Actual_Type (Typ)
+ and then Instantiation_Depth (Sloc (Typ)) = 0
then
Error_Msg_Sloc := Sloc (Predicate_Function (T));
Error_Msg_Node_2 := T;
@@ -4317,6 +4319,43 @@ package body Sem_Ch13 is
-- now we can store the result as the predicate list.
Set_Static_Predicate (Typ, Plist);
+
+ -- The processing for static predicates coalesced ranges and also
+ -- eliminated duplicates. We might as well replace the alternatives
+ -- list of the right operand of the membership test with the static
+ -- predicate list, which will be more efficient.
+
+ declare
+ New_Alts : constant List_Id := New_List;
+ Old_Node : Node_Id;
+ New_Node : Node_Id;
+
+ begin
+ Old_Node := First (Plist);
+ while Present (Old_Node) loop
+ New_Node := New_Copy (Old_Node);
+
+ if Nkind (New_Node) = N_Range then
+ Set_Low_Bound (New_Node, New_Copy (Low_Bound (Old_Node)));
+ Set_High_Bound (New_Node, New_Copy (High_Bound (Old_Node)));
+ end if;
+
+ Append_To (New_Alts, New_Node);
+ Next (Old_Node);
+ end loop;
+
+ -- Now update the membership test node
+
+ pragma Assert (Nkind (Expr) = N_In);
+
+ if List_Length (New_Alts) = 1 then
+ Set_Right_Opnd (Expr, First (New_Alts));
+ Set_Alternatives (Expr, No_List);
+ else
+ Set_Alternatives (Expr, New_Alts);
+ Set_Right_Opnd (Expr, Empty);
+ end if;
+ end;
end Build_Static_Predicate;
-- Start of processing for Build_Predicate_Function
===================================================================
@@ -4516,7 +4516,8 @@ package body Exp_Ch3 is
-- there is an initializing expression, or for default initialization
-- when we have at least one case of an explicit default initial value.
- if Present (Predicate_Function (Typ))
+ if not Suppress_Assignment_Checks (N)
+ and then Present (Predicate_Function (Typ))
and then
(Present (Expr)
or else
@@ -5029,7 +5030,11 @@ package body Exp_Ch3 is
if Do_Range_Check (Expr) then
Set_Do_Range_Check (Expr, False);
- Generate_Range_Check (Expr, Typ, CE_Range_Check_Failed);
+
+ if not Suppress_Assignment_Checks (N) then
+ Generate_Range_Check
+ (Expr, Typ, CE_Range_Check_Failed);
+ end if;
end if;
end if;
end if;