If the type of the aggregate is derived, and constrains discriminants of the parent type, these discriminants are not components of the aggregate, and must be initialized by the code generated by the compiler. They are not visible components of the object, but can become visible with a view conversion to the ancestor.
This patch adds the missing support to the frontend to generate assignments initializing hidden discriminants in extension aggregates. The following test must compile and execute without errors. package Pkg is type ROOT is tagged null record; type NT_B1 (D2 : Natural) is new Root with record S2 : String(1..D2); end record; type NT_B2 (D3 : Natural) is new NT_B1 (D2 => 10) with null record; end; with Pkg; use Pkg; procedure Do_Test is String10 : String(1..10) := "1234567890"; G : NT_B2 := (ROOT with D3 => 5, S2 => String10); N : Natural; begin N := NT_B1(G).D2; if N /= 10 then raise Program_Error; end if; end; Tested on x86_64-pc-linux-gnu, committed on trunk 2011-08-03 Javier Miranda <mira...@adacore.com> * exp_aggr.adb (Init_Hidden_Discriminants): New subprogram of Build_Record_Aggr_Code. (Build_Record_Aggr_Code): Add missing support to initialize hidden discriminants in extension aggregates.
Index: exp_aggr.adb =================================================================== --- exp_aggr.adb (revision 177237) +++ exp_aggr.adb (working copy) @@ -1854,6 +1854,11 @@ -- to finalization list F. Init_Pr conditions the call to the init proc -- since it may already be done due to ancestor initialization. + 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. + function Is_Int_Range_Bounds (Bounds : Node_Id) return Boolean; -- Check whether Bounds is a range node and its lower and higher bounds -- are integers literals. @@ -2156,6 +2161,56 @@ return L; end Init_Controller; + ------------------------------- + -- Init_Hidden_Discriminants -- + ------------------------------- + + procedure Init_Hidden_Discriminants (Typ : Entity_Id; List : List_Id) is + Btype : Entity_Id; + Parent_Type : Entity_Id; + Disc : Entity_Id; + Discr_Val : Elmt_Id; + + begin + Btype := Base_Type (Typ); + while Is_Derived_Type (Btype) + and then Present (Stored_Constraint (Btype)) + loop + Parent_Type := Etype (Btype); + + Disc := First_Discriminant (Parent_Type); + Discr_Val := First_Elmt (Stored_Constraint (Base_Type (Typ))); + while Present (Discr_Val) loop + + -- Only those discriminants of the parent that are not + -- renamed by discriminants of the derived type need to + -- be added explicitly. + + if not Is_Entity_Name (Node (Discr_Val)) + or else Ekind (Entity (Node (Discr_Val))) /= E_Discriminant + then + Comp_Expr := + Make_Selected_Component (Loc, + Prefix => New_Copy_Tree (Target), + Selector_Name => New_Occurrence_Of (Disc, Loc)); + + Instr := + Make_OK_Assignment_Statement (Loc, + Name => Comp_Expr, + Expression => New_Copy_Tree (Node (Discr_Val))); + + Set_No_Ctrl_Actions (Instr); + Append_To (List, Instr); + end if; + + Next_Discriminant (Disc); + Next_Elmt (Discr_Val); + end loop; + + Btype := Base_Type (Parent_Type); + end loop; + end Init_Hidden_Discriminants; + ------------------------- -- Is_Int_Range_Bounds -- ------------------------- @@ -2741,6 +2796,17 @@ end if; end; + -- Generate assignments of hidden assignments. If the base type is an + -- unchecked union, the discriminants are unknown to the back-end and + -- absent from a value 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); + end if; + -- Normal case (not an extension aggregate) else @@ -2752,60 +2818,8 @@ if Has_Discriminants (Typ) and then not Is_Unchecked_Union (Base_Type (Typ)) then - -- If the type is derived, and constrains discriminants of the - -- parent type, these discriminants are not components of the - -- aggregate, and must be initialized explicitly. They are not - -- visible components of the object, but can become visible with - -- a view conversion to the ancestor. + Init_Hidden_Discriminants (Typ, L); - declare - Btype : Entity_Id; - Parent_Type : Entity_Id; - Disc : Entity_Id; - Discr_Val : Elmt_Id; - - begin - Btype := Base_Type (Typ); - while Is_Derived_Type (Btype) - and then Present (Stored_Constraint (Btype)) - loop - Parent_Type := Etype (Btype); - - Disc := First_Discriminant (Parent_Type); - Discr_Val := - First_Elmt (Stored_Constraint (Base_Type (Typ))); - while Present (Discr_Val) loop - - -- Only those discriminants of the parent that are not - -- renamed by discriminants of the derived type need to - -- be added explicitly. - - if not Is_Entity_Name (Node (Discr_Val)) - or else - Ekind (Entity (Node (Discr_Val))) /= E_Discriminant - then - Comp_Expr := - Make_Selected_Component (Loc, - Prefix => New_Copy_Tree (Target), - Selector_Name => New_Occurrence_Of (Disc, Loc)); - - Instr := - Make_OK_Assignment_Statement (Loc, - Name => Comp_Expr, - Expression => New_Copy_Tree (Node (Discr_Val))); - - Set_No_Ctrl_Actions (Instr); - Append_To (L, Instr); - end if; - - Next_Discriminant (Disc); - Next_Elmt (Discr_Val); - end loop; - - Btype := Base_Type (Parent_Type); - end loop; - end; - -- Generate discriminant init values for the visible discriminants declare