From: Gary Dismukes <dismu...@adacore.com>

There are cases where GNAT introduces a dependence on the secondary stack
in a build-in-place function with a result subtype that is definite, when
this dependence could be avoided.  In particular this is done for record
types that requires finalization due to having a controlled component.

At one time such functions required the secondary stack in order to
properly handle cases where the function might raise an exception
(to avoid improper finalization in the caller), but that is no longer
necessary.  We remove the dependence of these functions on the SS,
along with the BIPalloc formal and the generation of the big if_statement
that uses that formal.

An additional small change is to revise the condition for determining when
to generate SS mark/release within functions.

gcc/ada/ChangeLog:

        * exp_ch6.ads (Make_Build_In_Place_Call_In_Allocator): Simplify comment.
        * exp_ch6.adb (Make_Build_In_Place_Call_In_Allocator): Remove obsolete
        comment about not being able to allocate fixed-size controlled results
        on the caller side, and replace another obsolete comment with a simpler
        comment. Call Build_Allocate_Deallocate_Proc when the function doesn't
        need a BIPalloc formal to ensure that function results with controlled
        parts allocated on the caller side will be chained for finalization.
        (Make_Build_In_Place_Call_In_Object_Declaration): Call 
Needs_BIP_Collection
        on the function's Entity_Id rather than the function call.
        (Needs_BIP_Collection): If a BIP function doesn't need a BIPalloc formal
        then it doesn't need a BIP collection either; return False in that case.
        (Needs_BIP_Alloc_Form): Remove test of Needs_BIP_Collection.
        * exp_ch7.adb (Expand_Cleanup_Actions): Move test of Uses_Sec_Stack
        to be the first conjunct in setting of Needs_Sec_Stack_Mark, and put
        the other tests in a disjunction subsidiary to that. Improve preceding
        comment.

Tested on x86_64-pc-linux-gnu, committed on master.

---
 gcc/ada/exp_ch6.adb | 49 +++++++++++++++------------------------------
 gcc/ada/exp_ch6.ads |  6 ++----
 gcc/ada/exp_ch7.adb | 20 +++++++++---------
 3 files changed, 28 insertions(+), 47 deletions(-)

diff --git a/gcc/ada/exp_ch6.adb b/gcc/ada/exp_ch6.adb
index 5056b1f990fa..58361e10bd9c 100644
--- a/gcc/ada/exp_ch6.adb
+++ b/gcc/ada/exp_ch6.adb
@@ -9093,27 +9093,6 @@ package body Exp_Ch6 is
       --  tagged, the called function itself must perform the allocation of
       --  the return object, so we pass parameters indicating that.
 
-      --  But that's also the case when the result subtype needs finalization
-      --  actions because the caller side allocation may result in undesirable
-      --  finalization. Consider the following example:
-      --
-      --    function Make_Lim_Ctrl return Lim_Ctrl is
-      --    begin
-      --       return Result : Lim_Ctrl := raise Program_Error do
-      --          null;
-      --       end return;
-      --    end Make_Lim_Ctrl;
-      --
-      --    Obj : Lim_Ctrl_Ptr := new Lim_Ctrl'(Make_Lim_Ctrl);
-      --
-      --  Even though the size of limited controlled type Lim_Ctrl is known,
-      --  allocating Obj at the caller side will chain Obj on Lim_Ctrl_Ptr's
-      --  finalization collection. The subsequent call to Make_Lim_Ctrl will
-      --  fail during the initialization actions for Result, which means that
-      --  Result (and Obj by extension) should not be finalized. However Obj
-      --  will be finalized when access type Lim_Ctrl_Ptr goes out of scope
-      --  since it is already attached on the its finalization collection.
-
       if Needs_BIP_Alloc_Form (Function_Id) then
          Temp_Init := Empty;
 
@@ -9278,11 +9257,7 @@ package body Exp_Ch6 is
          end if;
       end;
 
-      --  When the function has a controlling result, an allocation-form
-      --  parameter must be passed indicating that the caller is allocating
-      --  the result object. This is needed because such a function can be
-      --  called as a dispatching operation and must be treated similarly
-      --  to functions with unconstrained result subtypes.
+      --  Add implicit actuals for the BIP formal parameters, if any
 
       Add_Unconstrained_Actuals_To_Build_In_Place_Call
         (Func_Call,
@@ -9307,6 +9282,14 @@ package body Exp_Ch6 is
       Add_Access_Actual_To_Build_In_Place_Call
         (Func_Call, Function_Id, Return_Obj_Actual);
 
+      --  If the allocation is done in the caller, create a custom Allocate
+      --  procedure if need be.
+
+      if not Needs_BIP_Alloc_Form (Function_Id) then
+         Build_Allocate_Deallocate_Proc
+           (Declaration_Node (Return_Obj_Access), Mark => Allocator);
+      end if;
+
       --  Finally, replace the allocator node with a reference to the temp
 
       Rewrite (Allocator, New_Occurrence_Of (Return_Obj_Access, Loc));
@@ -9768,7 +9751,7 @@ package body Exp_Ch6 is
          --  ensure that the heap allocation can properly chain the object
          --  and later finalize it when the library unit goes out of scope.
 
-         if Needs_BIP_Collection (Func_Call) then
+         if Needs_BIP_Collection (Function_Id) then
             Build_Finalization_Collection
               (Typ            => Ptr_Typ,
                For_Lib_Level  => True,
@@ -10331,6 +10314,12 @@ package body Exp_Ch6 is
       Typ : constant Entity_Id := Underlying_Type (Etype (Func_Id));
 
    begin
+      --  No need for BIP_Collection if allocation is always done in the caller
+
+      if not Needs_BIP_Alloc_Form (Func_Id) then
+         return False;
+      end if;
+
       --  A formal for the finalization collection is needed for build-in-place
       --  functions whose result type needs finalization or is a tagged type.
       --  Tagged primitive build-in-place functions need such a formal because
@@ -10355,12 +10344,6 @@ package body Exp_Ch6 is
       Typ : constant Entity_Id := Underlying_Type (Etype (Func_Id));
 
    begin
-      --  See Make_Build_In_Place_Call_In_Allocator for the rationale
-
-      if Needs_BIP_Collection (Func_Id) then
-         return True;
-      end if;
-
       --  A formal giving the allocation method is needed for build-in-place
       --  functions whose result type is returned on the secondary stack or
       --  is a tagged type. Tagged primitive build-in-place functions need
diff --git a/gcc/ada/exp_ch6.ads b/gcc/ada/exp_ch6.ads
index 5919627a4e7e..3867270e71a9 100644
--- a/gcc/ada/exp_ch6.ads
+++ b/gcc/ada/exp_ch6.ads
@@ -301,10 +301,8 @@ package Exp_Ch6 is
    --  BIP_Alloc_Form parameter (see type BIP_Formal_Kind).
 
    function Needs_BIP_Collection (Func_Id : Entity_Id) return Boolean;
-   --  Ada 2005 (AI-318-02): Return True if the result subtype of function
-   --  Func_Id might need finalization actions. This includes build-in-place
-   --  functions with tagged result types, since they can be invoked via
-   --  dispatching calls, and descendant types may require finalization.
+   --  Ada 2005 (AI-318-02): Return True if the function needs an implicit
+   --  BIP_Collection parameter (see type BIP_Formal_Kind).
 
    function Needs_BIP_Task_Actuals (Func_Id : Entity_Id) return Boolean;
    --  Return True if the function returns an object of a type that has tasks.
diff --git a/gcc/ada/exp_ch7.adb b/gcc/ada/exp_ch7.adb
index 62e9d2cbb73f..d60c6edecdff 100644
--- a/gcc/ada/exp_ch7.adb
+++ b/gcc/ada/exp_ch7.adb
@@ -4758,18 +4758,18 @@ package body Exp_Ch7 is
 
       --  We mark the secondary stack if it is used in this construct, and
       --  we're not returning a function result on the secondary stack, except
-      --  that a build-in-place function that might or might not return on the
-      --  secondary stack always needs a mark. A run-time test is required in
-      --  the case where the build-in-place function has a BIP_Alloc extra
-      --  parameter (see Create_Finalizer).
+      --  that a build-in-place function that only conditionally returns on
+      --  the secondary stack will also need a mark. A run-time test for doing
+      --  the release call is needed in the case where the build-in-place
+      --  function has a BIP_Alloc_Form parameter (see Create_Finalizer).
 
       Needs_Sec_Stack_Mark   : constant Boolean :=
-                                   (Uses_Sec_Stack (Scop)
-                                     and then
-                                       not Sec_Stack_Needed_For_Return (Scop))
-                                 or else
-                                   (Is_Build_In_Place_Function (Scop)
-                                     and then Needs_BIP_Alloc_Form (Scop));
+                                 Uses_Sec_Stack (Scop)
+                                   and then
+                                 (not Sec_Stack_Needed_For_Return (Scop)
+                                   or else
+                                     (Is_Build_In_Place_Function (Scop)
+                                       and then Needs_BIP_Alloc_Form (Scop)));
 
       Needs_Custom_Cleanup   : constant Boolean :=
                                  Nkind (N) = N_Block_Statement
-- 
2.43.0

Reply via email to