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

Reply via email to