In the case a class-wide limited (build-in-place) function that returns a call to another build-in-place function with a controlled result, the compiler passes null as the value for the implicit finalization master parameter rather than passing along its own finalization master formal. This fails a null access check in the case where the class-wide function is called to initialize an alloctor. The implicit formal must be passed along if the outer function calls another function (necessarily also build-in-place) in a return statement.
The following test must compile and execute quietly with -gnat05: with Ada.Finalization; use Ada.Finalization; package Ctrlled_BIP_Pkg is type Update_Lock is limited new Limited_Controlled with null record; function Lock_Updates return Update_Lock; type Update_Lock_Access is access all Update_Lock'Class; end Ctrlled_BIP_Pkg; package body Ctrlled_BIP_Pkg is function Lock_Updates return Update_Lock is begin return (Limited_Controlled with others => <>); end Lock_Updates; end Ctrlled_BIP_Pkg; with Ctrlled_BIP_Pkg; use Ctrlled_BIP_Pkg; procedure Ctrlled_BIP_Bug is function Wrapper return Ctrlled_BIP_Pkg.Update_Lock'Class is begin return Ctrlled_BIP_Pkg.Lock_Updates; end Wrapper; Lock : Update_Lock_Access; begin Lock := new Update_Lock'Class'(Wrapper); end Ctrlled_BIP_Bug; Tested on x86_64-pc-linux-gnu, committed on trunk 2011-09-02 Gary Dismukes <dismu...@adacore.com> * exp_ch6.adb (Add_Finalization_Master_Actual_To_Build_In_Place_Call): Add new formal Master_Exp. When present, add that expression to the call as an extra actual. (Make_Build_In_Place_Call_In_Object_Declaration): Add variable Fmaster_Actual and in the case of a BIP call initializing a return object of an enclosing BIP function set it to a new reference to the implicit finalization master formal of the enclosing function. Fmaster_Actual is then passed to the new formal Master_Exp on the call to Add_Finalization_Master_Actual_To_Build_ In_Place_Call. Move initializations of Enclosing_Func to its declaration.
Index: exp_ch6.adb =================================================================== --- exp_ch6.adb (revision 178433) +++ exp_ch6.adb (working copy) @@ -111,13 +111,15 @@ -- Extra_Formal in Subprogram_Call. procedure Add_Finalization_Master_Actual_To_Build_In_Place_Call - (Func_Call : Node_Id; - Func_Id : Entity_Id; - Ptr_Typ : Entity_Id := Empty); + (Func_Call : Node_Id; + Func_Id : Entity_Id; + Ptr_Typ : Entity_Id := Empty; + Master_Exp : Node_Id := Empty); -- Ada 2005 (AI-318-02): If the result type of a build-in-place call needs -- finalization actions, add an actual parameter which is a pointer to the - -- finalization master of the caller. If Ptr_Typ is left Empty, this will - -- result in an automatic "null" value for the actual. + -- finalization master of the caller. If Master_Exp is not Empty, then that + -- will be passed as the actual. Otherwise, if Ptr_Typ is left Empty, this + -- will result in an automatic "null" value for the actual. procedure Add_Task_Actuals_To_Build_In_Place_Call (Function_Call : Node_Id; @@ -311,9 +313,10 @@ ----------------------------------------------------------- procedure Add_Finalization_Master_Actual_To_Build_In_Place_Call - (Func_Call : Node_Id; - Func_Id : Entity_Id; - Ptr_Typ : Entity_Id := Empty) + (Func_Call : Node_Id; + Func_Id : Entity_Id; + Ptr_Typ : Entity_Id := Empty; + Master_Exp : Node_Id := Empty) is begin if not Needs_BIP_Finalization_Master (Func_Id) then @@ -329,9 +332,16 @@ Desig_Typ : Entity_Id; begin + -- If there is a finalization master actual, such as the implicit + -- finalization master of an enclosing build-in-place function, + -- then this must be added as an extra actual of the call. + + if Present (Master_Exp) then + Actual := Master_Exp; + -- Case where the context does not require an actual master - if No (Ptr_Typ) then + elsif No (Ptr_Typ) then Actual := Make_Null (Loc); else @@ -7561,7 +7571,9 @@ Ptr_Typ_Decl : Node_Id; Def_Id : Entity_Id; New_Expr : Node_Id; - Enclosing_Func : Entity_Id; + Enclosing_Func : constant Entity_Id := + Enclosing_Subprogram (Obj_Def_Id); + Fmaster_Actual : Node_Id := Empty; Pass_Caller_Acc : Boolean := False; begin @@ -7613,8 +7625,6 @@ if Is_Return_Object (Defining_Identifier (Object_Decl)) then Pass_Caller_Acc := True; - Enclosing_Func := Enclosing_Subprogram (Obj_Def_Id); - -- When the enclosing function has a BIP_Alloc_Form formal then we -- pass it along to the callee (such as when the enclosing function -- has an unconstrained or tagged result type). @@ -7636,6 +7646,13 @@ (Func_Call, Function_Id, Alloc_Form => Caller_Allocation); end if; + if Needs_BIP_Finalization_Master (Enclosing_Func) then + Fmaster_Actual := + New_Reference_To + (Build_In_Place_Formal + (Enclosing_Func, BIP_Finalization_Master), Loc); + end if; + -- Retrieve the BIPacc formal from the enclosing function and convert -- it to the access type of the callee's BIP_Object_Access formal. @@ -7686,14 +7703,18 @@ Establish_Transient_Scope (Object_Decl, Sec_Stack => True); end if; + -- Pass along any finalization master actual, which is needed in the + -- case where the called function initializes a return object of an + -- enclosing build-in-place function. + Add_Finalization_Master_Actual_To_Build_In_Place_Call - (Func_Call, Function_Id); + (Func_Call => Func_Call, + Func_Id => Function_Id, + Master_Exp => Fmaster_Actual); if Nkind (Parent (Object_Decl)) = N_Extended_Return_Statement and then Has_Task (Result_Subt) then - Enclosing_Func := Enclosing_Subprogram (Obj_Def_Id); - -- Here we're passing along the master that was passed in to this -- function.