From: Javier Miranda <[email protected]>
This patch extends the currrent support for constructors to support the
initialization of limited types.
gcc/ada/ChangeLog:
* errout.adb (Set_Msg_Node): Improve readability of message for
constructors name, replacing the internal compiler name
generated for direct attribute definitions with a nicer name.
* erroutc.ads (Replace_With_Attribute_Definition): Promote from
a nested subprogram declaration to a public package-level
declaration.
* erroutc.adb (Replace_With_Attribute_Definition): Move its
implementation to package level.
* exp_attr.adb (Expand_N_Attribute_Reference [Attribute_Make]):
Code cleanup; handle assignment statement and limited type
object declaration.
* exp_ch3.adb (Build_Implicit_Parameterless_Constructor): Add
comment.
(Build_Default_Simple_Initialization): Add comment.
* exp_ch4.adb (Expand_N_Allocator): Fix No_Initialization for
internally generated allocators of types with constructors.
* exp_ch6.adb (Prepend_Constructor_Procedure_Prologue): Install
formals and refactor its body to be consistent with the GNAT
style.
* sem_ch3.adb (OK_For_Limited_Init_In_05): Accept T'Make since
it is semantically equivalent to a function call.
* sem_ch6.adb (Analyze_Direct_Attribute_Definition): Handle
incomplete and private type declarations.
* sem_ch13.adb (Diagnose_Misplaced_Aspects): Remove misleading
error for aspect 'Initializes.
* sem_res.adb (Resolve_Actuals): Skip check on the first actual
of init-proc and constructors because the constructor may be
invoked to initialize a constant object, which is allowed.
Tested on x86_64-pc-linux-gnu, committed on master.
---
gcc/ada/errout.adb | 11 +
gcc/ada/erroutc.adb | 78 +++--
gcc/ada/erroutc.ads | 6 +
gcc/ada/exp_attr.adb | 192 ++++++++++---
gcc/ada/exp_ch3.adb | 7 +
gcc/ada/exp_ch4.adb | 9 +-
gcc/ada/exp_ch6.adb | 668 ++++++++++++++++++++++---------------------
gcc/ada/sem_ch13.adb | 17 +-
gcc/ada/sem_ch3.adb | 6 +-
gcc/ada/sem_ch6.adb | 6 +-
gcc/ada/sem_res.adb | 11 +-
11 files changed, 582 insertions(+), 429 deletions(-)
diff --git a/gcc/ada/errout.adb b/gcc/ada/errout.adb
index 2c427b7515e..cf11a0a6c1c 100644
--- a/gcc/ada/errout.adb
+++ b/gcc/ada/errout.adb
@@ -3853,6 +3853,17 @@ package body Errout is
if Is_Internal_Name then
Kill_Message := True;
end if;
+
+ -- Replace compiler generated name for direct attribute definitions with
+ -- a nicer name.
+
+ if Name_Len > 5
+ and then Name_Buffer (1) = 'D'
+ and then Name_Buffer (Name_Len - 3 .. Name_Len) = "_Att"
+ then
+ Replace_With_Attribute_Definition;
+ end if;
+
-- Remaining step is to adjust casing and possibly add 'Class
Adjust_Name_Case (Global_Name_Buffer, Loc);
diff --git a/gcc/ada/erroutc.adb b/gcc/ada/erroutc.adb
index b46adc18abc..aa2810b5b04 100644
--- a/gcc/ada/erroutc.adb
+++ b/gcc/ada/erroutc.adb
@@ -1448,6 +1448,41 @@ package body Erroutc is
end loop;
end Prescan_Message;
+ ---------------------------------------
+ -- Replace_With_Attribute_Definition --
+ ---------------------------------------
+
+ procedure Replace_With_Attribute_Definition is
+ First : constant Integer := 2;
+ Last : constant Integer := Name_Len - 4;
+ Att_Buf : Bounded_String (Max_Length => Name_Len - 7);
+
+ begin
+ Until_Tick :
+ for J in First .. Last loop
+
+ -- J could be at the position separating the prefix from the
+ -- attribute name.
+
+ if Name_Buffer (J) = '_' then
+ Att_Buf.Length := 0;
+ Append (Att_Buf, Name_Buffer (J + 1 .. Last));
+ Set_Casing (Att_Buf, All_Lower_Case);
+
+ if Is_Direct_Attribute_Definition_Name (Name_Find (Att_Buf)) then
+ Name_Buffer (J) := ''';
+ exit Until_Tick;
+ end if;
+ end if;
+ end loop Until_Tick;
+
+ -- Remove prefix 'D' and suffix "_Att"
+
+ Name_Buffer (1 .. Last - 1) := Name_Buffer (2 .. Last);
+ Name_Len := Last - 1;
+ Set_Casing (All_Lower_Case);
+ end Replace_With_Attribute_Definition;
+
----------------
-- Same_Error --
----------------
@@ -1713,46 +1748,6 @@ package body Erroutc is
----------------------------
procedure Set_Msg_Insertion_Name is
- procedure Replace_With_Attribute_Definition;
- -- This procedure handles direct attribute definition names of the form:
- -- 'D' Prefix_Name "_" Attribute_Name "_Att"
- -- Specifically, it replace the current Namet.Global_Name_Buffer with an
- -- all lowercase string of the prefix, and a tick attribute; at this
- -- stage there is no way to recognize more than an ending attribute ???
- --
- -- Note that, at this point, it is not possible to restore the original
- -- casing thus lowercase is default.a
-
- procedure Replace_With_Attribute_Definition is
- First : constant Integer := 2;
- Last : constant Integer := Name_Len - 4;
- Att_Buf : Bounded_String (Max_Length => Name_Len - 7);
- begin
- Until_Tick :
- for J in First .. Last loop
-
- -- J could be at the position separating the prefix from the
- -- attribute name.
-
- if Name_Buffer (J) = '_' then
- Att_Buf.Length := 0;
- Append (Att_Buf, Name_Buffer (J + 1 .. Last));
- Set_Casing (Att_Buf, All_Lower_Case);
- if Is_Direct_Attribute_Definition_Name (Name_Find (Att_Buf))
- then
- Name_Buffer (J) := ''';
- exit Until_Tick;
- end if;
- end if;
- end loop Until_Tick;
-
- -- Remove prefix 'D' and suffix "_Att"
-
- Name_Buffer (1 .. Last - 1) := Name_Buffer (2 .. Last);
- Name_Len := Last - 1;
- Set_Casing (All_Lower_Case);
- end Replace_With_Attribute_Definition;
-
begin
if Error_Msg_Name_1 = No_Name then
null;
@@ -1798,6 +1793,9 @@ package body Erroutc is
-- Else output with surrounding quotes in proper casing mode
else
+ -- Replace compiler generated name for direct attribute
+ -- definitions with a nicer one.
+
if Name_Buffer (1) = 'D'
and then Name_Buffer (Name_Len - 3 .. Name_Len) = "_Att"
then
diff --git a/gcc/ada/erroutc.ads b/gcc/ada/erroutc.ads
index 2a3f7e3c6bc..039c342d05e 100644
--- a/gcc/ada/erroutc.ads
+++ b/gcc/ada/erroutc.ads
@@ -770,6 +770,12 @@ package Erroutc is
-- Iterate over all of the errors in the error chain and mark all messages
-- as deleted if they match the Filter.
+ procedure Replace_With_Attribute_Definition;
+ -- The caller has placed in Namet.Global_Name_Buffer the internal encoding
+ -- of a direct attribute definition; this subprogram rewrites that name to
+ -- a user-readable T'attribute string. The original source casing cannot
+ -- be recovered from the names table, so the result is all lowercase.
+
function Same_Error (M1, M2 : Error_Msg_Id) return Boolean;
-- See if two messages have the same text. Returns true if the text of the
-- two messages is identical, or if one of them is the same as the other
diff --git a/gcc/ada/exp_attr.adb b/gcc/ada/exp_attr.adb
index b299dacebfc..aa5d9696804 100644
--- a/gcc/ada/exp_attr.adb
+++ b/gcc/ada/exp_attr.adb
@@ -5433,27 +5433,12 @@ package body Exp_Attr is
when Attribute_Make =>
declare
Constructor_Params : List_Id := New_Copy_List (Expressions (N));
- Constructor_Rhs : Node_Id;
- Result_Decl : Node_Id;
- Result_Id : constant Entity_Id :=
- Make_Temporary (Loc, 'D', N);
+
begin
if Is_Empty_List (Constructor_Params) then
Constructor_Params := New_List;
end if;
- Result_Decl := Make_Object_Declaration (Loc,
- Defining_Identifier => Result_Id,
- Object_Definition =>
- New_Occurrence_Of (Typ, Loc));
-
- -- Suppress default initialization for result object.
- -- Default init (except for tag, if tagged) will instead be
- -- performed in the constructor procedure.
-
- Mutate_Ekind (Result_Id, E_Variable);
- Set_Suppress_Initialization (Result_Id);
-
-- A call to the copy constructor can be a special case. Even if
-- no copy constructor is declared (both explicitly by the user or
-- implicitly by the compiler), the call needs to succeed. In this
@@ -5462,45 +5447,168 @@ package body Exp_Attr is
if Is_Copy_Constructor_Call (N)
and then not Has_Copy_Constructor (Entity (Pref))
then
- if Nkind (First (Exprs)) = N_Parameter_Association
- then
- Constructor_Rhs :=
- Relocate_Node (Explicit_Actual_Parameter (First (Exprs)));
+ if Nkind (First (Exprs)) = N_Parameter_Association then
+ Rewrite (N,
+ Relocate_Node
+ (Explicit_Actual_Parameter (First (Exprs))));
else
- Constructor_Rhs := Relocate_Node (First (Exprs));
+ Rewrite (N, Relocate_Node (First (Exprs)));
end if;
+ Analyze_And_Resolve (N, Typ);
+
-- Otherwise build a prefixed-notation call
else
declare
- Constructor_Name : constant Node_Id :=
- Make_Selected_Component (Loc,
- Prefix => New_Occurrence_Of (Result_Id, Loc),
- Selector_Name => Make_Identifier (Loc,
- Direct_Attribute_Definition_Name
- (Typ, Name_Constructor)));
Constructor_Call : Node_Id;
- begin
- Set_Is_Prefixed_Call (Constructor_Name);
- Constructor_Call :=
- Make_Procedure_Call_Statement (Loc,
- Parameter_Associations => Constructor_Params,
- Name => Constructor_Name);
- Set_Is_Expanded_Constructor_Call (Constructor_Call, True);
+ Constructor_Name : Node_Id;
+ Result_Decl : Node_Id;
+ Result_Id : Entity_Id;
- Constructor_Rhs :=
- Make_Expression_With_Actions (Loc,
- Actions => New_List (Result_Decl, Constructor_Call),
- Expression => New_Occurrence_Of (Result_Id, Loc));
+ begin
+ -- Expand Lhs := T'Make (...) into:
+
+ -- Lhs.<Type>_constructor_Att (...)
+
+ if Nkind (Parent (N)) = N_Assignment_Statement then
+ Constructor_Name :=
+ Make_Selected_Component (Loc,
+ Prefix =>
+ New_Copy_Tree (Name (Parent (N))),
+ Selector_Name =>
+ Make_Identifier (Loc,
+ Direct_Attribute_Definition_Name (Typ,
+ Name_Constructor)));
+
+ Constructor_Call :=
+ Make_Procedure_Call_Statement (Loc,
+ Parameter_Associations => Constructor_Params,
+ Name => Constructor_Name);
+
+ Rewrite (Parent (N), Constructor_Call);
+ Analyze (Parent (N));
+
+ -- Expand Obj : <Type> := T'Make (...), where <Type> T is a
+ -- limited type, into:
+
+ -- Obj : <Type>;
+ -- Obj.<Type>_constructor_Att (...)
+
+ elsif Nkind (Parent (N)) = N_Object_Declaration
+ and then Is_Limited_Type (Ptyp)
+ then
+ Result_Decl := Parent (N);
+ Result_Id := Defining_Identifier (Result_Decl);
+
+ Set_Suppress_Initialization (Result_Id);
+
+ -- For class-wide type object declarations we add a
+ -- view conversion as the prefixed-call prefix so that
+ -- analysis resolves to the specific type constructor.
+
+ if Is_Class_Wide_Type (Etype (Result_Id)) then
+ Constructor_Name :=
+ Make_Selected_Component (Loc,
+ Prefix =>
+ Make_Type_Conversion (Loc,
+ Subtype_Mark =>
+ New_Occurrence_Of (Ptyp, Loc),
+ Expression =>
+ New_Occurrence_Of (Result_Id, Loc)),
+ Selector_Name =>
+ Make_Identifier (Loc,
+ Direct_Attribute_Definition_Name (Typ,
+ Name_Constructor)));
+ else
+ Constructor_Name :=
+ Make_Selected_Component (Loc,
+ Prefix =>
+ New_Occurrence_Of (Result_Id, Loc),
+ Selector_Name =>
+ Make_Identifier (Loc,
+ Direct_Attribute_Definition_Name (Typ,
+ Name_Constructor)));
+ end if;
+
+ Constructor_Call :=
+ Make_Procedure_Call_Statement (Loc,
+ Parameter_Associations => Constructor_Params,
+ Name => Constructor_Name);
+
+ -- Clear Comes_From_Source so that the expansion of the
+ -- object declaration is not handled as a source-level
+ -- construct and generates a redundant initialization
+ -- call.
+
+ Set_Comes_From_Source (Parent (N), False);
+
+ Set_Has_Init_Expression (Parent (N), False);
+ Set_Expression (Parent (N), Empty);
+ Insert_After (Parent (N), Constructor_Call);
+
+ declare
+ Errors : constant Nat := Serious_Errors_Detected;
+
+ begin
+ Analyze (Constructor_Call);
+
+ -- If the analysis of the call reported errors (for
+ -- example, because of a missing argument in the
+ -- source code) then prevent Analyze_Declarations
+ -- from re-analyzing this call: Transform_Object_
+ -- Operation modifies the actuals in place, and a
+ -- second pass would produce spurious errors.
+
+ if Serious_Errors_Detected > Errors then
+ Set_Analyzed (Constructor_Call);
+ end if;
+ end;
+
+ -- Expand T'Make (...) into:
+
+ -- do
+ -- tmp : <Type>;
+ -- tmp.<Type>_constructor_Att (...)
+ -- in tmp end
+
+ else
+ Result_Id := Make_Temporary (Loc, 'D', N);
+ Mutate_Ekind (Result_Id, E_Variable);
+
+ Result_Decl :=
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => Result_Id,
+ Object_Definition => New_Occurrence_Of (Typ, Loc));
+ Set_Suppress_Initialization (Result_Id);
+
+ Constructor_Name :=
+ Make_Selected_Component (Loc,
+ Prefix =>
+ New_Occurrence_Of (Result_Id, Loc),
+ Selector_Name =>
+ Make_Identifier (Loc,
+ Direct_Attribute_Definition_Name (Typ,
+ Name_Constructor)));
+
+ Constructor_Call :=
+ Make_Procedure_Call_Statement (Loc,
+ Parameter_Associations => Constructor_Params,
+ Name => Constructor_Name);
+
+ Rewrite (N,
+ Make_Expression_With_Actions (Loc,
+ Actions =>
+ New_List (Result_Decl, Constructor_Call),
+ Expression =>
+ New_Occurrence_Of (Result_Id, Loc)));
+
+ Analyze_And_Resolve (N, Typ);
+ end if;
end;
end if;
-
- Rewrite (N, Constructor_Rhs);
end;
- Analyze_And_Resolve (N, Typ);
-
--------------
-- Mantissa --
--------------
diff --git a/gcc/ada/exp_ch3.adb b/gcc/ada/exp_ch3.adb
index 12cbd58a42b..d92ab21976d 100644
--- a/gcc/ada/exp_ch3.adb
+++ b/gcc/ada/exp_ch3.adb
@@ -1406,6 +1406,9 @@ package body Exp_Ch3 is
and then Comes_From_Source (N)
and then Needs_Construction (Typ)
then
+ -- If the parameterless constructor is not available, the
+ -- constructor call will cause reporting an error later.
+
return
Make_Attribute_Reference (Loc,
Prefix => New_Occurrence_Of (Typ, Loc),
@@ -1790,6 +1793,7 @@ package body Exp_Ch3 is
Body_Stmts, Parameters, Aspect_Specs : List_Id;
Spec_Node, Stmt : Node_Id;
Self, From : Entity_Id;
+
begin
-- Only build copy constructor for user-defined non-limited tagged
-- record types that needs construction without having declared a copy
@@ -1997,6 +2001,7 @@ package body Exp_Ch3 is
Loc : constant Source_Ptr := Sloc (Typ);
Constructor_Id : Entity_Id;
Spec_Node : Node_Id;
+
begin
-- The implicit parameterless constructor doesn't need to do anything.
-- In fact, during subprogram expansion, prepending the prologue of
@@ -2039,6 +2044,8 @@ package body Exp_Ch3 is
Freeze_Extra_Formals (Constructor_Id);
+ -- Aspect Initialize enables default initialization
+
declare
Ignore : Node_Id;
Default_Initialize : constant Node_Id :=
diff --git a/gcc/ada/exp_ch4.adb b/gcc/ada/exp_ch4.adb
index 1bad0f9a3c8..e8eaa7556b7 100644
--- a/gcc/ada/exp_ch4.adb
+++ b/gcc/ada/exp_ch4.adb
@@ -4562,13 +4562,14 @@ package body Exp_Ch4 is
Error_Msg_N ("?_a?use of an anonymous access type allocator", N);
end if;
- -- Here we set no initialization on types with constructors since we
- -- generate initialization for the separately.
+ -- Suppress default initialization on internally generated allocators
+ -- since they are initialized separately.
- if Needs_Construction (Directly_Designated_Type (PtrT))
+ if not Comes_From_Source (Parent (N))
+ and then Needs_Construction (Directly_Designated_Type (PtrT))
and then Nkind (Expression (N)) = N_Identifier
then
- Set_No_Initialization (N, False);
+ Set_No_Initialization (N);
end if;
-- RM E.2.2(17). We enforce that the expected type of an allocator
diff --git a/gcc/ada/exp_ch6.adb b/gcc/ada/exp_ch6.adb
index 968a7db4914..79359f5f846 100644
--- a/gcc/ada/exp_ch6.adb
+++ b/gcc/ada/exp_ch6.adb
@@ -5924,353 +5924,361 @@ package body Exp_Ch6 is
procedure Prepend_Constructor_Procedure_Prologue
(Spec_Id : Entity_Id; Body_Id : Entity_Id; L : List_Id)
is
+ function Init_From_Initialize_Expression
+ (Component : Entity_Id) return Node_Id;
+ -- If the Initialize aspect for the constructor procedure contains
+ -- the given component or the default others, then return the
+ -- initial value expression specified there. Otherwise, return
+ -- Empty.
- function First_Param_Type return Entity_Id is
- (Implementation_Base_Type (Etype (First_Formal (Spec_Id))));
+ function Init_From_Default_Or_Constructor
+ (Component : Entity_Id) return Node_Id;
+ -- If the component declaration includes a default initial value
+ -- expression or its type has a parameterless constructor
+ -- available, then return that expression (or a corresponding Make
+ -- call in the constructor case). Otherwise, return Empty.
- begin
- if not (Nkind (Specification (N)) = N_Procedure_Specification
- and then Is_Constructor (Spec_Id))
- then
- return; -- the usual case
- end if;
+ function Make_Init_Proc_Call
+ (Component : Entity_Id;
+ Component_Name : Node_Id) return Node_Id;
+ -- Build and return a call to the init proc for the type of the
+ -- component to initialize it.
- Push_Scope (Spec_Id);
+ function Make_Parent_Constructor_Call
+ (Parent_Type : Entity_Id) return Node_Id;
+ -- Builds and returns a call to the appropriate constructor procedure
+ -- of the parent type. This function is called only in the case of a
+ -- Constructor procedure for a type extension.
- -- Initialize the first parameter.
- -- First_Param_Type is a record type (tagged or untagged) or
- -- a type extension. If it is a type extension, then we begin by
- -- calling the appropriate constructor procedure for the _parent
- -- part. In the absence of a Super aspect specification, the
- -- "appropriate" constructor is the one that takes only a single
- -- parameter (the object being initialized). Additional actual
- -- parameters for the constructor call may be provided via a
- -- Super aspect specification, in which case a different
- -- constructor procedure will be invoked.
- --
- -- For each remaining component we first check to see if it
- -- is mentioned in the Initialize aspect specification (if any) for
- -- Body_Id. If so, then evaluate the expression given for that
- -- component in the aspect specification and assign it to the
- -- given component of the first parameter. If not, and if an
- -- explicit default initial value is provided for the given component
- -- in the type declaration, then do the same thing with that
- -- expression instead. Otherwise perform normal default
- -- initialization for the component - invoke the init proc for the
- -- component's type if one exists, and otherwise do nothing.
+ --------------------------------
+ -- From_Initialize_Expression --
+ --------------------------------
- -- We do not perform tag initialization here. That is dealt with
- -- elsewhere. The init proc for a tagged type is
- -- passed an extra parameter indicating whether to perform
- -- tag initialization.
-
- -- In the case of a type (tagged or untagged) that is not
- -- an extension, we could just generate a single assignment,
- -- taking the RHS from the Initialize aspect value (which is an
- -- N_Aggregate node). But that gets complicated in the case of
- -- an extension, so we handle all cases one component at a time.
-
- declare
- Initialize_Aspect : constant Node_Id :=
+ function Init_From_Initialize_Expression
+ (Component : Entity_Id) return Node_Id
+ is
+ Initialize_Aspect : constant Node_Id :=
Find_Aspect (Body_Id, Aspect_Initialize);
-
First_Initialize_Comp_Assoc : constant Node_Id :=
(if Present (Initialize_Aspect)
then First (Component_Associations
(Expression (Initialize_Aspect)))
else Empty);
+ Component_Cursor : Node_Id := First_Initialize_Comp_Assoc;
+ Choice : Node_Id;
+ Others_Expression : Node_Id := Empty;
- Component : Entity_Id := First_Entity (First_Param_Type);
- Comp_List, Initialize_List, Tag_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;
- -- Tag_List contains the initialization for the tag;
- -- Parent_List contains the parent constructor call.
+ -- ??? Technically, this is quadratic (linear search called
+ -- a linear number of times). When/if we see performance
+ -- problems with hundreds of components mentioned in one
+ -- Initialize aspect specification, we can revisit this.
+ begin
+ while Present (Component_Cursor) loop
+ Choice := First (Choices (Component_Cursor));
- function Init_From_Initialize_Expression
- (Component : Entity_Id) return Node_Id;
- -- If the Initialize aspect for the constructor procedure contains
- -- the given component or the default others, then return the
- -- initial value expression specified there. Otherwise, return
- -- Empty.
+ while Present (Choice) loop
+ -- The others expression is used in case there is no
+ -- explicit component association for the given one.
- function Init_From_Default_Or_Constructor
- (Component : Entity_Id) return Node_Id;
- -- If the component declaration includes a default initial value
- -- expression or its type has a parameterless constructor
- -- available, then return that expression (or a corresponding Make
- -- call in the constructor case). Otherwise, return Empty.
+ if Nkind (Choice) = N_Others_Choice
+ and then Comes_From_Source (Choice)
+ then
+ Others_Expression := Expression (Component_Cursor);
- function Make_Init_Proc_Call (Component : Entity_Id;
- Component_Name : Node_Id)
- return Node_Id;
- -- Builds and returns a call to the init proc for the type of
- -- the component in order to initialize the given component.
- -- The init proc must exist.
-
- function Make_Parent_Constructor_Call (Parent_Type : Entity_Id)
- return Node_Id;
- -- Builds and returns a call to the appropriate constructor
- -- procedure of the parent type.
- -- This function is called only in the case of a
- -- Constructor procedure for a type extension.
-
- --------------------------------
- -- From_Initialize_Expression --
- --------------------------------
-
- function Init_From_Initialize_Expression (Component : Entity_Id)
- return Node_Id
- is
- Component_Cursor : Node_Id := First_Initialize_Comp_Assoc;
- Choice : Node_Id;
- Others_Expression : Node_Id := Empty;
-
- -- ??? Technically, this is quadratic (linear search called
- -- a linear number of times). When/if we see performance
- -- problems with hundreds of components mentioned in one
- -- Initialize aspect specification, we can revisit this.
- begin
- while Present (Component_Cursor) loop
- Choice := First (Choices (Component_Cursor));
-
- while Present (Choice) loop
- -- The others expression is used in case there is no
- -- explicit component association for the given one.
-
- if Nkind (Choice) = N_Others_Choice
- and then Comes_From_Source (Choice)
- then
- Others_Expression := Expression (Component_Cursor);
-
- elsif Nkind (Choice) = N_Identifier
- and then Chars (Choice) = Chars (Component)
- then
- return Expression (Component_Cursor);
- end if;
- Next (Choice);
- end loop;
-
- Next (Component_Cursor);
+ elsif Nkind (Choice) = N_Identifier
+ and then Chars (Choice) = Chars (Component)
+ then
+ return Expression (Component_Cursor);
+ end if;
+ Next (Choice);
end loop;
- return Others_Expression;
- end Init_From_Initialize_Expression;
-
- --------------------------------------
- -- Init_From_Default_Or_Constructor --
- --------------------------------------
-
- function Init_From_Default_Or_Constructor (Component : Entity_Id)
- return Node_Id is
- begin
- if Present (Expression (Parent (Component))) then
- return Expression (Parent (Component));
- end if;
-
- -- In case the type needs construction and a parameterless
- -- constructor is present, then it can be implicitly used it
- -- here.
-
- if Needs_Construction (Etype (Component))
- and then Has_Parameterless_Constructor (Etype (Component))
- then
- return Make_Attribute_Reference (Loc,
- Prefix =>
- New_Occurrence_Of (Etype (Component), Loc),
- Attribute_Name => Name_Make);
- end if;
-
- return Empty;
- end Init_From_Default_Or_Constructor;
-
- -------------------------
- -- Make_Init_Proc_Call --
- -------------------------
-
- function Make_Init_Proc_Call (Component : Entity_Id;
- Component_Name : Node_Id)
- return Node_Id
- is
- Params : constant List_Id := New_List (Component_Name);
- Init_Proc : constant Entity_Id :=
- Base_Init_Proc (Etype (Component));
- begin
- if Is_Tagged_Type (Etype (Component)) then
- Append (Make_Mode_Literal (Loc, Full_Init), Params);
- end if;
-
- return Init_Proc_Call : constant Node_Id :=
- Make_Procedure_Call_Statement (Loc,
- Name => New_Occurrence_Of (Init_Proc, Loc),
- Parameter_Associations => Params)
- do
- pragma Assert (Check_Number_Of_Actuals
- (Subp_Call => Init_Proc_Call,
- Subp_Id => Init_Proc));
- end return;
- end Make_Init_Proc_Call;
-
- ----------------------------------
- -- Make_Parent_Constructor_Call --
- ----------------------------------
-
- function Make_Parent_Constructor_Call (Parent_Type : Entity_Id)
- return Node_Id
- is
- Actual_Parameters : List_Id := No_List;
- Super_Aspect : constant Node_Id :=
- Find_Aspect (Body_Id, Aspect_Super);
-
- -- Do not confuse the Super aspect with the Super attribute.
- -- Both are referenced here, but they are not related as
- -- closely as some aspect/attribute homonym pairs are.
- -- The attribute takes an object as a prefix. The aspect
- -- can be specified for the body of a constructor procedure.
- begin
- if Present (Super_Aspect) then
- declare
- Super_Expr : constant Node_Id :=
- Expression (Super_Aspect);
- Expr : Node_Id;
- begin
- -- Super without expression is a call to the parent
- -- parameterless constructor.
-
- if No (Super_Expr) then
- Actual_Parameters := No_List;
-
- elsif Nkind (Super_Expr) /= N_Aggregate then
- Expr := New_Copy_Tree (Super_Expr);
- Set_Paren_Count (Expr, 0);
- Actual_Parameters := New_List (Expr);
-
- else
- -- Interpret this "aggregate" as a list of
- -- actual parameter expressions.
-
- Actual_Parameters := New_List;
- Expr := First (Expressions (Super_Expr));
- while Present (Expr) loop
- Append (New_Copy_Tree (Expr), Actual_Parameters);
- Next (Expr);
- end loop;
- end if;
- end;
- end if;
-
- return Make_Assignment_Statement (Loc,
- Name =>
- Make_Attribute_Reference (Loc,
- Prefix =>
- New_Occurrence_Of (First_Formal (Spec_Id), Loc),
- Attribute_Name => Name_Super),
- Expression =>
- Make_Attribute_Reference (Loc,
- Prefix =>
- New_Occurrence_Of (Parent_Type, Loc),
- Attribute_Name => Name_Make,
- Expressions => Actual_Parameters));
- end Make_Parent_Constructor_Call;
-
- begin
- while Present (Component) loop
-
- -- Skip if not a component, this may happen when initialization
- -- expressions contain strings.
-
- if Ekind (Component) /= E_Component then
- goto Next_Component;
- 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));
-
- elsif Chars (Component) = Name_uParent
- and then Needs_Construction (Etype (Component))
- then
- Append_To (Parent_List,
- Make_Parent_Constructor_Call
- (Parent_Type => Etype (Component)));
-
- else
- declare
- Maybe_Initialize : constant Node_Id :=
- Init_From_Initialize_Expression (Component);
- Maybe_Default_Or_Constructor : constant Node_Id :=
- Init_From_Default_Or_Constructor (Component);
-
- function Make_Component_Name return Node_Id is
- (Make_Selected_Component (Loc,
- Prefix =>
- New_Occurrence_Of (First_Formal (Spec_Id), Loc),
- Selector_Name =>
- Make_Identifier (Loc, Chars (Component))));
- begin
- -- Handle case where initial value for this component is
- -- specified either in an Initialize aspect specification
- -- or as part of the component declaration.
-
- if Present (Maybe_Initialize)
- or else Present (Maybe_Default_Or_Constructor)
- 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,
- Build_Component_Assignment (Loc,
- Prefix =>
- New_Occurrence_Of
- (First_Formal (Spec_Id), Loc),
- Prefix_Type => First_Param_Type,
- Proc_Id => Body_Id,
- Component_Id => Component,
- Default_Expr =>
- New_Copy_Tree (Init, New_Scope => Body_Id)));
- end;
-
- -- Handle case where component's type has an init proc
- elsif Has_Non_Null_Base_Init_Proc (Etype (Component)) then
- Append_To (Comp_List,
- Make_Init_Proc_Call (
- Component => Component,
- Component_Name => Make_Component_Name));
- else
- pragma Assert (not Is_Tagged_Type (Etype (Component)));
- end if;
- end;
- end if;
-
- <<Next_Component>>
- Next_Entity (Component);
+ Next (Component_Cursor);
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.
+ return Others_Expression;
+ end Init_From_Initialize_Expression;
- 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);
- end;
+ --------------------------------------
+ -- Init_From_Default_Or_Constructor --
+ --------------------------------------
- Pop_Scope;
+ function Init_From_Default_Or_Constructor
+ (Component : Entity_Id) return Node_Id is
+ begin
+ if Present (Expression (Parent (Component))) then
+ return Expression (Parent (Component));
+ end if;
+
+ -- In case the type needs construction and a parameterless
+ -- constructor is present, then it can be implicitly used it
+ -- here.
+
+ if Needs_Construction (Etype (Component))
+ and then Has_Parameterless_Constructor (Etype (Component))
+ then
+ return Make_Attribute_Reference (Loc,
+ Prefix =>
+ New_Occurrence_Of (Etype (Component), Loc),
+ Attribute_Name => Name_Make);
+ end if;
+
+ return Empty;
+ end Init_From_Default_Or_Constructor;
+
+ -------------------------
+ -- Make_Init_Proc_Call --
+ -------------------------
+
+ function Make_Init_Proc_Call
+ (Component : Entity_Id;
+ Component_Name : Node_Id) return Node_Id
+ is
+ Params : constant List_Id := New_List (Component_Name);
+ Init_Proc : constant Entity_Id := Base_Init_Proc
+ (Etype (Component));
+ begin
+ pragma Assert (Present (Init_Proc));
+
+ if Is_Tagged_Type (Etype (Component)) then
+ Append (Make_Mode_Literal (Loc, Full_Init), Params);
+ end if;
+
+ return Init_Proc_Call : constant Node_Id :=
+ Make_Procedure_Call_Statement (Loc,
+ Name => New_Occurrence_Of (Init_Proc, Loc),
+ Parameter_Associations => Params)
+ do
+ pragma Assert (Check_Number_Of_Actuals
+ (Subp_Call => Init_Proc_Call,
+ Subp_Id => Init_Proc));
+ end return;
+ end Make_Init_Proc_Call;
+
+ ----------------------------------
+ -- Make_Parent_Constructor_Call --
+ ----------------------------------
+
+ function Make_Parent_Constructor_Call
+ (Parent_Type : Entity_Id) return Node_Id
+ is
+ Actual_Parameters : List_Id := No_List;
+ Lhs : Node_Id;
+ Super_Aspect : constant Node_Id :=
+ Find_Aspect (Body_Id, Aspect_Super);
+
+ -- Do not confuse the Super aspect with the Super attribute.
+ -- Both are referenced here, but they are not related as
+ -- closely as some aspect/attribute homonym pairs are.
+ -- The attribute takes an object as a prefix. The aspect
+ -- can be specified for the body of a constructor procedure.
+ begin
+ if Present (Super_Aspect) then
+ declare
+ Super_Expr : constant Node_Id := Expression (Super_Aspect);
+ Expr : Node_Id;
+
+ begin
+ -- Super without expression is a call to the parent
+ -- parameterless constructor.
+
+ if No (Super_Expr) then
+ Actual_Parameters := No_List;
+
+ elsif Nkind (Super_Expr) /= N_Aggregate then
+ Expr := New_Copy_Tree (Super_Expr);
+ Set_Paren_Count (Expr, 0);
+ Actual_Parameters := New_List (Expr);
+
+ else
+ -- Interpret this "aggregate" as a list of actual
+ -- parameter expressions.
+
+ Actual_Parameters := New_List;
+ Expr := First (Expressions (Super_Expr));
+ while Present (Expr) loop
+ Append (New_Copy_Tree (Expr), Actual_Parameters);
+ Next (Expr);
+ end loop;
+ end if;
+ end;
+ end if;
+
+ Lhs :=
+ Make_Attribute_Reference (Loc,
+ Prefix =>
+ New_Occurrence_Of (First_Formal (Spec_Id), Loc),
+ Attribute_Name => Name_Super);
+ Set_Assignment_OK (Lhs);
+
+ return Make_Assignment_Statement (Loc,
+ Name => Lhs,
+ Expression =>
+ Make_Attribute_Reference (Loc,
+ Prefix => New_Occurrence_Of (Parent_Type, Loc),
+ Attribute_Name => Name_Make,
+ Expressions => Actual_Parameters));
+ end Make_Parent_Constructor_Call;
+
+ -- Local variables
+
+ First_Param_Type : constant Entity_Id :=
+ Implementation_Base_Type
+ (Etype (First_Formal (Spec_Id)));
+ 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;
+ -- Tag_List contains the initialization for the tag;
+ -- Parent_List contains the parent constructor call.
+
+ -- Start of processing for Prepend_Constructor_Procedure_Prologue
+
+ begin
+ pragma Assert (Is_Constructor (Spec_Id));
+
+ Install_Formals (Spec_Id);
+ Push_Scope (Spec_Id);
+
+ -- First_Param_Type is a record type (tagged or untagged) or a type
+ -- extension. If it is a type extension, then we begin by calling the
+ -- appropriate constructor procedure for the _parent part. In the
+ -- absence of a Super aspect specification, the "appropriate"
+ -- constructor is the one that takes only a single parameter (the
+ -- object being initialized). Additional actual parameters for the
+ -- constructor call may be provided via a Super aspect specification,
+ -- in which case a different constructor procedure will be invoked.
+ --
+ -- For each remaining component we first check to see if it is
+ -- mentioned in the Initialize aspect specification (if any) for
+ -- Body_Id. If so, then evaluate the expression given for that
+ -- component in the aspect specification and assign it to the given
+ -- component of the first parameter. If not, and if an explicit
+ -- default initial value is provided for the given component in the
+ -- type declaration, then do the same thing with that expression
+ -- instead. Otherwise perform normal default initialization for the
+ -- component - invoke the init proc for the component's type if one
+ -- exists, and otherwise do nothing.
+
+ -- In the case of a type (tagged or untagged) that is not an
+ -- extension, we could just generate a single assignment, taking the
+ -- RHS from the Initialize aspect value (which is an N_Aggregate
+ -- node). But that gets complicated in the case of an extension, so
+ -- we handle all cases one component at a time.
+
+ Component := First_Entity (First_Param_Type);
+ while Present (Component) loop
+
+ -- Skip if not a component, this may happen when initialization
+ -- expressions contain strings.
+
+ if Ekind (Component) /= E_Component then
+ goto Next_Component;
+ 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));
+
+ elsif Chars (Component) = Name_uParent
+ and then Needs_Construction (Etype (Component))
+ then
+ Append_To (Parent_List,
+ Make_Parent_Constructor_Call
+ (Parent_Type => Etype (Component)));
+
+ else
+ declare
+ Maybe_Initialize : constant Node_Id :=
+ Init_From_Initialize_Expression (Component);
+ Maybe_Default_Or_Constructor : constant Node_Id :=
+ Init_From_Default_Or_Constructor (Component);
+
+ function Make_Component_Name return Node_Id
+ is (Make_Selected_Component (Loc,
+ Prefix =>
+ New_Occurrence_Of (First_Formal (Spec_Id), Loc),
+ Selector_Name =>
+ Make_Identifier (Loc, Chars (Component))));
+ begin
+ -- Handle case where initial value for this component is
+ -- specified either in an Initialize aspect specification
+ -- or as part of the component declaration.
+
+ if Present (Maybe_Initialize)
+ or else Present (Maybe_Default_Or_Constructor)
+ 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,
+ Build_Component_Assignment (Loc,
+ Prefix =>
+ New_Occurrence_Of (First_Formal (Spec_Id), Loc),
+ Prefix_Type => First_Param_Type,
+ Proc_Id => Body_Id,
+ Component_Id => Component,
+ Default_Expr => New_Copy_Tree (Init,
+ New_Scope => Body_Id)));
+ end;
+
+ -- Handle case where component's type has an init proc
+
+ elsif Has_Non_Null_Base_Init_Proc (Etype (Component)) then
+
+ if not Has_Discriminants (Etype (Component)) then
+ Append_To (Comp_List,
+ Make_Init_Proc_Call (
+ Component => Component,
+ Component_Name => Make_Component_Name));
+ else
+ Append_List_To (Comp_List,
+ Build_Initialization_Call
+ (N => Parent (Component),
+ Id_Ref => Make_Component_Name,
+ Typ => Etype (Component),
+ In_Init_Proc => True,
+ Enclos_Type => First_Param_Type));
+ end if;
+
+ else
+ pragma Assert (not Is_Tagged_Type (Etype (Component)));
+ end if;
+ end;
+ end if;
+
+ <<Next_Component>>
+ 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.
+
+ 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);
+
+ End_Scope;
end Prepend_Constructor_Procedure_Prologue;
-- Local variables
@@ -6508,8 +6516,12 @@ package body Exp_Ch6 is
-- If the subprogram is a constructor procedure then prepend
-- and analyze initialization code.
- Prepend_Constructor_Procedure_Prologue
- (Spec_Id => Spec_Id, Body_Id => Body_Id, L => L);
+ if Nkind (Specification (N)) = N_Procedure_Specification
+ and then Is_Constructor (Spec_Id)
+ then
+ Prepend_Constructor_Procedure_Prologue
+ (Spec_Id => Spec_Id, Body_Id => Body_Id, L => L);
+ end if;
-- Set to encode entity names in package body before gigi is called
diff --git a/gcc/ada/sem_ch13.adb b/gcc/ada/sem_ch13.adb
index 5c786e7fb4c..e9c6ef6b7d7 100644
--- a/gcc/ada/sem_ch13.adb
+++ b/gcc/ada/sem_ch13.adb
@@ -6059,22 +6059,19 @@ package body Sem_Ch13 is
elsif Asp_Nam = Name_Post then
Misplaced_Aspect_Error (Asp, Name_Refined_Post);
+ -- Likely a misspelling of Initialize aspect (singular) that can
+ -- be used in stubs.
+
+ elsif Asp_Nam = Name_Initializes then
+ Error_Msg_Name_1 := Name_Initialize;
+ Error_Msg_N ("\possible misspelling of%", Asp);
+
-- Otherwise a language-defined aspect is misplaced
else
Error_Msg_N
("aspect specification must appear on initial declaration",
Asp);
-
- -- Improve the error message for likely misspelling since the
- -- Initialize aspect (singular) can be used in stubs but the
- -- Initializes aspect (plural) cannot and would raise a
- -- misleading error here.
-
- if Asp_Nam = Name_Initializes then
- Error_Msg_Name_1 := Name_Initialize;
- Error_Msg_N ("\possible misspelling of%", Asp);
- end if;
end if;
Next (Asp);
diff --git a/gcc/ada/sem_ch3.adb b/gcc/ada/sem_ch3.adb
index e07d24c1565..52eaf0f3399 100644
--- a/gcc/ada/sem_ch3.adb
+++ b/gcc/ada/sem_ch3.adb
@@ -21124,8 +21124,12 @@ package body Sem_Ch3 is
-- attribute will be changed to a call, but the attribute by itself
-- can occur with -gnatc.
+ -- Similarly, T'Make (GNAT-specific constructor attribute) is also
+ -- allowed because it is semantically equivalent to a function call.
+
when N_Attribute_Reference =>
- return Attribute_Name (Original_Node (Exp)) = Name_Input;
+ return Attribute_Name (Original_Node (Exp)) in Name_Input
+ | Name_Make;
-- "return raise ..." is OK
diff --git a/gcc/ada/sem_ch6.adb b/gcc/ada/sem_ch6.adb
index fd12a557108..95cd7c0f35e 100644
--- a/gcc/ada/sem_ch6.adb
+++ b/gcc/ada/sem_ch6.adb
@@ -5278,11 +5278,13 @@ package body Sem_Ch6 is
Att_N : constant Node_Id := Original_Node (N);
Prefix_E : constant Entity_Id :=
- Get_Name_Entity_Id (Chars (Prefix (Defining_Unit_Name (Att_N))));
+ Get_Full_View
+ (Current_Entity (Prefix (Defining_Unit_Name (Att_N))));
Att_Name : constant Name_Id :=
Attribute_Name (Defining_Unit_Name (Att_N));
- -- Start of processing for Analyze_Direct_Attribute_Definition
+ -- Start of processing for Analyze_Direct_Attribute_Definition
+
begin
pragma Assert (N /= Att_N);
diff --git a/gcc/ada/sem_res.adb b/gcc/ada/sem_res.adb
index 028e170021e..9ea8edc5259 100644
--- a/gcc/ada/sem_res.adb
+++ b/gcc/ada/sem_res.adb
@@ -4808,9 +4808,16 @@ package body Sem_Res is
-- component may initialize a nested component of a constant
-- designated object. In this context the object is variable.
+ -- Similarly, a constructor may be invoked to initialize a
+ -- constant variable, and this is allowed.
+
if not Is_OK_Variable_For_Out_Formal (A)
- and then not Is_Init_Proc (Nam)
- and then not Is_Expanded_Constructor_Call (N)
+ and then not
+ (A = First_Actual (N)
+ and then
+ (Is_Init_Proc (Nam)
+ or else Is_Constructor (Nam)
+ or else Is_Expanded_Constructor_Call (N)))
then
Error_Msg_NE ("actual for& must be a variable", A, F);
--
2.53.0