aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/exp_util.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/exp_util.adb')
-rw-r--r--gcc/ada/exp_util.adb771
1 files changed, 471 insertions, 300 deletions
diff --git a/gcc/ada/exp_util.adb b/gcc/ada/exp_util.adb
index b8c6a9f..9077891 100644
--- a/gcc/ada/exp_util.adb
+++ b/gcc/ada/exp_util.adb
@@ -167,6 +167,9 @@ package body Exp_Util is
-- Force evaluation of bounds of a slice, which may be given by a range
-- or by a subtype indication with or without a constraint.
+ function Is_Expression_Of_Func_Return (N : Node_Id) return Boolean;
+ -- Return True if N is the expression of a function return
+
function Is_Uninitialized_Aggregate
(Exp : Node_Id;
T : Entity_Id) return Boolean;
@@ -1081,10 +1084,12 @@ package body Exp_Util is
Make_Attribute_Reference (Loc,
Prefix =>
(if Is_Allocate then
- Duplicate_Subexpr_No_Checks (Expression (Alloc_Expr))
+ Duplicate_Subexpr_No_Checks
+ (Expression (Alloc_Expr), New_Scope => Proc_Id)
else
Make_Explicit_Dereference (Loc,
- Duplicate_Subexpr_No_Checks (Expr))),
+ Duplicate_Subexpr_No_Checks
+ (Expr, New_Scope => Proc_Id))),
Attribute_Name => Name_Alignment)));
end if;
@@ -1137,7 +1142,9 @@ package body Exp_Util is
if Is_RTE (Etype (Temp), RE_Tag_Ptr) then
Param :=
Make_Explicit_Dereference (Loc,
- Prefix => Duplicate_Subexpr_No_Checks (Temp));
+ Prefix =>
+ Duplicate_Subexpr_No_Checks
+ (Temp, New_Scope => Proc_Id));
-- In the default case, obtain the tag of the object about
-- to be allocated / deallocated. Generate:
@@ -1157,7 +1164,9 @@ package body Exp_Util is
Param :=
Make_Attribute_Reference (Loc,
- Prefix => Duplicate_Subexpr_No_Checks (Temp),
+ Prefix =>
+ Duplicate_Subexpr_No_Checks
+ (Temp, New_Scope => Proc_Id),
Attribute_Name => Name_Tag);
end if;
@@ -1517,7 +1526,228 @@ package body Exp_Util is
New_E := Type_Map.Get (Entity (N));
if Present (New_E) then
- Rewrite (N, New_Occurrence_Of (New_E, Sloc (N)));
+ declare
+
+ Ctrl_Type : constant Entity_Id
+ := Find_Dispatching_Type (Par_Subp);
+
+ function Must_Map_Call_To_Parent_Primitive
+ (Call_Node : Node_Id;
+ Check_Parents : Boolean := True) return Boolean;
+ -- If Call_Node is a call to a primitive function F of the
+ -- tagged type T associated with Par_Subp that either has
+ -- any actuals that involve controlling formals of Par_Subp,
+ -- or else the call to F is an actual parameter of an
+ -- enclosing call to a primitive of T that has any actuals
+ -- that involve controlling formals of Par_Subp (and
+ -- recursively up the tree of enclosing function calls),
+ -- returns True; otherwise returns False. Returning True
+ -- implies that the call to F must be mapped to a call
+ -- that instead targets the corresponding function F of
+ -- the tagged type for which Subp is a primitive function.
+ -- Checks_Parent specifies whether this function should
+ -- recursively check enclosing calls.
+
+ ---------------------------------------
+ -- Must_Map_Call_To_Parent_Primitive --
+ ---------------------------------------
+
+ function Must_Map_Call_To_Parent_Primitive
+ (Call_Node : Node_Id;
+ Check_Parents : Boolean := True) return Boolean
+ is
+ pragma Assert (Nkind (Call_Node) = N_Function_Call);
+
+ Actual : Node_Id := First_Actual (Call_Node);
+
+ function Expr_Has_Ctrl_Formal_Ref
+ (Expr : Node_Id) return Boolean;
+ -- Determines whether Expr is or contains a reference
+ -- to a controlling formal and returns True if so. More
+ -- specifically, if Expr is not directly a reference
+ -- to a formal, it can be an access attribute or Old
+ -- attribute whose immediate object prefix is such
+ -- a reference (possibly through a chain of multiple
+ -- such attributes); or else it can be a dereference
+ -- of a controlling formal; or else it can be either
+ -- a dependent expression of a conditional expression,
+ -- or the expression of a declare expression that
+ -- qualifies as such. Returns True if the expression
+ -- satisifies one of those requirements; otherwise
+ -- returns False.
+
+ ------------------------------
+ -- Expr_Has_Ctrl_Formal_Ref --
+ ------------------------------
+
+ function Expr_Has_Ctrl_Formal_Ref
+ (Expr : Node_Id) return Boolean
+ is
+
+ function Is_Controlling_Formal_Ref
+ (N : Node_Id) return Boolean;
+ -- Returns True if and only if N denotes a reference
+ -- to a controlling formal declared for Par_Subp, or
+ -- Subp as formals may have been rewritten before the
+ -- test happens.
+
+ -------------------------------
+ -- Is_Controlling_Formal_Ref --
+ -------------------------------
+
+ function Is_Controlling_Formal_Ref
+ (N : Node_Id) return Boolean
+ is
+ begin
+ return Nkind (N) in N_Identifier | N_Expanded_Name
+ and then Is_Formal (Entity (N))
+ and then Is_Controlling_Formal (Entity (N))
+ and then Scope (Entity (N)) in Par_Subp | Subp;
+ end Is_Controlling_Formal_Ref;
+
+ -- Start of processing for Expr_Has_Ctrl_Formal_Ref
+
+ begin
+ if (Nkind (Expr) = N_Attribute_Reference
+ and then Attribute_Name (Expr)
+ in Name_Old
+ | Name_Access
+ | Name_Unchecked_Access
+ | Name_Unrestricted_Access)
+ or else Nkind (Expr) = N_Explicit_Dereference
+ then
+ return Expr_Has_Ctrl_Formal_Ref (Prefix (Expr));
+
+ elsif Nkind (Expr) = N_If_Expression then
+ declare
+ Then_Expr : constant Node_Id :=
+ Pick (Expressions (Expr), 2);
+ Else_Expr : constant Node_Id :=
+ Pick (Expressions (Expr), 3);
+ begin
+ return Expr_Has_Ctrl_Formal_Ref (Then_Expr)
+ or else Expr_Has_Ctrl_Formal_Ref (Else_Expr);
+ end;
+
+ elsif Nkind (Expr) = N_Case_Expression then
+ declare
+ Case_Expr_Alt : Node_Id :=
+ First (Alternatives (Expr));
+ begin
+ while Present (Case_Expr_Alt) loop
+ if Expr_Has_Ctrl_Formal_Ref
+ (Expression (Case_Expr_Alt))
+ then
+ return True;
+ end if;
+
+ Next (Case_Expr_Alt);
+ end loop;
+ end;
+
+ return False;
+
+ -- Case of a declare_expression
+
+ elsif Nkind (Expr) = N_Expression_With_Actions
+ and then Comes_From_Source (Expr)
+ then
+ return Expr_Has_Ctrl_Formal_Ref (Expression (Expr));
+
+ -- All other cases must be references to a formal
+
+ else
+ return Is_Controlling_Formal_Ref (Expr);
+ end if;
+ end Expr_Has_Ctrl_Formal_Ref;
+
+ -- Start of processing for Must_Map_Call_To_Parent_Primitive
+
+ begin
+ if Is_Entity_Name (Name (Call_Node))
+ and then Is_Dispatching_Operation
+ (Entity (Name (Call_Node)))
+ and then
+ Is_Ancestor
+ (Ctrl_Type,
+ Find_Dispatching_Type
+ (Entity (Name (Call_Node))))
+ then
+ while Present (Actual) loop
+
+ -- If at least one actual references a controlling
+ -- formal parameter of a class-wide Pre/Post
+ -- aspect's associated subprogram (including
+ -- a direct prefix of an access attribute or
+ -- dereference), the rule in RM 6.1.1(7) applies,
+ -- and we want to map the call to target the
+ -- corresponding function of the derived type.
+
+ if Expr_Has_Ctrl_Formal_Ref (Actual) then
+ return True;
+
+ -- RM 6.1.1(7) also applies to Result attributes
+ -- of primitive functions with controlling results.
+
+ elsif Is_Attribute_Result (Actual)
+ and then Has_Controlling_Result (Subp)
+ then
+ return True;
+
+ -- Recursively check any actuals that are function
+ -- calls with controlling results.
+
+ elsif Nkind (Actual) = N_Function_Call
+ and then
+ Has_Controlling_Result
+ (Entity (Name (Actual)))
+ and then
+ Must_Map_Call_To_Parent_Primitive
+ (Actual, Check_Parents => False)
+ then
+ return True;
+ end if;
+
+ Next_Actual (Actual);
+ end loop;
+
+ -- Recursively check parents that are function calls,
+ -- to handle cases like "F1 (F2, F3 (X))", where
+ -- Call_Node is the call to F2, and we need to map
+ -- F1, F2, and F3 due to the reference to formal X.
+
+ if Check_Parents
+ and then Nkind (Parent (Call_Node)) = N_Function_Call
+ then
+ return Must_Map_Call_To_Parent_Primitive
+ (Parent (Call_Node));
+ end if;
+
+ return False;
+
+ else
+ return False;
+ end if;
+ end Must_Map_Call_To_Parent_Primitive;
+
+ begin
+ -- If N's entity is in the map, then the entity is either
+ -- a formal of the parent subprogram that should necessarily
+ -- be mapped, or it's a function call's target entity that
+ -- that should be mapped if the call involves any actuals
+ -- that reference formals of the parent subprogram (or the
+ -- function call is part of an enclosing call that similarly
+ -- qualifies for mapping). Rewrite a node that references
+ -- any such qualified entity to a new node referencing the
+ -- corresponding entity associated with the derived type.
+
+ if not Is_Subprogram (Entity (N))
+ or else Nkind (Parent (N)) /= N_Function_Call
+ or else Must_Map_Call_To_Parent_Primitive (Parent (N))
+ then
+ Rewrite (N, New_Occurrence_Of (New_E, Sloc (N)));
+ end if;
+ end;
end if;
-- Update type of function call node, which should be the same as
@@ -1956,7 +2186,7 @@ package body Exp_Util is
-- time capture the visibility of the proper package part.
Set_Parent (Expr, Typ_Decl);
- Preanalyze_Assert_Expression (Expr, Any_Boolean);
+ Preanalyze_And_Resolve_Assert_Expression (Expr, Any_Boolean);
-- Save a copy of the expression with all replacements and analysis
-- already taken place in case a derived type inherits the pragma.
@@ -1969,8 +2199,8 @@ package body Exp_Util is
-- If the pragma comes from an aspect specification, replace the
-- saved expression because all type references must be substituted
- -- for the call to Preanalyze_Spec_Expression in Check_Aspect_At_xxx
- -- routines.
+ -- for the call to Preanalyze_And_Resolve_Spec_Expression in
+ -- Check_Aspect_At_xxx routines.
if Present (DIC_Asp) then
Set_Expression_Copy (DIC_Asp, New_Copy_Tree (Expr));
@@ -3217,7 +3447,7 @@ package body Exp_Util is
-- part.
Set_Parent (Expr, Parent (Prag_Expr));
- Preanalyze_Assert_Expression (Expr, Any_Boolean);
+ Preanalyze_And_Resolve_Assert_Expression (Expr, Any_Boolean);
-- Save a copy of the expression when T is tagged to detect
-- errors and capture the visibility of the proper package part
@@ -3229,8 +3459,8 @@ package body Exp_Util is
-- If the pragma comes from an aspect specification, replace
-- the saved expression because all type references must be
- -- substituted for the call to Preanalyze_Spec_Expression in
- -- Check_Aspect_At_xxx routines.
+ -- substituted for the call to Preanalyze_And_Resolve_Spec_
+ -- Expression in Check_Aspect_At_xxx routines.
if Present (Prag_Asp) then
Set_Expression_Copy (Prag_Asp, New_Copy_Tree (Expr));
@@ -5062,12 +5292,13 @@ package body Exp_Util is
function Duplicate_Subexpr
(Exp : Node_Id;
- Name_Req : Boolean := False;
- Renaming_Req : Boolean := False) return Node_Id
+ New_Scope : Entity_Id := Empty;
+ Name_Req : Boolean := False;
+ Renaming_Req : Boolean := False) return Node_Id
is
begin
Remove_Side_Effects (Exp, Name_Req, Renaming_Req);
- return New_Copy_Tree (Exp);
+ return New_Copy_Tree (Exp, New_Scope => New_Scope);
end Duplicate_Subexpr;
---------------------------------
@@ -5076,8 +5307,9 @@ package body Exp_Util is
function Duplicate_Subexpr_No_Checks
(Exp : Node_Id;
- Name_Req : Boolean := False;
- Renaming_Req : Boolean := False) return Node_Id
+ New_Scope : Entity_Id := Empty;
+ Name_Req : Boolean := False;
+ Renaming_Req : Boolean := False) return Node_Id
is
New_Exp : Node_Id;
@@ -5087,7 +5319,7 @@ package body Exp_Util is
Name_Req => Name_Req,
Renaming_Req => Renaming_Req);
- New_Exp := New_Copy_Tree (Exp);
+ New_Exp := New_Copy_Tree (Exp, New_Scope => New_Scope);
Remove_Checks (New_Exp);
return New_Exp;
end Duplicate_Subexpr_No_Checks;
@@ -5098,14 +5330,15 @@ package body Exp_Util is
function Duplicate_Subexpr_Move_Checks
(Exp : Node_Id;
- Name_Req : Boolean := False;
- Renaming_Req : Boolean := False) return Node_Id
+ New_Scope : Entity_Id := Empty;
+ Name_Req : Boolean := False;
+ Renaming_Req : Boolean := False) return Node_Id
is
New_Exp : Node_Id;
begin
Remove_Side_Effects (Exp, Name_Req, Renaming_Req);
- New_Exp := New_Copy_Tree (Exp);
+ New_Exp := New_Copy_Tree (Exp, New_Scope => New_Scope);
Remove_Checks (Exp);
return New_Exp;
end Duplicate_Subexpr_Move_Checks;
@@ -5949,9 +6182,10 @@ package body Exp_Util is
-- now known to be protected, the finalization routine is the one
-- defined on the corresponding record of the ancestor (corresponding
-- records do not automatically inherit operations, but maybe they
- -- should???)
+ -- should???). This does not apply to array types, where every base
+ -- type has a finalization routine that depends on the first subtype.
- if Is_Untagged_Derivation (Btyp) then
+ if Is_Untagged_Derivation (Btyp) and then not Is_Array_Type (Btyp) then
if Is_Protected_Type (Btyp) then
Utyp := Corresponding_Record_Type (Root_Type (Btyp));
@@ -8075,20 +8309,24 @@ package body Exp_Util is
elsif Nkind (Parent (P)) in N_Variant | N_Record_Definition then
null;
- -- Do not insert freeze nodes within the loop generated for
- -- an aggregate, because they may be elaborated too late for
- -- subsequent use in the back end: within a package spec the
- -- loop is part of the elaboration procedure and is only
- -- elaborated during the second pass.
-
- -- If the loop comes from source, or the entity is local to the
- -- loop itself it must remain within.
-
- elsif Nkind (Parent (P)) = N_Loop_Statement
- and then not Comes_From_Source (Parent (P))
+ -- Do not insert freeze nodes within a block or loop generated
+ -- for an aggregate, because they may be elaborated too late
+ -- for subsequent use in the back end: within a package spec,
+ -- the block or loop is part of the elaboration procedure and
+ -- is only elaborated during the second pass.
+
+ -- If the block or loop comes from source, or the entity is
+ -- local to the block or loop itself, it must remain within.
+
+ elsif ((Nkind (Parent (P)) = N_Handled_Sequence_Of_Statements
+ and then
+ Nkind (Parent (Parent (P))) = N_Block_Statement
+ and then not Comes_From_Source (Parent (Parent (P))))
+ or else (Nkind (Parent (P)) = N_Loop_Statement
+ and then not Comes_From_Source (Parent (P))))
and then Nkind (First (Ins_Actions)) = N_Freeze_Entity
- and then
- Scope (Entity (First (Ins_Actions))) /= Current_Scope
+ and then not
+ Within_Scope (Entity (First (Ins_Actions)), Current_Scope)
then
null;
@@ -8103,19 +8341,31 @@ package body Exp_Util is
return;
end if;
- -- the expansion of Task and protected type declarations can
+ -- The expansion of task and protected type declarations can
-- create declarations for temporaries which, like other actions
- -- are inserted and analyzed before the current declaraation.
- -- However, the current scope is the synchronized type, and
- -- for unnesting it is critical that the proper scope for these
- -- generated entities be the enclosing one.
+ -- are inserted and analyzed before the current declaration.
+ -- However, in some cases, the current scope is the synchronized
+ -- type, and for unnesting it is critical that the proper scope
+ -- for these generated entities be the enclosing one.
when N_Task_Type_Declaration
| N_Protected_Type_Declaration =>
- Push_Scope (Scope (Current_Scope));
- Insert_List_Before_And_Analyze (P, Ins_Actions);
- Pop_Scope;
+ declare
+ Skip_Scope : constant Boolean :=
+ Ekind (Current_Scope) in Concurrent_Kind;
+ begin
+ if Skip_Scope then
+ Push_Scope (Scope (Current_Scope));
+ end if;
+
+ Insert_List_Before_And_Analyze (P, Ins_Actions);
+
+ if Skip_Scope then
+ Pop_Scope;
+ end if;
+ end;
+
return;
-- A special case, N_Raise_xxx_Error can act either as a statement
@@ -8563,6 +8813,20 @@ package body Exp_Util is
end if;
end Is_Captured_Function_Call;
+ -------------------------------------------------
+ -- Is_Constr_Array_Subt_Of_Unc_With_Controlled --
+ -------------------------------------------------
+
+ function Is_Constr_Array_Subt_Of_Unc_With_Controlled (Typ : Entity_Id)
+ return Boolean
+ is
+ begin
+ return Is_Array_Type (Typ)
+ and then Is_Constrained (Typ)
+ and then Has_Controlled_Component (Typ)
+ and then not Is_Constrained (First_Subtype (Typ));
+ end Is_Constr_Array_Subt_Of_Unc_With_Controlled;
+
------------------------------------------
-- Is_Conversion_Or_Reference_To_Formal --
------------------------------------------
@@ -8606,6 +8870,97 @@ package body Exp_Util is
and then Nkind (Name (N)) = N_Explicit_Dereference;
end Is_Expanded_Class_Wide_Interface_Object_Decl;
+ ----------------------------------
+ -- Is_Expression_Of_Func_Return --
+ ----------------------------------
+
+ function Is_Expression_Of_Func_Return (N : Node_Id) return Boolean is
+ Par : constant Node_Id := Parent (N);
+
+ begin
+ return Nkind (Par) = N_Simple_Return_Statement
+ or else (Nkind (Par) in N_Object_Declaration
+ | N_Object_Renaming_Declaration
+ and then Is_Return_Object (Defining_Entity (Par)));
+ end Is_Expression_Of_Func_Return;
+
+ ---------------------------
+ -- Is_Finalizable_Access --
+ ---------------------------
+
+ function Is_Finalizable_Access (Decl : Node_Id) return Boolean is
+ Obj : constant Entity_Id := Defining_Identifier (Decl);
+ Typ : constant Entity_Id := Base_Type (Etype (Obj));
+ Desig : constant Entity_Id := Available_View (Designated_Type (Typ));
+ Expr : constant Node_Id := Expression (Decl);
+
+ Secondary_Stack_Val : constant Uint :=
+ UI_From_Int (BIP_Allocation_Form'Pos (Secondary_Stack));
+
+ Actual : Node_Id;
+ Call : Node_Id;
+ Formal : Node_Id;
+ Param : Node_Id;
+
+ begin
+ -- The prerequisite is a reference to a controlled object
+
+ if No (Expr)
+ or else Nkind (Expr) /= N_Reference
+ or else not Needs_Finalization (Desig)
+ then
+ return False;
+ end if;
+
+ Call := Unqual_Conv (Prefix (Expr));
+
+ -- For a BIP function call, the only case where the return object needs
+ -- to be finalized through Obj is when it is allocated on the secondary
+ -- stack; when it is allocated in the caller, it is finalized directly,
+ -- and when it is allocated on the global heap or in a storage pool, it
+ -- is finalized through another mechanism.
+
+ -- Obj : Access_Typ :=
+ -- BIP_Function_Call (BIPalloc => Secondary_Stack, ...)'reference;
+
+ if Is_Build_In_Place_Function_Call (Call) then
+
+ -- Examine all parameter associations of the function call
+
+ Param := First (Parameter_Associations (Call));
+ while Present (Param) loop
+ if Nkind (Param) = N_Parameter_Association then
+ Formal := Selector_Name (Param);
+ Actual := Explicit_Actual_Parameter (Param);
+
+ -- A match for BIPalloc => Secondary_Stack has been found
+
+ if Is_Build_In_Place_Entity (Formal)
+ and then BIP_Suffix_Kind (Formal) = BIP_Alloc_Form
+ and then Nkind (Actual) = N_Integer_Literal
+ and then Intval (Actual) = Secondary_Stack_Val
+ then
+ return True;
+ end if;
+ end if;
+
+ Next (Param);
+ end loop;
+
+ -- For a non-BIP function call, the only case where the return object
+ -- need not be finalized is when it itself is going to be returned.
+
+ -- Obj : Typ := Non_BIP_Function_Call'reference;
+
+ elsif Nkind (Call) = N_Function_Call
+ and then not Is_Related_To_Func_Return (Obj)
+ then
+ return True;
+ end if;
+
+ return False;
+ end Is_Finalizable_Access;
+
------------------------------
-- Is_Finalizable_Transient --
------------------------------
@@ -8617,19 +8972,6 @@ package body Exp_Util is
Obj_Id : constant Entity_Id := Defining_Identifier (Decl);
Obj_Typ : constant Entity_Id := Base_Type (Etype (Obj_Id));
- function Initialized_By_Aliased_BIP_Func_Call
- (Trans_Id : Entity_Id) return Boolean;
- -- Determine whether transient object Trans_Id is initialized by a
- -- build-in-place function call where the BIPalloc parameter either
- -- does not exist or is Caller_Allocation, and BIPaccess is not null.
- -- This case creates an aliasing between the returned value and the
- -- value denoted by BIPaccess.
-
- function Initialized_By_Reference (Trans_Id : Entity_Id) return Boolean;
- -- Determine whether transient object Trans_Id is initialized by a
- -- reference to another object. This is the only case where we can
- -- possibly finalize a transient object through an access value.
-
function Is_Aliased
(Trans_Id : Entity_Id;
First_Stmt : Node_Id) return Boolean;
@@ -8655,115 +8997,6 @@ package body Exp_Util is
-- Return True if N is directly part of a build-in-place return
-- statement.
- ------------------------------------------
- -- Initialized_By_Aliased_BIP_Func_Call --
- ------------------------------------------
-
- function Initialized_By_Aliased_BIP_Func_Call
- (Trans_Id : Entity_Id) return Boolean
- is
- Call : Node_Id := Expression (Parent (Trans_Id));
-
- begin
- -- Build-in-place calls usually appear in 'reference format
-
- if Nkind (Call) = N_Reference then
- Call := Prefix (Call);
- end if;
-
- Call := Unqual_Conv (Call);
-
- -- We search for a formal with a matching suffix. We can't search
- -- for the full name, because of the code at the end of Sem_Ch6.-
- -- Create_Extra_Formals, which copies the Extra_Formals over to
- -- the Alias of an instance, which will cause the formals to have
- -- "incorrect" names. See also Exp_Ch6.Build_In_Place_Formal.
-
- if Is_Build_In_Place_Function_Call (Call) then
- declare
- Caller_Allocation_Val : constant Uint :=
- UI_From_Int (BIP_Allocation_Form'Pos (Caller_Allocation));
- Access_Suffix : constant String :=
- BIP_Formal_Suffix (BIP_Object_Access);
- Alloc_Suffix : constant String :=
- BIP_Formal_Suffix (BIP_Alloc_Form);
-
- function Has_Suffix (Name, Suffix : String) return Boolean;
- -- Return True if Name has suffix Suffix
-
- ----------------
- -- Has_Suffix --
- ----------------
-
- function Has_Suffix (Name, Suffix : String) return Boolean is
- Len : constant Natural := Suffix'Length;
-
- begin
- return Name'Length > Len
- and then Name (Name'Last - Len + 1 .. Name'Last) = Suffix;
- end Has_Suffix;
-
- Access_OK : Boolean := False;
- Alloc_OK : Boolean := True;
- Param : Node_Id;
-
- begin
- -- Examine all parameter associations of the function call
-
- Param := First (Parameter_Associations (Call));
-
- while Present (Param) loop
- if Nkind (Param) = N_Parameter_Association
- and then Nkind (Selector_Name (Param)) = N_Identifier
- then
- declare
- Actual : constant Node_Id :=
- Explicit_Actual_Parameter (Param);
- Formal : constant Node_Id :=
- Selector_Name (Param);
- Name : constant String :=
- Get_Name_String (Chars (Formal));
-
- begin
- -- A nonnull BIPaccess has been found
-
- if Has_Suffix (Name, Access_Suffix)
- and then Nkind (Actual) /= N_Null
- then
- Access_OK := True;
-
- -- A BIPalloc has been found
-
- elsif Has_Suffix (Name, Alloc_Suffix)
- and then Nkind (Actual) = N_Integer_Literal
- then
- Alloc_OK := Intval (Actual) = Caller_Allocation_Val;
- end if;
- end;
- end if;
-
- Next (Param);
- end loop;
-
- return Access_OK and Alloc_OK;
- end;
- end if;
-
- return False;
- end Initialized_By_Aliased_BIP_Func_Call;
-
- ------------------------------
- -- Initialized_By_Reference --
- ------------------------------
-
- function Initialized_By_Reference (Trans_Id : Entity_Id) return Boolean
- is
- Expr : constant Node_Id := Expression (Parent (Trans_Id));
-
- begin
- return Present (Expr) and then Nkind (Expr) = N_Reference;
- end Initialized_By_Reference;
-
----------------
-- Is_Aliased --
----------------
@@ -8869,13 +9102,16 @@ package body Exp_Util is
Stmt := First_Stmt;
while Present (Stmt) loop
- -- Transient objects initialized by a reference are finalized
- -- (see Initialized_By_Reference above), so we must make sure
- -- not to finalize the referenced object twice. And we cannot
- -- finalize it at all if it is referenced by the nontransient
- -- object serviced by the transient scope.
-
- if Nkind (Stmt) = N_Object_Declaration then
+ -- (Transient) objects initialized by a reference to another named
+ -- object are never finalized (see Is_Finalizable_Access), so we
+ -- need not worry about finalizing (transient) referenced objects
+ -- twice. Therefore, we only need to look at the nontransient
+ -- object serviced by the transient scope, if it exists and is
+ -- declared as a reference to another named object.
+
+ if Nkind (Stmt) = N_Object_Declaration
+ and then Stmt = N
+ then
Expr := Expression (Stmt);
-- Aliasing of the form:
@@ -8889,8 +9125,8 @@ package body Exp_Util is
return True;
end if;
- -- (Transient) renamings are never finalized so we need not bother
- -- about finalizing transient renamed objects twice. Therefore, we
+ -- (Transient) renamings are never finalized so we need not worry
+ -- about finalizing (transient) renamed objects twice. Therefore,
-- we only need to look at the nontransient object serviced by the
-- transient scope, if it exists and is declared as a renaming.
@@ -9090,12 +9326,11 @@ package body Exp_Util is
function Is_Part_Of_BIP_Return_Statement (N : Node_Id) return Boolean is
Subp : constant Entity_Id := Current_Subprogram;
Context : Node_Id;
+
begin
-- First check if N is part of a BIP function
- if No (Subp)
- or else not Is_Build_In_Place_Function (Subp)
- then
+ if No (Subp) or else not Is_Build_In_Place_Function (Subp) then
return False;
end if;
@@ -9119,6 +9354,15 @@ package body Exp_Util is
-- Start of processing for Is_Finalizable_Transient
begin
+ -- If the node serviced by the transient context is a return statement,
+ -- then the finalization needs to be deferred to the generic machinery.
+
+ if Nkind (N) = N_Simple_Return_Statement
+ or else Is_Part_Of_BIP_Return_Statement (N)
+ then
+ return False;
+ end if;
+
-- Handle access types
if Is_Access_Type (Desig) then
@@ -9128,34 +9372,27 @@ package body Exp_Util is
return
Ekind (Obj_Id) in E_Constant | E_Variable
and then Needs_Finalization (Desig)
- and then Nkind (N) /= N_Simple_Return_Statement
- and then not Is_Part_Of_BIP_Return_Statement (N)
-- Do not consider a transient object that was already processed
and then not Is_Finalized_Transient (Obj_Id)
- -- Do not consider renamed or 'reference-d transient objects because
- -- the act of renaming extends the object's lifetime.
+ -- Do not consider iterators because those are treated as normal
+ -- controlled objects and are processed by the usual finalization
+ -- machinery. This avoids the double finalization of an iterator.
- and then not Is_Aliased (Obj_Id, Decl)
+ and then not Is_Iterator (Desig)
- -- If the transient object is of an access type, check that it is
- -- initialized by a reference to another object.
+ -- If the transient object is of an access type, check that it must
+ -- be finalized.
and then (not Is_Access_Type (Obj_Typ)
- or else Initialized_By_Reference (Obj_Id))
-
- -- Do not consider transient objects which act as indirect aliases
- -- of build-in-place function results.
+ or else Is_Finalizable_Access (Decl))
- and then not Initialized_By_Aliased_BIP_Func_Call (Obj_Id)
+ -- Do not consider renamed transient objects because the act of
+ -- renaming extends the object's lifetime.
- -- Do not consider iterators because those are treated as normal
- -- controlled objects and are processed by the usual finalization
- -- machinery. This avoids the double finalization of an iterator.
-
- and then not Is_Iterator (Desig)
+ and then not Is_Aliased (Obj_Id, Decl)
-- Do not consider containers in the context of iterator loops. Such
-- transient objects must exist for as long as the loop is around,
@@ -9224,22 +9461,6 @@ package body Exp_Util is
and then Present (LSP_Subprogram (E));
end Is_LSP_Wrapper;
- --------------------------
- -- Is_Non_BIP_Func_Call --
- --------------------------
-
- function Is_Non_BIP_Func_Call (Expr : Node_Id) return Boolean is
- begin
- -- The expected call is of the format
- --
- -- Func_Call'reference
-
- return
- Nkind (Expr) = N_Reference
- and then Nkind (Prefix (Expr)) = N_Function_Call
- and then not Is_Build_In_Place_Function_Call (Prefix (Expr));
- end Is_Non_BIP_Func_Call;
-
----------------------------------
-- Is_Possibly_Unaligned_Object --
----------------------------------
@@ -9512,21 +9733,16 @@ package body Exp_Util is
function Is_Related_To_Func_Return (Id : Entity_Id) return Boolean is
Expr : constant Node_Id := Related_Expression (Id);
+
begin
-- In the case of a function with a class-wide result that returns
-- a call to a function with a specific result, we introduce a
-- type conversion for the return expression. We do not want that
-- type conversion to influence the result of this function.
- return
- Present (Expr)
- and then Nkind (Unqual_Conv (Expr)) = N_Explicit_Dereference
- and then (Nkind (Parent (Expr)) = N_Simple_Return_Statement
- or else
- (Nkind (Parent (Expr)) in N_Object_Declaration
- | N_Object_Renaming_Declaration
- and then
- Is_Return_Object (Defining_Entity (Parent (Expr)))));
+ return Present (Expr)
+ and then Nkind (Unqual_Conv (Expr)) = N_Explicit_Dereference
+ and then Is_Expression_Of_Func_Return (Expr);
end Is_Related_To_Func_Return;
--------------------------------
@@ -9612,55 +9828,6 @@ package body Exp_Util is
end if;
end Is_Renamed_Object;
- --------------------------------------
- -- Is_Secondary_Stack_BIP_Func_Call --
- --------------------------------------
-
- function Is_Secondary_Stack_BIP_Func_Call (Expr : Node_Id) return Boolean is
- Actual : Node_Id;
- Call : Node_Id := Expr;
- Formal : Node_Id;
- Param : Node_Id;
-
- begin
- -- Build-in-place calls usually appear in 'reference format. Note that
- -- the accessibility check machinery may add an extra 'reference due to
- -- side-effect removal.
-
- while Nkind (Call) = N_Reference loop
- Call := Prefix (Call);
- end loop;
-
- Call := Unqual_Conv (Call);
-
- if Is_Build_In_Place_Function_Call (Call) then
-
- -- Examine all parameter associations of the function call
-
- Param := First (Parameter_Associations (Call));
- while Present (Param) loop
- if Nkind (Param) = N_Parameter_Association then
- Formal := Selector_Name (Param);
- Actual := Explicit_Actual_Parameter (Param);
-
- -- A match for BIPalloc => 2 has been found
-
- if Is_Build_In_Place_Entity (Formal)
- and then BIP_Suffix_Kind (Formal) = BIP_Alloc_Form
- and then Nkind (Actual) = N_Integer_Literal
- and then Intval (Actual) = Uint_2
- then
- return True;
- end if;
- end if;
-
- Next (Param);
- end loop;
- end if;
-
- return False;
- end Is_Secondary_Stack_BIP_Func_Call;
-
------------------------------
-- Is_Secondary_Stack_Thunk --
------------------------------
@@ -10871,11 +11038,10 @@ package body Exp_Util is
-- operator on private type might not be visible and won't be
-- resolved.
- else pragma Assert (Is_RTE (Base_Type (Typ), RE_Big_Integer)
- or else
- Is_RTE (Base_Type (Typ), RO_GH_Big_Integer)
- or else
- Is_RTE (Base_Type (Typ), RO_SP_Big_Integer));
+ else
+ pragma Assert
+ (Is_RTE (Base_Type (Typ), RE_Big_Integer)
+ or else Is_RTE (Base_Type (Typ), RO_SP_Big_Integer));
return
Make_Function_Call (Loc,
Name =>
@@ -12704,18 +12870,22 @@ package body Exp_Util is
-- Otherwise we generate a reference to the expression
else
- -- Special processing for function calls that return a limited type.
- -- We need to build a declaration that will enable build-in-place
- -- expansion of the call. This is not done if the context is already
- -- an object declaration, to prevent infinite recursion.
-
- -- This is relevant only in Ada 2005 mode. In Ada 95 programs we have
- -- to accommodate functions returning limited objects by reference.
-
- if Ada_Version >= Ada_2005
- and then Nkind (Exp) = N_Function_Call
- and then Is_Inherently_Limited_Type (Etype (Exp))
+ -- Special processing for function calls with a result type that is
+ -- either BIP or a constrained array with controlled component and
+ -- an unconstrained first subtype, when the context is neither an
+ -- object declaration (to prevent infinite recursion) nor a function
+ -- return (to propagate the anonymous return object).
+
+ -- We need to build an object declaration to trigger build-in-place
+ -- expansion of the call in the former case, and addition of bounds
+ -- to the object in the latter case.
+
+ if Nkind (Exp) = N_Function_Call
+ and then (Is_Build_In_Place_Result_Type (Exp_Type)
+ or else
+ Is_Constr_Array_Subt_Of_Unc_With_Controlled (Exp_Type))
and then Nkind (Parent (Exp)) /= N_Object_Declaration
+ and then not Is_Expression_Of_Func_Return (Exp)
then
declare
Obj : constant Entity_Id := Make_Temporary (Loc, 'F', Exp);
@@ -13324,7 +13494,6 @@ package body Exp_Util is
Nested_Constructs : Boolean) return Boolean
is
Decl : Node_Id;
- Expr : Node_Id;
Obj_Id : Entity_Id;
Obj_Typ : Entity_Id;
Pack_Id : Entity_Id;
@@ -13362,7 +13531,6 @@ package body Exp_Util is
elsif Nkind (Decl) = N_Object_Declaration then
Obj_Id := Defining_Identifier (Decl);
Obj_Typ := Base_Type (Etype (Obj_Id));
- Expr := Expression (Decl);
-- Bypass any form of processing for objects which have their
-- finalization disabled. This applies only to objects at the
@@ -13416,21 +13584,10 @@ package body Exp_Util is
then
return True;
- -- The object is of the form:
- -- Obj : Access_Typ := Non_BIP_Function_Call'reference;
- --
- -- Obj : Access_Typ :=
- -- BIP_Function_Call (BIPalloc => 2, ...)'reference;
+ -- The object is an access-to-controlled that must be finalized
elsif Is_Access_Type (Obj_Typ)
- and then Needs_Finalization
- (Available_View (Designated_Type (Obj_Typ)))
- and then Present (Expr)
- and then
- (Is_Secondary_Stack_BIP_Func_Call (Expr)
- or else
- (Is_Non_BIP_Func_Call (Expr)
- and then not Is_Related_To_Func_Return (Obj_Id)))
+ and then Is_Finalizable_Access (Decl)
then
return True;
@@ -14439,6 +14596,11 @@ package body Exp_Util is
when N_Aggregate =>
return Compile_Time_Known_Aggregate (N);
+ -- A reference is side-effect-free
+
+ when N_Reference =>
+ return True;
+
-- We consider that anything else has side effects. This is a bit
-- crude, but we are pretty close for most common cases, and we
-- are certainly correct (i.e. we never return True when the
@@ -14466,7 +14628,16 @@ package body Exp_Util is
else
N := First (L);
while Present (N) loop
- if not Side_Effect_Free (N, Name_Req, Variable_Ref) then
+ if Nkind (N) = N_Parameter_Association then
+ if not
+ Side_Effect_Free
+ (Explicit_Actual_Parameter (N), Name_Req, Variable_Ref)
+ then
+ return False;
+ end if;
+
+ Next (N);
+ elsif not Side_Effect_Free (N, Name_Req, Variable_Ref) then
return False;
else
Next (N);