@@ -2727,6 +2727,11 @@ package Einfo is
-- instantiation of a child unit, and whose entities are not visible
-- during analysis of the instance.
+-- Is_Ignored_For_Finalization
+-- Defined in constants and variables. Set when an object must be ignored
+-- by the general finalization mechanism because its cleanup actions are
+-- already accounted for.
+
-- Is_Ignored_Ghost_Entity
-- Applies to all entities. Set for abstract states, [generic] packages,
-- [generic] subprograms, components, discriminants, formal parameters,
@@ -2734,13 +2739,6 @@ package Einfo is
-- pragma Ghost or inherit "ghostness" from an enclosing construct, and
-- subject to Assertion_Policy Ghost => Ignore.
-
-- Is_Immediately_Visible
-- Defined in all entities. Set if entity is immediately visible, i.e.
-- is defined in some currently open scope (RM 8.3(4)).
@@ -5325,7 +5323,7 @@ package Einfo is
-- Is_Elaboration_Warnings_OK_Id (constants only)
-- Is_Eliminated
-- Is_Finalized_Transient
- -- Is_Ignored_Transient
+ -- Is_Ignored_For_Finalization
-- Is_Independent
-- Is_Return_Object
-- Is_True_Constant
@@ -6213,7 +6211,7 @@ package Einfo is
-- Is_Elaboration_Warnings_OK_Id
-- Is_Eliminated
-- Is_Finalized_Transient
- -- Is_Ignored_Transient
+ -- Is_Ignored_For_Finalization
-- Is_Independent
-- Is_Return_Object
-- Is_Safe_To_Reevaluate
@@ -6317,7 +6317,7 @@ package body Exp_Aggr is
and then No_Ctrl_Actions (Parent_Node)
then
Mutate_Ekind (Tmp, E_Variable);
- Set_Is_Ignored_Transient (Tmp);
+ Set_Is_Ignored_For_Finalization (Tmp);
end if;
Insert_Action (N, Tmp_Decl);
@@ -241,18 +241,6 @@ package body Exp_Ch4 is
-- and X is a simple entity, and op is a comparison operator, optimizes it
-- into a comparison of X'First and X'Last.
- procedure Process_Transient_In_Expression
- (Obj_Decl : Node_Id;
- Expr : Node_Id;
- Stmts : List_Id);
- -- Subsidiary routine to the expansion of expression_with_actions, if and
- -- case expressions. Generate all necessary code to finalize a transient
- -- object when the enclosing context is elaborated or evaluated. Obj_Decl
- -- denotes the declaration of the transient object, which is usually the
- -- result of a controlled function call. Expr denotes the expression with
- -- actions, if expression, or case expression node. Stmts denotes one of
- -- the actions list of Expr, which contains Decl.
-
procedure Process_Transients_In_Expression
(Expr : Node_Id;
Stmts : List_Id);
@@ -5643,10 +5631,6 @@ package body Exp_Ch4 is
UI_Max (Hi1, Hi2) - UI_Min (Lo1, Lo2) < Too_Large_Length_For_Array;
end OK_For_Single_Subtype;
- Optimize_Return_Stmt : Boolean := False;
- -- Flag set when the if expression can be optimized in the context of
- -- a simple return statement.
-
-- Local variables
Actions : List_Id;
@@ -5655,6 +5639,10 @@ package body Exp_Ch4 is
New_If : Node_Id;
New_N : Node_Id;
+ Optimize_Return_Stmt : Boolean := False;
+ -- Flag set when the if expression can be optimized in the context of
+ -- a simple return statement.
+
-- Start of processing for Expand_N_If_Expression
begin
@@ -14917,174 +14905,178 @@ package body Exp_Ch4 is
Analyze_And_Resolve (N, Typ, Suppress => Overflow_Check);
end Optimize_Length_Comparison;
- -------------------------------------
- -- Process_Transient_In_Expression --
- -------------------------------------
+ --------------------------------------
+ -- Process_Transients_In_Expression --
+ --------------------------------------
- procedure Process_Transient_In_Expression
- (Obj_Decl : Node_Id;
- Expr : Node_Id;
- Stmts : List_Id)
+ procedure Process_Transients_In_Expression
+ (Expr : Node_Id;
+ Stmts : List_Id)
is
- Loc : constant Source_Ptr := Sloc (Obj_Decl);
- Obj_Id : constant Entity_Id := Defining_Identifier (Obj_Decl);
+ procedure Process_Transient_In_Expression (Obj_Decl : Node_Id);
+ -- Process the object whose declaration Obj_Decl is present in Stmts
- Hook_Context : constant Node_Id := Find_Hook_Context (Expr);
- -- The node on which to insert the hook as an action. This is usually
- -- the innermost enclosing non-transient construct.
+ -------------------------------------
+ -- Process_Transient_In_Expression --
+ -------------------------------------
- Fin_Call : Node_Id;
- Hook_Assign : Node_Id;
- Hook_Clear : Node_Id;
- Hook_Decl : Node_Id;
- Hook_Insert : Node_Id;
- Ptr_Decl : Node_Id;
+ procedure Process_Transient_In_Expression (Obj_Decl : Node_Id) is
+ Loc : constant Source_Ptr := Sloc (Obj_Decl);
+ Obj_Id : constant Entity_Id := Defining_Identifier (Obj_Decl);
- Fin_Context : Node_Id;
- -- The node after which to insert the finalization actions of the
- -- transient object.
+ Hook_Context : constant Node_Id := Find_Hook_Context (Expr);
+ -- The node on which to insert the hook as an action. This is usually
+ -- the innermost enclosing non-transient construct.
- begin
- pragma Assert (Nkind (Expr) in N_Case_Expression
- | N_Expression_With_Actions
- | N_If_Expression);
+ Fin_Call : Node_Id;
+ Hook_Assign : Node_Id;
+ Hook_Clear : Node_Id;
+ Hook_Decl : Node_Id;
+ Hook_Insert : Node_Id;
+ Ptr_Decl : Node_Id;
- -- When the context is a Boolean evaluation, all three nodes capture the
- -- result of their computation in a local temporary:
+ Fin_Context : Node_Id;
+ -- The node after which to insert the finalization actions of the
+ -- transient object.
- -- do
- -- Trans_Id : Ctrl_Typ := ...;
- -- Result : constant Boolean := ... Trans_Id ...;
- -- <finalize Trans_Id>
- -- in Result end;
+ begin
+ pragma Assert (Nkind (Expr) in N_Case_Expression
+ | N_Expression_With_Actions
+ | N_If_Expression);
- -- As a result, the finalization of any transient objects can take place
- -- just after the result is captured, except for the case of conditional
- -- expressions in a simple return statement because the return statement
- -- will be distributed into the conditional expressions (see the special
- -- handling of simple return statements a few lines below).
+ -- When the context is a Boolean evaluation, all three nodes capture
+ -- the result of their computation in a local temporary:
- -- ??? could this be extended to elementary types?
+ -- do
+ -- Trans_Id : Ctrl_Typ := ...;
+ -- Result : constant Boolean := ... Trans_Id ...;
+ -- <finalize Trans_Id>
+ -- in Result end;
- if Is_Boolean_Type (Etype (Expr))
- and then (Nkind (Expr) = N_Expression_With_Actions
- or else Nkind (Parent (Expr)) /= N_Simple_Return_Statement)
- then
- Fin_Context := Last (Stmts);
+ -- As a result, the finalization of any transient objects can take
+ -- place just after the result is captured, except for the case of
+ -- conditional expressions in a simple return statement because the
+ -- return statement will be distributed into dependent expressions
+ -- (see the special handling of simple return statements below).
- -- Otherwise the immediate context may not be safe enough to carry
- -- out transient object finalization due to aliasing and nesting of
- -- constructs. Insert calls to [Deep_]Finalize after the innermost
- -- enclosing non-transient construct.
+ -- ??? could this be extended to elementary types?
- else
- Fin_Context := Hook_Context;
- end if;
+ if Is_Boolean_Type (Etype (Expr))
+ and then
+ (Nkind (Expr) = N_Expression_With_Actions
+ or else Nkind (Parent (Expr)) /= N_Simple_Return_Statement)
+ then
+ Fin_Context := Last (Stmts);
- -- Mark the transient object as successfully processed to avoid double
- -- finalization.
+ -- Otherwise the immediate context may not be safe enough to carry
+ -- out transient object finalization due to aliasing and nesting of
+ -- constructs. Insert calls to [Deep_]Finalize after the innermost
+ -- enclosing non-transient construct.
- Set_Is_Finalized_Transient (Obj_Id);
+ else
+ Fin_Context := Hook_Context;
+ end if;
- -- Construct all the pieces necessary to hook and finalize a transient
- -- object.
+ -- Mark the transient object as successfully processed to avoid
+ -- double finalization.
- Build_Transient_Object_Statements
- (Obj_Decl => Obj_Decl,
- Fin_Call => Fin_Call,
- Hook_Assign => Hook_Assign,
- Hook_Clear => Hook_Clear,
- Hook_Decl => Hook_Decl,
- Ptr_Decl => Ptr_Decl,
- Finalize_Obj => False);
+ Set_Is_Finalized_Transient (Obj_Id);
- -- Add the access type which provides a reference to the transient
- -- object. Generate:
+ -- Construct all the pieces necessary to hook and finalize a
+ -- transient object.
- -- type Ptr_Typ is access all Desig_Typ;
+ Build_Transient_Object_Statements
+ (Obj_Decl => Obj_Decl,
+ Fin_Call => Fin_Call,
+ Hook_Assign => Hook_Assign,
+ Hook_Clear => Hook_Clear,
+ Hook_Decl => Hook_Decl,
+ Ptr_Decl => Ptr_Decl,
+ Finalize_Obj => False);
- Insert_Action (Hook_Context, Ptr_Decl);
+ -- Add the access type which provides a reference to the transient
+ -- object. Generate:
- -- Add the temporary which acts as a hook to the transient object.
- -- Generate:
+ -- type Ptr_Typ is access all Desig_Typ;
- -- Hook : Ptr_Id := null;
+ Insert_Action (Hook_Context, Ptr_Decl);
- Insert_Action (Hook_Context, Hook_Decl);
+ -- Add the temporary which acts as a hook to the transient object.
+ -- Generate:
- -- When the transient object is initialized by an aggregate, the hook
- -- must capture the object after the last aggregate assignment takes
- -- place. Only then is the object considered initialized. Generate:
+ -- Hook : Ptr_Id := null;
- -- Hook := Ptr_Typ (Obj_Id);
- -- <or>
- -- Hook := Obj_Id'Unrestricted_Access;
+ Insert_Action (Hook_Context, Hook_Decl);
- if Ekind (Obj_Id) in E_Constant | E_Variable
- and then Present (Last_Aggregate_Assignment (Obj_Id))
- then
- Hook_Insert := Last_Aggregate_Assignment (Obj_Id);
+ -- When the transient object is initialized by an aggregate, the hook
+ -- must capture the object after the last aggregate assignment takes
+ -- place. Only then is the object considered initialized. Generate:
- -- Otherwise the hook seizes the related object immediately
+ -- Hook := Ptr_Typ (Obj_Id);
+ -- <or>
+ -- Hook := Obj_Id'Unrestricted_Access;
- else
- Hook_Insert := Obj_Decl;
- end if;
+ if Ekind (Obj_Id) in E_Constant | E_Variable
+ and then Present (Last_Aggregate_Assignment (Obj_Id))
+ then
+ Hook_Insert := Last_Aggregate_Assignment (Obj_Id);
- Insert_After_And_Analyze (Hook_Insert, Hook_Assign);
+ -- Otherwise the hook seizes the related object immediately
- -- When the node is part of a return statement, there is no need to
- -- insert a finalization call, as the general finalization mechanism
- -- (see Build_Finalizer) would take care of the transient object on
- -- subprogram exit. Note that it would also be impossible to insert the
- -- finalization code after the return statement as this will render it
- -- unreachable.
+ else
+ Hook_Insert := Obj_Decl;
+ end if;
- if Nkind (Fin_Context) = N_Simple_Return_Statement then
- null;
+ Insert_After_And_Analyze (Hook_Insert, Hook_Assign);
- -- Finalize the hook after the context has been evaluated. Generate:
+ -- When the node is part of a return statement, there is no need to
+ -- insert a finalization call, as the general finalization mechanism
+ -- (see Build_Finalizer) would take care of the transient object on
+ -- subprogram exit. Note that it would also be impossible to insert
+ -- the finalization code after the return statement as this will
+ -- render it unreachable.
- -- if Hook /= null then
- -- [Deep_]Finalize (Hook.all);
- -- Hook := null;
- -- end if;
+ if Nkind (Fin_Context) = N_Simple_Return_Statement then
+ null;
- -- Note that the value returned by Find_Hook_Context may be an operator
- -- node, which is not a list member. We must locate the proper node in
- -- in the tree after which to insert the finalization code.
+ -- Finalize the hook after the context has been evaluated. Generate:
- else
- while not Is_List_Member (Fin_Context) loop
- Fin_Context := Parent (Fin_Context);
- end loop;
+ -- if Hook /= null then
+ -- [Deep_]Finalize (Hook.all);
+ -- Hook := null;
+ -- end if;
- pragma Assert (Present (Fin_Context));
+ -- But the node returned by Find_Hook_Context may be an operator,
+ -- which is not a list member. We must locate the proper node
+ -- in the tree after which to insert the finalization code.
- Insert_Action_After (Fin_Context,
- Make_Implicit_If_Statement (Obj_Decl,
- Condition =>
- Make_Op_Ne (Loc,
- Left_Opnd =>
- New_Occurrence_Of (Defining_Entity (Hook_Decl), Loc),
- Right_Opnd => Make_Null (Loc)),
+ else
+ while not Is_List_Member (Fin_Context) loop
+ Fin_Context := Parent (Fin_Context);
+ end loop;
- Then_Statements => New_List (
- Fin_Call,
- Hook_Clear)));
- end if;
- end Process_Transient_In_Expression;
+ pragma Assert (Present (Fin_Context));
- --------------------------------------
- -- Process_Transients_In_Expression --
- --------------------------------------
+ Insert_Action_After (Fin_Context,
+ Make_Implicit_If_Statement (Obj_Decl,
+ Condition =>
+ Make_Op_Ne (Loc,
+ Left_Opnd =>
+ New_Occurrence_Of (Defining_Entity (Hook_Decl), Loc),
+ Right_Opnd => Make_Null (Loc)),
+
+ Then_Statements => New_List (
+ Fin_Call,
+ Hook_Clear)));
+ end if;
+ end Process_Transient_In_Expression;
+
+ -- Local variables
- procedure Process_Transients_In_Expression
- (Expr : Node_Id;
- Stmts : List_Id)
- is
Decl : Node_Id;
+ -- Start of processing for Process_Transients_In_Expression
+
begin
pragma Assert (Nkind (Expr) in N_Case_Expression
| N_Expression_With_Actions
@@ -15095,7 +15087,7 @@ package body Exp_Ch4 is
if Nkind (Decl) = N_Object_Declaration
and then Is_Finalizable_Transient (Decl, Expr)
then
- Process_Transient_In_Expression (Decl, Expr, Stmts);
+ Process_Transient_In_Expression (Decl);
end if;
Next (Decl);
@@ -5441,29 +5441,6 @@ package body Exp_Ch6 is
is
Par : constant Node_Id := Parent (N);
- function Is_Element_Reference (N : Node_Id) return Boolean;
- -- Determine whether node N denotes a reference to an Ada 2012 container
- -- element.
-
- --------------------------
- -- Is_Element_Reference --
- --------------------------
-
- function Is_Element_Reference (N : Node_Id) return Boolean is
- Ref : constant Node_Id := Original_Node (N);
-
- begin
- -- Analysis marks an element reference by setting the generalized
- -- indexing attribute of an indexed component before the component
- -- is rewritten into a function call.
-
- return
- Nkind (Ref) = N_Indexed_Component
- and then Present (Generalized_Indexing (Ref));
- end Is_Element_Reference;
-
- -- Start of processing for Expand_Ctrl_Function_Call
-
begin
-- Optimization: if the returned value is returned again, then no need
-- to copy/readjust/finalize, we can just pass the value through (see
@@ -5505,26 +5482,6 @@ package body Exp_Ch6 is
if Nkind (Par) /= N_Reference then
Remove_Side_Effects (N);
end if;
-
- -- The side effect removal of the function call produced a temporary.
- -- When the context is a case expression, if expression, or expression
- -- with actions, the lifetime of the temporary must be extended to match
- -- that of the context. Otherwise the function result will be finalized
- -- too early and affect the result of the expression. To prevent this
- -- unwanted effect, the temporary should not be considered for clean up
- -- actions by the general finalization machinery.
-
- -- Exception to this rule are references to Ada 2012 container elements.
- -- Such references must be finalized at the end of each iteration of the
- -- related quantified expression, otherwise the container will remain
- -- busy.
-
- if Nkind (N) = N_Explicit_Dereference
- and then Within_Case_Or_If_Expression (N)
- and then not Is_Element_Reference (N)
- then
- Set_Is_Ignored_Transient (Entity (Prefix (N)));
- end if;
end Expand_Ctrl_Function_Call;
----------------------------------------
@@ -1265,7 +1265,7 @@ package body Exp_Ch7 is
-- Associate the Finalize_Address primitive of the designated type
-- with the finalization master of the access type. The designated
- -- type must be forzen as Finalize_Address is generated when the
+ -- type must be frozen, as Finalize_Address is generated when the
-- freeze node is expanded.
elsif Is_Frozen (Desig_Typ)
@@ -2257,19 +2257,19 @@ package body Exp_Ch7 is
if For_Package and then Finalize_Storage_Only (Obj_Typ) then
null;
- -- Finalization of transient objects are treated separately in
+ -- Finalization of transient objects is treated separately in
-- order to handle sensitive cases. These include:
-- * Conditional expressions
-- * Expressions with actions
-- * Transient scopes
- -- If one of those contexts has marked the transient object as
- -- ignored, do not generate finalization actions for it.
+ elsif Is_Finalized_Transient (Obj_Id) then
+ null;
- elsif Is_Finalized_Transient (Obj_Id)
- or else Is_Ignored_Transient (Obj_Id)
- then
+ -- Finalization of specific objects is also treated separately
+
+ elsif Is_Ignored_For_Finalization (Obj_Id) then
null;
-- Ignored Ghost objects do not need any cleanup actions
@@ -13020,19 +13020,19 @@ package body Exp_Util is
if Lib_Level and then Finalize_Storage_Only (Obj_Typ) then
null;
- -- Finalization of transient objects are treated separately in
+ -- Finalization of transient objects is treated separately in
-- order to handle sensitive cases. These include:
-- * Conditional expressions
-- * Expressions with actions
-- * Transient scopes
- -- If one of those contexts has marked the transient object as
- -- ignored, do not generate finalization actions for it.
+ elsif Is_Finalized_Transient (Obj_Id) then
+ null;
- elsif Is_Finalized_Transient (Obj_Id)
- or else Is_Ignored_Transient (Obj_Id)
- then
+ -- Finalization of specific objects is also treated separately
+
+ elsif Is_Ignored_For_Finalization (Obj_Id) then
null;
-- Ignored Ghost objects do not need any cleanup actions because
@@ -721,8 +721,8 @@ package Gen_IL.Fields is
Is_Hidden,
Is_Hidden_Non_Overridden_Subpgm,
Is_Hidden_Open_Scope,
+ Is_Ignored_For_Finalization,
Is_Ignored_Ghost_Entity,
- Is_Ignored_Transient,
Is_Immediately_Visible,
Is_Implementation_Defined,
Is_Imported,
@@ -337,7 +337,7 @@ begin -- Gen_IL.Gen.Gen_Entities
Sm (Esize, Uint),
Sm (Interface_Name, Node_Id),
Sm (Is_Finalized_Transient, Flag),
- Sm (Is_Ignored_Transient, Flag),
+ Sm (Is_Ignored_For_Finalization, Flag),
Sm (Linker_Section_Pragma, Node_Id),
Sm (Related_Expression, Node_Id),
Sm (Status_Flag_Or_Transient_Decl, Node_Id)));