The following patch updates the freezing of expressions to insert the
generated freeze nodes prior to the expression that produced them when
the context is a transient scope within a type initialization procedure.
This ensures that the nodes are properly interleaved with respect to the
constructs that generated them.

Tested on x86_64-pc-linux-gnu, committed on trunk

2019-07-01  Hristian Kirtchev  <kirtc...@adacore.com>

gcc/ada/

        * freeze.adb (Freeze_Expression): Remove the horrible useless
        name hiding of N. Insert the freeze nodes generated by the
        expression prior to the expression when the nearest enclosing
        scope is transient.

gcc/testsuite/

        * gnat.dg/freezing1.adb, gnat.dg/freezing1.ads,
        gnat.dg/freezing1_pack.adb, gnat.dg/freezing1_pack.ads: New
        testcase.
--- gcc/ada/freeze.adb
+++ gcc/ada/freeze.adb
@@ -7665,9 +7665,8 @@ package body Freeze is
         or else Ekind (Current_Scope) = E_Void
       then
          declare
-            N            : constant Node_Id := Current_Scope;
-            Freeze_Nodes : List_Id          := No_List;
-            Pos          : Int              := Scope_Stack.Last;
+            Freeze_Nodes : List_Id := No_List;
+            Pos          : Int     := Scope_Stack.Last;
 
          begin
             if Present (Desig_Typ) then
@@ -7700,7 +7699,19 @@ package body Freeze is
             end if;
 
             if Is_Non_Empty_List (Freeze_Nodes) then
-               if No (Scope_Stack.Table (Pos).Pending_Freeze_Actions) then
+
+               --  When the current scope is transient, insert the freeze nodes
+               --  prior to the expression that produced them. Transient scopes
+               --  may create additional declarations when finalizing objects
+               --  or managing the secondary stack. Inserting the freeze nodes
+               --  of those constructs prior to the scope would result in a
+               --  freeze-before-declaration, therefore the freeze node must
+               --  remain interleaved with their constructs.
+
+               if Scope_Is_Transient then
+                  Insert_Actions (N, Freeze_Nodes);
+
+               elsif No (Scope_Stack.Table (Pos).Pending_Freeze_Actions) then
                   Scope_Stack.Table (Pos).Pending_Freeze_Actions :=
                     Freeze_Nodes;
                else

--- /dev/null
new file mode 100644
+++ gcc/testsuite/gnat.dg/freezing1.adb
@@ -0,0 +1,5 @@
+--  { dg-do compile }
+
+package body Freezing1 is
+   procedure Foo is null;
+end Freezing1;

--- /dev/null
new file mode 100644
+++ gcc/testsuite/gnat.dg/freezing1.ads
@@ -0,0 +1,10 @@
+with Freezing1_Pack; use Freezing1_Pack;
+
+package Freezing1 is
+   type T is abstract tagged record
+      Collection : access I_Interface_Collection'Class :=
+        new I_Interface_Collection'Class'(Factory.Create_Collection);
+   end record;
+
+   procedure Foo;
+end Freezing1;

--- /dev/null
new file mode 100644
+++ gcc/testsuite/gnat.dg/freezing1_pack.adb
@@ -0,0 +1,8 @@
+package body Freezing1_Pack is
+   function Create_Collection
+     (Factory : in T_Factory) return I_Interface_Collection'Class
+   is
+   begin
+      return Implem'(null record);
+   end Create_Collection;
+end Freezing1_Pack;

--- /dev/null
new file mode 100644
+++ gcc/testsuite/gnat.dg/freezing1_pack.ads
@@ -0,0 +1,16 @@
+package Freezing1_Pack is
+   type T_Factory is abstract tagged private;
+   type I_Interface_Collection is interface;
+
+   Factory : constant T_Factory;
+
+   function Create_Collection
+     (Factory : in T_Factory) return I_Interface_Collection'Class;
+
+   type Implem is new I_Interface_Collection with null record;
+
+private
+   type T_Factory is tagged null record;
+
+   Factory : constant T_Factory := T_Factory'(null record);
+end Freezing1_Pack;

Reply via email to