From: Eric Botcazou <ebotca...@adacore.com>

The mechanim deferring the expansion of record aggregates nested in other
aggregates with intermediate conditional expressions is disabled in the
case where they contain self-references, because of a technical limitation
in the replacements done by Build_Record_Aggr_Code.  This change lifts it.

gcc/ada/ChangeLog:

        * exp_aggr.adb (Traverse_Proc_For_Aggregate): New generic procedure.
        (Replace_Discriminants): Instantiate it instead of Traverse_Proc.
        (Replace_Self_Reference): Likewise.
        (Convert_To_Assignments): Remove limitation for nested aggregates
        that contain self-references.

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

---
 gcc/ada/exp_aggr.adb | 90 ++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 82 insertions(+), 8 deletions(-)

diff --git a/gcc/ada/exp_aggr.adb b/gcc/ada/exp_aggr.adb
index 9162e9694f9..d0ccaa4f3ff 100644
--- a/gcc/ada/exp_aggr.adb
+++ b/gcc/ada/exp_aggr.adb
@@ -2268,6 +2268,16 @@ package body Exp_Aggr is
       --  If default expression of a component mentions a discriminant of the
       --  type, it must be rewritten as the discriminant of the target object.
 
+      generic
+         with function Process (N : Node_Id) return Traverse_Result is <>;
+      procedure Traverse_Proc_For_Aggregate (N : Node_Id);
+      pragma Inline (Traverse_Proc_For_Aggregate);
+      --  This extends Traverse_Proc from Atree by looking into the Actions
+      --  list of conditional expressions, which are semantic fields and not
+      --  syntactic ones like the Actions of an N_Expression_With_Actions.
+      --  This makes it possible to delay the expansion of these conditional
+      --  expressions when they appear within the aggregate.
+
       ---------------------------------
       -- Ancestor_Discriminant_Value --
       ---------------------------------
@@ -2825,11 +2835,78 @@ package body Exp_Aggr is
          return OK;
       end Rewrite_Discriminant;
 
+      ---------------------------------
+      -- Traverse_Proc_For_Aggregate --
+      ---------------------------------
+
+      procedure Traverse_Proc_For_Aggregate (N : Node_Id) is
+
+         function Process_For_Aggregate (N : Node_Id) return Traverse_Result;
+         --  Call Process on N and on the nodes in the Actions list of N if
+         --  it is a conditional expression.
+
+         procedure Traverse_Node is new Traverse_Proc (Process_For_Aggregate);
+         --  Call Process_For_Aggregate on the subtree rooted at N
+
+         ---------------------------
+         -- Process_For_Aggregate --
+         ---------------------------
+
+         function Process_For_Aggregate (N : Node_Id) return Traverse_Result is
+
+            procedure Traverse_List (L : List_Id);
+            pragma Inline (Traverse_List);
+            --  Call Traverse_Node on the nodes of list L
+
+            --------------------
+            -- Traverse_List --
+            --------------------
+
+            procedure Traverse_List (L : List_Id) is
+               N : Node_Id := First (L);
+
+            begin
+               while Present (N) loop
+                  Traverse_Node (N);
+                  Next (N);
+               end loop;
+            end Traverse_List;
+
+            --  Local variables
+
+            Alt     : Node_Id;
+            Discard : Traverse_Final_Result;
+            pragma Unreferenced (Discard);
+
+         --  Start of processing for Process_For_Aggregate
+
+         begin
+            Discard := Process (N);
+
+            if Nkind (N) = N_Case_Expression then
+               Alt := First (Alternatives (N));
+               while Present (Alt) loop
+                  Traverse_List (Actions (Alt));
+                  Next (Alt);
+               end loop;
+
+            elsif Nkind (N) = N_If_Expression then
+               Traverse_List (Then_Actions (N));
+               Traverse_List (Else_Actions (N));
+            end if;
+
+            return OK;
+         end Process_For_Aggregate;
+
+      begin
+         Traverse_Node (N);
+      end Traverse_Proc_For_Aggregate;
+
       procedure Replace_Discriminants is
-        new Traverse_Proc (Rewrite_Discriminant);
+        new Traverse_Proc_For_Aggregate (Rewrite_Discriminant);
 
       procedure Replace_Self_Reference is
-        new Traverse_Proc (Replace_Type);
+        new Traverse_Proc_For_Aggregate (Replace_Type);
 
    --  Start of processing for Build_Record_Aggr_Code
 
@@ -4131,16 +4208,13 @@ package body Exp_Aggr is
       if
          --  Internal aggregates (transformed when expanding the parent),
          --  excluding container aggregates as these are transformed into
-         --  subprogram calls later. So far aggregates with self-references
-         --  are not supported if they appear in a conditional expression.
+         --  subprogram calls later.
 
          (Nkind (Parent_Node) = N_Component_Association
-           and then not Is_Container_Aggregate (Parent (Parent_Node))
-           and then not (In_Cond_Expr and then Has_Self_Reference (N)))
+           and then not Is_Container_Aggregate (Parent (Parent_Node)))
 
          or else (Nkind (Parent_Node) in N_Aggregate | N_Extension_Aggregate
-                   and then not Is_Container_Aggregate (Parent_Node)
-                   and then not (In_Cond_Expr and then Has_Self_Reference (N)))
+                   and then not Is_Container_Aggregate (Parent_Node))
 
          --  Allocator (see Convert_Aggr_In_Allocator)
 
-- 
2.43.0

Reply via email to