From: squirek <squi...@adacore.com> The patch implements the experimental constructors RFC. Currently a WIP.
gcc/ada/ChangeLog: * aspects.ads: Add support for constructors. * exp_aggr.adb: Likewise. * exp_attr.adb: Likewise. * exp_ch3.adb: Likewise. * exp_ch4.adb: Likewise. * exp_util.adb: Likewise. * gen_il-fields.ads: Likewise. * gen_il-gen-gen_entities.adb: Likewise. * gen_il-gen-gen_nodes.adb: Likewise. * par-ch4.adb: Likewise. * sem_aggr.adb: Likewise. * sem_attr.adb, sem_attr.ads: Likewise. * sem_ch13.adb: Likewise. * sem_ch3.adb: Likewise. * sem_ch5.adb: Likewise. * sem_ch6.adb: Likewise. * sem_res.adb: Likewise. * sem_util.adb, sem_util.ads: Likewise. * snames.ads-tmpl: Likewise. Tested on x86_64-pc-linux-gnu, committed on master. --- gcc/ada/aspects.ads | 10 + gcc/ada/exp_aggr.adb | 9 +- gcc/ada/exp_attr.adb | 311 ++++++++++++++++++++++++++++ gcc/ada/exp_ch3.adb | 39 +++- gcc/ada/exp_ch4.adb | 9 + gcc/ada/exp_util.adb | 11 +- gcc/ada/gen_il-fields.ads | 4 + gcc/ada/gen_il-gen-gen_entities.adb | 3 + gcc/ada/gen_il-gen-gen_nodes.adb | 1 + gcc/ada/par-ch4.adb | 42 +++- gcc/ada/sem_aggr.adb | 24 +++ gcc/ada/sem_attr.adb | 142 +++++++++---- gcc/ada/sem_attr.ads | 6 + gcc/ada/sem_ch13.adb | 98 ++++++++- gcc/ada/sem_ch3.adb | 8 + gcc/ada/sem_ch5.adb | 6 +- gcc/ada/sem_ch6.adb | 83 ++++++++ gcc/ada/sem_res.adb | 2 + gcc/ada/sem_util.adb | 44 ++++ gcc/ada/sem_util.ads | 7 + gcc/ada/snames.ads-tmpl | 3 + 21 files changed, 809 insertions(+), 53 deletions(-) diff --git a/gcc/ada/aspects.ads b/gcc/ada/aspects.ads index 70ea12023ab..9d44ed4dec3 100644 --- a/gcc/ada/aspects.ads +++ b/gcc/ada/aspects.ads @@ -81,6 +81,7 @@ package Aspects is Aspect_Bit_Order, Aspect_Component_Size, Aspect_Constant_Indexing, + Aspect_Constructor, -- GNAT Aspect_Contract_Cases, -- GNAT Aspect_Convention, Aspect_CPU, @@ -106,6 +107,7 @@ package Aspects is Aspect_GNAT_Annotate, -- GNAT Aspect_Implicit_Dereference, Aspect_Initial_Condition, -- GNAT + Aspect_Initialize, -- GNAT Aspect_Initializes, -- GNAT Aspect_Input, Aspect_Integer_Literal, @@ -428,6 +430,7 @@ package Aspects is Aspect_Bit_Order => Expression, Aspect_Component_Size => Expression, Aspect_Constant_Indexing => Name, + Aspect_Constructor => Name, Aspect_Contract_Cases => Expression, Aspect_Convention => Name, Aspect_CPU => Expression, @@ -453,6 +456,7 @@ package Aspects is Aspect_GNAT_Annotate => Expression, Aspect_Implicit_Dereference => Name, Aspect_Initial_Condition => Expression, + Aspect_Initialize => Expression, Aspect_Initializes => Expression, Aspect_Input => Name, Aspect_Integer_Literal => Name, @@ -529,6 +533,7 @@ package Aspects is Aspect_Component_Size => True, Aspect_Constant_Indexing => False, Aspect_Contract_Cases => False, + Aspect_Constructor => False, Aspect_Convention => True, Aspect_CPU => False, Aspect_Default_Component_Value => True, @@ -556,6 +561,7 @@ package Aspects is Aspect_GNAT_Annotate => False, Aspect_Implicit_Dereference => False, Aspect_Initial_Condition => False, + Aspect_Initialize => False, Aspect_Initializes => False, Aspect_Input => False, Aspect_Integer_Literal => False, @@ -698,6 +704,7 @@ package Aspects is Aspect_Constant_After_Elaboration => Name_Constant_After_Elaboration, Aspect_Constant_Indexing => Name_Constant_Indexing, Aspect_Contract_Cases => Name_Contract_Cases, + Aspect_Constructor => Name_Constructor, Aspect_Convention => Name_Convention, Aspect_CPU => Name_CPU, Aspect_CUDA_Device => Name_CUDA_Device, @@ -742,6 +749,7 @@ package Aspects is Aspect_Inline => Name_Inline, Aspect_Inline_Always => Name_Inline_Always, Aspect_Initial_Condition => Name_Initial_Condition, + Aspect_Initialize => Name_Initialize, Aspect_Initializes => Name_Initializes, Aspect_Input => Name_Input, Aspect_Integer_Literal => Name_Integer_Literal, @@ -965,6 +973,7 @@ package Aspects is Aspect_Asynchronous => Always_Delay, Aspect_Attach_Handler => Always_Delay, Aspect_Constant_Indexing => Always_Delay, + Aspect_Constructor => Always_Delay, Aspect_CPU => Always_Delay, Aspect_CUDA_Device => Always_Delay, Aspect_CUDA_Global => Always_Delay, @@ -1070,6 +1079,7 @@ package Aspects is Aspect_Import => Never_Delay, Aspect_Initial_Condition => Never_Delay, Aspect_Local_Restrictions => Never_Delay, + Aspect_Initialize => Never_Delay, Aspect_Initializes => Never_Delay, Aspect_Max_Entry_Queue_Length => Never_Delay, Aspect_Max_Queue_Length => Never_Delay, diff --git a/gcc/ada/exp_aggr.adb b/gcc/ada/exp_aggr.adb index 8f1869cc709..5450402f474 100644 --- a/gcc/ada/exp_aggr.adb +++ b/gcc/ada/exp_aggr.adb @@ -4327,6 +4327,7 @@ package body Exp_Aggr is Typ : constant Entity_Id := Etype (N); Dims : constant Nat := Number_Dimensions (Typ); Max_Others_Replicate : constant Nat := Max_Aggregate_Size (N); + Ctyp : constant Entity_Id := Component_Type (Typ); Static_Components : Boolean := True; @@ -4803,7 +4804,13 @@ package body Exp_Aggr is -- components because in this case will need to call the corresponding -- IP procedure. - if Has_Default_Init_Comps (N) then + if Has_Default_Init_Comps (N) + or else Present (Constructor_Name (Ctyp)) + or else (Is_Access_Type (Ctyp) + and then Present + (Constructor_Name + (Directly_Designated_Type (Ctyp)))) + then return; end if; diff --git a/gcc/ada/exp_attr.adb b/gcc/ada/exp_attr.adb index 455cc226bbf..f1f8424d720 100644 --- a/gcc/ada/exp_attr.adb +++ b/gcc/ada/exp_attr.adb @@ -24,6 +24,7 @@ ------------------------------------------------------------------------------ with Accessibility; use Accessibility; +with Aspects; use Aspects; with Atree; use Atree; with Checks; use Checks; with Debug; use Debug; @@ -4985,6 +4986,316 @@ package body Exp_Attr is Analyze_And_Resolve (N, Typ); + ---------- + -- Make -- + ---------- + + when Attribute_Make => + declare + Params : List_Id; + Param : Node_Id; + Par : Node_Id; + Construct : Entity_Id; + Obj : Node_Id := Empty; + Make_Expr : Node_Id := N; + + Formal : Entity_Id; + Replace_Expr : Node_Id; + Init_Param : Node_Id; + Construct_Call : Node_Id; + Curr_Nam : Node_Id := Empty; + + function Replace_Formal_Ref + (N : Node_Id) return Traverse_Result; + + function Replace_Formal_Ref + (N : Node_Id) return Traverse_Result is + begin + if Is_Entity_Name (N) + and then Chars (Formal) = Chars (N) + then + Rewrite (N, + New_Copy_Tree (Replace_Expr)); + end if; + + return OK; + end Replace_Formal_Ref; + + procedure Search_And_Replace_Formal is new + Traverse_Proc (Replace_Formal_Ref); + + begin + -- Remove side effects for constructor call + + Param := First (Expressions (N)); + while Present (Param) loop + if Nkind (Param) = N_Parameter_Association then + Remove_Side_Effects (Explicit_Actual_Parameter (Param), + Check_Side_Effects => False); + else + Remove_Side_Effects (Param, Check_Side_Effects => False); + end if; + + Next (Param); + end loop; + + -- Construct the parameters list + + Params := New_Copy_List (Expressions (N)); + if Is_Empty_List (Params) then + Params := New_List; + end if; + + -- Identify the enclosing parent for the non-copy cases + + Par := Parent (N); + if Nkind (Par) = N_Qualified_Expression then + Par := Parent (Par); + Make_Expr := Par; + end if; + if Nkind (Par) = N_Allocator then + Par := Parent (Par); + Curr_Nam := Make_Explicit_Dereference + (Loc, Prefix => Empty); + Obj := Curr_Nam; + end if; + + declare + Base_Obj : Node_Id := Empty; + Typ_Comp : Entity_Id; + Agg_Comp : Entity_Id; + Comp_Nam : Node_Id := Empty; + begin + while Nkind (Par) not in N_Object_Declaration + | N_Assignment_Statement + loop + if Nkind (Par) = N_Aggregate then + Typ_Comp := First_Entity (Etype (Par)); + Agg_Comp := First (Expressions (Par)); + loop + if No (Agg_Comp) then + return; + end if; + + if Agg_Comp = Make_Expr then + Comp_Nam := + Make_Selected_Component (Loc, + Prefix => Empty, + Selector_Name => + New_Occurrence_Of (Typ_Comp, Loc)); + + Make_Expr := Parent (Make_Expr); + Par := Parent (Par); + exit; + end if; + + Next_Entity (Typ_Comp); + Next (Agg_Comp); + end loop; + elsif Nkind (Par) = N_Component_Association then + Comp_Nam := + Make_Selected_Component (Loc, + Prefix => Empty, + Selector_Name => + Make_Identifier (Loc, + (Chars (First (Choices (Par)))))); + + Make_Expr := Parent (Parent (Make_Expr)); + Par := Parent (Parent (Par)); + else + declare + Temp : constant Entity_Id := + Make_Temporary (Loc, 'T', N); + begin + Rewrite (N, + Make_Expression_With_Actions (Loc, + Actions => New_List ( + Make_Object_Declaration (Loc, + Defining_Identifier => Temp, + Object_Definition => + New_Occurrence_Of (Typ, Loc), + Expression => + New_Copy_Tree (N))), + Expression => New_Occurrence_Of (Temp, Loc))); + Analyze_And_Resolve (N); + return; + end; + end if; + + if No (Curr_Nam) then + Curr_Nam := Comp_Nam; + Obj := Curr_Nam; + elsif Has_Prefix (Curr_Nam) then + Set_Prefix (Curr_Nam, Comp_Nam); + Curr_Nam := Comp_Nam; + end if; + end loop; + + Base_Obj := (case Nkind (Par) is + when N_Assignment_Statement => + New_Copy_Tree (Name (Par)), + when N_Object_Declaration => + New_Occurrence_Of + (Defining_Identifier (Par), Loc), + when others => (raise Program_Error)); + + if Present (Curr_Nam) then + Set_Prefix (Curr_Nam, Base_Obj); + else + Obj := Base_Obj; + end if; + end; + + Prepend_To (Params, Obj); + + -- Find the constructor we are interested in by doing a + -- pseudo-pass to resolve the constructor call. + + declare + Dummy_Params : List_Id := New_Copy_List (Expressions (N)); + Dummy_Self : Node_Id; + Dummy_Block : Node_Id; + Dummy_Call : Node_Id; + Dummy_Id : Entity_Id := Make_Temporary (Loc, 'D', N); + begin + if Is_Empty_List (Dummy_Params) then + Dummy_Params := New_List; + end if; + + Dummy_Self := Make_Object_Declaration (Loc, + Defining_Identifier => Dummy_Id, + Object_Definition => + New_Occurrence_Of (Typ, Loc)); + Prepend_To (Dummy_Params, New_Occurrence_Of (Dummy_Id, Loc)); + + Dummy_Call := Make_Procedure_Call_Statement (Loc, + Parameter_Associations => Dummy_Params, + Name => + (if not Has_Prefix (Pref) then + Make_Identifier (Loc, + Chars (Constructor_Name (Typ))) + else + Make_Expanded_Name (Loc, + Chars => + Chars (Constructor_Name (Typ)), + Prefix => + New_Copy_Tree (Prefix (Pref)), + Selector_Name => + Make_Identifier (Loc, + Chars (Constructor_Name (Typ)))))); + Set_Is_Expanded_Constructor_Call (Dummy_Call, True); + + Dummy_Block := Make_Block_Statement (Loc, + Declarations => New_List (Dummy_Self), + Handled_Statement_Sequence => + Make_Handled_Sequence_Of_Statements (Loc, + Statements => New_List (Dummy_Call))); + + Expander_Active := False; + + Insert_After_And_Analyze + (Enclosing_Declaration_Or_Statement (Par), Dummy_Block); + + Expander_Active := True; + + -- Finally, we can get the constructor based on our pseudo-pass + + Construct := Entity (Name (Dummy_Call)); + + -- Replace the Typ'Make attribute with an aggregate featuring + -- then relevant aggregate from the correct constructor's + -- Inializeaspect if it is present - otherwise, simply use a + -- box. + + if Has_Aspect (Construct, Aspect_Initialize) then + Rewrite (N, + New_Copy_Tree + (Find_Value_Of_Aspect (Construct, Aspect_Initialize))); + + Param := Next (First (Params)); + Formal := Next_Entity (First_Entity (Construct)); + while Present (Param) loop + if Nkind (Param) = N_Parameter_Association then + Formal := Selector_Name (Param); + Replace_Expr := Explicit_Actual_Parameter (Param); + else + Replace_Expr := Param; + end if; + + Init_Param := First (Component_Associations (N)); + while Present (Init_Param) loop + Search_And_Replace_Formal (Expression (Init_Param)); + + Next (Init_Param); + end loop; + + if Nkind (Param) /= N_Parameter_Association then + Next_Entity (Formal); + end if; + Next (Param); + end loop; + + Init_Param := First (Component_Associations (N)); + while Present (Init_Param) loop + if Nkind (Expression (Init_Param)) = N_Attribute_Reference + and then Attribute_Name + (Expression (Init_Param)) = Name_Make + then + Insert_After (Par, + Make_Assignment_Statement (Loc, + Name => + Make_Selected_Component (Loc, + Prefix => + New_Copy_Tree (First (Params)), + Selector_Name => + Make_Identifier (Loc, + Chars (First (Choices (Init_Param))))), + Expression => + New_Copy_Tree (Expression (Init_Param)))); + + Rewrite (Expression (Init_Param), + Make_Aggregate (Loc, + Expressions => New_List, + Component_Associations => New_List ( + Make_Component_Association (Loc, + Choices => + New_List (Make_Others_Choice (Loc)), + Expression => Empty, + Box_Present => True)))); + end if; + + Next (Init_Param); + end loop; + else + Rewrite (N, + Make_Aggregate (Loc, + Expressions => New_List, + Component_Associations => New_List ( + Make_Component_Association (Loc, + Choices => New_List (Make_Others_Choice (Loc)), + Expression => Empty, + Box_Present => True)))); + end if; + + -- Rewrite this block to be null and pretend it didn't happen + + Rewrite (Dummy_Block, Make_Null_Statement (Loc)); + end; + + Analyze_And_Resolve (N, Typ); + + -- Finally, insert the constructor call + + Construct_Call := + Make_Procedure_Call_Statement (Loc, + Name => + New_Occurrence_Of (Construct, Loc), + Parameter_Associations => Params); + + Set_Is_Expanded_Constructor_Call (Construct_Call); + Insert_After (Par, Construct_Call); + end; + -------------- -- Mantissa -- -------------- diff --git a/gcc/ada/exp_ch3.adb b/gcc/ada/exp_ch3.adb index fa87149aec0..c11e74b9fd8 100644 --- a/gcc/ada/exp_ch3.adb +++ b/gcc/ada/exp_ch3.adb @@ -3765,6 +3765,21 @@ package body Exp_Ch3 is Actions := Build_Assignment (Id, Expression (Decl)); end if; + -- Expand components with constructors to have the 'Make + -- attribute. + + elsif Present (Constructor_Name (Typ)) + and then Present (Default_Constructor (Typ)) + then + Set_Expression (Decl, + Make_Attribute_Reference (Loc, + Attribute_Name => Name_Make, + Prefix => + Subtype_Indication + (Component_Definition (Decl)))); + Analyze (Expression (Decl)); + Actions := Build_Assignment (Id, Expression (Decl)); + -- CPU, Dispatching_Domain, Priority, and Secondary_Stack_Size -- components are filled in with the corresponding rep-item -- expression of the concurrent type (if any). @@ -6754,12 +6769,13 @@ package body Exp_Ch3 is procedure Expand_N_Object_Declaration (N : Node_Id) is Loc : constant Source_Ptr := Sloc (N); Def_Id : constant Entity_Id := Defining_Identifier (N); - Expr : constant Node_Id := Expression (N); Obj_Def : constant Node_Id := Object_Definition (N); Typ : constant Entity_Id := Etype (Def_Id); Base_Typ : constant Entity_Id := Base_Type (Typ); Next_N : constant Node_Id := Next (N); + Expr : Node_Id := Expression (N); + Special_Ret_Obj : constant Boolean := Is_Special_Return_Object (Def_Id); -- If this is a special return object, it will be allocated differently -- and ultimately rewritten as a renaming, so initialization activities @@ -7476,7 +7492,11 @@ package body Exp_Ch3 is -- Don't do anything for deferred constants. All proper actions will be -- expanded during the full declaration. - if No (Expr) and Constant_Present (N) then + if No (Expr) + and then Constant_Present (N) + and then (No (Constructor_Name (Typ)) + or else No (Default_Constructor (Typ))) + then return; end if; @@ -7501,6 +7521,21 @@ package body Exp_Ch3 is return; end if; + -- Expand objects with default constructors to have the 'Make + -- attribute. + + if Comes_From_Source (N) + and then No (Expr) + and then Present (Constructor_Name (Typ)) + and then Present (Default_Constructor (Typ)) + then + Expr := Make_Attribute_Reference (Loc, + Attribute_Name => Name_Make, + Prefix => Object_Definition (N)); + Set_Expression (N, Expr); + Analyze_And_Resolve (Expr); + end if; + -- Make shared memory routines for shared passive variable if Is_Shared_Passive (Def_Id) then diff --git a/gcc/ada/exp_ch4.adb b/gcc/ada/exp_ch4.adb index eb9fb6bba56..88e5f360bbf 100644 --- a/gcc/ada/exp_ch4.adb +++ b/gcc/ada/exp_ch4.adb @@ -4491,6 +4491,15 @@ 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. + + if Present (Constructor_Name (Directly_Designated_Type (PtrT))) + and then Nkind (Expression (N)) = N_Identifier + then + Set_No_Initialization (N, False); + end if; + -- RM E.2.2(17). We enforce that the expected type of an allocator -- shall not be a remote access-to-class-wide-limited-private type. -- We probably shouldn't be doing this legality check during expansion, diff --git a/gcc/ada/exp_util.adb b/gcc/ada/exp_util.adb index 519d04b67b4..028ee01873b 100644 --- a/gcc/ada/exp_util.adb +++ b/gcc/ada/exp_util.adb @@ -14474,7 +14474,16 @@ package body Exp_Util is else N := First (L); while Present (N) loop - if not Side_Effect_Free (N, Name_Req, Variable_Ref) then + if Nkind (N) = N_Parameter_Association then + if not + Side_Effect_Free + (Explicit_Actual_Parameter (N), Name_Req, Variable_Ref) + then + return False; + end if; + + Next (N); + elsif not Side_Effect_Free (N, Name_Req, Variable_Ref) then return False; else Next (N); diff --git a/gcc/ada/gen_il-fields.ads b/gcc/ada/gen_il-fields.ads index f664449ed96..2780dc7acc1 100644 --- a/gcc/ada/gen_il-fields.ads +++ b/gcc/ada/gen_il-fields.ads @@ -255,6 +255,7 @@ package Gen_IL.Fields is Is_Elsif, Is_Entry_Barrier_Function, Is_Expanded_Build_In_Place_Call, + Is_Expanded_Constructor_Call, Is_Expanded_Prefixed_Call, Is_Folded_In_Parser, Is_Generic_Contract_Pragma, @@ -471,6 +472,8 @@ package Gen_IL.Fields is Component_Clause, Component_Size, Component_Type, + Constructor_List, + Constructor_Name, Contract, Contract_Wrapper, Corresponding_Concurrent_Type, @@ -819,6 +822,7 @@ package Gen_IL.Fields is Modulus, Must_Be_On_Byte_Boundary, Must_Have_Preelab_Init, + Needs_Construction, Needs_Debug_Info, Needs_No_Actuals, Never_Set_In_Source, diff --git a/gcc/ada/gen_il-gen-gen_entities.adb b/gcc/ada/gen_il-gen-gen_entities.adb index 2dc255c78c8..d653107a699 100644 --- a/gcc/ada/gen_il-gen-gen_entities.adb +++ b/gcc/ada/gen_il-gen-gen_entities.adb @@ -454,6 +454,8 @@ begin -- Gen_IL.Gen.Gen_Entities Pre => "Ekind (Base_Type (N)) in Access_Subprogram_Kind"), Sm (Class_Wide_Equivalent_Type, Node_Id), Sm (Class_Wide_Type, Node_Id), + Sm (Constructor_List, Elist_Id), + Sm (Constructor_Name, Node_Id), Sm (Contract, Node_Id), Sm (Current_Use_Clause, Node_Id), Sm (Derived_Type_Link, Node_Id), @@ -512,6 +514,7 @@ begin -- Gen_IL.Gen.Gen_Entities Sm (Linker_Section_Pragma, Node_Id), Sm (Must_Be_On_Byte_Boundary, Flag), Sm (Must_Have_Preelab_Init, Flag), + Sm (Needs_Construction, Flag), Sm (No_Tagged_Streams_Pragma, Node_Id, Pre => "Is_Tagged_Type (N)"), Sm (Non_Binary_Modulus, Flag, Base_Type_Only), diff --git a/gcc/ada/gen_il-gen-gen_nodes.adb b/gcc/ada/gen_il-gen-gen_nodes.adb index 5fe91a366e5..b1c554d083d 100644 --- a/gcc/ada/gen_il-gen-gen_nodes.adb +++ b/gcc/ada/gen_il-gen-gen_nodes.adb @@ -303,6 +303,7 @@ begin -- Gen_IL.Gen.Gen_Nodes Sm (Is_Known_Guaranteed_ABE, Flag), Sm (Is_SPARK_Mode_On_Node, Flag), Sm (No_Elaboration_Check, Flag), + Sm (Is_Expanded_Constructor_Call, Flag), Sm (Is_Expanded_Prefixed_Call, Flag))); Cc (N_Function_Call, N_Subprogram_Call, diff --git a/gcc/ada/par-ch4.adb b/gcc/ada/par-ch4.adb index ca02f1baac1..8267a0c06d3 100644 --- a/gcc/ada/par-ch4.adb +++ b/gcc/ada/par-ch4.adb @@ -592,6 +592,20 @@ package body Ch4 is Explicit_Actual_Parameter => Rnam)); exit; + -- 'Make is a special attribute that takes a variable + -- amount of parameters. + + elsif All_Extensions_Allowed + and then Attr_Name = Name_Make + then + Scan; + Rnam := P_Expression; + Append_To (Expressions (Name_Node), + Make_Parameter_Association (Sloc (Rnam), + Selector_Name => Expr, + Explicit_Actual_Parameter => Rnam)); + exit; + -- For all other cases named notation is illegal else @@ -3473,8 +3487,9 @@ package body Ch4 is function P_Allocator return Node_Id is Alloc_Node : Node_Id; - Type_Node : Node_Id; Null_Exclusion_Present : Boolean; + Scan_State : Saved_Scan_State; + Type_Node : Node_Id; begin Alloc_Node := New_Node (N_Allocator, Token_Ptr); @@ -3496,6 +3511,31 @@ package body Ch4 is Null_Exclusion_Present := P_Null_Exclusion; Set_Null_Exclusion_Present (Alloc_Node, Null_Exclusion_Present); + + -- Check for 'Make + + if All_Extensions_Allowed + and then Token = Tok_Identifier + then + Save_Scan_State (Scan_State); + Type_Node := P_Qualified_Simple_Name_Resync; + if Token = Tok_Apostrophe then + Scan; + if Token_Name = Name_Make then + Restore_Scan_State (Scan_State); + Set_Expression + (Alloc_Node, + Make_Qualified_Expression (Token_Ptr, + Subtype_Mark => Check_Subtype_Mark (Type_Node), + Expression => P_Expression_Or_Range_Attribute)); + return Alloc_Node; + end if; + end if; + Restore_Scan_State (Scan_State); + end if; + + -- Otherwise continue parsing the subtype + Type_Node := P_Subtype_Mark_Resync; if Token = Tok_Apostrophe then diff --git a/gcc/ada/sem_aggr.adb b/gcc/ada/sem_aggr.adb index a7ec772823f..3b470977c1b 100644 --- a/gcc/ada/sem_aggr.adb +++ b/gcc/ada/sem_aggr.adb @@ -6984,6 +6984,30 @@ package body Sem_Aggr is -- Check the dimensions of the components in the record aggregate Analyze_Dimension_Extension_Or_Record_Aggregate (N); + + -- Do a pass for constructors which rely on things being fully expanded + + declare + function Resolve_Make_Expr (N : Node_Id) return Traverse_Result; + -- Recurse in the aggregate and resolve references to 'Make + + function Resolve_Make_Expr (N : Node_Id) return Traverse_Result is + begin + if Nkind (N) = N_Attribute_Reference + and then Attribute_Name (N) = Name_Make + then + Set_Analyzed (N, False); + Resolve (N); + end if; + + return OK; + end Resolve_Make_Expr; + + procedure Search_And_Resolve_Make_Expr is new + Traverse_Proc (Resolve_Make_Expr); + begin + Search_And_Resolve_Make_Expr (N); + end; end Resolve_Record_Aggregate; ----------------------------- diff --git a/gcc/ada/sem_attr.adb b/gcc/ada/sem_attr.adb index 08da29a2198..7fdbe02d86f 100644 --- a/gcc/ada/sem_attr.adb +++ b/gcc/ada/sem_attr.adb @@ -3317,7 +3317,7 @@ package body Sem_Attr is E1 := Empty; E2 := Empty; - else + elsif Aname /= Name_Make then E1 := First (Exprs); -- Skip analysis for case of Restriction_Set, we do not expect @@ -5164,6 +5164,36 @@ package body Sem_Attr is Check_Not_Incomplete_Type; Set_Etype (N, Universal_Integer); + ---------- + -- Make -- + ---------- + + when Attribute_Make => declare + Expr : Entity_Id; + begin + -- Should this be assert? Parsing should fail if it hits 'Make + -- and all extensions aren't enabled ??? + + if not All_Extensions_Allowed then + return; + end if; + + Set_Etype (N, Etype (P)); + + if Present (Expressions (N)) then + Expr := First (Expressions (N)); + while Present (Expr) loop + if Nkind (Expr) = N_Parameter_Association then + Analyze (Explicit_Actual_Parameter (Expr)); + else + Analyze (Expr); + end if; + + Next (Expr); + end loop; + end if; + end; + -------------- -- Mantissa -- -------------- @@ -8713,6 +8743,13 @@ package body Sem_Attr is Set_Etype (N, C_Type); return; + -- Handle 'Make constructor calls + + elsif All_Extensions_Allowed + and then Id = Attribute_Make + then + P_Type := P_Entity; + -- No other cases are foldable (they certainly aren't static, and at -- the moment we don't try to fold any cases other than the ones above). @@ -8724,9 +8761,10 @@ package body Sem_Attr is -- If either attribute or the prefix is Any_Type, then propagate -- Any_Type to the result and don't do anything else at all. - if P_Type = Any_Type + if Id /= Attribute_Make + and then (P_Type = Any_Type or else (Present (E1) and then Etype (E1) = Any_Type) - or else (Present (E2) and then Etype (E2) = Any_Type) + or else (Present (E2) and then Etype (E2) = Any_Type)) then Set_Etype (N, Any_Type); return; @@ -8839,7 +8877,9 @@ package body Sem_Attr is Static := False; Set_Is_Static_Expression (N, False); - elsif Id /= Attribute_Max_Alignment_For_Allocation then + elsif Id not in Attribute_Max_Alignment_For_Allocation + | Attribute_Make + then if not Is_Constrained (P_Type) or else (Id /= Attribute_First and then Id /= Attribute_Last and then @@ -8915,53 +8955,55 @@ package body Sem_Attr is -- of the expressions to be scalar in order for the attribute to be -- considered to be static. - declare - E : Node_Id; + if Id /= Attribute_Make then + declare + E : Node_Id; - begin - E := E1; + begin + E := E1; - while Present (E) loop + while Present (E) loop - -- If expression is not static, then the attribute reference - -- result certainly cannot be static. + -- If expression is not static, then the attribute reference + -- result certainly cannot be static. - if not Is_Static_Expression (E) then - Static := False; + if not Is_Static_Expression (E) then + Static := False; + Set_Is_Static_Expression (N, False); + end if; + + if Raises_Constraint_Error (E) then + Set_Raises_Constraint_Error (N); + end if; + + -- If the result is not known at compile time, or is not of + -- a scalar type, then the result is definitely not static, + -- so we can quit now. + + if not Compile_Time_Known_Value (E) + or else not Is_Scalar_Type (Etype (E)) + then + Check_Expressions; + return; + + -- If the expression raises a constraint error, then so does + -- the attribute reference. We keep going in this case because + -- we are still interested in whether the attribute reference + -- is static even if it is not static. + + elsif Raises_Constraint_Error (E) then + Set_Raises_Constraint_Error (N); + end if; + + Next (E); + end loop; + + if Raises_Constraint_Error (Prefix (N)) then Set_Is_Static_Expression (N, False); - end if; - - if Raises_Constraint_Error (E) then - Set_Raises_Constraint_Error (N); - end if; - - -- If the result is not known at compile time, or is not of - -- a scalar type, then the result is definitely not static, - -- so we can quit now. - - if not Compile_Time_Known_Value (E) - or else not Is_Scalar_Type (Etype (E)) - then - Check_Expressions; return; - - -- If the expression raises a constraint error, then so does - -- the attribute reference. We keep going in this case because - -- we are still interested in whether the attribute reference - -- is static even if it is not static. - - elsif Raises_Constraint_Error (E) then - Set_Raises_Constraint_Error (N); end if; - - Next (E); - end loop; - - if Raises_Constraint_Error (Prefix (N)) then - Set_Is_Static_Expression (N, False); - return; - end if; - end; + end; + end if; -- Deal with the case of a static attribute reference that raises -- constraint error. The Raises_Constraint_Error flag will already @@ -9779,6 +9821,13 @@ package body Sem_Attr is end if; end Machine_Size; + ---------- + -- Make -- + ---------- + + when Attribute_Make => + Set_Etype (N, Etype (Prefix (N))); + -------------- -- Mantissa -- -------------- @@ -11096,7 +11145,9 @@ package body Sem_Attr is -- If this is still an attribute reference, then it has not been folded -- and that means that its expressions are in a non-static context. - elsif Nkind (N) = N_Attribute_Reference then + elsif Nkind (N) = N_Attribute_Reference + and then Attribute_Name (N) /= Name_Make + then Check_Expressions; -- Note: the else case not covered here are odd cases where the @@ -12961,6 +13012,7 @@ package body Sem_Attr is if Expander_Active and then Present (Expressions (N)) + and then Attr_Id /= Attribute_Make then declare Expr : Node_Id := First (Expressions (N)); diff --git a/gcc/ada/sem_attr.ads b/gcc/ada/sem_attr.ads index 8208048d813..1c54370316e 100644 --- a/gcc/ada/sem_attr.ads +++ b/gcc/ada/sem_attr.ads @@ -319,6 +319,12 @@ package Sem_Attr is -- This attribute is identical to the Object_Size attribute. It is -- provided for compatibility with the DEC attribute of this name. + ---------- + -- Make -- + ---------- + + Attribute_Make => True, + ---------------------- -- Max_Integer_Size -- ---------------------- diff --git a/gcc/ada/sem_ch13.adb b/gcc/ada/sem_ch13.adb index de5716e6fd0..5bac131c192 100644 --- a/gcc/ada/sem_ch13.adb +++ b/gcc/ada/sem_ch13.adb @@ -54,6 +54,7 @@ with Restrict; use Restrict; with Rident; use Rident; with Rtsfind; use Rtsfind; with Sem; use Sem; +with Sem_Aggr; use Sem_Aggr; with Sem_Aux; use Sem_Aux; with Sem_Case; use Sem_Case; with Sem_Cat; use Sem_Cat; @@ -3873,6 +3874,89 @@ package body Sem_Ch13 is goto Continue; end Initial_Condition; + -- Initialize + + when Aspect_Initialize => Initialize : declare + Aspect_Comp : Node_Id; + Type_Comp : Node_Id; + Typ : Entity_Id; + Dummy_Aggr : Node_Id; + begin + -- Error checking + + if not All_Extensions_Allowed then + goto Continue; + end if; + + if Ekind (E) /= E_Procedure then + Error_Msg_N ("Initialize must apply to a constructor", N); + end if; + + if Present (Expressions (Expression (Aspect))) then + Error_Msg_N ("only component associations allowed", N); + end if; + + -- Install the others for the aggregate if necessary + + Typ := Etype (First_Entity (E)); + + if No (First_Entity (Typ)) then + Error_Msg_N + ("Initialize can only apply to contructors" + & " whose type has one or more components", N); + end if; + + Aspect_Comp := + First (Component_Associations (Expression (Aspect))); + Type_Comp := First_Entity (Typ); + while Present (Type_Comp) loop + if No (Aspect_Comp) then + Append_To + (Component_Associations (Expression (Aspect)), + Make_Component_Association (Loc, + Choices => + New_List (Make_Others_Choice (Loc)), + Box_Present => True)); + exit; + elsif Nkind (First (Choices (Aspect_Comp))) + = N_Others_Choice + then + exit; + end if; + + Next (Aspect_Comp); + Next_Entity (Type_Comp); + end loop; + + -- Push the scope and formals for analysis + + Push_Scope (E); + Install_Formals (Defining_Unit_Name (Specification (N))); + + -- Analyze the components + + Aspect_Comp := + First (Component_Associations (Expression (Aspect))); + while Present (Aspect_Comp) loop + if Present (Expression (Aspect_Comp)) then + Analyze (Expression (Aspect_Comp)); + end if; + + Next (Aspect_Comp); + end loop; + + -- Do a psuedo pass over the aggregate to ensure it is valid + + Expander_Active := False; + Dummy_Aggr := New_Copy_Tree (Expression (Aspect)); + Resolve_Aggregate (Dummy_Aggr, Typ); + Expander_Active := True; + + -- Return the scope + + End_Scope; + end Initialize; + -- Initializes -- Aspect Initializes is never delayed because it is equivalent @@ -4346,6 +4430,10 @@ package body Sem_Ch13 is Analyze_Aspect_Implicit_Dereference; goto Continue; + when Aspect_Constructor => + Set_Constructor_Name (E, Expr); + Set_Needs_Construction (E); + -- Dimension when Aspect_Dimension => @@ -10799,7 +10887,8 @@ package body Sem_Ch13 is -- name, so we need to verify that one of these interpretations is -- the one available at at the freeze point. - elsif A_Id in Aspect_Input + elsif A_Id in Aspect_Constructor + | Aspect_Input | Aspect_Output | Aspect_Read | Aspect_Write @@ -11109,7 +11198,8 @@ package body Sem_Ch13 is -- Special case, the expression of these aspects is just an entity -- that does not need any resolution, so just analyze. - when Aspect_Input + when Aspect_Constructor + | Aspect_Input | Aspect_Output | Aspect_Put_Image | Aspect_Read @@ -11321,6 +11411,7 @@ package body Sem_Ch13 is | Aspect_GNAT_Annotate | Aspect_Implicit_Dereference | Aspect_Initial_Condition + | Aspect_Initialize | Aspect_Initializes | Aspect_Max_Entry_Queue_Length | Aspect_Max_Queue_Length @@ -16342,6 +16433,9 @@ package body Sem_Ch13 is => null; + when Aspect_Constructor => + null; + when Aspect_Dynamic_Predicate | Aspect_Ghost_Predicate | Aspect_Predicate diff --git a/gcc/ada/sem_ch3.adb b/gcc/ada/sem_ch3.adb index d47e3711e59..bfef653a720 100644 --- a/gcc/ada/sem_ch3.adb +++ b/gcc/ada/sem_ch3.adb @@ -23144,6 +23144,14 @@ package body Sem_Ch3 is Propagate_Concurrent_Flags (T, Etype (Component)); + -- Propagate information about constructor dependence + + if Ekind (Etype (Component)) /= E_Void + and then Needs_Construction (Etype (Component)) + then + Set_Needs_Construction (T); + end if; + if Ekind (Component) /= E_Component then null; diff --git a/gcc/ada/sem_ch5.adb b/gcc/ada/sem_ch5.adb index 12d6426671e..0c2cb2cb91d 100644 --- a/gcc/ada/sem_ch5.adb +++ b/gcc/ada/sem_ch5.adb @@ -534,7 +534,11 @@ package body Sem_Ch5 is if In_Inlined_Body then null; - elsif not Is_Variable (Lhs) then + elsif not Is_Variable (Lhs) + and then not (not Comes_From_Source (Lhs) + and then Nkind (Lhs) in N_Has_Etype + and then Needs_Construction (Etype (Lhs))) + then -- Ada 2005 (AI-327): Check assignment to the attribute Priority of a -- protected object. diff --git a/gcc/ada/sem_ch6.adb b/gcc/ada/sem_ch6.adb index dcbcc608f83..723be172a91 100644 --- a/gcc/ada/sem_ch6.adb +++ b/gcc/ada/sem_ch6.adb @@ -5401,6 +5401,89 @@ package body Sem_Ch6 is End_Scope; + -- Register the subprogram in a Constructor_List when it is a valid + -- constructor. + + if All_Extensions_Allowed + and then Present (First_Formal (Designator)) + then + + declare + First_Form_Type : constant Entity_Id := + Etype (First_Formal (Designator)); + + Construct : Elmt_Id; + begin + -- Valid constructors have a "controlling" formal of a type + -- with the Constructor aspect specified. Additionally, the + -- subprogram name must match value described by the aspect. + + -- Additionally, constructor declarations must exist within the + -- same scope as the type declaration and before the type is + -- frozen. + + -- For example: + -- + -- type Foo is null record with Constructor => Bar; + -- + -- procedure Bar (Self : in out Foo); + -- + + if Present (Constructor_Name (First_Form_Type)) + and then Current_Scope = Scope (First_Form_Type) + and then Chars (Constructor_Name (First_Form_Type)) + = Chars (Designator) + and then Ekind (Designator) = E_Procedure + and then Nkind (Parent (N)) = N_Subprogram_Declaration + then + -- If the constructor list is empty than we don't have to + -- look for duplicates - we simply create the list and + -- add it. + + if No (Constructor_List (First_Form_Type)) then + Set_Constructor_List + (First_Form_Type, New_Elmt_List (Designator)); + + -- Otherwise, we need to check the constructor hasen't + -- already been added (e.g. a specification and body) and + -- that there isn't a constructor with the same number of + -- type of formals. + + -- NOTE: The Constructor_List is sorted by the number of + -- parameters. + + else + Construct := First_Elmt + (Constructor_List (First_Form_Type)); + + -- Skip over constructors with less than the number of + -- parameters than Designator ??? + + -- Loop through the constructors looking for ones which + -- "match." + + Outter : loop + + -- When we are at the end of the constructor list we + -- know there are no matches, so it is safe to add. + + if No (Construct) then + Append_Elmt + (Designator, + Constructor_List (First_Form_Type)); + exit Outter; + end if; + + -- Loop through the formals and check the formals + -- match on type ??? + + Next_Elmt (Construct); + end loop Outter; + end if; + end if; + end; + end if; + -- The subprogram scope is pushed and popped around the processing of -- the return type for consistency with call above to Process_Formals -- (which itself can call Analyze_Return_Type), and to ensure that any diff --git a/gcc/ada/sem_res.adb b/gcc/ada/sem_res.adb index 1ae72fab662..96e8da6b54e 100644 --- a/gcc/ada/sem_res.adb +++ b/gcc/ada/sem_res.adb @@ -4842,6 +4842,7 @@ package body Sem_Res is if not Is_OK_Variable_For_Out_Formal (A) and then not Is_Init_Proc (Nam) + and then not Is_Expanded_Constructor_Call (N) then Error_Msg_NE ("actual for& must be a variable", A, F); @@ -8146,6 +8147,7 @@ package body Sem_Res is and then not Preanalysis_Active and then not Is_Imported (E) and then Nkind (Parent (E)) /= N_Object_Renaming_Declaration + and then not Needs_Construction (Etype (E)) then if No_Initialization (Parent (E)) or else (Present (Full_View (E)) diff --git a/gcc/ada/sem_util.adb b/gcc/ada/sem_util.adb index 1196e09f207..204366a87c5 100644 --- a/gcc/ada/sem_util.adb +++ b/gcc/ada/sem_util.adb @@ -6635,6 +6635,30 @@ package body Sem_Util is return Is_Class_Wide_Type (Typ) or else Needs_Finalization (Typ); end CW_Or_Needs_Finalization; + ------------------------- + -- Default_Constructor -- + ------------------------- + + function Default_Constructor (Typ : Entity_Id) return Entity_Id is + Construct : Elmt_Id; + begin + pragma Assert (Is_Type (Typ)); + if No (Constructor_Name (Typ)) or else No (Constructor_List (Typ)) then + return Empty; + end if; + + Construct := First_Elmt (Constructor_List (Typ)); + while Present (Construct) loop + if Parameter_Count (Elists.Node (Construct)) = 1 then + return Elists.Node (Construct); + end if; + + Next_Elmt (Construct); + end loop; + + return Empty; + end Default_Constructor; + --------------------- -- Defining_Entity -- --------------------- @@ -25405,6 +25429,8 @@ package body Sem_Util is end if; if Nkind (P) = N_Selected_Component + -- and then Ekind (Entity (Selector_Name (P))) + -- in Record_Field_Kind and then Present (Entry_Formal (Entity (Selector_Name (P)))) then -- Case of a reference to an entry formal @@ -26135,6 +26161,24 @@ package body Sem_Util is return Empty; end Param_Entity; + --------------------- + -- Parameter_Count -- + --------------------- + + function Parameter_Count (Subp : Entity_Id) return Nat is + Result : Nat := 0; + Param : Entity_Id; + begin + Param := First_Entity (Subp); + while Present (Param) loop + Result := Result + 1; + + Param := Next_Entity (Param); + end loop; + + return Result; + end Parameter_Count; + ---------------------- -- Policy_In_Effect -- ---------------------- diff --git a/gcc/ada/sem_util.ads b/gcc/ada/sem_util.ads index c88724f8626..3c2ae1e54b5 100644 --- a/gcc/ada/sem_util.ads +++ b/gcc/ada/sem_util.ads @@ -647,6 +647,10 @@ package Sem_Util is -- as Needs_Finalization except with pragma Restrictions (No_Finalization), -- in which case we know that class-wide objects do not need finalization. + function Default_Constructor (Typ : Entity_Id) return Entity_Id; + -- Determine the default constructor (e.g. the constructor with only one + -- formal parameter) for a given type Typ. + function Defining_Entity (N : Node_Id) return Entity_Id; -- Given a declaration N, returns the associated defining entity. If the -- declaration has a specification, the entity is obtained from the @@ -2860,6 +2864,9 @@ package Sem_Util is -- WARNING: this routine should be used in debugging scenarios such as -- tracking down undefined symbols as it is fairly low level. + function Parameter_Count (Subp : Entity_Id) return Nat; + -- Return the number of parameters for a given subprogram Subp. + function Param_Entity (N : Node_Id) return Entity_Id; -- Given an expression N, determines if the expression is a reference -- to a formal (of a subprogram or entry), and if so returns the Id diff --git a/gcc/ada/snames.ads-tmpl b/gcc/ada/snames.ads-tmpl index 95ece32858c..a6abfb25737 100644 --- a/gcc/ada/snames.ads-tmpl +++ b/gcc/ada/snames.ads-tmpl @@ -147,6 +147,7 @@ package Snames is -- Names of aspects for which there are no matching pragmas or attributes -- so that they need to be included for aspect specification use. + Name_Constructor : constant Name_Id := N + $; Name_Default_Value : constant Name_Id := N + $; Name_Default_Component_Value : constant Name_Id := N + $; Name_Designated_Storage_Model : constant Name_Id := N + $; @@ -1080,6 +1081,7 @@ package Snames is Name_Img : constant Name_Id := N + $; -- GNAT Name_Input : constant Name_Id := N + $; Name_Machine : constant Name_Id := N + $; + Name_Make : constant Name_Id := N + $; -- GNAT Name_Max : constant Name_Id := N + $; Name_Min : constant Name_Id := N + $; Name_Model : constant Name_Id := N + $; @@ -1614,6 +1616,7 @@ package Snames is Attribute_Img, Attribute_Input, Attribute_Machine, + Attribute_Make, Attribute_Max, Attribute_Min, Attribute_Model, -- 2.43.0