This patch corrects the transient object machinery to disregard aliasing when the associated context is a Boolean expression with actions. This is because the Boolean result is always known after the action list has been evaluated, therefore the transient objects must be finalized at that point.
------------ -- Source -- ------------ -- types.ads with Ada.Finalization; use Ada.Finalization; package Types is type Ctrl is new Limited_Controlled with record Val : Integer := 0; end record; function F1 (Obj : Ctrl) return Integer; function F2 (Val : Integer) return Ctrl'Class; procedure Finalize (Obj : in out Ctrl); procedure Test (Flag : Boolean; Obj : Ctrl); end Types; -- types.adb with Ada.Text_IO; use Ada.Text_IO; package body Types is procedure Finalize (Obj : in out Ctrl) is begin Put_Line ("fin" & Obj.Val'Img); end Finalize; function F1 (Obj : Ctrl) return Integer is begin return Obj.Val + 1; end F1; function F2 (Val : Integer) return Ctrl'Class is begin Put_Line ("ini" & Val'Img); return Ctrl'(Limited_Controlled with Val => Val); end F2; procedure Test (Flag : Boolean; Obj : Ctrl) is begin if Flag and then F2 (F1 (Obj)).Val = 42 then raise Program_Error; end if; end Test; end Types; -- main.adb with Ada.Text_IO; use Ada.Text_IO; with Types; use Types; procedure Main is begin declare Obj : Ctrl; begin Obj.Val := 1; Test (True, Obj); exception when others => Put_Line ("ERROR: unexpected exception 1"); end; declare Obj : Ctrl; begin Obj.Val := 41; Test (True, Obj); Put_Line ("ERROR: exception not raised"); exception when Program_Error => null; when others => Put_Line ("ERROR: unexpected exception 2"); end; end Main; ---------------------------- -- Compilation and output -- ---------------------------- $ gnatmake -q main.adb $ ./main ini 2 fin 2 fin 1 ini 42 fin 42 fin 41 Tested on x86_64-pc-linux-gnu, committed on trunk 2014-07-29 Hristian Kirtchev <kirtc...@adacore.com> * exp_ch4.adb (Process_Transient_Object): Remove constant In_Cond_Expr, use its initialization expression in place. * exp_ch7.adb (Process_Declarations): There is no need to check that a transient object being hooked is controlled as it would not have been hooked in the first place. * exp_util.adb (Is_Aliased): 'Reference-d or renamed transient objects are not considered aliased when the related context is a Boolean expression_with_actions. (Requires_Cleanup_Actions): There is no need to check that a transient object being hooked is controlled as it would not have been hooked in the first place.
Index: exp_ch4.adb =================================================================== --- exp_ch4.adb (revision 213156) +++ exp_ch4.adb (working copy) @@ -12616,9 +12616,6 @@ -- If False, call to finalizer includes a test of whether the hook -- pointer is null. - In_Cond_Expr : constant Boolean := - Within_Case_Or_If_Expression (Rel_Node); - begin -- Step 0: determine where to attach finalization actions in the tree @@ -12636,10 +12633,10 @@ -- conditional expression. Finalize_Always := - not (In_Cond_Expr - or else - Nkind_In (Original_Node (Rel_Node), N_Case_Expression, - N_If_Expression)); + not Within_Case_Or_If_Expression (Rel_Node) + and then not Nkind_In + (Original_Node (Rel_Node), N_Case_Expression, + N_If_Expression); declare Loc : constant Source_Ptr := Sloc (Rel_Node); Index: exp_ch7.adb =================================================================== --- exp_ch7.adb (revision 213157) +++ exp_ch7.adb (working copy) @@ -1817,9 +1817,7 @@ elsif Is_Access_Type (Obj_Typ) and then Present (Status_Flag_Or_Transient_Decl (Obj_Id)) and then Nkind (Status_Flag_Or_Transient_Decl (Obj_Id)) = - N_Object_Declaration - and then Is_Finalizable_Transient - (Status_Flag_Or_Transient_Decl (Obj_Id), Decl) + N_Object_Declaration then Processing_Actions (Has_No_Init => True); Index: exp_util.adb =================================================================== --- exp_util.adb (revision 213156) +++ exp_util.adb (working copy) @@ -3435,9 +3435,8 @@ or else Etype (Assoc_Node) /= Standard_Void_Type) and then Nkind (Assoc_Node) /= N_Procedure_Call_Statement and then (Nkind (Assoc_Node) /= N_Attribute_Reference - or else - not Is_Procedure_Attribute_Name - (Attribute_Name (Assoc_Node))) + or else not Is_Procedure_Attribute_Name + (Attribute_Name (Assoc_Node))) then N := Assoc_Node; P := Parent (Assoc_Node); @@ -4557,6 +4556,17 @@ -- Start of processing for Is_Aliased begin + -- 'Reference-d or renamed transient objects are not consider aliased + -- when the related context is a Boolean expression_with_actions. The + -- Boolean result is always known after the action list is evaluated, + -- therefore the transient objects must be finalized at that point. + + if Nkind (Rel_Node) = N_Expression_With_Actions + and then Is_Boolean_Type (Etype (Rel_Node)) + then + return False; + end if; + Stmt := First_Stmt; while Present (Stmt) loop if Nkind (Stmt) = N_Object_Declaration then @@ -4652,8 +4662,7 @@ if Nkind (Stmt) = N_Object_Declaration and then Present (Expression (Stmt)) and then Nkind (Expression (Stmt)) = N_Reference - and then Nkind (Prefix (Expression (Stmt))) = - N_Function_Call + and then Nkind (Prefix (Expression (Stmt))) = N_Function_Call then Call := Prefix (Expression (Stmt)); @@ -7441,9 +7450,7 @@ elsif Is_Access_Type (Obj_Typ) and then Present (Status_Flag_Or_Transient_Decl (Obj_Id)) and then Nkind (Status_Flag_Or_Transient_Decl (Obj_Id)) = - N_Object_Declaration - and then Is_Finalizable_Transient - (Status_Flag_Or_Transient_Decl (Obj_Id), Decl) + N_Object_Declaration then return True; @@ -7464,9 +7471,8 @@ -- treated as controlled since they require manual cleanup. elsif Ekind (Obj_Id) = E_Variable - and then - (Is_Simple_Protected_Type (Obj_Typ) - or else Has_Simple_Protected_Object (Obj_Typ)) + and then (Is_Simple_Protected_Type (Obj_Typ) + or else Has_Simple_Protected_Object (Obj_Typ)) then return True; end if; @@ -7529,9 +7535,7 @@ and then not Is_Access_Subprogram_Type (Typ) and then Needs_Finalization (Available_View (Designated_Type (Typ)))) - or else - (Is_Type (Typ) - and then Needs_Finalization (Typ))) + or else (Is_Type (Typ) and then Needs_Finalization (Typ))) and then Requires_Cleanup_Actions (Actions (Decl), Lib_Level, Nested_Constructs) then @@ -7756,7 +7760,8 @@ if Ialign /= No_Uint and then Ialign > Maximum_Alignment then return True; - elsif Ialign /= No_Uint and then Oalign /= No_Uint + elsif Ialign /= No_Uint + and then Oalign /= No_Uint and then Ialign <= Oalign then return True; @@ -8327,7 +8332,7 @@ when N_Range => return Side_Effect_Free (Low_Bound (N), Name_Req, Variable_Ref) - and then + and then Side_Effect_Free (High_Bound (N), Name_Req, Variable_Ref); -- A slice is side effect free if it is a side effect free