summaryrefslogtreecommitdiff
path: root/gcc/ada/exp_ch6.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/exp_ch6.adb')
-rw-r--r--gcc/ada/exp_ch6.adb1092
1 files changed, 1065 insertions, 27 deletions
diff --git a/gcc/ada/exp_ch6.adb b/gcc/ada/exp_ch6.adb
index d48544fdada..adc0987fc44 100644
--- a/gcc/ada/exp_ch6.adb
+++ b/gcc/ada/exp_ch6.adb
@@ -3947,7 +3947,7 @@ package body Exp_Ch6 is
-- result from the secondary stack.
if Needs_Finalization (Etype (Subp)) then
- if not Is_Immutably_Limited_Type (Etype (Subp))
+ if not Is_Limited_View (Etype (Subp))
and then
(No (First_Formal (Subp))
or else
@@ -4311,7 +4311,7 @@ package body Exp_Ch6 is
if No (Checks) then
Checks :=
- Make_If_Statement (Loc,
+ Make_Implicit_If_Statement (CCs,
Condition => Cond,
Then_Statements => New_List (Error));
@@ -4481,7 +4481,7 @@ package body Exp_Ch6 is
-- end if;
Append_To (Decls,
- Make_If_Statement (Loc,
+ Make_Implicit_If_Statement (CCs,
Condition => Relocate_Node (Case_Guard),
Then_Statements => New_List (
Set (Flag),
@@ -4536,7 +4536,7 @@ package body Exp_Ch6 is
end if;
CG_Checks :=
- Make_If_Statement (Loc,
+ Make_Implicit_If_Statement (CCs,
Condition =>
Make_Op_Eq (Loc,
Left_Opnd => New_Reference_To (Count, Loc),
@@ -7100,7 +7100,7 @@ package body Exp_Ch6 is
then
null;
- elsif Is_Immutably_Limited_Type (Typ) then
+ elsif Is_Limited_View (Typ) then
Set_Returns_By_Ref (Spec_Id);
elsif Present (Utyp) and then CW_Or_Has_Controlled_Part (Utyp) then
@@ -7702,7 +7702,7 @@ package body Exp_Ch6 is
-- the type of the expression may be.
if not Comes_From_Extended_Return_Statement (N)
- and then Is_Immutably_Limited_Type (Etype (Expression (N)))
+ and then Is_Limited_View (Etype (Expression (N)))
and then Ada_Version >= Ada_2005
and then not Debug_Flag_Dot_L
@@ -7781,7 +7781,7 @@ package body Exp_Ch6 is
-- type that requires special processing (indicated by the fact that
-- it requires a cleanup scope for the secondary stack case).
- if Is_Immutably_Limited_Type (Exptyp)
+ if Is_Limited_View (Exptyp)
or else Is_Limited_Interface (Exptyp)
then
null;
@@ -8084,8 +8084,9 @@ package body Exp_Ch6 is
-- AI05-0073: If function has a controlling access result, check that
-- the tag of the return value, if it is not null, matches designated
-- type of return type.
- -- The return expression is referenced twice in the code below, so
- -- it must be made free of side effects. Given that different compilers
+
+ -- The return expression is referenced twice in the code below, so it
+ -- must be made free of side effects. Given that different compilers
-- may evaluate these parameters in different order, both occurrences
-- perform a copy.
@@ -8489,6 +8490,1050 @@ package body Exp_Ch6 is
end Expand_Simple_Function_Return;
--------------------------------
+ -- Expand_Subprogram_Contract --
+ --------------------------------
+
+ procedure Expand_Subprogram_Contract
+ (N : Node_Id;
+ Spec_Id : Entity_Id;
+ Body_Id : Entity_Id)
+ is
+ procedure Add_Invariant_And_Predicate_Checks
+ (Subp_Id : Entity_Id;
+ Stmts : in out List_Id;
+ Result : out Node_Id);
+ -- Process the result of function Subp_Id (if applicable) and all its
+ -- formals. Add invariant and predicate checks where applicable. The
+ -- routine appends all the checks to list Stmts. If Subp_Id denotes a
+ -- function, Result contains the entity of parameter _Result, to be
+ -- used in the creation of procedure _Postconditions.
+
+ procedure Append_Enabled_Item (Item : Node_Id; List : in out List_Id);
+ -- Append a node to a list. If there is no list, create a new one. When
+ -- the item denotes a pragma, it is added to the list only when it is
+ -- enabled.
+
+ procedure Build_Postconditions_Procedure
+ (Subp_Id : Entity_Id;
+ Stmts : List_Id;
+ Result : Entity_Id);
+ -- Create the body of procedure _Postconditions which handles various
+ -- assertion actions on exit from subprogram Subp_Id. Stmts is the list
+ -- of statements to be checked on exit. Parameter Result is the entity
+ -- of parameter _Result when Subp_Id denotes a function.
+
+ function Build_Pragma_Check_Equivalent
+ (Prag : Node_Id;
+ Subp_Id : Entity_Id := Empty;
+ Inher_Id : Entity_Id := Empty) return Node_Id;
+ -- Transform a [refined] pre- or postcondition denoted by Prag into an
+ -- equivalent pragma Check. When the pre- or postcondition is inherited,
+ -- the routine corrects the references of all formals of Inher_Id to
+ -- point to the formals of Subp_Id.
+
+ procedure Collect_Body_Postconditions (Stmts : in out List_Id);
+ -- Process all postconditions found in the declarations of the body. The
+ -- routine appends the pragma Check equivalents to list Stmts.
+
+ procedure Collect_Spec_Postconditions
+ (Subp_Id : Entity_Id;
+ Stmts : in out List_Id);
+ -- Process all [inherited] postconditions of subprogram spec Subp_Id.
+ -- The routine appends the pragma Check equivalents to list Stmts.
+
+ procedure Collect_Spec_Preconditions (Subp_Id : Entity_Id);
+ -- Process all [inherited] preconditions of subprogram spec Subp_Id. The
+ -- routine prepends the pragma Check equivalents to the declarations of
+ -- the body.
+
+ procedure Prepend_To_Declarations (Item : Node_Id);
+ -- Prepend a single item to the declarations of the subprogram body
+
+ procedure Process_Contract_Cases
+ (Subp_Id : Entity_Id;
+ Stmts : in out List_Id);
+ -- Process pragma Contract_Cases of subprogram spec Subp_Id. The routine
+ -- appends the expanded code to list Stmts.
+
+ ----------------------------------------
+ -- Add_Invariant_And_Predicate_Checks --
+ ----------------------------------------
+
+ procedure Add_Invariant_And_Predicate_Checks
+ (Subp_Id : Entity_Id;
+ Stmts : in out List_Id;
+ Result : out Node_Id)
+ is
+ procedure Add_Invariant_Access_Checks (Id : Entity_Id);
+ -- Id denotes the return value of a function or a formal parameter.
+ -- Add an invariant check if the type of Id is access to a type with
+ -- invariants. The routine appends the generated code to Stmts.
+
+ function Invariant_Checks_OK (Typ : Entity_Id) return Boolean;
+ -- Determine whether type Typ can benefit from invariant checks. To
+ -- qualify, the type must have a non-null invariant procedure and
+ -- subprogram Subp_Id must appear visible from the point of view of
+ -- the type.
+
+ function Predicate_Checks_OK (Typ : Entity_Id) return Boolean;
+ -- Determine whether type Typ can benefit from predicate checks. To
+ -- qualify, the type must have at least one checked predicate.
+
+ ---------------------------------
+ -- Add_Invariant_Access_Checks --
+ ---------------------------------
+
+ procedure Add_Invariant_Access_Checks (Id : Entity_Id) is
+ Loc : constant Source_Ptr := Sloc (N);
+ Ref : Node_Id;
+ Typ : Entity_Id;
+
+ begin
+ Typ := Etype (Id);
+
+ if Is_Access_Type (Typ) and then not Is_Access_Constant (Typ) then
+ Typ := Designated_Type (Typ);
+
+ if Invariant_Checks_OK (Typ) then
+ Ref :=
+ Make_Explicit_Dereference (Loc,
+ Prefix => New_Occurrence_Of (Id, Loc));
+ Set_Etype (Ref, Typ);
+
+ -- Generate:
+ -- if <Id> /= null then
+ -- <invariant_call (<Ref>)>
+ -- end if;
+
+ Append_Enabled_Item
+ (Item =>
+ Make_If_Statement (Loc,
+ Condition =>
+ Make_Op_Ne (Loc,
+ Left_Opnd => New_Occurrence_Of (Id, Loc),
+ Right_Opnd => Make_Null (Loc)),
+ Then_Statements => New_List (
+ Make_Invariant_Call (Ref))),
+ List => Stmts);
+ end if;
+ end if;
+ end Add_Invariant_Access_Checks;
+
+ -------------------------
+ -- Invariant_Checks_OK --
+ -------------------------
+
+ function Invariant_Checks_OK (Typ : Entity_Id) return Boolean is
+ function Has_Null_Body (Proc_Id : Entity_Id) return Boolean;
+ -- Determine whether the body of procedure Proc_Id contains a sole
+ -- null statement, possibly followed by an optional return.
+
+ function Has_Public_Visibility_Of_Subprogram return Boolean;
+ -- Determine whether type Typ has public visibility of subprogram
+ -- Subp_Id.
+
+ -------------------
+ -- Has_Null_Body --
+ -------------------
+
+ function Has_Null_Body (Proc_Id : Entity_Id) return Boolean is
+ Body_Id : Entity_Id;
+ Decl : Node_Id;
+ Spec : Node_Id;
+ Stmt1 : Node_Id;
+ Stmt2 : Node_Id;
+
+ begin
+ Spec := Parent (Proc_Id);
+ Decl := Parent (Spec);
+
+ -- Retrieve the entity of the invariant procedure body
+
+ if Nkind (Spec) = N_Procedure_Specification
+ and then Nkind (Decl) = N_Subprogram_Declaration
+ then
+ Body_Id := Corresponding_Body (Decl);
+
+ -- The body acts as a spec
+
+ else
+ Body_Id := Proc_Id;
+ end if;
+
+ -- The body will be generated later
+
+ if No (Body_Id) then
+ return False;
+ end if;
+
+ Spec := Parent (Body_Id);
+ Decl := Parent (Spec);
+
+ pragma Assert
+ (Nkind (Spec) = N_Procedure_Specification
+ and then Nkind (Decl) = N_Subprogram_Body);
+
+ Stmt1 := First (Statements (Handled_Statement_Sequence (Decl)));
+
+ -- Look for a null statement followed by an optional return
+ -- statement.
+
+ if Nkind (Stmt1) = N_Null_Statement then
+ Stmt2 := Next (Stmt1);
+
+ if Present (Stmt2) then
+ return Nkind (Stmt2) = N_Simple_Return_Statement;
+ else
+ return True;
+ end if;
+ end if;
+
+ return False;
+ end Has_Null_Body;
+
+ -----------------------------------------
+ -- Has_Public_Visibility_Of_Subprogram --
+ -----------------------------------------
+
+ function Has_Public_Visibility_Of_Subprogram return Boolean is
+ Subp_Decl : constant Node_Id := Unit_Declaration_Node (Subp_Id);
+ Vis_Decls : constant List_Id :=
+ Visible_Declarations (Specification
+ (Unit_Declaration_Node (Scope (Typ))));
+ begin
+ -- An Initialization procedure must be considered visible even
+ -- though it is internally generated.
+
+ if Is_Init_Proc (Defining_Entity (Subp_Decl)) then
+ return True;
+
+ -- Internally generated code is never publicly visible except
+ -- for a subprogram that is the implementation of an expression
+ -- function. In that case the visibility is determined by the
+ -- last check.
+
+ elsif not Comes_From_Source (Subp_Decl)
+ and then
+ (Nkind (Original_Node (Subp_Decl)) /= N_Expression_Function
+ or else not
+ Comes_From_Source (Defining_Entity (Subp_Decl)))
+ then
+ return False;
+
+ -- Determine whether the subprogram is declared in the visible
+ -- declarations of the package containing the type.
+
+ else
+ return List_Containing (Subp_Decl) = Vis_Decls;
+ end if;
+ end Has_Public_Visibility_Of_Subprogram;
+
+ -- Start of processing for Invariant_Checks_OK
+
+ begin
+ return
+ Has_Invariants (Typ)
+ and then Present (Invariant_Procedure (Typ))
+ and then not Has_Null_Body (Invariant_Procedure (Typ))
+ and then Has_Public_Visibility_Of_Subprogram;
+ end Invariant_Checks_OK;
+
+ -------------------------
+ -- Predicate_Checks_OK --
+ -------------------------
+
+ function Predicate_Checks_OK (Typ : Entity_Id) return Boolean is
+ function Has_Checked_Predicate return Boolean;
+ -- Determine whether type Typ has or inherits at least one
+ -- predicate aspect or pragma, for which the applicable policy is
+ -- Checked.
+
+ ---------------------------
+ -- Has_Checked_Predicate --
+ ---------------------------
+
+ function Has_Checked_Predicate return Boolean is
+ Anc : Entity_Id;
+ Pred : Node_Id;
+
+ begin
+ -- Climb the ancestor type chain staring from the input. This
+ -- is done because the input type may lack aspect/pragma
+ -- predicate and simply inherit those from its ancestor.
+
+ -- Note that predicate pragmas include all three cases of
+ -- predicate aspects (Predicate, Dynamic_Predicate,
+ -- Static_Predicate), so this routine checks for all three
+ -- cases.
+
+ Anc := Typ;
+ while Present (Anc) loop
+ Pred := Get_Pragma (Anc, Pragma_Predicate);
+
+ if Present (Pred) and then not Is_Ignored (Pred) then
+ return True;
+ end if;
+
+ Anc := Nearest_Ancestor (Anc);
+ end loop;
+
+ return False;
+ end Has_Checked_Predicate;
+
+ -- Start of processing for Predicate_Checks_OK
+
+ begin
+ return
+ Has_Predicates (Typ)
+ and then Present (Predicate_Function (Typ))
+ and then Has_Checked_Predicate;
+ end Predicate_Checks_OK;
+
+ -- Local variables
+
+ Loc : constant Source_Ptr := Sloc (N);
+ Formal : Entity_Id;
+ Typ : Entity_Id;
+
+ -- Start of processing for Add_Invariant_And_Predicate_Checks
+
+ begin
+ Result := Empty;
+
+ -- Do not generate any checks if no code is being generated
+
+ if not Expander_Active then
+ return;
+ end if;
+
+ -- Process the result of a function
+
+ if Ekind_In (Subp_Id, E_Function, E_Generic_Function) then
+ Typ := Etype (Subp_Id);
+
+ -- Generate _Result which is used in procedure _Postconditions to
+ -- verify the return value.
+
+ Result := Make_Defining_Identifier (Loc, Name_uResult);
+ Set_Etype (Result, Typ);
+
+ -- Add an invariant check when the return type has invariants and
+ -- the related function is visible to the outside.
+
+ if Invariant_Checks_OK (Typ) then
+ Append_Enabled_Item
+ (Item =>
+ Make_Invariant_Call (New_Occurrence_Of (Result, Loc)),
+ List => Stmts);
+ end if;
+
+ -- Add an invariant check when the return type is an access to a
+ -- type with invariants.
+
+ Add_Invariant_Access_Checks (Result);
+ end if;
+
+ -- Add invariant and predicates for all formals that qualify
+
+ Formal := First_Formal (Subp_Id);
+ while Present (Formal) loop
+ Typ := Etype (Formal);
+
+ if Ekind (Formal) /= E_In_Parameter
+ or else Is_Access_Type (Typ)
+ then
+ if Invariant_Checks_OK (Typ) then
+ Append_Enabled_Item
+ (Item =>
+ Make_Invariant_Call (New_Occurrence_Of (Formal, Loc)),
+ List => Stmts);
+ end if;
+
+ Add_Invariant_Access_Checks (Formal);
+
+ if Predicate_Checks_OK (Typ) then
+ Append_Enabled_Item
+ (Item =>
+ Make_Predicate_Check
+ (Typ, New_Reference_To (Formal, Loc)),
+ List => Stmts);
+ end if;
+ end if;
+
+ Next_Formal (Formal);
+ end loop;
+ end Add_Invariant_And_Predicate_Checks;
+
+ -------------------------
+ -- Append_Enabled_Item --
+ -------------------------
+
+ procedure Append_Enabled_Item (Item : Node_Id; List : in out List_Id) is
+ begin
+ -- Do not chain ignored or disabled pragmas
+
+ if Nkind (Item) = N_Pragma
+ and then (Is_Ignored (Item) or else Is_Disabled (Item))
+ then
+ null;
+
+ -- Add the item
+
+ else
+ if No (List) then
+ List := New_List;
+ end if;
+
+ Append (Item, List);
+ end if;
+ end Append_Enabled_Item;
+
+ ------------------------------------
+ -- Build_Postconditions_Procedure --
+ ------------------------------------
+
+ procedure Build_Postconditions_Procedure
+ (Subp_Id : Entity_Id;
+ Stmts : List_Id;
+ Result : Entity_Id)
+ is
+ procedure Insert_After_Last_Declaration (Stmt : Node_Id);
+ -- Insert node Stmt after the last declaration of the subprogram body
+
+ -----------------------------------
+ -- Insert_After_Last_Declaration --
+ -----------------------------------
+
+ procedure Insert_After_Last_Declaration (Stmt : Node_Id) is
+ Decls : List_Id := Declarations (N);
+
+ begin
+ -- Ensure that the body has a declaration list
+
+ if No (Decls) then
+ Decls := New_List;
+ Set_Declarations (N, Decls);
+ end if;
+
+ Append_To (Decls, Stmt);
+ end Insert_After_Last_Declaration;
+
+ -- Local variables
+
+ Loc : constant Source_Ptr := Sloc (N);
+ Params : List_Id := No_List;
+ Proc_Id : Entity_Id;
+
+ -- Start of processing for Build_Postconditions_Procedure
+
+ begin
+ -- Do not create the routine if no code is being generated
+
+ if not Expander_Active then
+ return;
+
+ -- Nothing to do if there are no actions to check on exit
+
+ elsif No (Stmts) then
+ return;
+ end if;
+
+ Proc_Id := Make_Defining_Identifier (Loc, Name_uPostconditions);
+
+ -- The related subprogram is a function, create the specification of
+ -- parameter _Result.
+
+ if Present (Result) then
+ Params := New_List (
+ Make_Parameter_Specification (Loc,
+ Defining_Identifier => Result,
+ Parameter_Type =>
+ New_Reference_To (Etype (Result), Loc)));
+ end if;
+
+ -- Insert _Postconditions after the last declaration of the body.
+ -- This ensures that the body will not cause any premature freezing
+ -- as it may mention types:
+
+ -- procedure Proc (Obj : Array_Typ) is
+ -- procedure _postconditions is
+ -- begin
+ -- ... Obj ...
+ -- end _postconditions;
+
+ -- subtype T is Array_Typ (Obj'First (1) .. Obj'Last (1));
+ -- begin
+
+ -- In the example above, Obj is of type T but the incorrect placement
+ -- of _Postconditions will cause a crash in gigi due to an out of
+ -- order reference. The body of _Postconditions must be placed after
+ -- the declaration of Temp to preserve correct visibility.
+
+ Insert_After_Last_Declaration (
+ Make_Subprogram_Body (Loc,
+ Specification =>
+ Make_Procedure_Specification (Loc,
+ Defining_Unit_Name => Proc_Id,
+ Parameter_Specifications => Params),
+
+ Declarations => Empty_List,
+ Handled_Statement_Sequence =>
+ Make_Handled_Sequence_Of_Statements (Loc, Stmts)));
+
+ -- Set the attributes of the related subprogram to capture the
+ -- generated procedure.
+
+ if Ekind_In (Subp_Id, E_Generic_Procedure, E_Procedure) then
+ Set_Postcondition_Proc (Subp_Id, Proc_Id);
+ end if;
+
+ Set_Has_Postconditions (Subp_Id);
+ end Build_Postconditions_Procedure;
+
+ -----------------------------------
+ -- Build_Pragma_Check_Equivalent --
+ -----------------------------------
+
+ function Build_Pragma_Check_Equivalent
+ (Prag : Node_Id;
+ Subp_Id : Entity_Id := Empty;
+ Inher_Id : Entity_Id := Empty) return Node_Id
+ is
+ Loc : constant Source_Ptr := Sloc (Prag);
+ Prag_Nam : constant Name_Id := Pragma_Name (Prag);
+ Check_Prag : Node_Id;
+ Formals_Map : Elist_Id;
+ Inher_Formal : Entity_Id;
+ Msg_Arg : Node_Id;
+ Nam : Name_Id;
+ Subp_Formal : Entity_Id;
+
+ begin
+ Formals_Map := No_Elist;
+
+ -- When the pre- or postcondition is inherited, map the formals of
+ -- the inherited subprogram to those of the current subprogram.
+
+ if Present (Inher_Id) then
+ pragma Assert (Present (Subp_Id));
+
+ Formals_Map := New_Elmt_List;
+
+ -- Create a relation <inherited formal> => <subprogram formal>
+
+ Inher_Formal := First_Formal (Inher_Id);
+ Subp_Formal := First_Formal (Subp_Id);
+ while Present (Inher_Formal) and then Present (Subp_Formal) loop
+ Append_Elmt (Inher_Formal, Formals_Map);
+ Append_Elmt (Subp_Formal, Formals_Map);
+
+ Next_Formal (Inher_Formal);
+ Next_Formal (Subp_Formal);
+ end loop;
+ end if;
+
+ -- Copy the original pragma while performing substitutions (if
+ -- applicable).
+
+ Check_Prag :=
+ New_Copy_Tree
+ (Source => Prag,
+ Map => Formals_Map,
+ New_Scope => Current_Scope);
+
+ -- Mark the pragma as being internally generated and reset the
+ -- Analyzed flag.
+
+ Set_Comes_From_Source (Check_Prag, False);
+ Set_Analyzed (Check_Prag, False);
+
+ -- For a postcondition pragma within a generic, preserve the pragma
+ -- for later expansion. This is also used when an error was detected,
+ -- thus setting Expander_Active to False.
+
+ if Prag_Nam = Name_Postcondition and then not Expander_Active then
+ return Check_Prag;
+ end if;
+
+ if Present (Corresponding_Aspect (Prag)) then
+ Nam := Chars (Identifier (Corresponding_Aspect (Prag)));
+ else
+ Nam := Prag_Nam;
+ end if;
+
+ -- Convert the copy into pragma Check by correcting the name and
+ -- adding a check_kind argument.
+
+ Set_Pragma_Identifier
+ (Check_Prag, Make_Identifier (Loc, Name_Check));
+
+ Prepend_To (Pragma_Argument_Associations (Check_Prag),
+ Make_Pragma_Argument_Association (Loc,
+ Expression => Make_Identifier (Loc, Nam)));
+
+ -- Update the error message when the pragma is inherited
+
+ if Present (Inher_Id) then
+ Msg_Arg := Last (Pragma_Argument_Associations (Check_Prag));
+
+ if Chars (Msg_Arg) = Name_Message then
+ String_To_Name_Buffer (Strval (Expression (Msg_Arg)));
+
+ -- Insert "inherited" to improve the error message
+
+ if Name_Buffer (1 .. 8) = "failed p" then
+ Insert_Str_In_Name_Buffer ("inherited ", 8);
+ Set_Strval (Expression (Msg_Arg), String_From_Name_Buffer);
+ end if;
+ end if;
+ end if;
+
+ return Check_Prag;
+ end Build_Pragma_Check_Equivalent;
+
+ ---------------------------------
+ -- Collect_Body_Postconditions --
+ ---------------------------------
+
+ procedure Collect_Body_Postconditions (Stmts : in out List_Id) is
+ procedure Collect_Body_Postconditions_Of_Kind (Post_Nam : Name_Id);
+ -- Process postconditions of a particular kind denoted by Post_Nam
+
+ -----------------------------------------
+ -- Collect_Body_Postconditions_Of_Kind --
+ -----------------------------------------
+
+ procedure Collect_Body_Postconditions_Of_Kind (Post_Nam : Name_Id) is
+ Check_Prag : Node_Id;
+ Decl : Node_Id;
+
+ begin
+ pragma Assert (Nam_In (Post_Nam, Name_Postcondition,
+ Name_Refined_Post));
+
+ -- Inspect the declarations of the subprogram body looking for a
+ -- pragma that matches the desired name.
+
+ Decl := First (Declarations (N));
+ while Present (Decl) loop
+ if Nkind (Decl) = N_Pragma then
+ if Pragma_Name (Decl) = Post_Nam then
+ Analyze (Decl);
+ Check_Prag := Build_Pragma_Check_Equivalent (Decl);
+
+ if Expander_Active then
+ Append_Enabled_Item
+ (Item => Check_Prag,
+ List => Stmts);
+
+ -- When analyzing a generic unit, save the pragma for
+ -- later.
+
+ else
+ Prepend_To_Declarations (Check_Prag);
+ end if;
+ end if;
+
+ -- Skip internally generated code
+
+ elsif not Comes_From_Source (Decl) then
+ null;
+
+ -- Postconditions in bodies are usually grouped at the top of
+ -- the declarations. There is no point in inspecting the whole
+ -- source list.
+
+ else
+ exit;
+ end if;
+
+ Next (Decl);
+ end loop;
+ end Collect_Body_Postconditions_Of_Kind;
+
+ -- Start of processing for Collect_Body_Postconditions
+
+ begin
+ Collect_Body_Postconditions_Of_Kind (Name_Refined_Post);
+ Collect_Body_Postconditions_Of_Kind (Name_Postcondition);
+ end Collect_Body_Postconditions;
+
+ ---------------------------------
+ -- Collect_Spec_Postconditions --
+ ---------------------------------
+
+ procedure Collect_Spec_Postconditions
+ (Subp_Id : Entity_Id;
+ Stmts : in out List_Id)
+ is
+ Inher_Subps : constant Subprogram_List :=
+ Inherited_Subprograms (Subp_Id);
+ Check_Prag : Node_Id;
+ Prag : Node_Id;
+ Inher_Subp_Id : Entity_Id;
+
+ begin
+ -- Process the contract of the spec
+
+ Prag := Pre_Post_Conditions (Contract (Subp_Id));
+ while Present (Prag) loop
+ if Pragma_Name (Prag) = Name_Postcondition then
+ Check_Prag := Build_Pragma_Check_Equivalent (Prag);
+
+ if Expander_Active then
+ Append_Enabled_Item
+ (Item => Check_Prag,
+ List => Stmts);
+
+ -- When analyzing a generic unit, save the pragma for later
+
+ else
+ Prepend_To_Declarations (Check_Prag);
+ end if;
+ end if;
+
+ Prag := Next_Pragma (Prag);
+ end loop;
+
+ -- Process the contracts of all inherited subprograms, looking for
+ -- class-wide postconditions.
+
+ for Index in Inher_Subps'Range loop
+ Inher_Subp_Id := Inher_Subps (Index);
+
+ Prag := Pre_Post_Conditions (Contract (Inher_Subp_Id));
+ while Present (Prag) loop
+ if Pragma_Name (Prag) = Name_Postcondition
+ and then Class_Present (Prag)
+ then
+ Check_Prag :=
+ Build_Pragma_Check_Equivalent
+ (Prag => Prag,
+ Subp_Id => Subp_Id,
+ Inher_Id => Inher_Subp_Id);
+
+ if Expander_Active then
+ Append_Enabled_Item
+ (Item => Check_Prag,
+ List => Stmts);
+
+ -- When analyzing a generic unit, save the pragma for later
+
+ else
+ Prepend_To_Declarations (Check_Prag);
+ end if;
+ end if;
+
+ Prag := Next_Pragma (Prag);
+ end loop;
+ end loop;
+ end Collect_Spec_Postconditions;
+
+ --------------------------------
+ -- Collect_Spec_Preconditions --
+ --------------------------------
+
+ procedure Collect_Spec_Preconditions (Subp_Id : Entity_Id) is
+ procedure Merge_Preconditions (From : Node_Id; Into : Node_Id);
+ -- Merge two class-wide preconditions by "or else"-ing them. The
+ -- changes are accumulated in parameter Into. Update the error
+ -- message of Into.
+
+ -------------------------
+ -- Merge_Preconditions --
+ -------------------------
+
+ procedure Merge_Preconditions (From : Node_Id; Into : Node_Id) is
+ function Expression_Arg (Prag : Node_Id) return Node_Id;
+ -- Return the boolean expression argument of a precondition while
+ -- updating its parenteses count for the subsequent merge.
+
+ function Message_Arg (Prag : Node_Id) return Node_Id;
+ -- Return the message argument of a precondition
+
+ --------------------
+ -- Expression_Arg --
+ --------------------
+
+ function Expression_Arg (Prag : Node_Id) return Node_Id is
+ Args : constant List_Id := Pragma_Argument_Associations (Prag);
+ Arg : constant Node_Id := Get_Pragma_Arg (Next (First (Args)));
+
+ begin
+ if Paren_Count (Arg) = 0 then
+ Set_Paren_Count (Arg, 1);
+ end if;
+
+ return Arg;
+ end Expression_Arg;
+
+ -----------------
+ -- Message_Arg --
+ -----------------
+
+ function Message_Arg (Prag : Node_Id) return Node_Id is
+ Args : constant List_Id := Pragma_Argument_Associations (Prag);
+ begin
+ return Get_Pragma_Arg (Last (Args));
+ end Message_Arg;
+
+ -- Local variables
+
+ From_Expr : constant Node_Id := Expression_Arg (From);
+ From_Msg : constant Node_Id := Message_Arg (From);
+ Into_Expr : constant Node_Id := Expression_Arg (Into);
+ Into_Msg : constant Node_Id := Message_Arg (Into);
+ Loc : constant Source_Ptr := Sloc (Into);
+
+ -- Start of processing for Merge_Preconditions
+
+ begin
+ -- Merge the two preconditions by "or else"-ing them
+
+ Rewrite (Into_Expr,
+ Make_Or_Else (Loc,
+ Right_Opnd => Relocate_Node (Into_Expr),
+ Left_Opnd => From_Expr));
+
+ -- Merge the two error messages to produce a single message of the
+ -- form:
+
+ -- failed precondition from ...
+ -- also failed inherited precondition from ...
+
+ if not Exception_Locations_Suppressed then
+ Start_String (Strval (Into_Msg));
+ Store_String_Char (ASCII.LF);
+ Store_String_Chars (" also ");
+ Store_String_Chars (Strval (From_Msg));
+
+ Set_Strval (Into_Msg, End_String);
+ end if;
+ end Merge_Preconditions;
+
+ -- Local variables
+
+ Inher_Subps : constant Subprogram_List :=
+ Inherited_Subprograms (Subp_Id);
+ Check_Prag : Node_Id;
+ Class_Pre : Node_Id := Empty;
+ Inher_Subp_Id : Entity_Id;
+ Prag : Node_Id;
+
+ -- Start of processing for Collect_Spec_Preconditions
+
+ begin
+ -- Process the contract of the spec
+
+ Prag := Pre_Post_Conditions (Contract (Subp_Id));
+ while Present (Prag) loop
+ if Pragma_Name (Prag) = Name_Precondition then
+ Check_Prag := Build_Pragma_Check_Equivalent (Prag);
+
+ -- Save the sole class-wide precondition (if any) for the next
+ -- step where it will be merged with inherited preconditions.
+
+ if Class_Present (Prag) then
+ Class_Pre := Check_Prag;
+
+ -- Accumulate the corresponding Check pragmas to the top of the
+ -- declarations. Prepending the items ensures that they will
+ -- be evaluated in their original order.
+
+ else
+ Prepend_To_Declarations (Check_Prag);
+ end if;
+ end if;
+
+ Prag := Next_Pragma (Prag);
+ end loop;
+
+ -- Process the contracts of all inherited subprograms, looking for
+ -- class-wide preconditions.
+
+ for Index in Inher_Subps'Range loop
+ Inher_Subp_Id := Inher_Subps (Index);
+
+ Prag := Pre_Post_Conditions (Contract (Inher_Subp_Id));
+ while Present (Prag) loop
+ if Pragma_Name (Prag) = Name_Precondition
+ and then Class_Present (Prag)
+ then
+ Check_Prag :=
+ Build_Pragma_Check_Equivalent
+ (Prag => Prag,
+ Subp_Id => Subp_Id,
+ Inher_Id => Inher_Subp_Id);
+
+ -- The spec or an inherited subprogram already yielded a
+ -- class-wide precondition. Merge the existing precondition
+ -- with the current one using "or else".
+
+ if Present (Class_Pre) then
+ Merge_Preconditions (Check_Prag, Class_Pre);
+ else
+ Class_Pre := Check_Prag;
+ end if;
+ end if;
+
+ Prag := Next_Pragma (Prag);
+ end loop;
+ end loop;
+
+ -- Add the merged class-wide preconditions (if any)
+
+ if Present (Class_Pre) then
+ Prepend_To_Declarations (Class_Pre);
+ end if;
+ end Collect_Spec_Preconditions;
+
+ -----------------------------
+ -- Prepend_To_Declarations --
+ -----------------------------
+
+ procedure Prepend_To_Declarations (Item : Node_Id) is
+ Decls : List_Id := Declarations (N);
+
+ begin
+ -- Ensure that the body has a declarative list
+
+ if No (Decls) then
+ Decls := New_List;
+ Set_Declarations (N, Decls);
+ end if;
+
+ Prepend_To (Decls, Item);
+ end Prepend_To_Declarations;
+
+ ----------------------------
+ -- Process_Contract_Cases --
+ ----------------------------
+
+ procedure Process_Contract_Cases
+ (Subp_Id : Entity_Id;
+ Stmts : in out List_Id)
+ is
+ Prag : Node_Id;
+
+ begin
+ -- Do not build the Contract_Cases circuitry if no code is being
+ -- generated.
+
+ if not Expander_Active then
+ return;
+ end if;
+
+ Prag := Contract_Test_Cases (Contract (Subp_Id));
+ while Present (Prag) loop
+ if Pragma_Name (Prag) = Name_Contract_Cases then
+ Expand_Contract_Cases
+ (CCs => Prag,
+ Subp_Id => Subp_Id,
+ Decls => Declarations (N),
+ Stmts => Stmts);
+ end if;
+
+ Prag := Next_Pragma (Prag);
+ end loop;
+ end Process_Contract_Cases;
+
+ -- Local variables
+
+ Post_Stmts : List_Id := No_List;
+ Result : Entity_Id;
+ Subp_Id : Entity_Id;
+
+ -- Start of processing for Expand_Subprogram_Contract
+
+ begin
+ if Present (Spec_Id) then
+ Subp_Id := Spec_Id;
+ else
+ Subp_Id := Body_Id;
+ end if;
+
+ -- Do not process a predicate function as its body will end up with a
+ -- recursive call to itself and blow up the stack.
+
+ if Ekind (Subp_Id) = E_Function
+ and then Is_Predicate_Function (Subp_Id)
+ then
+ return;
+
+ -- Do not process TSS subprograms
+
+ elsif Get_TSS_Name (Subp_Id) /= TSS_Null then
+ return;
+ end if;
+
+ -- The expansion of a subprogram contract involves the relocation of
+ -- various contract assertions to the declarations of the body in a
+ -- particular order. The order is as follows:
+
+ -- function Example (...) return ... is
+ -- procedure _Postconditions (...) is
+ -- begin
+ -- <refined postconditions from body>
+ -- <postconditions from body>
+ -- <postconditions from spec>
+ -- <inherited postconditions>
+ -- <contract cases>
+ -- <invariant check of function result (if applicable)>
+ -- <invariant and predicate checks of parameters>
+ -- end _Postconditions;
+
+ -- <inherited preconditions>
+ -- <preconditions from spec>
+ -- <preconditions from body>
+ -- <refined preconditions from body>
+
+ -- <source declarations>
+ -- begin
+ -- <source statements>
+
+ -- _Preconditions (Result);
+ -- return Result;
+ -- end Example;
+
+ -- Routine _Postconditions holds all contract assertions that must be
+ -- verified on exit from the related routine.
+
+ -- Collect all [inherited] preconditions from the spec, transform them
+ -- into Check pragmas and add them to the declarations of the body in
+ -- the order outlined above.
+
+ if Present (Spec_Id) then
+ Collect_Spec_Preconditions (Spec_Id);
+ end if;
+
+ -- Transform all [refined] postconditions of the body into Check
+ -- pragmas. The resulting pragmas are accumulated in list Post_Stmts.
+
+ Collect_Body_Postconditions (Post_Stmts);
+
+ -- Transform all [inherited] postconditions from the spec into Check
+ -- pragmas. The resulting pragmas are accumulated in list Post_Stmts.
+
+ if Present (Spec_Id) then
+ Collect_Spec_Postconditions (Spec_Id, Post_Stmts);
+
+ -- Transform pragma Contract_Cases from the spec into its circuitry
+
+ Process_Contract_Cases (Spec_Id, Post_Stmts);
+ end if;
+
+ -- Apply invariant and predicate checks on the result of a function (if
+ -- applicable) and all formals. The resulting checks are accumulated in
+ -- list Post_Stmts.
+
+ Add_Invariant_And_Predicate_Checks (Subp_Id, Post_Stmts, Result);
+
+ -- Construct procedure _Postconditions
+
+ Build_Postconditions_Procedure (Subp_Id, Post_Stmts, Result);
+ end Expand_Subprogram_Contract;
+
+ --------------------------------
-- Is_Build_In_Place_Function --
--------------------------------
@@ -8527,7 +9572,7 @@ package body Exp_Ch6 is
-- may return objects of nonlimited descendants.
else
- return Is_Immutably_Limited_Type (Etype (E))
+ return Is_Limited_View (Etype (E))
and then Ada_Version >= Ada_2005
and then not Debug_Flag_Dot_L;
end if;
@@ -8554,7 +9599,11 @@ package body Exp_Ch6 is
-- disabled (such as with -gnatc) since those would trip over the raise
-- of Program_Error below.
- if not Expander_Active then
+ -- In SPARK mode, build-in-place calls are not expanded, so that we
+ -- may end up with a call that is neither resolved to an entity, nor
+ -- an indirect call.
+
+ if not Full_Expander_Active then
return False;
end if;
@@ -8571,14 +9620,7 @@ package body Exp_Ch6 is
return False;
else
- -- In SPARK mode, build-in-place calls are not expanded, so that we
- -- may end up with a call that is neither resolved to an entity, nor
- -- an indirect call.
-
- if SPARK_Mode then
- return False;
-
- elsif Is_Entity_Name (Name (Exp_Node)) then
+ if Is_Entity_Name (Name (Exp_Node)) then
Function_Id := Entity (Name (Exp_Node));
-- In the case of an explicitly dereferenced call, use the subprogram
@@ -8771,7 +9813,7 @@ package body Exp_Ch6 is
Typ : constant Entity_Id := Etype (Subp);
Utyp : constant Entity_Id := Underlying_Type (Typ);
begin
- if Is_Immutably_Limited_Type (Typ) then
+ if Is_Limited_View (Typ) then
Set_Returns_By_Ref (Subp);
elsif Present (Utyp) and then CW_Or_Has_Controlled_Part (Utyp) then
Set_Returns_By_Ref (Subp);
@@ -9047,14 +10089,10 @@ package body Exp_Ch6 is
then
null;
- -- Do not generate the call to Set_Finalize_Address in SPARK mode
- -- because it is not necessary and results in unwanted expansion.
- -- This expansion is also not carried out in CodePeer mode because
- -- Finalize_Address is never built.
+ -- Do not generate the call to Set_Finalize_Address in CodePeer mode
+ -- because Finalize_Address is never built.
- elsif not SPARK_Mode
- and then not CodePeer_Mode
- then
+ elsif not CodePeer_Mode then
Insert_Action (Allocator,
Make_Set_Finalize_Address_Call (Loc,
Typ => Etype (Function_Id),