[multiple changes]
[platform/upstream/gcc.git] / gcc / ada / exp_ch7.adb
index f8730f3..591606e 100644 (file)
@@ -6,7 +6,7 @@
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 1992-2012, Free Software Foundation, Inc.         --
+--          Copyright (C) 1992-2013, Free Software Foundation, Inc.         --
 --                                                                          --
 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
@@ -148,6 +148,7 @@ package body Exp_Ch7 is
    --  Set the field Node_To_Be_Wrapped of the current scope
 
    --  ??? The entire comment needs to be rewritten
+   --  ??? which entire comment?
 
    -----------------------------
    -- Finalization Management --
@@ -309,11 +310,11 @@ package body Exp_Ch7 is
       Defer_Abort : Boolean;
       Fin_Id      : out Entity_Id);
    --  N may denote an accept statement, block, entry body, package body,
-   --  package spec, protected body, subprogram body, and a task body. Create
+   --  package spec, protected body, subprogram body, or a task body. Create
    --  a procedure which contains finalization calls for all controlled objects
    --  declared in the declarative or statement region of N. The calls are
    --  built in reverse order relative to the original declarations. In the
-   --  case of a tack body, the routine delays the creation of the finalizer
+   --  case of a task body, the routine delays the creation of the finalizer
    --  until all statements have been moved to the task body procedure.
    --  Clean_Stmts may contain additional context-dependent code used to abort
    --  asynchronous calls or complete tasks (see Build_Cleanup_Statements).
@@ -367,6 +368,11 @@ package body Exp_Ch7 is
    --  Given an arbitrary entity, traverse the scope chain looking for the
    --  first enclosing function. Return Empty if no function was found.
 
+   procedure Expand_Pragma_Initial_Condition (N : Node_Id);
+   --  Subsidiary to the expansion of package specs and bodies. Generate a
+   --  runtime check needed to verify the assumption introduced by pragma
+   --  Initial_Condition. N denotes the package spec or body.
+
    function Make_Call
      (Loc        : Source_Ptr;
       Proc_Id    : Entity_Id;
@@ -426,7 +432,7 @@ package body Exp_Ch7 is
            Typ   => Typ,
            Stmts => Make_Deep_Array_Body (Initialize_Case, Typ)));
 
-      if not Is_Immutably_Limited_Type (Typ) then
+      if not Is_Limited_View (Typ) then
          Set_TSS (Typ,
            Make_Deep_Proc
              (Prim  => Adjust_Case,
@@ -716,61 +722,100 @@ package body Exp_Ch7 is
    is
       Actuals      : List_Id;
       Proc_To_Call : Entity_Id;
+      Except       : Node_Id;
+      Stmts        : List_Id;
 
    begin
-      pragma Assert (Present (Data.E_Id));
       pragma Assert (Present (Data.Raised_Id));
 
-      --  Generate:
-      --    Get_Current_Excep.all.all
+      if Exception_Extra_Info
+        or else (For_Library and not Restricted_Profile)
+      then
+         if Exception_Extra_Info then
+
+            --  Generate:
+
+            --    Get_Current_Excep.all
+
+            Except :=
+              Make_Function_Call (Data.Loc,
+                Name =>
+                  Make_Explicit_Dereference (Data.Loc,
+                    Prefix =>
+                      New_Reference_To
+                        (RTE (RE_Get_Current_Excep), Data.Loc)));
+
+         else
+            --  Generate:
+
+            --    null
+
+            Except := Make_Null (Data.Loc);
+         end if;
+
+         if For_Library and then not Restricted_Profile then
+            Proc_To_Call := RTE (RE_Save_Library_Occurrence);
+            Actuals := New_List (Except);
 
-      Actuals := New_List (
-        Make_Explicit_Dereference (Data.Loc,
-          Prefix =>
-            Make_Function_Call (Data.Loc,
-              Name =>
-                Make_Explicit_Dereference (Data.Loc,
-                  Prefix =>
-                    New_Reference_To (RTE (RE_Get_Current_Excep),
-                                      Data.Loc)))));
+         else
+            Proc_To_Call := RTE (RE_Save_Occurrence);
+
+            --  The dereference occurs only when Exception_Extra_Info is true,
+            --  and therefore Except is not null.
+
+            Actuals :=
+              New_List (
+                New_Reference_To (Data.E_Id, Data.Loc),
+                Make_Explicit_Dereference (Data.Loc, Except));
+         end if;
+
+         --  Generate:
 
-      if For_Library and then not Restricted_Profile then
-         Proc_To_Call := RTE (RE_Save_Library_Occurrence);
+         --    when others =>
+         --       if not Raised_Id then
+         --          Raised_Id := True;
+
+         --          Save_Occurrence (E_Id, Get_Current_Excep.all.all);
+         --            or
+         --          Save_Library_Occurrence (Get_Current_Excep.all);
+         --       end if;
+
+         Stmts :=
+           New_List (
+             Make_If_Statement (Data.Loc,
+               Condition       =>
+                 Make_Op_Not (Data.Loc,
+                   Right_Opnd => New_Reference_To (Data.Raised_Id, Data.Loc)),
+
+               Then_Statements => New_List (
+                 Make_Assignment_Statement (Data.Loc,
+                   Name       => New_Reference_To (Data.Raised_Id, Data.Loc),
+                   Expression => New_Reference_To (Standard_True, Data.Loc)),
+
+                 Make_Procedure_Call_Statement (Data.Loc,
+                   Name                   =>
+                     New_Reference_To (Proc_To_Call, Data.Loc),
+                   Parameter_Associations => Actuals))));
 
       else
-         Proc_To_Call := RTE (RE_Save_Occurrence);
-         Prepend_To (Actuals, New_Reference_To (Data.E_Id, Data.Loc));
+         --  Generate:
+
+         --    Raised_Id := True;
+
+         Stmts := New_List (
+           Make_Assignment_Statement (Data.Loc,
+             Name       => New_Reference_To (Data.Raised_Id, Data.Loc),
+             Expression => New_Reference_To (Standard_True, Data.Loc)));
       end if;
 
       --  Generate:
-      --    when others =>
-      --       if not Raised_Id then
-      --          Raised_Id := True;
 
-      --          Save_Occurrence (E_Id, Get_Current_Excep.all.all);
-      --            or
-      --          Save_Library_Occurrence (Get_Current_Excep.all.all);
-      --       end if;
+      --    when others =>
 
       return
         Make_Exception_Handler (Data.Loc,
-          Exception_Choices =>
-            New_List (Make_Others_Choice (Data.Loc)),
-          Statements => New_List (
-            Make_If_Statement (Data.Loc,
-              Condition       =>
-                Make_Op_Not (Data.Loc,
-                  Right_Opnd => New_Reference_To (Data.Raised_Id, Data.Loc)),
-
-              Then_Statements => New_List (
-                Make_Assignment_Statement (Data.Loc,
-                  Name       => New_Reference_To (Data.Raised_Id, Data.Loc),
-                  Expression => New_Reference_To (Standard_True, Data.Loc)),
-
-                Make_Procedure_Call_Statement (Data.Loc,
-                  Name                   =>
-                    New_Reference_To (Proc_To_Call, Data.Loc),
-                  Parameter_Associations => Actuals)))));
+          Exception_Choices => New_List (Make_Others_Choice (Data.Loc)),
+          Statements        => Stmts);
    end Build_Exception_Handler;
 
    -------------------------------
@@ -889,10 +934,12 @@ package body Exp_Ch7 is
       then
          return;
 
-      --  Do not create finalization masters in Alfa mode because they result
+      --  Do not create finalization masters in SPARK mode because they result
       --  in unwanted expansion.
 
-      elsif Alfa_Mode then
+      --  More detail would be useful here ???
+
+      elsif GNATprove_Mode then
          return;
       end if;
 
@@ -1451,20 +1498,6 @@ package body Exp_Ch7 is
 
             Append_To (Finalizer_Stmts, Label);
 
-            --  The local exception does not need to be reraised for library-
-            --  level finalizers. Generate:
-            --
-            --    if Raised and then not Abort then
-            --       Raise_From_Controlled_Operation (E);
-            --    end if;
-
-            if not For_Package
-              and then Exceptions_OK
-            then
-               Append_To (Finalizer_Stmts,
-                 Build_Raise_Statement (Finalizer_Data));
-            end if;
-
             --  Create the jump block which controls the finalization flow
             --  depending on the value of the state counter.
 
@@ -1531,6 +1564,22 @@ package body Exp_Ch7 is
                 Name => New_Reference_To (RTE (RE_Abort_Undefer), Loc)));
          end if;
 
+         --  The local exception does not need to be reraised for library-level
+         --  finalizers. Note that this action must be carried out after object
+         --  clean up, secondary stack release and abort undeferral. Generate:
+
+         --    if Raised and then not Abort then
+         --       Raise_From_Controlled_Operation (E);
+         --    end if;
+
+         if Has_Ctrl_Objs
+           and then Exceptions_OK
+           and then not For_Package
+         then
+            Append_To (Finalizer_Stmts,
+              Build_Raise_Statement (Finalizer_Data));
+         end if;
+
          --  Generate:
          --    procedure Fin_Id is
          --       Abort  : constant Boolean := Triggered_By_Abort;
@@ -1551,6 +1600,7 @@ package body Exp_Ch7 is
          --       <finalization statements>  --  Added if Has_Ctrl_Objs
          --       <stack release>            --  Added if Mark_Id exists
          --       Abort_Undefer;             --  Added if abort is allowed
+         --       <exception propagation>    --  Added if Has_Ctrl_Objs
          --    end Fin_Id;
 
          --  Create the body of the finalizer
@@ -1842,11 +1892,23 @@ package body Exp_Ch7 is
                --  transients declared inside an Expression_With_Actions.
 
                elsif Is_Access_Type (Obj_Typ)
-                 and then Present (Return_Flag_Or_Transient_Decl (Obj_Id))
-                 and then Nkind (Return_Flag_Or_Transient_Decl (Obj_Id)) =
+                 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
-                            (Return_Flag_Or_Transient_Decl (Obj_Id), Decl)
+                            (Status_Flag_Or_Transient_Decl (Obj_Id), Decl)
+               then
+                  Processing_Actions (Has_No_Init => True);
+
+               --  Process intermediate results of an if expression with one
+               --  of the alternatives using a controlled function call.
+
+               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_Defining_Identifier
+                 and then Present (Expr)
+                 and then Nkind (Expr) = N_Null
                then
                   Processing_Actions (Has_No_Init => True);
 
@@ -1912,7 +1974,7 @@ package body Exp_Ch7 is
 
                elsif Needs_Finalization (Obj_Typ)
                  and then Is_Return_Object (Obj_Id)
-                 and then Present (Return_Flag_Or_Transient_Decl (Obj_Id))
+                 and then Present (Status_Flag_Or_Transient_Decl (Obj_Id))
                then
                   Processing_Actions (Has_No_Init => True);
 
@@ -2052,6 +2114,22 @@ package body Exp_Ch7 is
                then
                   Last_Top_Level_Ctrl_Construct := Decl;
                end if;
+
+            --  Handle the case where the original context has been wrapped in
+            --  a block to avoid interference between exception handlers and
+            --  At_End handlers. Treat the block as transparent and process its
+            --  contents.
+
+            elsif Nkind (Decl) = N_Block_Statement
+              and then Is_Finalization_Wrapper (Decl)
+            then
+               if Present (Handled_Statement_Sequence (Decl)) then
+                  Process_Declarations
+                    (Statements (Handled_Statement_Sequence (Decl)),
+                     Preprocess);
+               end if;
+
+               Process_Declarations (Declarations (Decl), Preprocess);
             end if;
 
             Prev_Non_Pragma (Decl);
@@ -2575,7 +2653,18 @@ package body Exp_Ch7 is
                 Obj_Ref => Obj_Ref,
                 Typ     => Obj_Typ);
 
-            if Exceptions_OK then
+            --  For CodePeer, the exception handlers normally generated here
+            --  generate complex flowgraphs which result in capacity problems.
+            --  Omitting these handlers for CodePeer is justified as follows:
+
+            --    If a handler is dead, then omitting it is surely ok
+
+            --    If a handler is live, then CodePeer should flag the
+            --      potentially-exception-raising construct that causes it
+            --      to be live. That is what we are interested in, not what
+            --      happens after the exception is raised.
+
+            if Exceptions_OK and not CodePeer_Mode then
                Fin_Stmts := New_List (
                  Make_Block_Statement (Loc,
                    Handled_Statement_Sequence =>
@@ -2627,27 +2716,8 @@ package body Exp_Ch7 is
             end if;
 
             if Ekind_In (Obj_Id, E_Constant, E_Variable)
-              and then Present (Return_Flag_Or_Transient_Decl (Obj_Id))
+              and then Present (Status_Flag_Or_Transient_Decl (Obj_Id))
             then
-               --  Return objects use a flag to aid their potential
-               --  finalization when the enclosing function fails to return
-               --  properly. Generate:
-
-               --    if not Flag then
-               --       <object finalization statements>
-               --    end if;
-
-               if Is_Return_Object (Obj_Id) then
-                  Fin_Stmts := New_List (
-                    Make_If_Statement (Loc,
-                      Condition     =>
-                        Make_Op_Not (Loc,
-                          Right_Opnd =>
-                            New_Reference_To
-                              (Return_Flag_Or_Transient_Decl (Obj_Id), Loc)),
-
-                    Then_Statements => Fin_Stmts));
-
                --  Temporaries created for the purpose of "exporting" a
                --  controlled transient out of an Expression_With_Actions (EWA)
                --  need guards. The following illustrates the usage of such
@@ -2675,19 +2745,35 @@ package body Exp_Ch7 is
                --       <object finalization statements>
                --    end if;
 
-               else
-                  pragma Assert
-                    (Nkind (Return_Flag_Or_Transient_Decl (Obj_Id)) =
-                       N_Object_Declaration);
-
+               if Nkind (Status_Flag_Or_Transient_Decl (Obj_Id)) =
+                                                      N_Object_Declaration
+               then
                   Fin_Stmts := New_List (
                     Make_If_Statement (Loc,
                       Condition       =>
                         Make_Op_Ne (Loc,
                           Left_Opnd  => New_Reference_To (Obj_Id, Loc),
                           Right_Opnd => Make_Null (Loc)),
-
                       Then_Statements => Fin_Stmts));
+
+               --  Return objects use a flag to aid in processing their
+               --  potential finalization when the enclosing function fails
+               --  to return properly. Generate:
+
+               --    if not Flag then
+               --       <object finalization statements>
+               --    end if;
+
+               else
+                  Fin_Stmts := New_List (
+                    Make_If_Statement (Loc,
+                      Condition     =>
+                        Make_Op_Not (Loc,
+                          Right_Opnd =>
+                            New_Reference_To
+                              (Status_Flag_Or_Transient_Decl (Obj_Id), Loc)),
+
+                    Then_Statements => Fin_Stmts));
                end if;
             end if;
          end if;
@@ -2726,10 +2812,10 @@ package body Exp_Ch7 is
    begin
       Fin_Id := Empty;
 
-      --  Do not perform this expansion in Alfa mode because it is not
+      --  Do not perform this expansion in SPARK mode because it is not
       --  necessary.
 
-      if Alfa_Mode then
+      if GNATprove_Mode then
          return;
       end if;
 
@@ -2888,10 +2974,10 @@ package body Exp_Ch7 is
       HSS : Node_Id;
 
    begin
-      --  Do not perform this expansion in Alfa mode because we do not create
+      --  Do not perform this expansion in SPARK mode because we do not create
       --  finalizers in the first place.
 
-      if Alfa_Mode then
+      if GNATprove_Mode then
          return;
       end if;
 
@@ -2995,8 +3081,6 @@ package body Exp_Ch7 is
          return;
       end if;
 
-      Data.Abort_Id  := Make_Temporary (Loc, 'A');
-      Data.E_Id      := Make_Temporary (Loc, 'E');
       Data.Raised_Id := Make_Temporary (Loc, 'R');
 
       --  In certain scenarios, finalization can be triggered by an abort. If
@@ -3016,37 +3100,49 @@ package body Exp_Ch7 is
         and then VM_Target = No_VM
         and then not For_Package
       then
+         Data.Abort_Id  := Make_Temporary (Loc, 'A');
+
          A_Expr := New_Reference_To (RTE (RE_Triggered_By_Abort), Loc);
 
-      --  No abort, .NET/JVM or library-level finalizers
+         --  Generate:
+
+         --    Abort_Id : constant Boolean := <A_Expr>;
+
+         Append_To (Decls,
+           Make_Object_Declaration (Loc,
+             Defining_Identifier => Data.Abort_Id,
+             Constant_Present    => True,
+             Object_Definition   => New_Reference_To (Standard_Boolean, Loc),
+             Expression          => A_Expr));
 
       else
-         A_Expr := New_Reference_To (Standard_False, Loc);
+         --  No abort, .NET/JVM or library-level finalizers
+
+         Data.Abort_Id  := Empty;
       end if;
 
-      --  Generate:
-      --    Abort_Id : constant Boolean := <A_Expr>;
+      if Exception_Extra_Info then
+         Data.E_Id      := Make_Temporary (Loc, 'E');
 
-      Append_To (Decls,
-        Make_Object_Declaration (Loc,
-          Defining_Identifier => Data.Abort_Id,
-          Constant_Present    => True,
-          Object_Definition   => New_Reference_To (Standard_Boolean, Loc),
-          Expression          => A_Expr));
+         --  Generate:
 
-      --  Generate:
-      --    E_Id : Exception_Occurrence;
+         --    E_Id : Exception_Occurrence;
 
-      E_Decl :=
-        Make_Object_Declaration (Loc,
-          Defining_Identifier => Data.E_Id,
-          Object_Definition   =>
-            New_Reference_To (RTE (RE_Exception_Occurrence), Loc));
-      Set_No_Initialization (E_Decl);
+         E_Decl :=
+           Make_Object_Declaration (Loc,
+             Defining_Identifier => Data.E_Id,
+             Object_Definition   =>
+               New_Reference_To (RTE (RE_Exception_Occurrence), Loc));
+         Set_No_Initialization (E_Decl);
 
-      Append_To (Decls, E_Decl);
+         Append_To (Decls, E_Decl);
+
+      else
+         Data.E_Id      := Empty;
+      end if;
 
       --  Generate:
+
       --    Raised_Id : Boolean := False;
 
       Append_To (Decls,
@@ -3064,12 +3160,15 @@ package body Exp_Ch7 is
      (Data : Finalization_Exception_Data) return Node_Id
    is
       Stmt : Node_Id;
+      Expr : Node_Id;
 
    begin
       --  Standard run-time and .NET/JVM targets use the specialized routine
       --  Raise_From_Controlled_Operation.
 
-      if RTE_Available (RE_Raise_From_Controlled_Operation) then
+      if Exception_Extra_Info
+        and then RTE_Available (RE_Raise_From_Controlled_Operation)
+      then
          Stmt :=
            Make_Procedure_Call_Statement (Data.Loc,
               Name                   =>
@@ -3089,6 +3188,23 @@ package body Exp_Ch7 is
       end if;
 
       --  Generate:
+
+      --    Raised_Id and then not Abort_Id
+      --      <or>
+      --    Raised_Id
+
+      Expr := New_Reference_To (Data.Raised_Id, Data.Loc);
+
+      if Present (Data.Abort_Id) then
+         Expr := Make_And_Then (Data.Loc,
+           Left_Opnd  => Expr,
+           Right_Opnd =>
+             Make_Op_Not (Data.Loc,
+               Right_Opnd => New_Reference_To (Data.Abort_Id, Data.Loc)));
+      end if;
+
+      --  Generate:
+
       --    if Raised_Id and then not Abort_Id then
       --       Raise_From_Controlled_Operation (E_Id);
       --         <or>
@@ -3097,13 +3213,7 @@ package body Exp_Ch7 is
 
       return
         Make_If_Statement (Data.Loc,
-          Condition       =>
-            Make_And_Then (Data.Loc,
-              Left_Opnd  => New_Reference_To (Data.Raised_Id, Data.Loc),
-              Right_Opnd =>
-                Make_Op_Not (Data.Loc,
-                  Right_Opnd => New_Reference_To (Data.Abort_Id, Data.Loc))),
-
+          Condition       => Expr,
           Then_Statements => New_List (Stmt));
    end Build_Raise_Statement;
 
@@ -3119,7 +3229,7 @@ package body Exp_Ch7 is
            Typ   => Typ,
            Stmts => Make_Deep_Record_Body (Initialize_Case, Typ)));
 
-      if not Is_Immutably_Limited_Type (Typ) then
+      if not Is_Limited_View (Typ) then
          Set_TSS (Typ,
            Make_Deep_Proc
              (Prim  => Adjust_Case,
@@ -3277,7 +3387,7 @@ package body Exp_Ch7 is
          --  with the array case and non-discriminated record cases.
 
          Error_Msg_N
-           ("task/protected object in variant record will not be freed?", N);
+           ("task/protected object in variant record will not be freed??", N);
          return New_List (Make_Null_Statement (Loc));
       end if;
 
@@ -3537,16 +3647,20 @@ package body Exp_Ch7 is
       --  If the node to wrap is an iteration_scheme, the expression is
       --  one of the bounds, and the expansion will make an explicit
       --  declaration for it (see Analyze_Iteration_Scheme, sem_ch5.adb),
-      --  so do not apply any transformations here.
+      --  so do not apply any transformations here. Same for an Ada 2012
+      --  iterator specification, where a block is created for the expression
+      --  that build the container.
 
-      elsif Nkind (Wrap_Node) = N_Iteration_Scheme then
+      elsif Nkind_In (Wrap_Node, N_Iteration_Scheme,
+                                 N_Iterator_Specification)
+      then
          null;
 
       --  In formal verification mode, if the node to wrap is a pragma check,
       --  this node and enclosed expression are not expanded, so do not apply
       --  any transformations here.
 
-      elsif Alfa_Mode
+      elsif GNATprove_Mode
         and then Nkind (Wrap_Node) = N_Pragma
         and then Get_Pragma_Id (Wrap_Node) = Pragma_Check
       then
@@ -3599,7 +3713,7 @@ package body Exp_Ch7 is
                                  and then VM_Target = No_VM;
 
       Actions_Required     : constant Boolean :=
-                               Requires_Cleanup_Actions (N)
+                               Requires_Cleanup_Actions (N, True)
                                  or else Is_Asynchronous_Call
                                  or else Is_Master
                                  or else Is_Protected_Body
@@ -3630,6 +3744,11 @@ package body Exp_Ch7 is
            Make_Block_Statement (Loc,
              Handled_Statement_Sequence => HSS);
 
+         --  Signal the finalization machinery that this particular block
+         --  contains the original context.
+
+         Set_Is_Finalization_Wrapper (Block);
+
          Set_Handled_Statement_Sequence (N,
            Make_Handled_Sequence_Of_Statements (Loc, New_List (Block)));
          HSS := Handled_Statement_Sequence (N);
@@ -3847,6 +3966,15 @@ package body Exp_Ch7 is
          end if;
 
          Build_Task_Activation_Call (N);
+
+         --  When the package is subject to pragma Initial_Condition, the
+         --  assertion expression must be verified at the end of the body
+         --  statements.
+
+         if Present (Get_Pragma (Spec_Ent, Pragma_Initial_Condition)) then
+            Expand_Pragma_Initial_Condition (N);
+         end if;
+
          Pop_Scope;
       end if;
 
@@ -3941,10 +4069,9 @@ package body Exp_Ch7 is
       if No_Body then
          Push_Scope (Id);
 
-         if Has_RACW (Id) then
-
-            --  Generate RACW subprogram bodies
+         --  Generate RACW subprogram bodies
 
+         if Has_RACW (Id) then
             Decls := Private_Declarations (Spec);
 
             if No (Decls) then
@@ -3960,11 +4087,19 @@ package body Exp_Ch7 is
             Analyze_List (Decls);
          end if;
 
+         --  Generate task activation call as last step of elaboration
+
          if Present (Activation_Chain_Entity (N)) then
+            Build_Task_Activation_Call (N);
+         end if;
 
-            --  Generate task activation call as last step of elaboration
+         --  When the package is subject to pragma Initial_Condition and lacks
+         --  a body, the assertion expression must be verified at the end of
+         --  the visible declarations. Otherwise the check is performed at the
+         --  end of the body statements (see Expand_N_Package_Body).
 
-            Build_Task_Activation_Call (N);
+         if Present (Get_Pragma (Id, Pragma_Initial_Condition)) then
+            Expand_Pragma_Initial_Condition (N);
          end if;
 
          Pop_Scope;
@@ -4002,6 +4137,88 @@ package body Exp_Ch7 is
       end if;
    end Expand_N_Package_Declaration;
 
+   -------------------------------------
+   -- Expand_Pragma_Initial_Condition --
+   -------------------------------------
+
+   procedure Expand_Pragma_Initial_Condition (N : Node_Id) is
+      Loc       : constant Source_Ptr := Sloc (N);
+      Check     : Node_Id;
+      Expr      : Node_Id;
+      Init_Cond : Node_Id;
+      List      : List_Id;
+      Pack_Id   : Entity_Id;
+
+   begin
+      if Nkind (N) = N_Package_Body then
+         Pack_Id := Corresponding_Spec (N);
+
+         if Present (Handled_Statement_Sequence (N)) then
+            List := Statements (Handled_Statement_Sequence (N));
+
+         --  The package body lacks statements, create an empty list
+
+         else
+            List := New_List;
+
+            Set_Handled_Statement_Sequence (N,
+              Make_Handled_Sequence_Of_Statements (Loc, Statements => List));
+         end if;
+
+      elsif Nkind (N) = N_Package_Declaration then
+         Pack_Id := Defining_Entity (N);
+
+         if Present (Visible_Declarations (Specification (N))) then
+            List := Visible_Declarations (Specification (N));
+
+         --  The package lacks visible declarations, create an empty list
+
+         else
+            List := New_List;
+
+            Set_Visible_Declarations (Specification (N), List);
+         end if;
+
+      --  This routine should not be used on anything other than packages
+
+      else
+         raise Program_Error;
+      end if;
+
+      Init_Cond := Get_Pragma (Pack_Id, Pragma_Initial_Condition);
+
+      --  The caller should check whether the package is subject to pragma
+      --  Initial_Condition.
+
+      pragma Assert (Present (Init_Cond));
+
+      Expr :=
+        Get_Pragma_Arg (First (Pragma_Argument_Associations (Init_Cond)));
+
+      --  The assertion expression was found to be illegal, do not generate the
+      --  runtime check as it will repeat the illegality.
+
+      if Error_Posted (Init_Cond) or else Error_Posted (Expr) then
+         return;
+      end if;
+
+      --  Generate:
+      --    pragma Check (Initial_Condition, <Expr>);
+
+      Check :=
+        Make_Pragma (Loc,
+          Chars                        => Name_Check,
+          Pragma_Argument_Associations => New_List (
+            Make_Pragma_Argument_Association (Loc,
+              Expression => Make_Identifier (Loc, Name_Initial_Condition)),
+
+            Make_Pragma_Argument_Association (Loc,
+              Expression => New_Copy_Tree (Expr))));
+
+      Append_To (List, Check);
+      Analyze (Check);
+   end Expand_Pragma_Initial_Condition;
+
    -----------------------------
    -- Find_Node_To_Be_Wrapped --
    -----------------------------
@@ -4238,9 +4455,13 @@ package body Exp_Ch7 is
    ------------------------------------
 
    procedure Insert_Actions_In_Scope_Around (N : Node_Id) is
-      SE     : Scope_Stack_Entry renames Scope_Stack.Table (Scope_Stack.Last);
-      After  : List_Id renames SE.Actions_To_Be_Wrapped_After;
-      Before : List_Id renames SE.Actions_To_Be_Wrapped_Before;
+      After  : constant List_Id :=
+        Scope_Stack.Table (Scope_Stack.Last).Actions_To_Be_Wrapped_After;
+      Before : constant List_Id :=
+        Scope_Stack.Table (Scope_Stack.Last).Actions_To_Be_Wrapped_Before;
+      --  Note: We used to use renamings of Scope_Stack.Table (Scope_Stack.
+      --  Last), but this was incorrect as Process_Transient_Object may
+      --  introduce new scopes and cause a reallocation of Scope_Stack.Table.
 
       procedure Process_Transient_Objects
         (First_Object : Node_Id;
@@ -4261,9 +4482,44 @@ package body Exp_Ch7 is
          Last_Object  : Node_Id;
          Related_Node : Node_Id)
       is
-         Requires_Hooking : constant Boolean :=
-                              Nkind_In (N, N_Function_Call,
-                                           N_Procedure_Call_Statement);
+         Must_Hook : Boolean := False;
+         --  Flag denoting whether the context requires transient variable
+         --  export to the outer finalizer.
+
+         function Is_Subprogram_Call (N : Node_Id) return Traverse_Result;
+         --  Determine whether an arbitrary node denotes a subprogram call
+
+         ------------------------
+         -- Is_Subprogram_Call --
+         ------------------------
+
+         function Is_Subprogram_Call (N : Node_Id) return Traverse_Result is
+         begin
+            --  A regular procedure or function call
+
+            if Nkind (N) in N_Subprogram_Call then
+               Must_Hook := True;
+               return Abandon;
+
+            --  Detect a call to a function that returns on the secondary stack
+
+            elsif Nkind (N) = N_Object_Declaration
+              and then Nkind (Original_Node (Expression (N))) = N_Function_Call
+            then
+               Must_Hook := True;
+               return Abandon;
+
+            --  Keep searching
+
+            else
+               return OK;
+            end if;
+         end Is_Subprogram_Call;
+
+         procedure Detect_Subprogram_Call is
+           new Traverse_Proc (Is_Subprogram_Call);
+
+         --  Local variables
 
          Built     : Boolean := False;
          Desig_Typ : Entity_Id;
@@ -4275,11 +4531,20 @@ package body Exp_Ch7 is
          Obj_Id    : Entity_Id;
          Obj_Ref   : Node_Id;
          Obj_Typ   : Entity_Id;
+         Prev_Fin  : Node_Id := Empty;
          Stmt      : Node_Id;
          Stmts     : List_Id;
          Temp_Id   : Entity_Id;
 
+      --  Start of processing for Process_Transient_Objects
+
       begin
+         --  Search the context for at least one subprogram call. If found, the
+         --  machinery exports all transient objects to the enclosing finalizer
+         --  due to the possibility of abnormal call termination.
+
+         Detect_Subprogram_Call (N);
+
          --  Examine all objects in the list First_Object .. Last_Object
 
          Stmt := First_Object;
@@ -4313,7 +4578,6 @@ package body Exp_Ch7 is
                   Fin_Decls := New_List;
 
                   Build_Object_Declarations (Fin_Data, Fin_Decls, Loc);
-                  Insert_List_Before_And_Analyze (First_Object, Fin_Decls);
 
                   Built := True;
                end if;
@@ -4329,7 +4593,7 @@ package body Exp_Ch7 is
                --  enclosing sequence of statements where their corresponding
                --  "hooks" are picked up by the finalization machinery.
 
-               if Requires_Hooking then
+               if Must_Hook then
                   declare
                      Expr   : Node_Id;
                      Ptr_Id : Entity_Id;
@@ -4369,7 +4633,7 @@ package body Exp_Ch7 is
                      --  the machinery in Build_Finalizer to recognize this
                      --  special case.
 
-                     Set_Return_Flag_Or_Transient_Decl (Temp_Id, Stmt);
+                     Set_Status_Flag_Or_Transient_Decl (Temp_Id, Stmt);
 
                      --  Step 3: Hook the transient object to the temporary
 
@@ -4404,7 +4668,7 @@ package body Exp_Ch7 is
                --  Generate:
                --    Temp := null;
 
-               if Requires_Hooking then
+               if Must_Hook then
                   Append_To (Stmts,
                     Make_Assignment_Statement (Loc,
                       Name       => New_Reference_To (Temp_Id, Loc),
@@ -4445,56 +4709,30 @@ package body Exp_Ch7 is
                        Exception_Handlers => New_List (
                          Build_Exception_Handler (Fin_Data))));
 
-               Insert_After_And_Analyze (Last_Object, Fin_Block);
+               --  The single raise statement must be inserted after all the
+               --  finalization blocks, and we put everything into a wrapper
+               --  block to clearly expose the construct to the back-end.
 
-               --  The raise statement must be inserted after all the
-               --  finalization blocks.
+               if Present (Prev_Fin) then
+                  Insert_Before_And_Analyze (Prev_Fin, Fin_Block);
+               else
+                  Insert_After_And_Analyze (Last_Object,
+                    Make_Block_Statement (Loc,
+                      Declarations => Fin_Decls,
+                      Handled_Statement_Sequence =>
+                        Make_Handled_Sequence_Of_Statements (Loc,
+                          Statements => New_List (Fin_Block))));
 
-               if No (Last_Fin) then
                   Last_Fin := Fin_Block;
                end if;
 
-            --  When the associated node is an array object, the expander may
-            --  sometimes generate a loop and create transient objects inside
-            --  the loop.
-
-            elsif Nkind (Related_Node) = N_Object_Declaration
-              and then Is_Array_Type
-                         (Base_Type
-                           (Etype (Defining_Identifier (Related_Node))))
-              and then Nkind (Stmt) = N_Loop_Statement
-            then
-               declare
-                  Block_HSS : Node_Id := First (Statements (Stmt));
-
-               begin
-                  --  The loop statements may have been wrapped in a block by
-                  --  Process_Statements_For_Controlled_Objects, inspect the
-                  --  handled sequence of statements.
-
-                  if Nkind (Block_HSS) = N_Block_Statement
-                    and then No (Next (Block_HSS))
-                  then
-                     Block_HSS := Handled_Statement_Sequence (Block_HSS);
-
-                     Process_Transient_Objects
-                       (First_Object => First (Statements (Block_HSS)),
-                        Last_Object  => Last (Statements (Block_HSS)),
-                        Related_Node => Related_Node);
-
-                  --  Inspect the statements of the loop
-
-                  else
-                     Process_Transient_Objects
-                       (First_Object => First (Statements (Stmt)),
-                        Last_Object  => Last (Statements (Stmt)),
-                        Related_Node => Related_Node);
-                  end if;
-               end;
+               Prev_Fin := Fin_Block;
+            end if;
 
-            --  Terminate the scan after the last object has been processed
+            --  Terminate the scan after the last object has been processed to
+            --  avoid touching unrelated code.
 
-            elsif Stmt = Last_Object then
+            if Stmt = Last_Object then
                exit;
             end if;
 
@@ -4522,10 +4760,10 @@ package body Exp_Ch7 is
       end if;
 
       declare
-         Node_To_Wrap  : constant Node_Id := Node_To_Be_Wrapped;
-         First_Obj  : Node_Id;
-         Last_Obj   : Node_Id;
-         Target     : Node_Id;
+         Node_To_Wrap : constant Node_Id := Node_To_Be_Wrapped;
+         First_Obj    : Node_Id;
+         Last_Obj     : Node_Id;
+         Target       : Node_Id;
 
       begin
          --  If the node to be wrapped is the trigger of an asynchronous
@@ -4585,11 +4823,13 @@ package body Exp_Ch7 is
          --  Reset the action lists
 
          if Present (Before) then
-            Before := No_List;
+            Scope_Stack.Table (Scope_Stack.Last).
+              Actions_To_Be_Wrapped_Before := No_List;
          end if;
 
          if Present (After) then
-            After := No_List;
+            Scope_Stack.Table (Scope_Stack.Last).
+              Actions_To_Be_Wrapped_After := No_List;
          end if;
       end;
    end Insert_Actions_In_Scope_Around;
@@ -4602,6 +4842,7 @@ package body Exp_Ch7 is
    begin
       return
         Is_Protected_Type (T)
+          and then not Uses_Lock_Free (T)
           and then not Has_Entries (T)
           and then Is_RTE (Find_Protection_Type (T), RE_Protection);
    end Is_Simple_Protected_Type;
@@ -7721,8 +7962,8 @@ package body Exp_Ch7 is
    -------------------------------
 
    procedure Wrap_Transient_Expression (N : Node_Id) is
-      Expr : constant Node_Id    := Relocate_Node (N);
       Loc  : constant Source_Ptr := Sloc (N);
+      Expr : Node_Id             := Relocate_Node (N);
       Temp : constant Entity_Id  := Make_Temporary (Loc, 'E', N);
       Typ  : constant Entity_Id  := Etype (N);
 
@@ -7733,14 +7974,31 @@ package body Exp_Ch7 is
       --    declare
       --       M : constant Mark_Id := SS_Mark;
       --       procedure Finalizer is ...  (See Build_Finalizer)
-
+      --
       --    begin
-      --       Temp := <Expr>;
+      --       Temp := <Expr>;                           --  general case
+      --       Temp := (if <Expr> then True else False); --  boolean case
       --
       --    at end
       --       Finalizer;
       --    end;
 
+      --  A special case is made for Boolean expressions so that the back-end
+      --  knows to generate a conditional branch instruction, if running with
+      --  -fpreserve-control-flow. This ensures that a control flow change
+      --  signalling the decision outcome occurs before the cleanup actions.
+
+      if Opt.Suppress_Control_Flow_Optimizations
+        and then Is_Boolean_Type (Typ)
+      then
+         Expr :=
+           Make_If_Expression (Loc,
+             Expressions => New_List (
+               Expr,
+               New_Occurrence_Of (Standard_True, Loc),
+               New_Occurrence_Of (Standard_False, Loc)));
+      end if;
+
       Insert_Actions (N, New_List (
         Make_Object_Declaration (Loc,
           Defining_Identifier => Temp,