summaryrefslogtreecommitdiff
path: root/gcc/ada/exp_ch3.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/exp_ch3.adb')
-rw-r--r--gcc/ada/exp_ch3.adb442
1 files changed, 279 insertions, 163 deletions
diff --git a/gcc/ada/exp_ch3.adb b/gcc/ada/exp_ch3.adb
index b24a20439c3..160cfea761f 100644
--- a/gcc/ada/exp_ch3.adb
+++ b/gcc/ada/exp_ch3.adb
@@ -2623,9 +2623,8 @@ package body Exp_Ch3 is
Statements => New_List (
Make_Procedure_Call_Statement (Loc,
- Name =>
+ Name =>
New_Occurrence_Of (Local_DF_Id, Loc),
-
Parameter_Associations => New_List (
Make_Identifier (Loc, Name_uInit),
New_Occurrence_Of (Standard_False, Loc))),
@@ -4857,20 +4856,16 @@ package body Exp_Ch3 is
Typ : constant Entity_Id := Etype (Def_Id);
Base_Typ : constant Entity_Id := Base_Type (Typ);
Expr_Q : Node_Id;
- Id_Ref : Node_Id;
- New_Ref : Node_Id;
-
- Init_After : Node_Id := N;
- -- Node after which the init proc call is to be inserted. This is
- -- normally N, except for the case of a shared passive variable, in
- -- which case the init proc call must be inserted only after the bodies
- -- of the shared variable procedures have been seen.
function Build_Equivalent_Aggregate return Boolean;
-- If the object has a constrained discriminated type and no initial
-- value, it may be possible to build an equivalent aggregate instead,
-- and prevent an actual call to the initialization procedure.
+ procedure Default_Initialize_Object (After : Node_Id);
+ -- Generate all default initialization actions for object Def_Id. Any
+ -- new code is inserted after node After.
+
function Rewrite_As_Renaming return Boolean;
-- Indicate whether to rewrite a declaration with initialization into an
-- object renaming declaration (see below).
@@ -4911,11 +4906,10 @@ package body Exp_Ch3 is
end if;
if Ekind (Current_Scope) = E_Package
- and then
- (Restriction_Active (No_Elaboration_Code)
- or else Is_Preelaborated (Current_Scope))
+ and then
+ (Restriction_Active (No_Elaboration_Code)
+ or else Is_Preelaborated (Current_Scope))
then
-
-- Building a static aggregate is possible if the discriminants
-- have static values and the other components have static
-- defaults or none.
@@ -5005,6 +4999,263 @@ package body Exp_Ch3 is
end if;
end Build_Equivalent_Aggregate;
+ -------------------------------
+ -- Default_Initialize_Object --
+ -------------------------------
+
+ procedure Default_Initialize_Object (After : Node_Id) is
+ function New_Object_Reference return Node_Id;
+ -- Return a new reference to Def_Id with attributes Assignment_OK and
+ -- Must_Not_Freeze already set.
+
+ --------------------------
+ -- New_Object_Reference --
+ --------------------------
+
+ function New_Object_Reference return Node_Id is
+ Obj_Ref : constant Node_Id := New_Occurrence_Of (Def_Id, Loc);
+
+ begin
+ -- The call to the type init proc or [Deep_]Finalize must not
+ -- freeze the related object as the call is internally generated.
+ -- This way legal rep clauses that apply to the object will not be
+ -- flagged. Note that the initialization call may be removed if
+ -- pragma Import is encountered or moved to the freeze actions of
+ -- the object because of an address clause.
+
+ Set_Assignment_OK (Obj_Ref);
+ Set_Must_Not_Freeze (Obj_Ref);
+
+ return Obj_Ref;
+ end New_Object_Reference;
+
+ -- Local variables
+
+ Abrt_HSS : Node_Id;
+ Abrt_Id : Entity_Id;
+ Abrt_Stmts : List_Id;
+ Aggr_Init : Node_Id;
+ Comp_Init : List_Id := No_List;
+ Fin_Call : Node_Id;
+ Fin_Stmts : List_Id := No_List;
+ Obj_Init : Node_Id := Empty;
+ Obj_Ref : Node_Id;
+
+ -- Start of processing for Default_Initialize_Object
+
+ begin
+ -- Step 1: Initialize the object
+
+ if Needs_Finalization (Typ) and then not No_Initialization (N) then
+ Obj_Init :=
+ Make_Init_Call
+ (Obj_Ref => New_Occurrence_Of (Def_Id, Loc),
+ Typ => Typ);
+ end if;
+
+ -- Step 2: Initialize the components of the object
+
+ -- Do not initialize the components if their initialization is
+ -- prohibited or the type represents a value type in a .NET VM.
+
+ if Has_Non_Null_Base_Init_Proc (Typ)
+ and then not No_Initialization (N)
+ and then not Initialization_Suppressed (Typ)
+ and then not Is_Value_Type (Typ)
+ then
+ -- Do not initialize the components if No_Default_Initialization
+ -- applies as the the actual restriction check will occur later
+ -- when the object is frozen as it is not known yet whether the
+ -- object is imported or not.
+
+ if not Restriction_Active (No_Default_Initialization) then
+
+ -- If the values of the components are compile-time known, use
+ -- their prebuilt aggregate form directly.
+
+ Aggr_Init := Static_Initialization (Base_Init_Proc (Typ));
+
+ if Present (Aggr_Init) then
+ Set_Expression
+ (N, New_Copy_Tree (Aggr_Init, New_Scope => Current_Scope));
+
+ -- If type has discriminants, try to build an equivalent
+ -- aggregate using discriminant values from the declaration.
+ -- This is a useful optimization, in particular if restriction
+ -- No_Elaboration_Code is active.
+
+ elsif Build_Equivalent_Aggregate then
+ null;
+
+ -- Otherwise invoke the type init proc
+
+ else
+ Obj_Ref := New_Object_Reference;
+
+ if Comes_From_Source (Def_Id) then
+ Initialization_Warning (Obj_Ref);
+ end if;
+
+ Comp_Init := Build_Initialization_Call (Loc, Obj_Ref, Typ);
+ end if;
+ end if;
+
+ -- Provide a default value if the object needs simple initialization
+ -- and does not already have an initial value. A generated temporary
+ -- do not require initialization because it will be assigned later.
+
+ elsif Needs_Simple_Initialization
+ (Typ, Initialize_Scalars
+ and then not Has_Following_Address_Clause (N))
+ and then not Is_Internal (Def_Id)
+ and then not Has_Init_Expression (N)
+ then
+ Set_No_Initialization (N, False);
+ Set_Expression (N, Get_Simple_Init_Val (Typ, N, Esize (Def_Id)));
+ Analyze_And_Resolve (Expression (N), Typ);
+ end if;
+
+ -- Step 3: Add partial finalization and abort actions, generate:
+
+ -- Type_Init_Proc (Obj);
+ -- begin
+ -- Deep_Initialize (Obj);
+ -- exception
+ -- when others =>
+ -- Deep_Finalize (Obj, Self => False);
+ -- raise;
+ -- end;
+
+ -- Step 3a: Build the finalization block (if applicable)
+
+ -- The finalization block is required when both the object and its
+ -- controlled components are to be initialized. The block finalizes
+ -- the components if the object initialization fails.
+
+ if Has_Controlled_Component (Typ)
+ and then Present (Comp_Init)
+ and then Present (Obj_Init)
+ and then not Restriction_Active (No_Exception_Propagation)
+ then
+ -- Generate:
+ -- Type_Init_Proc (Obj);
+
+ Fin_Stmts := Comp_Init;
+
+ -- Generate:
+ -- begin
+ -- Deep_Initialize (Obj);
+ -- exception
+ -- when others =>
+ -- Deep_Finalize (Obj, Self => False);
+ -- raise;
+ -- end;
+
+ Fin_Call :=
+ Make_Final_Call
+ (Obj_Ref => New_Object_Reference,
+ Typ => Typ,
+ Skip_Self => True);
+
+ if Present (Fin_Call) then
+
+ -- Do not emit warnings related to the elaboration order when a
+ -- controlled object is declared before the body of Finalize is
+ -- seen.
+
+ Set_No_Elaboration_Check (Fin_Call);
+
+ Append_To (Fin_Stmts,
+ Make_Block_Statement (Loc,
+ Declarations => No_List,
+
+ Handled_Statement_Sequence =>
+ Make_Handled_Sequence_Of_Statements (Loc,
+ Statements => New_List (Obj_Init),
+
+ Exception_Handlers => New_List (
+ Make_Exception_Handler (Loc,
+ Exception_Choices => New_List (
+ Make_Others_Choice (Loc)),
+
+ Statements => New_List (
+ Fin_Call,
+ Make_Raise_Statement (Loc)))))));
+ end if;
+
+ -- Finalization is not required, the initialization calls are passed
+ -- to the abort block building circuitry, generate:
+
+ -- Type_Init_Proc (Obj);
+ -- Deep_Initialize (Obj);
+
+ else
+ if Present (Comp_Init) then
+ Fin_Stmts := Comp_Init;
+ end if;
+
+ if Present (Obj_Init) then
+ if No (Fin_Stmts) then
+ Fin_Stmts := New_List;
+ end if;
+
+ Append_To (Fin_Stmts, Obj_Init);
+ end if;
+ end if;
+
+ -- Step 3b: Build the abort block (if applicable)
+
+ -- The abort block is required when aborts are allowed and there is
+ -- at least one initialization call that needs protection.
+
+ if Abort_Allowed
+ and then Present (Comp_Init)
+ and then Present (Obj_Init)
+ then
+ -- Generate:
+ -- Abort_Defer;
+
+ Prepend_To (Fin_Stmts, Build_Runtime_Call (Loc, RE_Abort_Defer));
+
+ -- Generate:
+ -- begin
+ -- Abort_Defer;
+ -- <finalization statements>
+ -- at end
+ -- Abort_Undefer_Direct;
+ -- end;
+
+ Abrt_Id := New_Internal_Entity (E_Block, Current_Scope, Loc, 'B');
+ Set_Etype (Abrt_Id, Standard_Void_Type);
+ Set_Scope (Abrt_Id, Current_Scope);
+
+ Abrt_HSS :=
+ Make_Handled_Sequence_Of_Statements (Loc,
+ Statements => Fin_Stmts,
+ At_End_Proc =>
+ New_Occurrence_Of (RTE (RE_Abort_Undefer_Direct), Loc));
+
+ Abrt_Stmts := New_List (
+ Make_Block_Statement (Loc,
+ Identifier => New_Occurrence_Of (Abrt_Id, Loc),
+ Declarations => No_List,
+ Handled_Statement_Sequence => Abrt_HSS));
+
+ Expand_At_End_Handler (Abrt_HSS, Abrt_Id);
+
+ -- Abort is not required, the construct from Step 3a is to be added
+ -- in the tree (either finalization block or single initialization
+ -- call).
+
+ else
+ Abrt_Stmts := Fin_Stmts;
+ end if;
+
+ -- Step 4: Insert the whole initialization sequence into the tree
+
+ Insert_Actions_After (After, Abrt_Stmts);
+ end Default_Initialize_Object;
+
-------------------------
-- Rewrite_As_Renaming --
-------------------------
@@ -5018,6 +5269,17 @@ package body Exp_Ch3 is
and then Is_Entity_Name (Obj_Def);
end Rewrite_As_Renaming;
+ -- Local variables
+
+ Id_Ref : Node_Id;
+ New_Ref : Node_Id;
+
+ Init_After : Node_Id := N;
+ -- Node after which the initialization actions are to be inserted. This
+ -- is normally N, except for the case of a shared passive variable, in
+ -- which case the init proc call must be inserted only after the bodies
+ -- of the shared variable procedures have been seen.
+
-- Start of processing for Expand_N_Object_Declaration
begin
@@ -5118,153 +5380,7 @@ package body Exp_Ch3 is
Make_Invariant_Call (New_Occurrence_Of (Def_Id, Loc)));
end if;
- -- Expand Initialize call for controlled objects. One may wonder why
- -- the Initialize Call is not done in the regular Init procedure
- -- attached to the record type. That's because the init procedure is
- -- recursively called on each component, including _Parent, thus the
- -- Init call for a controlled object would generate not only one
- -- Initialize call as it is required but one for each ancestor of
- -- its type. This processing is suppressed if No_Initialization set.
-
- if not Needs_Finalization (Typ) or else No_Initialization (N) then
- null;
-
- elsif not Abort_Allowed or else not Comes_From_Source (N) then
- Insert_Action_After (Init_After,
- Make_Init_Call
- (Obj_Ref => New_Occurrence_Of (Def_Id, Loc),
- Typ => Base_Typ));
-
- -- Abort allowed
-
- else
- -- We need to protect the initialize call
-
- -- begin
- -- Defer_Abort.all;
- -- Initialize (...);
- -- at end
- -- Undefer_Abort.all;
- -- end;
-
- -- ??? this won't protect the initialize call for controlled
- -- components which are part of the init proc, so this block
- -- should probably also contain the call to _init_proc but this
- -- requires some code reorganization...
-
- declare
- L : constant List_Id := New_List (
- Make_Init_Call
- (Obj_Ref => New_Occurrence_Of (Def_Id, Loc),
- Typ => Base_Typ));
-
- Blk : constant Node_Id :=
- Make_Block_Statement (Loc,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc, L));
-
- begin
- Prepend_To (L, Build_Runtime_Call (Loc, RE_Abort_Defer));
- Set_At_End_Proc (Handled_Statement_Sequence (Blk),
- New_Occurrence_Of (RTE (RE_Abort_Undefer_Direct), Loc));
- Insert_Actions_After (Init_After, New_List (Blk));
- Expand_At_End_Handler
- (Handled_Statement_Sequence (Blk), Entity (Identifier (Blk)));
- end;
- end if;
-
- -- Call type initialization procedure if there is one. We build the
- -- call and put it immediately after the object declaration, so that
- -- it will be expanded in the usual manner. Note that this will
- -- result in proper handling of defaulted discriminants.
-
- -- Need call if there is a base init proc
-
- if Has_Non_Null_Base_Init_Proc (Typ)
-
- -- Suppress call if No_Initialization set on declaration
-
- and then not No_Initialization (N)
-
- -- Suppress call for special case of value type for VM
-
- and then not Is_Value_Type (Typ)
-
- -- Suppress call if initialization suppressed for the type
-
- and then not Initialization_Suppressed (Typ)
- then
- -- Return without initializing when No_Default_Initialization
- -- applies. Note that the actual restriction check occurs later,
- -- when the object is frozen, because we don't know yet whether
- -- the object is imported, which is a case where the check does
- -- not apply.
-
- if Restriction_Active (No_Default_Initialization) then
- return;
- end if;
-
- -- The call to the initialization procedure does NOT freeze the
- -- object being initialized. This is because the call is not a
- -- source level call. This works fine, because the only possible
- -- statements depending on freeze status that can appear after the
- -- Init_Proc call are rep clauses which can safely appear after
- -- actual references to the object. Note that this call may
- -- subsequently be removed (if a pragma Import is encountered),
- -- or moved to the freeze actions for the object (e.g. if an
- -- address clause is applied to the object, causing it to get
- -- delayed freezing).
-
- Id_Ref := New_Occurrence_Of (Def_Id, Loc);
- Set_Must_Not_Freeze (Id_Ref);
- Set_Assignment_OK (Id_Ref);
-
- declare
- Init_Expr : constant Node_Id :=
- Static_Initialization (Base_Init_Proc (Typ));
-
- begin
- if Present (Init_Expr) then
- Set_Expression
- (N, New_Copy_Tree (Init_Expr, New_Scope => Current_Scope));
- return;
-
- -- If type has discriminants, try to build equivalent aggregate
- -- using discriminant values from the declaration. This
- -- is a useful optimization, in particular if restriction
- -- No_Elaboration_Code is active.
-
- elsif Build_Equivalent_Aggregate then
- return;
-
- else
- Initialization_Warning (Id_Ref);
-
- Insert_Actions_After (Init_After,
- Build_Initialization_Call (Loc, Id_Ref, Typ));
- end if;
- end;
-
- -- If simple initialization is required, then set an appropriate
- -- simple initialization expression in place. This special
- -- initialization is required even though No_Init_Flag is present,
- -- but is not needed if there was an explicit initialization.
-
- -- An internally generated temporary needs no initialization because
- -- it will be assigned subsequently. In particular, there is no point
- -- in applying Initialize_Scalars to such a temporary.
-
- elsif Needs_Simple_Initialization
- (Typ,
- Initialize_Scalars
- and then not Has_Following_Address_Clause (N))
- and then not Is_Internal (Def_Id)
- and then not Has_Init_Expression (N)
- then
- Set_No_Initialization (N, False);
- Set_Expression (N, Get_Simple_Init_Val (Typ, N, Esize (Def_Id)));
- Analyze_And_Resolve (Expression (N), Typ);
- end if;
+ Default_Initialize_Object (Init_After);
-- Generate attribute for Persistent_BSS if needed
@@ -7971,8 +8087,8 @@ package body Exp_Ch3 is
if Warning_Needed then
Error_Msg_N
- ("Objects of the type cannot be initialized "
- & "statically by default??", Parent (E));
+ ("Objects of the type cannot be initialized statically "
+ & "by default??", Parent (E));
end if;
end if;