From: Eric Botcazou <ebotca...@adacore.com> This makes the compiler generate cleanup code to deallocate the memory when the evaluation of the expression of an allocator raises an exception, if the expression is a call to a function that may raise, i.e. is not declared with the No_Raise aspect/pragma. This can also be disabled by means of -gnatdQ.
gcc/ada/ChangeLog: * debug.adb (dQ): Document usage. * exp_ch4.ads (Build_Cleanup_For_Allocator): New declaration. * exp_ch4.adb (Build_Cleanup_For_Allocator): New procedure. (Expand_Allocator_Expression): Build a cleanup to deallocate the memory when the evaluation of the expression raises an exception. * exp_ch6.adb (Make_Build_In_Place_Call_In_Allocator): Likewise. * exp_util.adb (Build_Allocate_Deallocate_Proc): Do not generate the detachment if the deallocation is for the cleanup of an allocator. * gen_il-fields.ads (Opt_Field_Enum): Add For_Allocator. * gen_il-gen-gen_nodes.adb (N_Free_Statement): Likewise. * sinfo.ads (For_Allocator): Document usage on N_Free_Statement. Tested on x86_64-pc-linux-gnu, committed on master. --- gcc/ada/debug.adb | 5 +- gcc/ada/exp_ch4.adb | 123 +++++++++++++++++++++++++------ gcc/ada/exp_ch4.ads | 9 +++ gcc/ada/exp_ch6.adb | 16 +++- gcc/ada/exp_util.adb | 5 ++ gcc/ada/gen_il-fields.ads | 1 + gcc/ada/gen_il-gen-gen_nodes.adb | 3 +- gcc/ada/sinfo.ads | 5 ++ 8 files changed, 140 insertions(+), 27 deletions(-) diff --git a/gcc/ada/debug.adb b/gcc/ada/debug.adb index 2d0c32b0f09..c4b6d035e5c 100644 --- a/gcc/ada/debug.adb +++ b/gcc/ada/debug.adb @@ -74,7 +74,7 @@ package body Debug is -- dN No file name information in exception messages -- dO Output immediate error messages -- dP Do not check for controlled objects in preelaborable packages - -- dQ + -- dQ Do not generate cleanups for qualified expressions of allocators -- dR Bypass check for correct version of s-rpc -- dS Never convert numbers to machine numbers in Sem_Eval -- dT Convert to machine numbers only for constant declarations @@ -640,6 +640,9 @@ package body Debug is -- in preelaborable packages, but this restriction is a huge pain, -- especially in the predefined library units. + -- dQ Do not generate cleanups to deallocate the memory in case qualified + -- expressions of allocators raise an exception. + -- dR Bypass the check for a proper version of s-rpc being present -- to use the -gnatz? switch. This allows debugging of the use -- of stubs generation without needing to have GLADE (or some diff --git a/gcc/ada/exp_ch4.adb b/gcc/ada/exp_ch4.adb index 18656ea24fd..75d79019f80 100644 --- a/gcc/ada/exp_ch4.adb +++ b/gcc/ada/exp_ch4.adb @@ -437,6 +437,37 @@ package body Exp_Ch4 is return; end Build_Boolean_Array_Proc_Call; + --------------------------------- + -- Build_Cleanup_For_Allocator -- + --------------------------------- + + function Build_Cleanup_For_Allocator + (Loc : Source_Ptr; + Obj_Id : Entity_Id; + Pool : Entity_Id; + Actions : List_Id) return Node_Id + is + Free_Stmt : constant Node_Id := + Make_Free_Statement (Loc, New_Occurrence_Of (Obj_Id, Loc)); + + begin + Set_For_Allocator (Free_Stmt); + Set_Storage_Pool (Free_Stmt, Pool); + + return + Make_Block_Statement (Loc, + Handled_Statement_Sequence => + Make_Handled_Sequence_Of_Statements (Loc, + Statements => Actions, + Exception_Handlers => New_List ( + Make_Exception_Handler (Loc, + Exception_Choices => New_List ( + Make_Others_Choice (Loc)), + Statements => New_List ( + Free_Stmt, + Make_Raise_Statement (Loc)))))); + end Build_Cleanup_For_Allocator; + ----------------------- -- Build_Eq_Call -- ----------------------- @@ -574,7 +605,12 @@ package body Exp_Ch4 is T : constant Entity_Id := Entity (Indic); PtrT : constant Entity_Id := Etype (N); DesigT : constant Entity_Id := Designated_Type (PtrT); + Pool : constant Node_Id := Storage_Pool (N); Special_Return : constant Boolean := For_Special_Return_Object (N); + Special_Pool : constant Boolean := + Present (Pool) + and then + (Is_RTE (Pool, RE_RS_Pool) or else Is_RTE (Pool, RE_SS_Pool)); Static_Match : constant Boolean := not Is_Constrained (DesigT) or else Subtypes_Statically_Match (T, DesigT); @@ -586,8 +622,7 @@ package body Exp_Ch4 is -- of Exp into the newly allocated memory. procedure Build_Explicit_Assignment (Temp : Entity_Id; Typ : Entity_Id); - -- If Exp is a conditional expression whose expansion has been delayed, - -- build the declaration of object Temp with Typ and initialization + -- Build the declaration of object Temp with Typ and initialization -- expression an uninitialized allocator for Etype (Exp), then perform -- assignment of Exp into the newly allocated memory. @@ -595,6 +630,22 @@ package body Exp_Ch4 is -- Build the declaration of object Temp with Typ and initialization -- expression the allocator N. + function Needs_Cleanup return Boolean is + (not Special_Pool + and then Is_Definite_Subtype (T) + and then Nkind (Exp) = N_Function_Call + and then not (Is_Entity_Name (Name (Exp)) + and then No_Raise (Entity (Name (Exp)))) + and then RTE_Available (RE_Free) + and then not Debug_Flag_QQ); + -- Return True if a cleanup needs to be built to deallocate the memory + -- when the evaluation of the expression raises an exception. This can + -- be done only if deallocation is available, but not for special pools + -- since such pools do not support deallocation. Moreover, this is not + -- needed for an indefinite allocation because the expression will be + -- evaluated first, in order to size the allocation. For now, we only + -- return True for a call to a function that may raise an exception. + ------------------------------ -- Build_Aggregate_In_Place -- ------------------------------ @@ -665,10 +716,32 @@ package body Exp_Ch4 is -- Arrange for the expression to be analyzed again and expanded + if Is_Delayed_Conditional_Expression (Expression (Assign)) then + Unanalyze_Delayed_Conditional_Expression (Expression (Assign)); + end if; + Set_Assignment_OK (Name (Assign)); - Set_Analyzed (Expression (Assign), False); - Set_No_Finalize_Actions (Assign); - Insert_Action (N, Assign); + + -- If the initialization expression is a function call, we do not + -- adjust after the assignment but, in either case, we do not + -- finalize before since the target is newly allocated memory. + + if Nkind (Exp) = N_Function_Call then + Set_No_Ctrl_Actions (Assign); + else + Set_No_Finalize_Actions (Assign); + end if; + + -- Build a cleanup if the assignment may raise an exception + + if Needs_Cleanup then + Insert_Action (N, + Build_Cleanup_For_Allocator (Loc, + Temp, Pool, New_List (Assign)), + Suppress => All_Checks); + else + Insert_Action (N, Assign, Suppress => All_Checks); + end if; end Build_Explicit_Assignment; ----------------------------- @@ -871,6 +944,20 @@ package body Exp_Ch4 is Analyze_And_Resolve (Expression (N), Entity (Indic)); end if; + -- If the designated type is class-wide, then the alignment and the + -- controlled nature of the expression are computed dynamically by + -- the code generated by Build_Allocate_Deallocate_Proc, which will + -- thus need to remove side effects from Exp first. But the below + -- test on Exp needs to have its final form to decide whether or not + -- to generate an Adjust call, so we preventively remove them here. + + if Is_Class_Wide_Type (DesigT) + and then Nkind (Exp) = N_Function_Call + and then not Special_Pool + then + Remove_Side_Effects (Exp); + end if; + -- Actions inserted before: -- Temp : constant PtrT := new T'(Expression); -- Temp._tag = T'tag; -- when not class-wide @@ -887,7 +974,7 @@ package body Exp_Ch4 is if Aggr_In_Place then Build_Aggregate_In_Place (Temp, PtrT); - elsif Delayed_Cond_Expr then + elsif Delayed_Cond_Expr or else Needs_Cleanup then Build_Explicit_Assignment (Temp, PtrT); else @@ -929,7 +1016,7 @@ package body Exp_Ch4 is if Aggr_In_Place then Build_Aggregate_In_Place (New_Temp, Def_Id); - elsif Delayed_Cond_Expr then + elsif Delayed_Cond_Expr or else Needs_Cleanup then Build_Explicit_Assignment (New_Temp, Def_Id); else @@ -995,22 +1082,6 @@ package body Exp_Ch4 is (Loc, TagR, Underlying_Type (TagT))); end if; - -- If the designated type is class-wide, then the alignment and the - -- controlled nature of the expression are computed dynamically by - -- the code generated by Build_Allocate_Deallocate_Proc, which will - -- thus need to remove side effects from Exp first. But the below - -- test on Exp needs to have its final form to decide whether or not - -- to generate an Adjust call, so we preventively remove them here. - - if Nkind (Exp) = N_Function_Call - and then Is_Class_Wide_Type (DesigT) - and then Present (Storage_Pool (N)) - and then not Is_RTE (Storage_Pool (N), RE_RS_Pool) - and then not Is_RTE (Storage_Pool (N), RE_SS_Pool) - then - Remove_Side_Effects (Exp); - end if; - -- Generate an Adjust call if the object will be moved. In Ada 2005, -- the object may be inherently limited, in which case there is no -- Adjust procedure, and the object is built in place. In Ada 95, the @@ -1141,7 +1212,11 @@ package body Exp_Ch4 is end if; Temp := Make_Temporary (Loc, 'P', N); - Build_Simple_Allocation (Temp, PtrT); + if Needs_Cleanup then + Build_Explicit_Assignment (Temp, PtrT); + else + Build_Simple_Allocation (Temp, PtrT); + end if; Build_Allocate_Deallocate_Proc (Declaration_Node (Temp), Mark => N); end if; diff --git a/gcc/ada/exp_ch4.ads b/gcc/ada/exp_ch4.ads index 22ffdc6496d..69914561e97 100644 --- a/gcc/ada/exp_ch4.ads +++ b/gcc/ada/exp_ch4.ads @@ -73,6 +73,15 @@ package Exp_Ch4 is procedure Expand_N_Type_Conversion (N : Node_Id); procedure Expand_N_Unchecked_Type_Conversion (N : Node_Id); + function Build_Cleanup_For_Allocator + (Loc : Source_Ptr; + Obj_Id : Entity_Id; + Pool : Entity_Id; + Actions : List_Id) return Node_Id; + -- Build a cleanup for the list of Actions that will deallocate the memory + -- allocated in Pool and designated by Obj_Id if the execution of Actions + -- raises an exception. + function Build_Eq_Call (Typ : Entity_Id; Loc : Source_Ptr; diff --git a/gcc/ada/exp_ch6.adb b/gcc/ada/exp_ch6.adb index 11b954fbabd..a339a223f09 100644 --- a/gcc/ada/exp_ch6.adb +++ b/gcc/ada/exp_ch6.adb @@ -8499,7 +8499,21 @@ package body Exp_Ch6 is Chain := Empty; end if; - Insert_Actions (Allocator, Actions); + -- See the Needs_Cleanup predicate in Expand_Allocator_Expression + + if Alloc_Form = Caller_Allocation + and then not For_Special_Return_Object (Allocator) + and then not (Is_Entity_Name (Name (Func_Call)) + and then No_Raise (Entity (Name (Func_Call)))) + and then RTE_Available (RE_Free) + and then not Debug_Flag_QQ + then + Insert_Action (Allocator, + Build_Cleanup_For_Allocator (Loc, + Return_Obj_Access, Storage_Pool (Allocator), Actions)); + else + Insert_Actions (Allocator, Actions); + end if; end; -- When the function has a controlling result, an allocation-form diff --git a/gcc/ada/exp_util.adb b/gcc/ada/exp_util.adb index 25f9f077174..66ba73226ed 100644 --- a/gcc/ada/exp_util.adb +++ b/gcc/ada/exp_util.adb @@ -1281,6 +1281,11 @@ package body Exp_Util is end if; end; + -- Nothing to generate for the cleanup of an allocator + + elsif For_Allocator (N) then + null; + -- Generate: -- if F then -- Detach_Object_From_Collection (Temp.all'Address); diff --git a/gcc/ada/gen_il-fields.ads b/gcc/ada/gen_il-fields.ads index b2a498003d8..52c6997e6c9 100644 --- a/gcc/ada/gen_il-fields.ads +++ b/gcc/ada/gen_il-fields.ads @@ -192,6 +192,7 @@ package Gen_IL.Fields is Float_Truncate, Formal_Type_Definition, Forwards_OK, + For_Allocator, For_Special_Return_Object, From_Aspect_Specification, From_At_Mod, diff --git a/gcc/ada/gen_il-gen-gen_nodes.adb b/gcc/ada/gen_il-gen-gen_nodes.adb index c83f9ac3ddb..9b8801b4b84 100644 --- a/gcc/ada/gen_il-gen-gen_nodes.adb +++ b/gcc/ada/gen_il-gen-gen_nodes.adb @@ -948,7 +948,8 @@ begin -- Gen_IL.Gen.Gen_Nodes (Sy (Expression, Node_Id, Default_Empty), Sm (Actual_Designated_Subtype, Node_Id), Sm (Procedure_To_Call, Node_Id), - Sm (Storage_Pool, Node_Id))); + Sm (Storage_Pool, Node_Id), + Sm (For_Allocator, Flag))); Cc (N_Goto_Statement, N_Statement_Other_Than_Procedure_Call, (Sy (Name, Node_Id, Default_Empty), diff --git a/gcc/ada/sinfo.ads b/gcc/ada/sinfo.ads index 2e1ac250c93..3db084ef391 100644 --- a/gcc/ada/sinfo.ads +++ b/gcc/ada/sinfo.ads @@ -1339,6 +1339,10 @@ package Sinfo is -- cannot figure it out. If both flags Forwards_OK and Backwards_OK are -- set, it means that the front end can assure no overlap of operands. + -- For_Allocator + -- Present in N_Free_Statement nodes. True if the statement is generated + -- for the cleanup of an allocator. + -- For_Special_Return_Object -- Present in N_Allocator nodes. True if the allocator is generated for -- the initialization of a special return object. @@ -8110,6 +8114,7 @@ package Sinfo is -- Storage_Pool -- Procedure_To_Call -- Actual_Designated_Subtype + -- For_Allocator -- Note: in the case where a debug source file is generated, the Sloc -- for this node points to the FREE keyword in the Sprint file output. -- 2.43.0