[COMMITTED,08/30] ada: Fix internal error on limited aggregate in nested conditional expression

Message ID 20240801151738.400796-8-poulhies@adacore.com
State Committed
Commit 7b1ad03b84fdd727b695da59703debd676c93f2e
Headers
Series [COMMITTED,01/30] ada: Remove obsolete workaround |

Commit Message

Marc Poulhiès Aug. 1, 2024, 3:17 p.m. UTC
  From: Eric Botcazou <ebotcazou@adacore.com>

This is a fallout of an earlier fix to Is_Build_In_Place_Aggregate_Return
that made it take into account intermediate conditional expressions, but
turned out to work only for a single nesting level of them.

The fix reuses the delayed expansion mechanism recently extended to deal
with conditional expressions in a straightforward way.

gcc/ada/

	* exp_aggr.adb (Convert_To_Assignments): Set Expansion_Delayed on
	intermediate conditional expressions for BIP aggregate returns
	too.
	* exp_ch4.adb (Expand_N_Case_Expression): Also deal with delayed
	expansion in the return case.
	(Expand_N_If_Expression): Likewise.

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

---
 gcc/ada/exp_aggr.adb | 28 ++++++++---------
 gcc/ada/exp_ch4.adb  | 73 ++++++++++++++++++++++++++++++++------------
 2 files changed, 66 insertions(+), 35 deletions(-)
  

Patch

diff --git a/gcc/ada/exp_aggr.adb b/gcc/ada/exp_aggr.adb
index c7730ca754a..2031d042fa5 100644
--- a/gcc/ada/exp_aggr.adb
+++ b/gcc/ada/exp_aggr.adb
@@ -4265,6 +4265,19 @@  package body Exp_Aggr is
 
          or else (Nkind (Parent_Node) = N_Assignment_Statement
                    and then Inside_Init_Proc)
+
+         --  (Ada 2005) An inherently limited type in a return statement, which
+         --  will be handled in a build-in-place fashion, and may be rewritten
+         --  as an extended return and have its own finalization machinery.
+         --  In the case of a simple return, the aggregate needs to be delayed
+         --  until the scope for the return statement has been created, so
+         --  that any finalization chain will be associated with that scope.
+         --  For extended returns, we delay expansion to avoid the creation
+         --  of an unwanted transient scope that could result in premature
+         --  finalization of the return object (which is built in place
+         --  within the caller's scope).
+
+         or else Is_Build_In_Place_Aggregate_Return (N)
       then
          Node := N;
 
@@ -4286,21 +4299,6 @@  package body Exp_Aggr is
          end loop;
 
          return;
-
-      --  (Ada 2005) An inherently limited type in a return statement, which
-      --  will be handled in a build-in-place fashion, and may be rewritten
-      --  as an extended return and have its own finalization machinery.
-      --  In the case of a simple return, the aggregate needs to be delayed
-      --  until the scope for the return statement has been created, so
-      --  that any finalization chain will be associated with that scope.
-      --  For extended returns, we delay expansion to avoid the creation
-      --  of an unwanted transient scope that could result in premature
-      --  finalization of the return object (which is built in place
-      --  within the caller's scope).
-
-      elsif Is_Build_In_Place_Aggregate_Return (N) then
-         Set_Expansion_Delayed (N);
-         return;
       end if;
 
       --  Otherwise, if a transient scope is required, create it now
diff --git a/gcc/ada/exp_ch4.adb b/gcc/ada/exp_ch4.adb
index f952005ed75..50c3cd430ce 100644
--- a/gcc/ada/exp_ch4.adb
+++ b/gcc/ada/exp_ch4.adb
@@ -5010,7 +5010,7 @@  package body Exp_Ch4 is
       Target     : Entity_Id := Empty;
       Target_Typ : Entity_Id;
 
-      Optimize_Assignment_Stmt : Boolean;
+      Optimize_Assignment_Stmt : Boolean := False;
       --  Small optimization: when the case expression appears in the context
       --  of a safe assignment statement, expand into
 
@@ -5029,18 +5029,22 @@  package body Exp_Ch4 is
 
    begin
       --  If the expansion of the expression has been delayed, we wait for the
-      --  rewriting of its parent as an assignment statement; when that's done,
-      --  we optimize the assignment (the very purpose of the manipulation).
+      --  rewriting of its parent as an assignment or return statement; when
+      --  that's done, we optimize the assignment or the return statement (the
+      --  very purpose of the manipulation).
 
       if Expansion_Delayed (N) then
-         if Nkind (Par) /= N_Assignment_Statement then
+         if Nkind (Par) = N_Assignment_Statement then
+            Optimize_Assignment_Stmt := True;
+
+         elsif Optimize_Return_Stmt then
+            null;
+
+         else
             return;
          end if;
 
-         Optimize_Assignment_Stmt := True;
-
-      else
-         Optimize_Assignment_Stmt := False;
+         Set_Expansion_Delayed (N, False);
       end if;
 
       --  Check for MINIMIZED/ELIMINATED overflow mode
@@ -5192,6 +5196,13 @@  package body Exp_Ch4 is
                  Make_Simple_Return_Statement (Alt_Loc,
                    Expression => Alt_Expr));
 
+               --  If the expression is itself a conditional expression whose
+               --  expansion has been delayed, analyze it again and expand it.
+
+               if Is_Delayed_Conditional_Expression (Alt_Expr) then
+                  Set_Analyzed (Alt_Expr, False);
+               end if;
+
             --  Take the unrestricted access of the expression value for non-
             --  scalar types. This approach avoids big copies and covers the
             --  limited and unconstrained cases.
@@ -5493,7 +5504,7 @@  package body Exp_Ch4 is
       New_N    : Node_Id;
       New_Then : Node_Id;
 
-      Optimize_Assignment_Stmt : Boolean;
+      Optimize_Assignment_Stmt : Boolean := False;
       --  Small optimization: when the if expression appears in the context of
       --  a safe assignment statement, expand into
 
@@ -5510,18 +5521,22 @@  package body Exp_Ch4 is
 
    begin
       --  If the expansion of the expression has been delayed, we wait for the
-      --  rewriting of its parent as an assignment statement; when that's done,
-      --  we optimize the assignment (the very purpose of the manipulation).
+      --  rewriting of its parent as an assignment or return statement; when
+      --  that's done, we optimize the assignment or the return statement (the
+      --  very purpose of the manipulation).
 
       if Expansion_Delayed (N) then
-         if Nkind (Par) /= N_Assignment_Statement then
+         if Nkind (Par) = N_Assignment_Statement then
+            Optimize_Assignment_Stmt := True;
+
+         elsif Optimize_Return_Stmt then
+            null;
+
+         else
             return;
          end if;
 
-         Optimize_Assignment_Stmt := True;
-
-      else
-         Optimize_Assignment_Stmt := False;
+         Set_Expansion_Delayed (N, False);
       end if;
 
       --  Deal with non-standard booleans
@@ -5652,15 +5667,33 @@  package body Exp_Ch4 is
          Process_Transients_In_Expression (N, Then_Actions (N));
          Process_Transients_In_Expression (N, Else_Actions (N));
 
+         New_Then := Relocate_Node (Thenx);
+
+         --  If the expression is itself a conditional expression whose
+         --  expansion has been delayed, analyze it again and expand it.
+
+         if Is_Delayed_Conditional_Expression (New_Then) then
+            Set_Analyzed (New_Then, False);
+         end if;
+
+         New_Else := Relocate_Node (Elsex);
+
+         --  If the expression is itself a conditional expression whose
+         --  expansion has been delayed, analyze it again and expand it.
+
+         if Is_Delayed_Conditional_Expression (New_Else) then
+            Set_Analyzed (New_Else, False);
+         end if;
+
          New_If :=
            Make_Implicit_If_Statement (N,
              Condition       => Relocate_Node (Cond),
              Then_Statements => New_List (
-               Make_Simple_Return_Statement (Sloc (Thenx),
-                 Expression => Relocate_Node (Thenx))),
+               Make_Simple_Return_Statement (Sloc (New_Then),
+                 Expression => New_Then)),
              Else_Statements => New_List (
-               Make_Simple_Return_Statement (Sloc (Elsex),
-                 Expression => Relocate_Node (Elsex))));
+               Make_Simple_Return_Statement (Sloc (New_Else),
+                 Expression => New_Else)));
 
          --  Preserve the original context for which the if statement is
          --  being generated. This is needed by the finalization machinery