aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/exp_ch3.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/exp_ch3.adb')
-rw-r--r--gcc/ada/exp_ch3.adb330
1 files changed, 317 insertions, 13 deletions
diff --git a/gcc/ada/exp_ch3.adb b/gcc/ada/exp_ch3.adb
index 066b37d17..af5dadd9a 100644
--- a/gcc/ada/exp_ch3.adb
+++ b/gcc/ada/exp_ch3.adb
@@ -88,6 +88,22 @@ package body Exp_Ch3 is
-- used for attachment of any actions required in its construction.
-- It also supplies the source location used for the procedure.
+ function Build_Array_Invariant_Proc
+ (A_Type : Entity_Id;
+ Nod : Node_Id) return Node_Id;
+ -- If the component of type of array type has invariants, build procedure
+ -- that checks invariant on all components of the array. Ada 2012 specifies
+ -- that an invariant on some type T must be applied to in-out parameters
+ -- and return values that include a part of type T. If the array type has
+ -- an otherwise specified invariant, the component check procedure is
+ -- called from within the user-specified invariant. Otherwise this becomes
+ -- the invariant procedure for the array type.
+
+ function Build_Record_Invariant_Proc
+ (R_Type : Entity_Id;
+ Nod : Node_Id) return Node_Id;
+ -- Ditto for record types.
+
function Build_Discriminant_Formals
(Rec_Id : Entity_Id;
Use_Dl : Boolean) return List_Id;
@@ -180,6 +196,14 @@ package body Exp_Ch3 is
-- Treat user-defined stream operations as renaming_as_body if the
-- subprogram they rename is not frozen when the type is frozen.
+ procedure Insert_Component_Invariant_Checks
+ (N : Node_Id;
+ Typ : Entity_Id;
+ Proc : Node_Id);
+ -- If a composite type has invariants and also has components with defined
+ -- invariants. the component invariant procedure is inserted into the user-
+ -- defined invariant procedure and added to the checks to be performed.
+
procedure Initialization_Warning (E : Entity_Id);
-- If static elaboration of the package is requested, indicate
-- when a type does meet the conditions for static initialization. If
@@ -635,7 +659,7 @@ package body Exp_Ch3 is
-- but it properly belongs with the array type declaration. However, if
-- the freeze node is for a subtype of a type declared in another unit
-- it seems preferable to use the freeze node as the source location of
- -- of the init proc. In any case this is preferable for gcov usage, and
+ -- the init proc. In any case this is preferable for gcov usage, and
-- the Sloc is not otherwise used by the compiler.
if In_Open_Scopes (Scope (A_Type)) then
@@ -784,7 +808,10 @@ package body Exp_Ch3 is
-- Build_Array_Invariant_Proc --
--------------------------------
- procedure Build_Array_Invariant_Proc (A_Type : Entity_Id; Nod : Node_Id) is
+ function Build_Array_Invariant_Proc
+ (A_Type : Entity_Id;
+ Nod : Node_Id) return Node_Id
+ is
Loc : constant Source_Ptr := Sloc (Nod);
Object_Name : constant Name_Id := New_Internal_Name ('I');
@@ -878,9 +905,7 @@ package body Exp_Ch3 is
Proc_Id :=
Make_Defining_Identifier (Loc,
- Chars => New_External_Name (Chars (A_Type), "Invariant"));
- Set_Has_Invariants (Proc_Id);
- Set_Invariant_Procedure (A_Type, Proc_Id);
+ Chars => New_External_Name (Chars (A_Type), "CInvariant"));
Body_Stmts := Check_One_Dimension (1);
@@ -908,10 +933,7 @@ package body Exp_Ch3 is
Set_Debug_Info_Off (Proc_Id);
end if;
- -- The procedure body is placed after the freeze node for the type.
-
- Insert_After (Nod, Proc_Body);
- Analyze (Proc_Body);
+ return Proc_Body;
end Build_Array_Invariant_Proc;
--------------------------------
@@ -3611,6 +3633,207 @@ package body Exp_Ch3 is
end if;
end Build_Record_Init_Proc;
+ --------------------------------
+ -- Build_Record_Invariant_Proc --
+ --------------------------------
+
+ function Build_Record_Invariant_Proc
+ (R_Type : Entity_Id;
+ Nod : Node_Id) return Node_Id
+ is
+ Loc : constant Source_Ptr := Sloc (Nod);
+
+ Object_Name : constant Name_Id := New_Internal_Name ('I');
+ -- Name for argument of invariant procedure
+
+ Object_Entity : constant Node_Id :=
+ Make_Defining_Identifier (Loc, Object_Name);
+ -- The procedure declaration entity for the argument
+
+ Invariant_Found : Boolean;
+ -- Set if any component needs an invariant check.
+
+ Proc_Id : Entity_Id;
+ Proc_Body : Node_Id;
+ Stmts : List_Id;
+ Type_Def : Node_Id;
+
+ function Build_Invariant_Checks (Comp_List : Node_Id) return List_Id;
+ -- Recursive procedure that generates a list of checks for components
+ -- that need it, and recurses through variant parts when present.
+
+ function Build_Component_Invariant_Call (Comp : Entity_Id)
+ return Node_Id;
+ -- Build call to invariant procedure for a record component.
+
+ ------------------------------------
+ -- Build_Component_Invariant_Call --
+ ------------------------------------
+
+ function Build_Component_Invariant_Call (Comp : Entity_Id)
+ return Node_Id
+ is
+ Sel_Comp : Node_Id;
+ Typ : Entity_Id;
+ Call : Node_Id;
+
+ begin
+ Invariant_Found := True;
+ Typ := Etype (Comp);
+
+ Sel_Comp :=
+ Make_Selected_Component (Loc,
+ Prefix => New_Occurrence_Of (Object_Entity, Loc),
+ Selector_Name => New_Occurrence_Of (Comp, Loc));
+
+ if Is_Access_Type (Typ) then
+ Sel_Comp := Make_Explicit_Dereference (Loc, Sel_Comp);
+ Typ := Designated_Type (Typ);
+ end if;
+
+ Call :=
+ Make_Procedure_Call_Statement (Loc,
+ Name =>
+ New_Occurrence_Of (Invariant_Procedure (Typ), Loc),
+ Parameter_Associations => New_List (Sel_Comp));
+
+ if Is_Access_Type (Etype (Comp)) then
+ Call :=
+ Make_If_Statement (Loc,
+ Condition =>
+ Make_Op_Ne (Loc,
+ Left_Opnd => Make_Null (Loc),
+ Right_Opnd =>
+ Make_Selected_Component (Loc,
+ Prefix => New_Occurrence_Of (Object_Entity, Loc),
+ Selector_Name => New_Occurrence_Of (Comp, Loc))),
+ Then_Statements => New_List (Call));
+ end if;
+
+ return Call;
+ end Build_Component_Invariant_Call;
+
+ ----------------------------
+ -- Build_Invariant_Checks --
+ ----------------------------
+
+ function Build_Invariant_Checks (Comp_List : Node_Id) return List_Id is
+ Decl : Node_Id;
+ Id : Entity_Id;
+ Stmts : List_Id;
+
+ begin
+ Stmts := New_List;
+ Decl := First_Non_Pragma (Component_Items (Comp_List));
+ while Present (Decl) loop
+ if Nkind (Decl) = N_Component_Declaration then
+ Id := Defining_Identifier (Decl);
+
+ if Has_Invariants (Etype (Id))
+ and then In_Open_Scopes (Scope (R_Type))
+ then
+ Append_To (Stmts, Build_Component_Invariant_Call (Id));
+
+ elsif Is_Access_Type (Etype (Id))
+ and then not Is_Access_Constant (Etype (Id))
+ and then Has_Invariants (Designated_Type (Etype (Id)))
+ and then In_Open_Scopes (Scope (Designated_Type (Etype (Id))))
+ then
+ Append_To (Stmts, Build_Component_Invariant_Call (Id));
+ end if;
+ end if;
+
+ Next (Decl);
+ end loop;
+
+ if Present (Variant_Part (Comp_List)) then
+ declare
+ Variant_Alts : constant List_Id := New_List;
+ Var_Loc : Source_Ptr;
+ Variant : Node_Id;
+ Variant_Stmts : List_Id;
+
+ begin
+ Variant :=
+ First_Non_Pragma (Variants (Variant_Part (Comp_List)));
+ while Present (Variant) loop
+ Variant_Stmts :=
+ Build_Invariant_Checks (Component_List (Variant));
+ Var_Loc := Sloc (Variant);
+ Append_To (Variant_Alts,
+ Make_Case_Statement_Alternative (Var_Loc,
+ Discrete_Choices =>
+ New_Copy_List (Discrete_Choices (Variant)),
+ Statements => Variant_Stmts));
+
+ Next_Non_Pragma (Variant);
+ end loop;
+
+ -- The expression in the case statement is the reference to
+ -- the discriminant of the target object.
+
+ Append_To (Stmts,
+ Make_Case_Statement (Var_Loc,
+ Expression =>
+ Make_Selected_Component (Var_Loc,
+ Prefix => New_Occurrence_Of (Object_Entity, Var_Loc),
+ Selector_Name => New_Occurrence_Of
+ (Entity
+ (Name (Variant_Part (Comp_List))), Var_Loc)),
+ Alternatives => Variant_Alts));
+ end;
+ end if;
+
+ return Stmts;
+ end Build_Invariant_Checks;
+
+ -- Start of processing for Build_Record_Invariant_Proc
+
+ begin
+ Invariant_Found := False;
+ Type_Def := Type_Definition (Parent (R_Type));
+
+ if Nkind (Type_Def) = N_Record_Definition
+ and then not Null_Present (Type_Def)
+ then
+ Stmts := Build_Invariant_Checks (Component_List (Type_Def));
+ else
+ return Empty;
+ end if;
+
+ if not Invariant_Found then
+ return Empty;
+ end if;
+
+ Proc_Id :=
+ Make_Defining_Identifier (Loc,
+ Chars => New_External_Name (Chars (R_Type), "Invariant"));
+
+ Proc_Body :=
+ Make_Subprogram_Body (Loc,
+ Specification =>
+ Make_Procedure_Specification (Loc,
+ Defining_Unit_Name => Proc_Id,
+ Parameter_Specifications => New_List (
+ Make_Parameter_Specification (Loc,
+ Defining_Identifier => Object_Entity,
+ Parameter_Type => New_Occurrence_Of (R_Type, Loc)))),
+
+ Declarations => Empty_List,
+ Handled_Statement_Sequence =>
+ Make_Handled_Sequence_Of_Statements (Loc,
+ Statements => Stmts));
+
+ Set_Ekind (Proc_Id, E_Procedure);
+ Set_Is_Public (Proc_Id, Is_Public (R_Type));
+ Set_Is_Internal (Proc_Id);
+ Set_Has_Completion (Proc_Id);
+
+ return Proc_Body;
+ -- Insert_After (Nod, Proc_Body);
+ -- Analyze (Proc_Body);
+ end Build_Record_Invariant_Proc;
+
----------------------------
-- Build_Slice_Assignment --
----------------------------
@@ -4910,8 +5133,15 @@ package body Exp_Ch3 is
-- Expr's type, both types share the same dispatch table and there is
-- no need to displace the pointer.
- elsif Comes_From_Source (N)
- and then Is_Interface (Typ)
+ elsif Is_Interface (Typ)
+
+ -- Avoid never-ending recursion because if Equivalent_Type is set
+ -- then we've done it already and must not do it again!
+
+ and then not
+ (Nkind (Object_Definition (N)) = N_Identifier
+ and then
+ Present (Equivalent_Type (Entity (Object_Definition (N)))))
then
pragma Assert (Is_Class_Wide_Type (Typ));
@@ -5195,6 +5425,8 @@ package body Exp_Ch3 is
and then not Is_CPP_Class (Typ)
and then Tagged_Type_Expansion
and then Nkind (Expr) /= N_Aggregate
+ and then (Nkind (Expr) /= N_Qualified_Expression
+ or else Nkind (Expression (Expr)) /= N_Aggregate)
then
declare
Full_Typ : constant Entity_Id := Underlying_Type (Typ);
@@ -5661,8 +5893,17 @@ package body Exp_Ch3 is
Build_Array_Init_Proc (Base, N);
end if;
- if Has_Invariants (Component_Type (Base)) then
- Build_Array_Invariant_Proc (Base, N);
+ if Has_Invariants (Component_Type (Base))
+ and then In_Open_Scopes (Scope (Component_Type (Base)))
+ then
+ -- Generate component invariant checking procedure. This is only
+ -- relevant if the array type is within the scope of the component
+ -- type. Otherwise an array object can only be built using the public
+ -- subprograms for the component type, and calls to those will have
+ -- invariant checks.
+
+ Insert_Component_Invariant_Checks
+ (N, Base, Build_Array_Invariant_Proc (Base, N));
end if;
end Expand_Freeze_Array_Type;
@@ -6630,6 +6871,12 @@ package body Exp_Ch3 is
end loop;
end;
end if;
+
+ -- Check whether individual components have a defined invariant,
+ -- and add the corresponding component invariant checks.
+
+ Insert_Component_Invariant_Checks
+ (N, Def_Id, Build_Record_Invariant_Proc (Def_Id, N));
end Expand_Freeze_Record_Type;
------------------------------
@@ -7394,6 +7641,63 @@ package body Exp_Ch3 is
return Is_RTU (S1, System) or else Is_RTU (S1, Ada);
end In_Runtime;
+ ---------------------------------------
+ -- Insert_Component_Invariant_Checks --
+ ---------------------------------------
+
+ procedure Insert_Component_Invariant_Checks
+ (N : Node_Id;
+ Typ : Entity_Id;
+ Proc : Node_Id)
+ is
+ Loc : constant Source_Ptr := Sloc (Typ);
+ Proc_Id : Entity_Id;
+
+ begin
+ if Present (Proc) then
+ Proc_Id := Defining_Entity (Proc);
+
+ if not Has_Invariants (Typ) then
+ Set_Has_Invariants (Typ);
+ Set_Has_Invariants (Proc_Id);
+ Set_Invariant_Procedure (Typ, Proc_Id);
+ Insert_After (N, Proc);
+ Analyze (Proc);
+
+ else
+
+ -- Find already created invariant body, insert body of component
+ -- invariant proc in it, and add call after other checks.
+
+ declare
+ Bod : Node_Id;
+ Inv_Id : constant Entity_Id := Invariant_Procedure (Typ);
+ Call : constant Node_Id :=
+ Make_Procedure_Call_Statement (Loc,
+ Name => New_Occurrence_Of (Proc_Id, Loc),
+ Parameter_Associations =>
+ New_List
+ (New_Reference_To (First_Formal (Inv_Id), Loc)));
+
+ begin
+
+ -- The invariant body has not been analyzed yet, so we do a
+ -- sequential search forward, and retrieve it by name.
+
+ Bod := Next (N);
+ while Present (Bod) loop
+ exit when Nkind (Bod) = N_Subprogram_Body
+ and then Chars (Defining_Entity (Bod)) = Chars (Inv_Id);
+ Next (Bod);
+ end loop;
+
+ Append_To (Declarations (Bod), Proc);
+ Append_To (Statements (Handled_Statement_Sequence (Bod)), Call);
+ end;
+ end if;
+ end if;
+ end Insert_Component_Invariant_Checks;
+
----------------------------
-- Initialization_Warning --
----------------------------