This occurs for an aggregate whose nominal subtype is the tagged extension
in a simplified case of ACATS cdd2a01. ACATS cdd2a01 is more involved and
passes because of an ad-hoc kludge in Expr_Aggr (Initialize_Discriminants)
which contains a bogus restriction.
Expr_Aggr contains 4 different procedures to initialize discriminants and
they tread on each other's toes while not covering all the cases, so this
removes 2 of them and keeps only Init_{Parent,Stored}_Discriminants.
Tested on x86-64/Linux, applied on the mainline.
2026-09-29 Eric Botcazou <[email protected]>
* exp_aggr.adb (Initialize_Discriminants): Delete.
(Build_Record_Aggr_Code.Init_Visible_Discriminants): Likewise.
(Build_Record_Aggr_Code.Init_Hidden_Discriminants): Rename into...
(Build_Record_Aggr_Code.Init_Parent_Discriminants): ...this. Remove
the two parameters and initialize all the parent discriminants.
(Build_Record_Aggr_Code.Init_Stored_Discriminants): Retrieve the
stored discriminants of the base type.
(Build_Record_Aggr_Code): Adjust to above changes.
(Convert_To_Assignments): Remove calls to Initialize_Discriminants.
* sem_aux.ads (First_Stored_Discriminant): Minor tweaks.
--
Eric Botcazou
diff --git a/gcc/ada/exp_aggr.adb b/gcc/ada/exp_aggr.adb
index 453727b63f4..8be767adb02 100644
--- a/gcc/ada/exp_aggr.adb
+++ b/gcc/ada/exp_aggr.adb
@@ -214,18 +214,6 @@ package body Exp_Aggr is
-- defaults. An aggregate for a type with mutable components must be
-- expanded into individual assignments.
- procedure Initialize_Discriminants (N : Node_Id; Typ : Entity_Id);
- -- If the type of the aggregate is a type extension with renamed discrimi-
- -- nants, we must initialize the hidden discriminants of the parent.
- -- Otherwise, the target object must not be initialized. The discriminants
- -- are initialized by calling the initialization procedure for the type.
- -- This is incorrect if the initialization of other components has any
- -- side effects. We restrict this call to the case where the parent type
- -- has a variant part, because this is the only case where the hidden
- -- discriminants are accessed, namely when calling discriminant checking
- -- functions of the parent type, and when applying a stream attribute to
- -- an object of the derived type.
-
---------------------------------------------------------
-- Local Subprograms for Container Aggregate Expansion --
---------------------------------------------------------
@@ -2282,26 +2270,17 @@ package body Exp_Aggr is
-- do not provide discriminants for it, check aggregate components for
-- values of the discriminants.
- procedure Init_Hidden_Discriminants (Typ : Entity_Id; List : List_Id);
- -- If Typ is derived, and constrains discriminants of the parent type,
- -- these discriminants are not components of the aggregate, and must be
- -- initialized. The assignments are appended to List. The same is done
- -- if Typ derives from an already constrained subtype of a discriminated
- -- parent type.
+ procedure Init_Parent_Discriminants;
+ -- If the type is a tagged extension and constrains discriminants of the
+ -- parent type, these discriminants are not components of the aggregate,
+ -- and must be initialized. Likewise if the type derives from an already
+ -- constrained subtype of a discriminated tagged type.
procedure Init_Stored_Discriminants;
- -- If the type is derived and has inherited discriminants, generate
- -- explicit assignments for each, using the store constraint of the
- -- type. Note that both visible and stored discriminants must be
- -- initialized in case the derived type has some renamed and some
- -- constrained discriminants.
-
- procedure Init_Visible_Discriminants;
- -- If type has discriminants, retrieve their values from aggregate,
- -- and generate explicit assignments for each. This does not include
- -- discriminants inherited from ancestor, which are handled above.
- -- The type of the aggregate is a subtype created ealier using the
- -- given values of the discriminant components of the aggregate.
+ -- If the type has discriminants, retrieve the values of the stored ones
+ -- from the type of the aggregate, and generate explicit assignments for
+ -- them. The type of the aggregate is a subtype built earlier using the
+ -- values of the discriminant components in the aggregate.
function Is_Int_Range_Bounds (Bounds : Node_Id) return Boolean;
-- Check whether Bounds is a range node and its lower and higher bounds
@@ -2570,55 +2549,18 @@ package body Exp_Aggr is
end Get_Explicit_Discriminant_Value;
-------------------------------
- -- Init_Hidden_Discriminants --
+ -- Init_Parent_Discriminants --
-------------------------------
- procedure Init_Hidden_Discriminants (Typ : Entity_Id; List : List_Id) is
- function Is_Completely_Hidden_Discriminant
- (Discr : Entity_Id) return Boolean;
- -- Determine whether Discr is a completely hidden discriminant of
- -- type Typ.
-
- ---------------------------------------
- -- Is_Completely_Hidden_Discriminant --
- ---------------------------------------
-
- function Is_Completely_Hidden_Discriminant
- (Discr : Entity_Id) return Boolean
- is
- Item : Entity_Id;
-
- begin
- -- Use First/Next_Entity as First/Next_Discriminant do not yield
- -- completely hidden discriminants.
-
- Item := First_Entity (Typ);
- while Present (Item) loop
- if Ekind (Item) = E_Discriminant
- and then Is_Completely_Hidden (Item)
- and then Chars (Original_Record_Component (Item)) =
- Chars (Discr)
- then
- return True;
- end if;
-
- Next_Entity (Item);
- end loop;
-
- return False;
- end Is_Completely_Hidden_Discriminant;
-
- -- Local variables
-
+ procedure Init_Parent_Discriminants is
Base_Typ : Entity_Id;
Discr : Entity_Id;
Discr_Constr : Elmt_Id;
- Discr_Init : Node_Id;
Discr_Val : Node_Id;
In_Aggr_Type : Boolean;
Par_Typ : Entity_Id;
- -- Start of processing for Init_Hidden_Discriminants
+ -- Start of processing for Init_Parent_Discriminants
begin
-- The constraints on the hidden discriminants, if present, are kept
@@ -2667,39 +2609,43 @@ package body Exp_Aggr is
while Present (Discr) and then Present (Discr_Constr) loop
Discr_Val := Node (Discr_Constr);
- -- The parent discriminant is renamed in the derived type,
- -- nothing to initialize.
-
- -- type Deriv_Typ (Discr : ...)
- -- is new Parent_Typ (Discr => Discr);
+ -- The parent discriminant is renamed in the derived type
if Is_Entity_Name (Discr_Val)
and then Ekind (Entity (Discr_Val)) = E_Discriminant
then
- null;
-
- -- When the parent discriminant is constrained at the type
- -- extension level, it does not appear in the derived type.
+ Comp_Expr :=
+ Make_Selected_Component (Loc,
+ Prefix => New_Copy_Tree (Target),
+ Selector_Name => New_Occurrence_Of (Discr, Loc));
+
+ Discr_Val :=
+ Get_Discriminant_Value
+ (Entity (Discr_Val),
+ Typ,
+ Discriminant_Constraint (N_Typ));
+
+ Instr :=
+ Make_OK_Assignment_Statement (Loc,
+ Name => Comp_Expr,
+ Expression => New_Copy_Tree (Discr_Val));
- -- type Deriv_Typ (Discr : ...)
- -- is new Parent_Typ (Discr => Discr,
- -- Hidden_Discr => Expression);
+ Append_To (L, Instr);
- elsif Is_Completely_Hidden_Discriminant (Discr) then
- null;
-
- -- Otherwise initialize the discriminant
+ -- The parent discriminant is constrained in the derived type
else
- Discr_Init :=
+ Comp_Expr :=
+ Make_Selected_Component (Loc,
+ Prefix => New_Copy_Tree (Target),
+ Selector_Name => New_Occurrence_Of (Discr, Loc));
+
+ Instr :=
Make_OK_Assignment_Statement (Loc,
- Name =>
- Make_Selected_Component (Loc,
- Prefix => New_Copy_Tree (Target),
- Selector_Name => New_Occurrence_Of (Discr, Loc)),
+ Name => Comp_Expr,
Expression => New_Copy_Tree (Discr_Val));
- Append_To (List, Discr_Init);
+ Append_To (L, Instr);
end if;
Next_Elmt (Discr_Constr);
@@ -2709,38 +2655,7 @@ package body Exp_Aggr is
In_Aggr_Type := False;
Base_Typ := Base_Type (Par_Typ);
end loop;
- end Init_Hidden_Discriminants;
-
- --------------------------------
- -- Init_Visible_Discriminants --
- --------------------------------
-
- procedure Init_Visible_Discriminants is
- Discriminant : Entity_Id;
- Discriminant_Value : Node_Id;
-
- begin
- Discriminant := First_Discriminant (Typ);
- while Present (Discriminant) loop
- Comp_Expr :=
- Make_Selected_Component (Loc,
- Prefix => New_Copy_Tree (Target),
- Selector_Name => New_Occurrence_Of (Discriminant, Loc));
-
- Discriminant_Value :=
- Get_Discriminant_Value
- (Discriminant, Typ, Discriminant_Constraint (N_Typ));
-
- Instr :=
- Make_OK_Assignment_Statement (Loc,
- Name => Comp_Expr,
- Expression => New_Copy_Tree (Discriminant_Value));
-
- Append_To (L, Instr);
-
- Next_Discriminant (Discriminant);
- end loop;
- end Init_Visible_Discriminants;
+ end Init_Parent_Discriminants;
-------------------------------
-- Init_Stored_Discriminants --
@@ -2751,7 +2666,7 @@ package body Exp_Aggr is
Discriminant_Value : Node_Id;
begin
- Discriminant := First_Stored_Discriminant (Typ);
+ Discriminant := First_Stored_Discriminant (Base_Type (Typ));
while Present (Discriminant) loop
Comp_Expr :=
Make_Selected_Component (Loc,
@@ -2760,7 +2675,7 @@ package body Exp_Aggr is
Discriminant_Value :=
Get_Discriminant_Value
- (Discriminant, N_Typ, Discriminant_Constraint (N_Typ));
+ (Discriminant, Typ, Discriminant_Constraint (N_Typ));
Instr :=
Make_OK_Assignment_Statement (Loc,
@@ -3137,14 +3052,14 @@ package body Exp_Aggr is
end if;
end if;
- -- Generate assignments of hidden discriminants. If the base type
+ -- Generate assignments of parent discriminants. If the base type
-- is an unchecked union, the discriminants are absent from values
-- of the type, so assignments for them are not emitted.
if Has_Discriminants (Typ)
and then not Is_Unchecked_Union (Base_Type (Typ))
then
- Init_Hidden_Discriminants (Typ, L);
+ Init_Parent_Discriminants;
end if;
-- If the ancestor part is a subtype mark for a controlled type,
@@ -3174,23 +3089,22 @@ package body Exp_Aggr is
-- Normal case (not an extension aggregate)
else
- -- Generate the discriminant expressions, component by component.
- -- If the base type is an unchecked union, the discriminants are
- -- absent from values of the type, so assignments for them are not
- -- emitted.
+ -- Generate assignments of all the discriminants. If the base type
+ -- is an unchecked union, the discriminants are absent from values
+ -- of the type, so assignments for them are not emitted.
if Has_Discriminants (Typ)
and then not Is_Unchecked_Union (Base_Type (Typ))
then
- Init_Hidden_Discriminants (Typ, L);
+ -- Generate assignments of parent discriminants
- -- Generate discriminant init values for the visible discriminants
+ if Is_Tagged_Type (Typ) then
+ Init_Parent_Discriminants;
+ end if;
- Init_Visible_Discriminants;
+ -- Generate assignments of stored discriminants
- if Is_Derived_Type (N_Typ) then
- Init_Stored_Discriminants;
- end if;
+ Init_Stored_Discriminants;
end if;
end if;
@@ -3900,8 +3814,6 @@ package body Exp_Aggr is
Set_No_Initialization (N);
- Initialize_Discriminants (N, Typ);
-
-- Park the generated statements if the declaration requires it and is
-- not the node that is wrapped in a transient scope.
@@ -4323,6 +4235,7 @@ package body Exp_Aggr is
then
declare
Lhs : constant Node_Id := Name (Parent_Node);
+
begin
-- Apply discriminant check if required
@@ -4364,7 +4277,6 @@ package body Exp_Aggr is
Set_No_Initialization (Instr);
Insert_Action (N, Instr);
- Initialize_Discriminants (Instr, Full_Typ);
Target_Expr := New_Occurrence_Of (Temp, Loc);
Aggr_Code := Build_Record_Aggr_Code (N, Full_Typ, Target_Expr);
@@ -9561,37 +9473,6 @@ package body Exp_Aggr is
return False;
end Has_Mutable_Components;
- ------------------------------
- -- Initialize_Discriminants --
- ------------------------------
-
- procedure Initialize_Discriminants (N : Node_Id; Typ : Entity_Id) is
- Loc : constant Source_Ptr := Sloc (N);
- Bas : constant Entity_Id := Base_Type (Typ);
- Par : constant Entity_Id := Etype (Bas);
- Decl : constant Node_Id := Parent (Par);
- Ref : Node_Id;
-
- begin
- if Is_Tagged_Type (Bas)
- and then Is_Derived_Type (Bas)
- and then Has_Discriminants (Par)
- and then Has_Discriminants (Bas)
- and then Number_Discriminants (Bas) /= Number_Discriminants (Par)
- and then Nkind (Decl) = N_Full_Type_Declaration
- and then Nkind (Type_Definition (Decl)) = N_Record_Definition
- and then
- Present (Variant_Part (Component_List (Type_Definition (Decl))))
- and then Nkind (N) /= N_Extension_Aggregate
- then
- -- Call init proc to set discriminants.
- -- There should eventually be a special procedure for this ???
-
- Ref := New_Occurrence_Of (Defining_Identifier (N), Loc);
- Insert_Actions_After (N, Build_Initialization_Call (N, Ref, Typ));
- end if;
- end Initialize_Discriminants;
-
----------------
-- Must_Slide --
----------------
diff --git a/gcc/ada/sem_aux.ads b/gcc/ada/sem_aux.ads
index 3bd3a466476..7fbcb925d5e 100644
--- a/gcc/ada/sem_aux.ads
+++ b/gcc/ada/sem_aux.ads
@@ -127,13 +127,13 @@ package Sem_Aux is
-- stored discriminants are the same as the actual discriminants of the
-- type, and hence this function is the same as First_Discriminant.
--
- -- For derived untagged types that rename discriminants in the root type
+ -- For derived untagged types that rename discriminants in the root type,
-- this is the first of the discriminants that occur in the root type. To
-- be precise, in this case stored discriminants are entities attached to
- -- the entity chain of the derived type which are a copy of the
- -- discriminants of the root type. Furthermore their Is_Completely_Hidden
- -- flag is set since although they are actually stored in the object, they
- -- are not in the set of discriminants that is visible in the type.
+ -- the entity chain of the derived type but which are a mere copy of the
+ -- discriminants of the root type. Furthermore, their Is_Completely_Hidden
+ -- flag is set since, although they are actually stored in the object, they
+ -- are not in the set of discriminants that are visible in the type.
--
-- For derived untagged types, the set of stored discriminants are the real
-- discriminants from Gigi's standpoint, i.e. those that will be stored in