From: Eric Botcazou <ebotcazou@adacore.com>
When transient scopes are being materialized, they can give rise to a block
created around the construct being wrapped or not, depending on the kind of
construct. In both cases finalization actions for the transient objects of
the scope are generated the same way, with normal finalization done manually
immediately after the construct and exceptional finalization deferred to the
enclosing scope by means of a hooking mechanism.
Now when the block is generated, it becomes this enclosing scope, so the
normal finalization that comes with it would also be done immediately after
the construct, even without normal finalization generated manually.
Therefore this change gets rid of the manual finalization as well as of the
hooking in the cases where the block is generated, leading to a significant
streamlining of the expanded code in these cases. This requires fixing a
small inaccuracy of the Within_Case_Or_If_Expression predicate, which must
only be concerned with the dependent expressions, since those are the only
ones to be treated specially by the finalization machinery.
It also contains a small cleanup for the description of the transient scope
management present at the beginning of the exp_ch7.adb file.
gcc/ada/
* exp_ch7.ads (Expand_Cleanup_Actions): Move declaration to the
Finalization Management section.
* exp_ch7.adb (Transient Scope Management): Move description down to
after that of the general finalization and make a few changes.
(Insert_Actions_In_Scope_Around): Call Process_Transients_In_Scope
only if cleanups are being handled.
(Process_Transients_In_Scope): Remove redundant test on Clean.
* exp_util.ads (Within_Case_Or_If_Expression): Adjust description.
* exp_util.adb (Within_Case_Or_If_Expression): Only return true if
within the dependent expressions of the conditional expressions.
Tested on x86_64-pc-linux-gnu, committed on master.
---
gcc/ada/exp_ch7.adb | 149 +++++++++++++++++++++++++------------------
gcc/ada/exp_ch7.ads | 12 ++--
gcc/ada/exp_util.adb | 16 ++++-
gcc/ada/exp_util.ads | 7 +-
4 files changed, 110 insertions(+), 74 deletions(-)
@@ -70,59 +70,6 @@ with Uintp; use Uintp;
package body Exp_Ch7 is
- --------------------------------
- -- Transient Scope Management --
- --------------------------------
-
- -- A transient scope is needed when certain temporary objects are created
- -- by the compiler. These temporary objects are allocated on the secondary
- -- stack and/or need finalization, and the transient scope is responsible
- -- for finalizing the objects and reclaiming the memory of the secondary
- -- stack at the appropriate time. They are generally objects allocated to
- -- store the result of a function returning an unconstrained or controlled
- -- value. Expressions needing to be wrapped in a transient scope may appear
- -- in three different contexts which lead to different kinds of transient
- -- scope expansion:
-
- -- 1. In a simple statement (procedure call, assignment, ...). In this
- -- case the instruction is wrapped into a transient block. See
- -- Wrap_Transient_Statement for details.
-
- -- 2. In an expression of a control structure (test in a IF statement,
- -- expression in a CASE statement, ...). See Wrap_Transient_Expression
- -- for details.
-
- -- 3. In a expression of an object_declaration. No wrapping is possible
- -- here, so the finalization actions, if any, are done right after the
- -- declaration and the secondary stack deallocation is done in the
- -- proper enclosing scope. See Wrap_Transient_Declaration for details.
-
- --------------------------------------------------
- -- Transient Blocks and Finalization Management --
- --------------------------------------------------
-
- procedure Insert_Actions_In_Scope_Around
- (N : Node_Id;
- Clean : Boolean;
- Manage_SS : Boolean);
- -- Insert the before-actions kept in the scope stack before N, and the
- -- after-actions after N, which must be a member of a list. If flag Clean
- -- is set, insert any cleanup actions. If flag Manage_SS is set, insert
- -- calls to mark and release the secondary stack.
-
- function Make_Transient_Block
- (Loc : Source_Ptr;
- Action : Node_Id;
- Par : Node_Id) return Node_Id;
- -- Action is a single statement or object declaration. Par is the proper
- -- parent of the generated block. Create a transient block whose name is
- -- the current scope and the only handled statement is Action. If Action
- -- involves controlled objects or secondary stack usage, the corresponding
- -- cleanup actions are performed at the end of the block.
-
- procedure Store_Actions_In_Scope (AK : Scope_Action_Kind; L : List_Id);
- -- Shared processing for Store_xxx_Actions_In_Scope
-
-----------------------------
-- Finalization Management --
-----------------------------
@@ -292,6 +239,84 @@ package body Exp_Ch7 is
-- Build the deep Initialize/Adjust/Finalize for a record Typ with
-- Has_Component_Component set and store them using the TSS mechanism.
+ --------------------------------
+ -- Transient Scope Management --
+ --------------------------------
+
+ -- A transient scope is needed when certain temporary objects are created
+ -- by the compiler. These temporary objects are allocated on the secondary
+ -- stack and/or need finalization, and the transient scope is responsible
+ -- for finalizing the objects and reclaiming the memory of the secondary
+ -- stack at the appropriate time. They are generally objects allocated to
+ -- store the result of a function returning an unconstrained or controlled
+ -- value. Expressions needing to be wrapped in a transient scope may appear
+ -- in three different contexts, which lead to different kinds of transient
+ -- scope expansion:
+
+ -- 1. In a simple statement (procedure call, assignment, ...). In this
+ -- case the statement is wrapped into a transient block, which takes
+ -- care of the finalization actions as well as the secondary stack
+ -- deallocation, See Wrap_Transient_Statement for details.
+
+ -- 2. In an expression of a control structure (test in a If statement,
+ -- expression in a Case statement, ...). In this case the expression
+ -- is replaced by a temporary and the enclosing statement is wrapped
+ -- into a transient block, which takes care of the finalization actions
+ -- and the secondary stack deallocation. See Wrap_Transient_Expression
+ -- for details.
+
+ -- 3. In an expression of an object declaration. No wrapping is possible
+ -- here, so the finalization actions performed on the normal path, if
+ -- any, are done right after the declaration, and those performed on
+ -- the exceptional path, as well as the secondary stack deallocation,
+ -- are deferred to the enclosing scope. See Wrap_Transient_Declaration
+ -- for details.
+
+ -- A transient scope is created by calling Establish_Transient_Scope on the
+ -- node that needs to be serviced by it (the serviced node can subsequently
+ -- be retrieved by invoking Node_To_Be_Wrapped when the current scope is a
+ -- transient scope). Once this has been done, the normal processing of the
+ -- Insert_Actions procedures is blocked and the procedures are redirected
+ -- to the Store_xxx_Actions_In_Scope procedures and Store_Actions_In_Scope
+ -- is ultimately invoked to store the pending actions.
+
+ -- A transient scope is finalized by calling one of the Wrap_Transient_xxx
+ -- procedures depending on the context as explained above. They ultimately
+ -- invoke Insert_Actions_In_Scope_Around as per the following picture:
+
+ -- Wrap_Transient_Expression Wrap_Transient_Statement
+ -- | |
+ -- V V
+ -- Make_Transient_Block
+ -- |
+ -- Wrap_Transient_Declaration |
+ -- | |
+ -- V V
+ -- Insert_Actions_In_Scope_Around
+
+ procedure Insert_Actions_In_Scope_Around
+ (N : Node_Id;
+ Clean : Boolean;
+ Manage_SS : Boolean);
+ -- Insert the before-actions kept in the scope stack before N, and the
+ -- after-actions after N, which must be a member of a list. If Clean is
+ -- true, insert any cleanup actions kept in the scope stack and generate
+ -- required finalization actions for the before-actions and after-actions.
+ -- If Manage_SS is true, insert calls to mark/release the secondary stack.
+
+ function Make_Transient_Block
+ (Loc : Source_Ptr;
+ Action : Node_Id;
+ Par : Node_Id) return Node_Id;
+ -- Action is a single statement or object declaration. Par is the proper
+ -- parent of the generated block. Create a transient block whose name is
+ -- the current scope and the only handled statement is Action. If Action
+ -- involves controlled objects or secondary stack usage, the corresponding
+ -- cleanup actions are performed at the end of the block.
+
+ procedure Store_Actions_In_Scope (AK : Scope_Action_Kind; L : List_Id);
+ -- Shared processing for Store_xxx_Actions_In_Scope
+
-------------------------------------------
-- Unnesting procedures for CCG and LLVM --
-------------------------------------------
@@ -5641,9 +5666,7 @@ package body Exp_Ch7 is
Blk_Ins := Last_Object;
end if;
- if Clean then
- Insert_List_After_And_Analyze (Blk_Ins, Act_Cleanup);
- end if;
+ Insert_List_After_And_Analyze (Blk_Ins, Act_Cleanup);
-- Examine all objects in the list First_Object .. Last_Object
@@ -5824,13 +5847,15 @@ package body Exp_Ch7 is
(Last_Obj, Build_SS_Release_Call (Loc, Mark_Id));
end if;
- -- Check for transient objects associated with Target and generate the
- -- appropriate finalization actions for them.
+ -- If we are handling cleanups, check for transient objects associated
+ -- with Target and generate the required finalization actions for them.
- Process_Transients_In_Scope
- (First_Object => First_Obj,
- Last_Object => Last_Obj,
- Related_Node => Target);
+ if Clean then
+ Process_Transients_In_Scope
+ (First_Object => First_Obj,
+ Last_Object => Last_Obj,
+ Related_Node => Target);
+ end if;
-- Reset the action lists
@@ -176,6 +176,12 @@ package Exp_Ch7 is
-- triggered by an abort, E_Id denotes the defining identifier of a local
-- exception occurrence, Raised_Id is the entity of a local boolean flag.
+ procedure Expand_Cleanup_Actions (N : Node_Id);
+ -- Expand the necessary stuff into a scope to enable finalization of local
+ -- objects and deallocation of transient data when exiting the scope. N is
+ -- one of N_Block_Statement, N_Subprogram_Body, N_Task_Body, N_Entry_Body,
+ -- or N_Extended_Return_Statement.
+
function Make_Adjust_Call
(Obj_Ref : Node_Id;
Typ : Entity_Id;
@@ -275,12 +281,6 @@ package Exp_Ch7 is
-- Transient Scope Management --
--------------------------------
- procedure Expand_Cleanup_Actions (N : Node_Id);
- -- Expand the necessary stuff into a scope to enable finalization of local
- -- objects and deallocation of transient data when exiting the scope. N is
- -- one of N_Block_Statement, N_Subprogram_Body, N_Task_Body, N_Entry_Body,
- -- or N_Extended_Return_Statement.
-
procedure Establish_Transient_Scope
(N : Node_Id;
Manage_Sec_Stack : Boolean);
@@ -14401,6 +14401,7 @@ package body Exp_Util is
----------------------------------
function Within_Case_Or_If_Expression (N : Node_Id) return Boolean is
+ Nod : Node_Id;
Par : Node_Id;
begin
@@ -14408,9 +14409,17 @@ package body Exp_Util is
-- can be expanded into Expression_With_Actions, hence the test of the
-- original node.
- Par := Parent (N);
+ Nod := N;
+ Par := Parent (Nod);
+
while Present (Par) loop
- if Nkind (Original_Node (Par)) in N_Case_Expression | N_If_Expression
+ if Nkind (Original_Node (Par)) = N_Case_Expression
+ and then Nod /= Expression (Original_Node (Par))
+ then
+ return True;
+
+ elsif Nkind (Original_Node (Par)) = N_If_Expression
+ and then Nod /= First (Expressions (Original_Node (Par)))
then
return True;
@@ -14430,7 +14439,8 @@ package body Exp_Util is
return False;
end if;
- Par := Parent (Par);
+ Nod := Par;
+ Par := Parent (Nod);
end loop;
return False;
@@ -1255,9 +1255,10 @@ package Exp_Util is
-- extension to verify legality rules on inherited conditions.
function Within_Case_Or_If_Expression (N : Node_Id) return Boolean;
- -- Determine whether arbitrary node N is immediately within a case or an if
- -- expression. The criterion is whether temporaries created by the actions
- -- attached to N need to outlive an enclosing case or if expression.
+ -- Determine whether arbitrary node N is immediately within a dependent
+ -- expression of a case or an if expression. The criterion is whether
+ -- temporaries created by the actions attached to N need to outlive an
+ -- enclosing case or if expression.
private
pragma Inline (Duplicate_Subexpr);