[COMMITTED] ada: Further cleanup in finalization machinery

Message ID 20231219142956.454370-1-poulhies@adacore.com
State Committed
Commit 54d049b2815a03d1f58dee4df1c4cc0b0faddcc1
Headers
Series [COMMITTED] ada: Further cleanup in finalization machinery |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 fail Patch failed to apply

Commit Message

Marc Poulhiès Dec. 19, 2023, 2:29 p.m. UTC
  From: Eric Botcazou <ebotcazou@adacore.com>

This streamlines the submachinery that makes it so that the finalization of
temporaries created for EWAs and conditional expressions is deferred to the
enclosing context.

The original implementation was using a deep tree traversal for EWAs, which
was later restricted to immediate subexpressions; this further flattens it
to the traversal of the immediate list of actions of the EWA in keeping with
the implementation for conditional expressions.

This should not change anything because the enclosing context found by the
machinery is the same, whatever the starting position in a nest of EWAs or
conditional expressions.

gcc/ada/

	* exp_ch4.adb (Process_If_Case_Statements): Rename into...
	(Process_Transients_In_Expression): ...this and beef up comment.
	(Expand_N_Case_Expression): Call Process_Transients_In_Expression
	unconditionally on the list of actions of each alternative.
	(Expand_N_Expression_With_Actions): Do not deal with actions in
	nested subexpressions, but call Process_Transients_In_Expression
	on the list of actions only.
	(Expand_N_If_Expression): Adjust to above renaming.  Add missing
	calls to Process_Transients_In_Expression in the case when an EWA
	is not used because of Minimize_Expression_With_Actions.

Tested on x86_64-pc-linux-gnu, committed on master.

---
 gcc/ada/exp_ch4.adb | 154 +++++++++++++++++++-------------------------
 1 file changed, 66 insertions(+), 88 deletions(-)
  

Patch

diff --git a/gcc/ada/exp_ch4.adb b/gcc/ada/exp_ch4.adb
index 99be96d3ab7..8f4cf0808dc 100644
--- a/gcc/ada/exp_ch4.adb
+++ b/gcc/ada/exp_ch4.adb
@@ -241,11 +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_If_Case_Statements (N : Node_Id; Stmts : List_Id);
-   --  Inspect and process statement list Stmt of if or case expression N for
-   --  transient objects. If such objects are found, the routine generates code
-   --  to clean them up when the context of the expression is evaluated.
-
    procedure Process_Transient_In_Expression
      (Obj_Decl : Node_Id;
       Expr     : Node_Id;
@@ -255,9 +250,25 @@  package body Exp_Ch4 is
    --  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 the
-   --  statement list which contains Decl, either at the top level or within a
-   --  nested construct.
+   --  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);
+   --  Subsidiary routine to the expansion of expression_with_actions, if and
+   --  case expressions. Inspect and process actions list Stmts of expression
+   --  Expr for transient objects. If such objects are found, the routine will
+   --  generate code to finalize them when the enclosing context is elaborated
+   --  or evaluated.
+
+   --  This specific processing is required for these expressions because the
+   --  management of transient objects for expressions implemented in Exp_Ch7
+   --  cannot deal with nested lists of actions whose effects may outlive the
+   --  lists and affect the result of the parent expressions. In these cases,
+   --  the lifetime of temporaries created in these lists must be extended to
+   --  match that of the enclosing context of the parent expressions and, in
+   --  particular, their finalization must be deferred to this context.
 
    procedure Rewrite_Comparison (N : Node_Id);
    --  If N is the node for a comparison whose outcome can be determined at
@@ -5411,14 +5422,10 @@  package body Exp_Ch4 is
                  Statements       => Stmts));
 
             --  Finalize any transient objects on exit from the alternative.
-            --  This needs to be done only when the case expression is _not_
-            --  later converted into an expression with actions, which already
-            --  contains this form of processing, and after Stmts is attached
+            --  Note that this needs to be done only after Stmts is attached
             --  to the Alternatives list above (for Safe_To_Capture_Value).
 
-            if Optimize_Return_Stmt or else not Is_Copy_Type (Typ) then
-               Process_If_Case_Statements (N, Stmts);
-            end if;
+            Process_Transients_In_Expression (N, Stmts);
          end;
 
          Next (Alt);
@@ -5482,12 +5489,6 @@  package body Exp_Ch4 is
       procedure Force_Boolean_Evaluation (Expr : Node_Id);
       --  Force the evaluation of Boolean expression Expr
 
-      function Process_Action (Act : Node_Id) return Traverse_Result;
-      --  Inspect and process a single action of an expression_with_actions for
-      --  transient objects. If such objects are found, the routine generates
-      --  code to clean them up when the context of the expression is evaluated
-      --  or elaborated.
-
       ------------------------------
       -- Force_Boolean_Evaluation --
       ------------------------------
@@ -5520,42 +5521,6 @@  package body Exp_Ch4 is
          Analyze (Expression (N));
       end Force_Boolean_Evaluation;
 
-      --------------------
-      -- Process_Action --
-      --------------------
-
-      function Process_Action (Act : Node_Id) return Traverse_Result is
-      begin
-         if Nkind (Act) = N_Object_Declaration
-           and then Is_Finalizable_Transient (Act, N)
-         then
-            Process_Transient_In_Expression (Act, N, Acts);
-            return Skip;
-
-         --  Avoid processing temporary function results multiple times when
-         --  dealing with nested expression_with_actions or nested blocks.
-         --  Similarly, do not process temporary function results in loops.
-         --  This is done by Expand_N_Loop_Statement and Build_Finalizer.
-         --  Note that we used to wrongly return Abandon instead of Skip here:
-         --  this is wrong since it means that we were ignoring lots of
-         --  relevant subsequent statements.
-
-         elsif Nkind (Act) in N_Expression_With_Actions
-                            | N_Block_Statement
-                            | N_Loop_Statement
-         then
-            return Skip;
-         end if;
-
-         return OK;
-      end Process_Action;
-
-      procedure Process_Single_Action is new Traverse_Proc (Process_Action);
-
-      --  Local variables
-
-      Act : Node_Id;
-
    --  Start of processing for Expand_N_Expression_With_Actions
 
    begin
@@ -5616,14 +5581,9 @@  package body Exp_Ch4 is
          Force_Evaluation (Expression (N));
       end if;
 
-      --  Process all transient objects found within the actions of the EWA
-      --  node.
+      --  Process transient objects found within the actions of the EWA node
 
-      Act := First (Acts);
-      while Present (Act) loop
-         Process_Single_Action (Act);
-         Next (Act);
-      end loop;
+      Process_Transients_In_Expression (N, Acts);
 
       --  Deal with case where there are no actions. In this case we simply
       --  rewrite the node with its expression since we don't need the actions
@@ -5802,8 +5762,8 @@  package body Exp_Ch4 is
          --  of actions. These temporaries need to be finalized after the if
          --  expression is evaluated.
 
-         Process_If_Case_Statements (N, Then_Actions (N));
-         Process_If_Case_Statements (N, Else_Actions (N));
+         Process_Transients_In_Expression (N, Then_Actions (N));
+         Process_Transients_In_Expression (N, Else_Actions (N));
 
          New_If :=
            Make_Implicit_If_Statement (N,
@@ -5843,8 +5803,8 @@  package body Exp_Ch4 is
          --  of actions. These temporaries need to be finalized after the if
          --  expression is evaluated.
 
-         Process_If_Case_Statements (N, Then_Actions (N));
-         Process_If_Case_Statements (N, Else_Actions (N));
+         Process_Transients_In_Expression (N, Then_Actions (N));
+         Process_Transients_In_Expression (N, Else_Actions (N));
 
          declare
             Cnn     : constant Entity_Id := Make_Temporary (Loc, 'C', N);
@@ -6186,13 +6146,20 @@  package body Exp_Ch4 is
         or else Present (Else_Actions (N))
         or else Force_Expand
       then
-
          --  We now wrap the actions into the appropriate expression
 
          if Minimize_Expression_With_Actions
            and then (Is_Elementary_Type (Underlying_Type (Typ))
                       or else Is_Constrained (Underlying_Type (Typ)))
          then
+            --  When the "then" or "else" expressions involve controlled
+            --  function calls, generated temporaries are chained on the
+            --  corresponding list of actions. These temporaries need to
+            --  be finalized after the if expression is evaluated.
+
+            Process_Transients_In_Expression (N, Then_Actions (N));
+            Process_Transients_In_Expression (N, Else_Actions (N));
+
             --  If we can't use N_Expression_With_Actions nodes, then we insert
             --  the following sequence of actions (using Insert_Actions):
 
@@ -6239,6 +6206,10 @@  package body Exp_Ch4 is
          --  Regular path using Expression_With_Actions
 
          else
+            --  We do not need to call Process_Transients_In_Expression on
+            --  the list of actions in this case, because the expansion of
+            --  Expression_With_Actions will do it.
+
             if Present (Then_Actions (N)) then
                Rewrite (Thenx,
                  Make_Expression_With_Actions (Sloc (Thenx),
@@ -14938,26 +14909,6 @@  package body Exp_Ch4 is
       Analyze_And_Resolve (N, Typ, Suppress => Overflow_Check);
    end Optimize_Length_Comparison;
 
-   --------------------------------
-   -- Process_If_Case_Statements --
-   --------------------------------
-
-   procedure Process_If_Case_Statements (N : Node_Id; Stmts : List_Id) is
-      Decl : Node_Id;
-
-   begin
-      Decl := First (Stmts);
-      while Present (Decl) loop
-         if Nkind (Decl) = N_Object_Declaration
-           and then Is_Finalizable_Transient (Decl, N)
-         then
-            Process_Transient_In_Expression (Decl, N, Stmts);
-         end if;
-
-         Next (Decl);
-      end loop;
-   end Process_If_Case_Statements;
-
    -------------------------------------
    -- Process_Transient_In_Expression --
    -------------------------------------
@@ -15116,6 +15067,33 @@  package body Exp_Ch4 is
       end if;
    end Process_Transient_In_Expression;
 
+   --------------------------------------
+   -- Process_Transients_In_Expression --
+   --------------------------------------
+
+   procedure Process_Transients_In_Expression
+     (Expr : Node_Id;
+      Stmts : List_Id)
+   is
+      Decl : Node_Id;
+
+   begin
+      pragma Assert (Nkind (Expr) in N_Case_Expression
+                                   | N_Expression_With_Actions
+                                   | N_If_Expression);
+
+      Decl := First (Stmts);
+      while Present (Decl) loop
+         if Nkind (Decl) = N_Object_Declaration
+           and then Is_Finalizable_Transient (Decl, Expr)
+         then
+            Process_Transient_In_Expression (Decl, Expr, Stmts);
+         end if;
+
+         Next (Decl);
+      end loop;
+   end Process_Transients_In_Expression;
+
    ------------------------
    -- Rewrite_Comparison --
    ------------------------