summaryrefslogtreecommitdiff
path: root/gcc/ada/exp_ch4.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/exp_ch4.adb')
-rw-r--r--gcc/ada/exp_ch4.adb237
1 files changed, 147 insertions, 90 deletions
diff --git a/gcc/ada/exp_ch4.adb b/gcc/ada/exp_ch4.adb
index 0802f2dfa51..ad65378cffb 100644
--- a/gcc/ada/exp_ch4.adb
+++ b/gcc/ada/exp_ch4.adb
@@ -1244,7 +1244,7 @@ package body Exp_Ch4 is
-- want to Adjust.
if not Aggr_In_Place
- and then not Is_Immutably_Limited_Type (T)
+ and then not Is_Limited_View (T)
then
Insert_Action (N,
@@ -1268,14 +1268,10 @@ package body Exp_Ch4 is
-- * .NET/JVM - these targets do not support address arithmetic
-- and unchecked conversion, key elements of Finalize_Address.
- -- * SPARK mode - the call is useless and results in unwanted
- -- expansion.
-
-- * CodePeer mode - TSS primitive Finalize_Address is not
-- created in this mode.
if VM_Target = No_VM
- and then not SPARK_Mode
and then not CodePeer_Mode
and then Present (Finalization_Master (PtrT))
and then Present (Temp_Decl)
@@ -4295,16 +4291,13 @@ package body Exp_Ch4 is
end if;
-- The finalization master must be inserted and analyzed as part of
- -- the current semantic unit. This form of expansion is not carried
- -- out in SPARK mode because it is useless. Note that the master is
- -- updated when analysis changes current units.
+ -- the current semantic unit. Note that the master is updated when
+ -- analysis changes current units.
- if not SPARK_Mode then
- if Present (Rel_Typ) then
- Set_Finalization_Master (PtrT, Finalization_Master (Rel_Typ));
- else
- Set_Finalization_Master (PtrT, Current_Anonymous_Master);
- end if;
+ if Present (Rel_Typ) then
+ Set_Finalization_Master (PtrT, Finalization_Master (Rel_Typ));
+ else
+ Set_Finalization_Master (PtrT, Current_Anonymous_Master);
end if;
end if;
@@ -4839,15 +4832,11 @@ package body Exp_Ch4 is
-- Set_Finalize_Address
-- (<PtrT>FM, <T>FD'Unrestricted_Access);
- -- Do not generate this call in the following cases:
- --
- -- * SPARK mode - the call is useless and results in
- -- unwanted expansion.
- --
- -- * CodePeer mode - TSS primitive Finalize_Address is
- -- not created in this mode.
+ -- Do not generate this call in CodePeer mode, as TSS
+ -- primitive Finalize_Address is not created in this
+ -- mode.
- elsif not (SPARK_Mode or CodePeer_Mode) then
+ elsif not CodePeer_Mode then
Insert_Action (N,
Make_Set_Finalize_Address_Call
(Loc => Loc,
@@ -4891,6 +4880,7 @@ package body Exp_Ch4 is
Loc : constant Source_Ptr := Sloc (N);
Typ : constant Entity_Id := Etype (N);
Cstmt : Node_Id;
+ Decl : Node_Id;
Tnn : Entity_Id;
Pnn : Entity_Id;
Actions : List_Id;
@@ -4958,19 +4948,24 @@ package body Exp_Ch4 is
Append_To (Actions,
Make_Full_Type_Declaration (Loc,
Defining_Identifier => Pnn,
- Type_Definition =>
+ Type_Definition =>
Make_Access_To_Object_Definition (Loc,
- All_Present => True,
- Subtype_Indication =>
- New_Reference_To (Typ, Loc))));
+ All_Present => True,
+ Subtype_Indication => New_Reference_To (Typ, Loc))));
Ttyp := Pnn;
end if;
Tnn := Make_Temporary (Loc, 'T');
- Append_To (Actions,
+
+ -- Create declaration for target of expression, and indicate that it
+ -- does not require initialization.
+
+ Decl :=
Make_Object_Declaration (Loc,
Defining_Identifier => Tnn,
- Object_Definition => New_Occurrence_Of (Ttyp, Loc)));
+ Object_Definition => New_Occurrence_Of (Ttyp, Loc));
+ Set_No_Initialization (Decl);
+ Append_To (Actions, Decl);
-- Now process the alternatives
@@ -7315,9 +7310,9 @@ package body Exp_Ch4 is
begin
Binary_Op_Validity_Checks (N);
- -- CodePeer and GNATprove want to see the unexpanded N_Op_Expon node
+ -- CodePeer wants to see the unexpanded N_Op_Expon node
- if CodePeer_Mode or SPARK_Mode then
+ if CodePeer_Mode then
return;
end if;
@@ -12140,24 +12135,44 @@ package body Exp_Ch4 is
(Decl : Node_Id;
Rel_Node : Node_Id)
is
- function Find_Enclosing_Context (N : Node_Id) return Node_Id;
- -- Find the logical context where N appears. The context is chosen such
- -- that it is possible to insert before and after it.
+ Hook_Context : Node_Id;
+ -- Node on which to insert the hook pointer (as an action)
- ----------------------------
- -- Find_Enclosing_Context --
- ----------------------------
+ Finalization_Context : Node_Id;
+ -- Node after which to insert finalization actions
+
+ Finalize_Always : Boolean;
+ -- If False, call to finalizer includes a test of whether the
+ -- hook pointer is null.
- function Find_Enclosing_Context (N : Node_Id) return Node_Id is
+ procedure Find_Enclosing_Contexts (N : Node_Id);
+ -- Find the logical context where N appears, and initializae
+ -- Hook_Context and Finalization_Context accordingly. Also
+ -- sets Finalize_Always.
+
+ -----------------------------
+ -- Find_Enclosing_Contexts --
+ -----------------------------
+
+ procedure Find_Enclosing_Contexts (N : Node_Id) is
Par : Node_Id;
Top : Node_Id;
+ Wrapped_Node : Node_Id;
+ -- Note: if we are in a transient scope, we want to reuse it as
+ -- the context for actions insertion, if possible. But if N is itself
+ -- part of the stored actions for the current transient scope,
+ -- then we need to insert at the appropriate (inner) location in
+ -- the not as an action on Node_To_Be_Wrapped.
+
+ In_Cond_Expr : constant Boolean := Within_Case_Or_If_Expression (N);
+
begin
-- When the node is inside a case/if expression, the lifetime of any
-- temporary controlled object is extended. Find a suitable insertion
-- node by locating the topmost case or if expressions.
- if Within_Case_Or_If_Expression (N) then
+ if In_Cond_Expr then
Par := N;
Top := N;
while Present (Par) loop
@@ -12187,7 +12202,8 @@ package body Exp_Ch4 is
N_Parameter_Association,
N_Pragma_Argument_Association)
then
- return Par;
+ Hook_Context := Par;
+ goto Hook_Context_Found;
-- Prevent the search from going too far
@@ -12198,26 +12214,10 @@ package body Exp_Ch4 is
Par := Parent (Par);
end loop;
- return Par;
-
- -- Short circuit operators in complex expressions are converted into
- -- expression_with_actions.
+ Hook_Context := Par;
+ goto Hook_Context_Found;
else
- -- Handle the case where the node is buried deep inside an if
- -- statement. The temporary controlled object must be finalized
- -- before the then, elsif or else statements are evaluated.
-
- -- if Something
- -- and then Ctrl_Func_Call
- -- then
- -- <result must be finalized at this point>
- -- <statements>
- -- end if;
-
- -- To achieve this, find the topmost logical operator. Generated
- -- actions are then inserted before/after it.
-
Par := N;
while Present (Par) loop
@@ -12254,14 +12254,23 @@ package body Exp_Ch4 is
-- Proc (... and then Ctrl_Func_Call ...);
+ if Scope_Is_Transient then
+ Wrapped_Node := Node_To_Be_Wrapped;
+ else
+ Wrapped_Node := Empty;
+ end if;
+
while Present (Par) loop
- if Nkind_In (Par, N_Assignment_Statement,
+ if Par = Wrapped_Node
+ or else
+ Nkind_In (Par, N_Assignment_Statement,
N_Object_Declaration,
N_Pragma,
N_Procedure_Call_Statement,
N_Simple_Return_Statement)
then
- return Par;
+ Hook_Context := Par;
+ goto Hook_Context_Found;
-- Prevent the search from going too far
@@ -12274,25 +12283,71 @@ package body Exp_Ch4 is
-- Return the topmost short circuit operator
- return Top;
+ Hook_Context := Top;
end if;
- end Find_Enclosing_Context;
+
+ <<Hook_Context_Found>>
+
+ -- Special case for Boolean EWAs: capture expression in a temporary,
+ -- whose declaration will serve as the context around which to insert
+ -- finalization code. The finalization thus remains local to the
+ -- specific condition being evaluated.
+
+ if Is_Boolean_Type (Etype (N)) then
+
+ -- In this case, the finalization context is chosen so that
+ -- we know at finalization point that the hook pointer is
+ -- never null, so no need for a test, we can call the finalizer
+ -- unconditionally, except in the case where the object is
+ -- created in a specific branch of a conditional expression.
+
+ Finalize_Always :=
+ not (In_Cond_Expr
+ or else
+ Nkind_In (Original_Node (N), N_Case_Expression,
+ N_If_Expression));
+
+ declare
+ Loc : constant Source_Ptr := Sloc (N);
+ Temp : constant Entity_Id := Make_Temporary (Loc, 'E', N);
+ begin
+ Append_To (Actions (N),
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => Temp,
+ Constant_Present => True,
+ Object_Definition =>
+ New_Occurrence_Of (Etype (N), Loc),
+ Expression => Expression (N)));
+ Finalization_Context := Last (Actions (N));
+
+ Analyze (Last (Actions (N)));
+
+ Set_Expression (N, New_Occurrence_Of (Temp, Loc));
+ Analyze (Expression (N));
+ end;
+
+ else
+ Finalize_Always := False;
+ Finalization_Context := Hook_Context;
+ end if;
+ end Find_Enclosing_Contexts;
-- Local variables
- Context : constant Node_Id := Find_Enclosing_Context (Rel_Node);
Loc : constant Source_Ptr := Sloc (Decl);
Obj_Id : constant Entity_Id := Defining_Identifier (Decl);
Obj_Typ : constant Node_Id := Etype (Obj_Id);
Desig_Typ : Entity_Id;
Expr : Node_Id;
- Fin_Call : Node_Id;
+ Fin_Stmts : List_Id;
Ptr_Id : Entity_Id;
Temp_Id : Entity_Id;
-- Start of processing for Process_Transient_Object
begin
+ Find_Enclosing_Contexts (Rel_Node);
+
-- Step 1: Create the access type which provides a reference to the
-- transient controlled object.
@@ -12309,7 +12364,7 @@ package body Exp_Ch4 is
Ptr_Id := Make_Temporary (Loc, 'A');
- Insert_Action (Context,
+ Insert_Action (Hook_Context,
Make_Full_Type_Declaration (Loc,
Defining_Identifier => Ptr_Id,
Type_Definition =>
@@ -12324,7 +12379,7 @@ package body Exp_Ch4 is
Temp_Id := Make_Temporary (Loc, 'T');
- Insert_Action (Context,
+ Insert_Action (Hook_Context,
Make_Object_Declaration (Loc,
Defining_Identifier => Temp_Id,
Object_Definition => New_Reference_To (Ptr_Id, Loc)));
@@ -12338,6 +12393,13 @@ package body Exp_Ch4 is
-- Step 3: Hook the transient object to the temporary
+ -- This must be inserted right after the object declaration, so that
+ -- the assignment is executed if, and only if, the object is actually
+ -- created (whereas the declaration of the hook pointer, and the
+ -- finalization call, may be inserted at an outer level, and may
+ -- remain unused for some executions, if the actual creation of
+ -- the object is conditional).
+
-- The use of unchecked conversion / unrestricted access is needed to
-- avoid an accessibility violation. Note that the finalization code is
-- structured in such a way that the "hook" is processed only when it
@@ -12377,34 +12439,29 @@ package body Exp_Ch4 is
-- insert the finalization code after the return statement as this will
-- render it unreachable.
- if Nkind (Context) /= N_Simple_Return_Statement then
- Fin_Call :=
- Make_Implicit_If_Statement (Decl,
- Condition =>
- Make_Op_Ne (Loc,
- Left_Opnd => New_Reference_To (Temp_Id, Loc),
- Right_Opnd => Make_Null (Loc)),
-
- Then_Statements => New_List (
- Make_Final_Call
- (Obj_Ref =>
- Make_Explicit_Dereference (Loc,
- Prefix => New_Reference_To (Temp_Id, Loc)),
- Typ => Desig_Typ),
-
- Make_Assignment_Statement (Loc,
- Name => New_Reference_To (Temp_Id, Loc),
- Expression => Make_Null (Loc))));
+ if Nkind (Finalization_Context) /= N_Simple_Return_Statement then
+ Fin_Stmts := New_List (
+ Make_Final_Call
+ (Obj_Ref =>
+ Make_Explicit_Dereference (Loc,
+ Prefix => New_Reference_To (Temp_Id, Loc)),
+ Typ => Desig_Typ),
- -- Use the Actions list of logical operators when inserting the
- -- finalization call. This ensures that all transient controlled
- -- objects are finalized after the operators are evaluated.
+ Make_Assignment_Statement (Loc,
+ Name => New_Reference_To (Temp_Id, Loc),
+ Expression => Make_Null (Loc)));
- if Nkind_In (Context, N_And_Then, N_Or_Else) then
- Insert_Action (Context, Fin_Call);
- else
- Insert_Action_After (Context, Fin_Call);
+ if not Finalize_Always then
+ Fin_Stmts := New_List (
+ Make_Implicit_If_Statement (Decl,
+ Condition =>
+ Make_Op_Ne (Loc,
+ Left_Opnd => New_Reference_To (Temp_Id, Loc),
+ Right_Opnd => Make_Null (Loc)),
+ Then_Statements => Fin_Stmts));
end if;
+
+ Insert_Actions_After (Finalization_Context, Fin_Stmts);
end if;
end Process_Transient_Object;