This fixes a wrong code issue with nested variant record types: the compiler 
generates move instructions that depend on an uninitialized variable, which 
was initially a SAVE_EXPR not instantiated early enough.

Tested on x86_64-suse-linux, applied on mainline, 10 and 9 branches.


2020-09-10  Eric Botcazou  <ebotca...@adacore.com>

        * gcc-interface/decl.c (build_subst_list): For a definition, make
        sure to instantiate the SAVE_EXPRs generated by the elaboration of
        the constraints in front of the elaboration of the type itself.


2020-09-10  Eric Botcazou  <ebotca...@adacore.com>

        * gnat.dg/discr59.adb: New test.
        * gnat.dg/discr59_pkg1.ads: New helper.
        * gnat.dg/discr59_pkg2.ads: Likewise.

-- 
Eric Botcazou
diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c
index 025714bd339..f85b2b5bbbb 100644
--- a/gcc/ada/gcc-interface/decl.c
+++ b/gcc/ada/gcc-interface/decl.c
@@ -8849,11 +8849,15 @@ build_subst_list (Entity_Id gnat_subtype, Entity_Id gnat_type, bool definition)
     if (!Is_Access_Type (Etype (Node (gnat_constr))))
       {
 	tree gnu_field = gnat_to_gnu_field_decl (gnat_discrim);
-	tree replacement = convert (TREE_TYPE (gnu_field),
-				    elaborate_expression
-				    (Node (gnat_constr), gnat_subtype,
-				     get_entity_char (gnat_discrim),
-				     definition, true, false));
+	tree replacement
+	  = elaborate_expression (Node (gnat_constr), gnat_subtype,
+				  get_entity_char (gnat_discrim),
+				  definition, true, false);
+	/* If this is a definition, we need to make sure that the SAVE_EXPRs
+	   are instantiated on every possibly path in size computations.  */
+	if (definition && TREE_CODE (replacement) == SAVE_EXPR)
+	  add_stmt (replacement);
+	replacement = convert (TREE_TYPE (gnu_field), replacement);
 	subst_pair s = { gnu_field, replacement };
 	gnu_list.safe_push (s);
       }
-- { dg-do run }

with Discr59_Pkg1; use Discr59_Pkg1;

procedure Discr59 is

   function At_Response_Decode return At_Response_Type is
      Fill : At_Response_Type (Alert, 1);
   begin
      return Fill;
   end;

   function Decode return Rec is
      Make : constant At_Response_Type := At_Response_Decode;
      Fill : Rec (At_Response, Make.Kind, Make.Units);
   begin
      return Fill;
   end;

   R : constant Rec := Decode;

begin
   null;
end;
generic

   Max_Length : Positive;

package Discr59_Pkg2 is

   type Token_Base_Type (Most : Natural) is record
      Text : String (1 .. Most) := (others => ' ');
      Last : Natural            := 0;
      Used : Natural            := 0;
   end record;

   type Token_Type is new Token_Base_Type (Max_Length);

end Discr59_Pkg2;
with Discr59_Pkg2;

package Discr59_Pkg1 is

   subtype Index_Type is Natural range 1 .. 300;

   type Code_Type is (Global_Query, Status_Query, Alert);

   type Id_Type is (None, At_Command, At_Response);

   package My_G is new Discr59_Pkg2 (21);

   type Arr is array (Index_Type range <>) of My_G.Token_Type;

   type Unit_List_Type (Last : Natural) is record
      A : Arr (1 .. Last);
   end record;

   type At_Response_Type (Kind : Code_Type; Units : Natural) is record
      case Kind is
         when Global_Query => Global_Query : Unit_List_Type (Units);
         when Status_Query => null;
         when Alert        => Alert : Unit_List_Type (Units);
      end case;
   end record;

   type Rec (Kind : Id_Type; Code : Code_Type; Units : Natural) is record
      case Kind is
         when None        => null;
         when At_Command  => null;
         when At_Response => At_Response : At_Response_Type (Code, Units);
      end case;
   end record;

end Discr59_Pkg1;

Reply via email to