From: Javier Miranda <[email protected]>

Enforce the following rule: If the component of a record type is of
a type that doesn't have a parameterless constructor, it has to be
initialized by one of these two mechanism: 1) through the default
value provided at component declaration, or 2) through an Initialize
aspect that can rely on constructor parameters.

Enforce the following rule: a constructor for a derived type whose
parent type needs construction and has no default parameterless
constructor must call the parent constructor through a Super aspect
to initialize its parent components.

Fix order of initialization of derived record type components.

gcc/ada/ChangeLog:

        * sem_ch6.adb (Constructor_Components_OK): New local subprogram of
        Analyze_Direct_Attribute_Definition. Checks performed when processing
        the body of a constructor.
        (Analyze_Direct_Attribute_Definition) <Name_Constructor>: Report an
        error on the body of a constructor for a derived type whose parent
        type needs construction and has no default parameterless constructor
        and has no Super aspect to initialize its parent components.
        * sem_ch7.adb (Inspect_Components_Needing_Construction): New local
        subprogram of Analyze_Package_Specification.
        (Inspect_Abstract_Constructors_Completion): Rename formal parameter.
        * exp_ch6.adb (Prepend_Constructor_Procedure_Prologue): Fix the order
        of initialization of record type components: parent components must
        be initialized first, then the own components following their
        declaration order.
        * sem_util.ads (First_Component_Declaration): New subprogram.
        * sem_util.adb (First_Component_Declaration): New utility subprogram
        that returns the first non-pragma non-inherited component declaration
        of a record type.

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

---
 gcc/ada/exp_ch6.adb  | 54 +++++++++++++++---------
 gcc/ada/sem_ch6.adb  | 97 ++++++++++++++++++++++++++++++++++++++------
 gcc/ada/sem_ch7.adb  | 62 ++++++++++++++++++++++++++--
 gcc/ada/sem_util.adb | 36 ++++++++++++++++
 gcc/ada/sem_util.ads | 10 +++++
 5 files changed, 223 insertions(+), 36 deletions(-)

diff --git a/gcc/ada/exp_ch6.adb b/gcc/ada/exp_ch6.adb
index 21275bbfe18..d9ab5ee108c 100644
--- a/gcc/ada/exp_ch6.adb
+++ b/gcc/ada/exp_ch6.adb
@@ -6145,13 +6145,14 @@ package body Exp_Ch6 is
          Component        : Entity_Id;
 
          Comp_List        : constant List_Id := New_List;
-         Initialize_List  : constant List_Id := New_List;
          Tag_List         : constant List_Id := New_List;
          Parent_List      : constant List_Id := New_List;
-         --  Comp_List contains the list of default initializations, init
-         --  procedure calls, or constructor calls for components;
-         --  Initialize_List contains the list of component initializations
-         --  coming from the Initialize aspect;
+         --  Comp_List contains component initializations (from the Initialize
+         --  aspect or component default expressions), in record declaration
+         --  order; when a component is named in the Initialize aspect, that
+         --  expression takes priority over the component's default expression,
+         --  which is used only when the component is not mentioned in the
+         --  Initialize aspect;
          --  Tag_List contains the initialization for the tag;
          --  Parent_List contains the parent constructor call.
 
@@ -6200,10 +6201,13 @@ package body Exp_Ch6 is
             end if;
 
             if Chars (Component) = Name_uTag then
-               Append_To (Tag_List,
-                 Make_Tag_Assignment_From_Type (Loc,
-                   Target => New_Occurrence_Of (First_Formal (Spec_Id), Loc),
-                   Typ    => First_Param_Type));
+               if Tagged_Type_Expansion then
+                  Append_To (Tag_List,
+                    Make_Tag_Assignment_From_Type (Loc,
+                      Target =>
+                        New_Occurrence_Of (First_Formal (Spec_Id), Loc),
+                      Typ    => First_Param_Type));
+               end if;
 
             elsif Chars (Component) = Name_uParent
               and then Needs_Construction (Etype (Component))
@@ -6215,6 +6219,21 @@ package body Exp_Ch6 is
                  Make_Parent_Constructor_Call
                    (Parent_Type => Etype (Component)));
 
+            --  Inherited components are handled by the parent constructor
+
+            elsif Original_Record_Component (Component) /= Component then
+               null;
+
+            --  A derived type with a parent that needs construction has a
+            --  Super aspect that initializes its parent components; otherwise
+            --  it had been rejected during semantic analysis (see subprogram
+            --  Sem_Ch6.Analyze_Direct_Attribute_Definition).
+
+            elsif Chars (Component) = Name_uParent
+              and then Needs_Construction (Etype (Component))
+            then
+               null;
+
             else
                declare
                   Maybe_Initialize             : constant Node_Id :=
@@ -6238,18 +6257,15 @@ package body Exp_Ch6 is
                   then
                      declare
                         Init : Node_Id;
-                        List : List_Id;
 
                      begin
                         if Present (Maybe_Initialize) then
                            Init := Maybe_Initialize;
-                           List := Initialize_List;
                         else
                            Init := Maybe_Default_Or_Constructor;
-                           List := Comp_List;
                         end if;
 
-                        Append_List_To (List,
+                        Append_List_To (Comp_List,
                           Build_Component_Assignment (Loc,
                             Prefix       =>
                               New_Occurrence_Of (First_Formal (Spec_Id), Loc),
@@ -6289,14 +6305,12 @@ package body Exp_Ch6 is
             Next_Entity (Component);
          end loop;
 
-         --  First, use default value initializations and init procedures,
-         --  then call the parent constructor (if any), then initialize all
-         --  other components through the Initialize aspect, last the tag.
+         --  First call the parent constructor (if any), then initialize all
+         --  components in record declaration order, then set the tag.
 
-         Append_List (Tag_List, Initialize_List);
-         Append_List (Initialize_List, Parent_List);
-         Append_List (Parent_List, Comp_List);
-         Insert_List_Before_And_Analyze (First (L), Comp_List);
+         Append_List (Comp_List, Parent_List);
+         Append_List (Tag_List, Parent_List);
+         Insert_List_Before_And_Analyze (First (L), Parent_List);
 
          End_Scope;
       end Prepend_Constructor_Procedure_Prologue;
diff --git a/gcc/ada/sem_ch6.adb b/gcc/ada/sem_ch6.adb
index 0f886a5db56..a2028768c40 100644
--- a/gcc/ada/sem_ch6.adb
+++ b/gcc/ada/sem_ch6.adb
@@ -5244,6 +5244,15 @@ package body Sem_Ch6 is
          --  already explicitly specifies the aspect or inherits the aspect
          --  from a type that explicitly specifies it.
 
+         function Constructor_Components_OK
+           (Typ : Entity_Id; Subp : Node_Id) return Boolean;
+         --  Called when processing the body of a constructor for record type
+         --  Typ. Checks non-inherited components of Typ and reports an error
+         --  on each component whose type is a record type with no default
+         --  parameterless constructor, no default initialization, and no
+         --  explicit default expression. Returns True if no such component
+         --  is found, and False if at least one error was emitted.
+
          -----------------------------------
          -- Add_Default_Initialize_Aspect --
          -----------------------------------
@@ -5362,12 +5371,50 @@ package body Sem_Ch6 is
             end if;
          end Create_And_Append_Aspect;
 
+         -------------------------------
+         -- Constructor_Components_OK --
+         -------------------------------
+
+         function Constructor_Components_OK
+           (Typ : Entity_Id; Subp : Node_Id) return Boolean
+         is
+            Comp_Decl : Node_Id;
+            Comp_Id   : Entity_Id;
+            Comp_Typ  : Entity_Id;
+            OK        : Boolean := True;
+
+         begin
+            Comp_Decl := First_Component_Declaration (Typ);
+            while Present (Comp_Decl) loop
+               if Nkind (Comp_Decl) = N_Component_Declaration then
+                  Comp_Id  := Defining_Identifier (Comp_Decl);
+                  Comp_Typ := Etype (Comp_Id);
+
+                  if Chars (Comp_Id) /= Name_uParent
+                    and then Is_Record_Type (Comp_Typ)
+                    and then not Has_Parameterless_Constructor (Comp_Typ)
+                    and then not Is_Fully_Initialized_Type (Comp_Typ)
+                    and then No (Expression (Comp_Decl))
+                  then
+                     Error_Msg_NE
+                       ("explicit initialization required for component &",
+                        Subp, Comp_Id);
+                     OK := False;
+                  end if;
+               end if;
+
+               Next_Non_Pragma (Comp_Decl);
+            end loop;
+
+            return OK;
+         end Constructor_Components_OK;
+
          --  Local variables
 
-         Att_N      : constant Node_Id := Original_Node (N);
-         Att_Prefix : constant Node_Id := Prefix (Defining_Unit_Name (Att_N));
-         Att_Name   : constant Name_Id :=
-           Attribute_Name (Defining_Unit_Name (Att_N));
+         Att_N      : constant Node_Id   := Original_Node (N);
+         Def_Name   : constant Entity_Id := Defining_Unit_Name (Att_N);
+         Att_Name   : constant Name_Id   := Attribute_Name (Def_Name);
+         Att_Prefix : constant Node_Id   := Prefix (Def_Name);
 
          Is_Class_Wide_Attr : constant Boolean :=
            Nkind (Att_Prefix) = N_Attribute_Reference
@@ -5384,6 +5431,9 @@ package body Sem_Ch6 is
       --  Start of processing for Analyze_Direct_Attribute_Definition
 
       begin
+         --  This node has been rewritten by the parser subprogram
+         --  Rewrite_Entity_If_Direct_Attribute_Def (par-ch6.adb)
+
          pragma Assert (N /= Att_N);
 
          Error_Msg_Name_1 := Att_Name;
@@ -5437,13 +5487,36 @@ package body Sem_Ch6 is
          case Att_Name is
 
             when Name_Constructor =>
-               --  If missing, add a default initialization aspect for this
-               --  constructor's body stub: Initialize => (others => <>).
 
-               if Parent_Kind (N) not in N_Subprogram_Declaration
-                                       | N_Abstract_Subprogram_Declaration
-               then
-                  if not Has_Aspect (Designator, Aspect_Initialize) then
+               if Parent_Kind (N) = N_Subprogram_Body then
+
+                  --  A constructor body for a derived type whose parent type
+                  --  needs construction and has no parameterless constructor
+                  --  must call its parent constructor through a Super aspect
+                  --  to initialize its parent components.
+
+                  if Present (Prefix_E)
+                    and then Is_Tagged_Type (Prefix_E)
+                    and then Is_Derived_Type (Prefix_E)
+                    and then Needs_Construction (Etype (Prefix_E))
+                    and then
+                      not Has_Parameterless_Constructor (Etype (Prefix_E))
+                    and then No (Find_Aspect (Designator, Aspect_Super))
+                  then
+                     Error_Msg_Name_1 := Name_Super;
+                     Error_Msg_NE
+                       ("missing % aspect to initialize components of parent"
+                        & " type &", Designator, Etype (Prefix_E));
+                  end if;
+
+                  --  If missing, add a default initialization aspect for this
+                  --  constructor's body: Initialize => (others => <>).
+
+                  if not Has_Aspect (Designator, Aspect_Initialize)
+                    and then Present (Prefix_E)
+                    and then Ekind (Prefix_E) = E_Record_Type
+                    and then Constructor_Components_OK (Prefix_E, Designator)
+                  then
                      Add_Default_Initialize_Aspect;
                   end if;
 
@@ -5453,7 +5526,7 @@ package body Sem_Ch6 is
                elsif No (Prefix_E) or else not Is_Type (Prefix_E) then
                   Error_Msg_N
                     ("prefix& of attribute% must be a type",
-                     Prefix (Defining_Unit_Name (Att_N)));
+                     Prefix (Def_Name));
 
                elsif Ekind (Designator) /= E_Procedure then
                   Error_Msg_N
@@ -5470,7 +5543,7 @@ package body Sem_Ch6 is
                         then Sloc (N)
                         else Sloc (First_Formal (Designator)));
                   begin
-                     Error_Msg_Node_1 := Defining_Unit_Name (Att_N);
+                     Error_Msg_Node_1 := Def_Name;
                      Error_Msg_Node_2 := Prefix_E;
                      Error_Msg
                        ("& must have a first IN OUT formal of type&", Problem);
diff --git a/gcc/ada/sem_ch7.adb b/gcc/ada/sem_ch7.adb
index 2709f0eb66a..22317dd9a93 100644
--- a/gcc/ada/sem_ch7.adb
+++ b/gcc/ada/sem_ch7.adb
@@ -1337,11 +1337,18 @@ package body Sem_Ch7 is
       --  primitive equality operator and, if so, make it so that it will be
       --  used as the predefined operator of the private view of the record.
 
-      procedure Inspect_Abstract_Constructors_Completion (Id : Entity_Id);
+      procedure Inspect_Abstract_Constructors_Completion (Pkg_Id : Entity_Id);
       --  For each abstract constructor in the visible part of package Id,
       --  verify that a non-abstract counterpart exists in the private part
       --  of the package, and emit an error for each that lacks one.
 
+      procedure Inspect_Components_Needing_Construction (Pkg_Id : Entity_Id);
+      --  For each record type declared in package Id that does not require
+      --  a constructor, report an error on components that have a type that
+      --  requires explicit constructor initialization (that is, a type that
+      --  needs construction which has no default parameterless constructor
+      --  and no default initialization expression).
+
       procedure Install_Parent_Private_Declarations (Inst_Id : Entity_Id);
       --  Given the package entity of a generic package instantiation or
       --  formal package whose corresponding generic is a child unit, installs
@@ -1458,9 +1465,10 @@ package body Sem_Ch7 is
       -- Inspect_Abstract_Constructors_Completion --
       ----------------------------------------------
 
-      procedure Inspect_Abstract_Constructors_Completion (Id : Entity_Id) is
-         First_Priv : constant Entity_Id := First_Private_Entity (Id);
-         Vis_E      : Entity_Id          := First_Entity (Id);
+      procedure Inspect_Abstract_Constructors_Completion (Pkg_Id : Entity_Id)
+      is
+         First_Priv : constant Entity_Id := First_Private_Entity (Pkg_Id);
+         Vis_E      : Entity_Id          := First_Entity (Pkg_Id);
 
       begin
          while Present (Vis_E) and then Vis_E /= First_Priv loop
@@ -1498,6 +1506,51 @@ package body Sem_Ch7 is
          end loop;
       end Inspect_Abstract_Constructors_Completion;
 
+      ---------------------------------------------
+      -- Inspect_Components_Needing_Construction --
+      ---------------------------------------------
+
+      procedure Inspect_Components_Needing_Construction (Pkg_Id : Entity_Id) is
+         Comp_Decl : Node_Id;
+         Comp_Id   : Entity_Id;
+         Comp_Typ  : Entity_Id;
+         E         : Entity_Id;
+
+      begin
+         E := First_Entity (Pkg_Id);
+
+         while Present (E) loop
+            if Is_Record_Type (E)
+              and then not Needs_Construction (E)
+              and then Comes_From_Source (E)
+              and then not Is_Class_Wide_Type (E)
+              and then Nkind (Parent (E)) = N_Full_Type_Declaration
+            then
+               Comp_Decl := First_Component_Declaration (E);
+
+               while Present (Comp_Decl) loop
+                  if Nkind (Comp_Decl) = N_Component_Declaration then
+                     Comp_Id  := Defining_Identifier (Comp_Decl);
+                     Comp_Typ := Etype (Comp_Id);
+
+                     if Needs_Construction (Comp_Typ)
+                       and then not Has_Parameterless_Constructor (Comp_Typ)
+                       and then No (Expression (Comp_Decl))
+                     then
+                        Error_Msg_NE
+                          ("& needs explicit constructor call",
+                           Comp_Id, Comp_Id);
+                     end if;
+                  end if;
+
+                  Next_Non_Pragma (Comp_Decl);
+               end loop;
+            end if;
+
+            Next_Entity (E);
+         end loop;
+      end Inspect_Components_Needing_Construction;
+
       ----------------------------------------
       -- Inspect_Unchecked_Union_Completion --
       ----------------------------------------
@@ -1945,6 +1998,7 @@ package body Sem_Ch7 is
 
       if Core_Extensions_Allowed then
          Inspect_Abstract_Constructors_Completion (Id);
+         Inspect_Components_Needing_Construction (Id);
       end if;
 
       E := First_Entity (Id);
diff --git a/gcc/ada/sem_util.adb b/gcc/ada/sem_util.adb
index 4c56f906c3c..d8bf6f0608f 100644
--- a/gcc/ada/sem_util.adb
+++ b/gcc/ada/sem_util.adb
@@ -14215,6 +14215,42 @@ package body Sem_Util is
       return Name_Find;
    end Add_Suffix;
 
+   ---------------------------------
+   -- First_Component_Declaration --
+   ---------------------------------
+
+   function First_Component_Declaration (Typ : Entity_Id) return Node_Id is
+      Type_Def  : Node_Id;
+      Comp_List : Node_Id := Empty;
+
+   begin
+      pragma Assert (Is_Record_Type (Typ)
+        and then Nkind (Parent (Typ)) = N_Full_Type_Declaration);
+
+      Type_Def := Type_Definition (Parent (Typ));
+
+      --  Locate the non-inherited component list: the record extension part
+      --  for a derived type, the type definition for a non-derived one.
+
+      if Is_Derived_Type (Typ) then
+         if Nkind (Type_Def) = N_Derived_Type_Definition
+           and then Present (Record_Extension_Part (Type_Def))
+         then
+            Comp_List := Component_List (Record_Extension_Part (Type_Def));
+         end if;
+
+      else
+         pragma Assert (Nkind (Type_Def) = N_Record_Definition);
+         Comp_List := Component_List (Type_Def);
+      end if;
+
+      if Present (Comp_List) then
+         return First_Non_Pragma (Component_Items (Comp_List));
+      else
+         return Empty;
+      end if;
+   end First_Component_Declaration;
+
    -------------------
    -- Remove_Suffix --
    -------------------
diff --git a/gcc/ada/sem_util.ads b/gcc/ada/sem_util.ads
index 97a219c88e8..c10900e8c7a 100644
--- a/gcc/ada/sem_util.ads
+++ b/gcc/ada/sem_util.ads
@@ -3185,6 +3185,16 @@ package Sem_Util is
    --  Inherit predicate functions and Has_Predicates flag from type From_Typ.
    --  Typ is the destination type.
 
+   function First_Component_Declaration (Typ : Entity_Id) return Node_Id;
+   --  Return the first non-pragma component declaration among the
+   --  non-inherited (own) components of record type Typ, or Empty when Typ
+   --  has no own component list or that list is empty. For a derived record
+   --  type the own components are those of the record extension part; for a
+   --  non-derived record type they are those of its type definition. Iterate
+   --  over the remaining own component declarations with Next_Non_Pragma. The
+   --  caller must ensure that Typ is a record type and Parent (Typ) is an
+   --  N_Full_Type_Declaration.
+
    procedure Record_Possible_Part_Of_Reference
      (Var_Id : Entity_Id;
       Ref    : Node_Id);
-- 
2.53.0

Reply via email to