OSDN Git Service

2011-12-05 Bob Duff <duff@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / exp_ch6.adb
index 11a2161..4c94604 100644 (file)
@@ -6,7 +6,7 @@
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 1992-2010, Free Software Foundation, Inc.         --
+--          Copyright (C) 1992-2011, 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- --
@@ -29,6 +29,7 @@ with Debug;    use Debug;
 with Einfo;    use Einfo;
 with Errout;   use Errout;
 with Elists;   use Elists;
+with Exp_Aggr; use Exp_Aggr;
 with Exp_Atag; use Exp_Atag;
 with Exp_Ch2;  use Exp_Ch2;
 with Exp_Ch3;  use Exp_Ch3;
@@ -69,6 +70,7 @@ with Sem_Util; use Sem_Util;
 with Sinfo;    use Sinfo;
 with Snames;   use Snames;
 with Stand;    use Stand;
+with Targparm; use Targparm;
 with Tbuild;   use Tbuild;
 with Uintp;    use Uintp;
 with Validsw;  use Validsw;
@@ -92,36 +94,29 @@ package body Exp_Ch6 is
    --  along directly to the build-in-place function. Finally, if Return_Object
    --  is empty, then pass a null literal as the actual.
 
-   procedure Add_Alloc_Form_Actual_To_Build_In_Place_Call
+   procedure Add_Unconstrained_Actuals_To_Build_In_Place_Call
      (Function_Call  : Node_Id;
       Function_Id    : Entity_Id;
       Alloc_Form     : BIP_Allocation_Form := Unspecified;
-      Alloc_Form_Exp : Node_Id             := Empty);
-   --  Ada 2005 (AI-318-02): Add an actual indicating the form of allocation,
-   --  if any, to be done by a build-in-place function. If Alloc_Form_Exp is
-   --  present, then use it, otherwise pass a literal corresponding to the
-   --  Alloc_Form parameter (which must not be Unspecified in that case).
-
-   procedure Add_Extra_Actual_To_Call
-     (Subprogram_Call : Node_Id;
-      Extra_Formal    : Entity_Id;
-      Extra_Actual    : Node_Id);
-   --  Adds Extra_Actual as a named parameter association for the formal
-   --  Extra_Formal in Subprogram_Call.
-
-   procedure Add_Final_List_Actual_To_Build_In_Place_Call
-     (Function_Call : Node_Id;
-      Function_Id   : Entity_Id;
-      Acc_Type      : Entity_Id;
-      Sel_Comp      : Node_Id := Empty);
-   --  Ada 2005 (AI-318-02): For a build-in-place call, if the result type has
-   --  controlled parts, add an actual parameter that is a pointer to
-   --  appropriate finalization list. The finalization list is that of the
-   --  current scope, except for "new Acc'(F(...))" in which case it's the
-   --  finalization list of the access type returned by the allocator. Acc_Type
-   --  is that type in the allocator case; Empty otherwise. If Sel_Comp is
-   --  not Empty, then it denotes a selected component and the finalization
-   --  list is obtained from the _controller list of the prefix object.
+      Alloc_Form_Exp : Node_Id             := Empty;
+      Pool_Actual    : Node_Id             := Make_Null (No_Location));
+   --  Ada 2005 (AI-318-02): Add the actuals needed for a build-in-place
+   --  function call that returns a caller-unknown-size result (BIP_Alloc_Form
+   --  and BIP_Storage_Pool). If Alloc_Form_Exp is present, then use it,
+   --  otherwise pass a literal corresponding to the Alloc_Form parameter
+   --  (which must not be Unspecified in that case). Pool_Actual is the
+   --  parameter to pass to BIP_Storage_Pool.
+
+   procedure Add_Finalization_Master_Actual_To_Build_In_Place_Call
+     (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 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;
@@ -133,9 +128,10 @@ package body Exp_Ch6 is
    --  expression to pass for the master. In most cases, this is the current
    --  master (_master). The two exceptions are: If the function call is the
    --  initialization expression for an allocator, we pass the master of the
-   --  access type. If the function call is the initialization expression for
-   --  a return object, we pass along the master passed in by the caller. The
-   --  activation chain to pass is always the local one.
+   --  access type. If the function call is the initialization expression for a
+   --  return object, we pass along the master passed in by the caller. The
+   --  activation chain to pass is always the local one. Note: Master_Actual
+   --  can be Empty, but only if there are no tasks.
 
    procedure Check_Overriding_Operation (Subp : Entity_Id);
    --  Subp is a dispatching operation. Check whether it may override an
@@ -159,35 +155,10 @@ package body Exp_Ch6 is
    --  the values are not changed for the call, we know immediately that
    --  we have an infinite recursion.
 
-   procedure Expand_Actuals (N : Node_Id; Subp : Entity_Id);
-   --  For each actual of an in-out or out parameter which is a numeric
-   --  (view) conversion of the form T (A), where A denotes a variable,
-   --  we insert the declaration:
-   --
-   --    Temp : T[ := T (A)];
-   --
-   --  prior to the call. Then we replace the actual with a reference to Temp,
-   --  and append the assignment:
-   --
-   --    A := TypeA (Temp);
-   --
-   --  after the call. Here TypeA is the actual type of variable A. For out
-   --  parameters, the initial declaration has no expression. If A is not an
-   --  entity name, we generate instead:
-   --
-   --    Var  : TypeA renames A;
-   --    Temp : T := Var;       --  omitting expression for out parameter.
-   --    ...
-   --    Var := TypeA (Temp);
-   --
-   --  For other in-out parameters, we emit the required constraint checks
-   --  before and/or after the call.
-   --
-   --  For all parameter modes, actuals that denote components and slices of
-   --  packed arrays are expanded into suitable temporaries.
-   --
-   --  For non-scalar objects that are possibly unaligned, add call by copy
-   --  code (copy in for IN and IN OUT, copy out for OUT and IN OUT).
+   procedure Expand_Ctrl_Function_Call (N : Node_Id);
+   --  N is a function call which returns a controlled object. Transform the
+   --  call into a temporary which retrieves the returned object from the
+   --  secondary stack using 'reference.
 
    procedure Expand_Inlined_Call
     (N         : Node_Id;
@@ -202,6 +173,12 @@ package body Exp_Ch6 is
    --  expressions in the body must be converted to the desired type (which
    --  is simply not noted in the tree without inline expansion).
 
+   procedure Expand_Non_Function_Return (N : Node_Id);
+   --  Called by Expand_N_Simple_Return_Statement in case we're returning from
+   --  a procedure body, entry body, accept statement, or extended return
+   --  statement. Note that all non-function returns are simple return
+   --  statements.
+
    function Expand_Protected_Object_Reference
      (N    : Node_Id;
       Scop : Entity_Id) return Node_Id;
@@ -215,9 +192,14 @@ package body Exp_Ch6 is
    --  reference to the object itself, and the call becomes a call to the
    --  corresponding protected subprogram.
 
-   function Is_Null_Procedure (Subp : Entity_Id) return Boolean;
-   --  Predicate to recognize stubbed procedures and null procedures, which
-   --  can be inlined unconditionally in all cases.
+   function Has_Unconstrained_Access_Discriminants
+     (Subtyp : Entity_Id) return Boolean;
+   --  Returns True if the given subtype is unconstrained and has one
+   --  or more access discriminants.
+
+   procedure Expand_Simple_Function_Return (N : Node_Id);
+   --  Expand simple return from function. In the case where we are returning
+   --  from a function body this is called by Expand_N_Simple_Return_Statement.
 
    ----------------------------------------------
    -- Add_Access_Actual_To_Build_In_Place_Call --
@@ -272,19 +254,21 @@ package body Exp_Ch6 is
       Add_Extra_Actual_To_Call (Function_Call, Obj_Acc_Formal, Obj_Address);
    end Add_Access_Actual_To_Build_In_Place_Call;
 
-   --------------------------------------------------
-   -- Add_Alloc_Form_Actual_To_Build_In_Place_Call --
-   --------------------------------------------------
+   ------------------------------------------------------
+   -- Add_Unconstrained_Actuals_To_Build_In_Place_Call --
+   ------------------------------------------------------
 
-   procedure Add_Alloc_Form_Actual_To_Build_In_Place_Call
+   procedure Add_Unconstrained_Actuals_To_Build_In_Place_Call
      (Function_Call  : Node_Id;
       Function_Id    : Entity_Id;
       Alloc_Form     : BIP_Allocation_Form := Unspecified;
-      Alloc_Form_Exp : Node_Id             := Empty)
+      Alloc_Form_Exp : Node_Id             := Empty;
+      Pool_Actual    : Node_Id             := Make_Null (No_Location))
    is
       Loc               : constant Source_Ptr := Sloc (Function_Call);
       Alloc_Form_Actual : Node_Id;
       Alloc_Form_Formal : Node_Id;
+      Pool_Formal       : Node_Id;
 
    begin
       --  The allocation form generally doesn't need to be passed in the case
@@ -326,7 +310,112 @@ package body Exp_Ch6 is
 
       Add_Extra_Actual_To_Call
         (Function_Call, Alloc_Form_Formal, Alloc_Form_Actual);
-   end Add_Alloc_Form_Actual_To_Build_In_Place_Call;
+
+      --  Pass the Storage_Pool parameter. This parameter is omitted on
+      --  .NET/JVM/ZFP as those targets do not support pools.
+
+      if VM_Target = No_VM
+        and then RTE_Available (RE_Root_Storage_Pool_Ptr)
+      then
+         Pool_Formal := Build_In_Place_Formal (Function_Id, BIP_Storage_Pool);
+         Analyze_And_Resolve (Pool_Actual, Etype (Pool_Formal));
+         Add_Extra_Actual_To_Call
+           (Function_Call, Pool_Formal, Pool_Actual);
+      end if;
+   end Add_Unconstrained_Actuals_To_Build_In_Place_Call;
+
+   -----------------------------------------------------------
+   -- Add_Finalization_Master_Actual_To_Build_In_Place_Call --
+   -----------------------------------------------------------
+
+   procedure Add_Finalization_Master_Actual_To_Build_In_Place_Call
+     (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
+         return;
+      end if;
+
+      declare
+         Formal : constant Entity_Id :=
+                    Build_In_Place_Formal (Func_Id, BIP_Finalization_Master);
+         Loc    : constant Source_Ptr := Sloc (Func_Call);
+
+         Actual    : Node_Id;
+         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
+
+         elsif No (Ptr_Typ) then
+            Actual := Make_Null (Loc);
+
+         else
+            Desig_Typ := Directly_Designated_Type (Ptr_Typ);
+
+            --  Check for a library-level access type whose designated type has
+            --  supressed finalization. Such an access types lack a master.
+            --  Pass a null actual to the callee in order to signal a missing
+            --  master.
+
+            if Is_Library_Level_Entity (Ptr_Typ)
+              and then Finalize_Storage_Only (Desig_Typ)
+            then
+               Actual := Make_Null (Loc);
+
+            --  Types in need of finalization actions
+
+            elsif Needs_Finalization (Desig_Typ) then
+
+               --  The general mechanism of creating finalization masters for
+               --  anonymous access types is disabled by default, otherwise
+               --  finalization masters will pop all over the place. Such types
+               --  use context-specific masters.
+
+               if Ekind (Ptr_Typ) = E_Anonymous_Access_Type
+                 and then No (Finalization_Master (Ptr_Typ))
+               then
+                  Build_Finalization_Master
+                    (Typ        => Ptr_Typ,
+                     Ins_Node   => Associated_Node_For_Itype (Ptr_Typ),
+                     Encl_Scope => Scope (Ptr_Typ));
+               end if;
+
+               --  Access-to-controlled types should always have a master
+
+               pragma Assert (Present (Finalization_Master (Ptr_Typ)));
+
+               Actual :=
+                 Make_Attribute_Reference (Loc,
+                   Prefix =>
+                     New_Reference_To (Finalization_Master (Ptr_Typ), Loc),
+                   Attribute_Name => Name_Unrestricted_Access);
+
+            --  Tagged types
+
+            else
+               Actual := Make_Null (Loc);
+            end if;
+         end if;
+
+         Analyze_And_Resolve (Actual, Etype (Formal));
+
+         --  Build the parameter association for the new actual and add it to
+         --  the end of the function's actuals.
+
+         Add_Extra_Actual_To_Call (Func_Call, Formal, Actual);
+      end;
+   end Add_Finalization_Master_Actual_To_Build_In_Place_Call;
 
    ------------------------------
    -- Add_Extra_Actual_To_Call --
@@ -381,79 +470,6 @@ package body Exp_Ch6 is
       end if;
    end Add_Extra_Actual_To_Call;
 
-   --------------------------------------------------
-   -- Add_Final_List_Actual_To_Build_In_Place_Call --
-   --------------------------------------------------
-
-   procedure Add_Final_List_Actual_To_Build_In_Place_Call
-     (Function_Call : Node_Id;
-      Function_Id   : Entity_Id;
-      Acc_Type      : Entity_Id;
-      Sel_Comp      : Node_Id := Empty)
-   is
-      Loc               : constant Source_Ptr := Sloc (Function_Call);
-      Final_List        : Node_Id;
-      Final_List_Actual : Node_Id;
-      Final_List_Formal : Node_Id;
-      Is_Ctrl_Result    : constant Boolean :=
-                            Needs_Finalization
-                              (Underlying_Type (Etype (Function_Id)));
-
-   begin
-      --  No such extra parameter is needed if there are no controlled parts.
-      --  The test for Needs_Finalization accounts for class-wide results
-      --  (which potentially have controlled parts, even if the root type
-      --  doesn't), and the test for a tagged result type is needed because
-      --  calls to such a function can in general occur in dispatching
-      --  contexts, which must be treated the same as a call to class-wide
-      --  functions. Both of these situations require that a finalization list
-      --  be passed.
-
-      if not Needs_BIP_Final_List (Function_Id) then
-         return;
-      end if;
-
-      --  Locate implicit finalization list parameter in the called function
-
-      Final_List_Formal := Build_In_Place_Formal (Function_Id, BIP_Final_List);
-
-      --  Create the actual which is a pointer to the appropriate finalization
-      --  list. Acc_Type is present if and only if this call is the
-      --  initialization of an allocator. Use the Current_Scope or the
-      --  Acc_Type as appropriate.
-
-      if Present (Acc_Type)
-        and then (Ekind (Acc_Type) = E_Anonymous_Access_Type
-                   or else
-                     Present (Associated_Final_Chain (Base_Type (Acc_Type))))
-      then
-         Final_List := Find_Final_List (Acc_Type);
-
-      --  If Sel_Comp is present and the function result is controlled, then
-      --  the finalization list will be obtained from the _controller list of
-      --  the selected component's prefix object.
-
-      elsif Present (Sel_Comp) and then Is_Ctrl_Result then
-         Final_List := Find_Final_List (Current_Scope, Sel_Comp);
-
-      else
-         Final_List := Find_Final_List (Current_Scope);
-      end if;
-
-      Final_List_Actual :=
-        Make_Attribute_Reference (Loc,
-          Prefix         => Final_List,
-          Attribute_Name => Name_Unrestricted_Access);
-
-      Analyze_And_Resolve (Final_List_Actual, Etype (Final_List_Formal));
-
-      --  Build the parameter association for the new actual and add it to the
-      --  end of the function's actuals.
-
-      Add_Extra_Actual_To_Call
-        (Function_Call, Final_List_Formal, Final_List_Actual);
-   end Add_Final_List_Actual_To_Build_In_Place_Call;
-
    ---------------------------------------------
    -- Add_Task_Actuals_To_Build_In_Place_Call --
    ---------------------------------------------
@@ -462,64 +478,64 @@ package body Exp_Ch6 is
      (Function_Call : Node_Id;
       Function_Id   : Entity_Id;
       Master_Actual : Node_Id)
-      --  Note: Master_Actual can be Empty, but only if there are no tasks
    is
-      Loc               : constant Source_Ptr := Sloc (Function_Call);
+      Loc           : constant Source_Ptr := Sloc (Function_Call);
+      Result_Subt   : constant Entity_Id :=
+                        Available_View (Etype (Function_Id));
+      Actual        : Node_Id;
+      Chain_Actual  : Node_Id;
+      Chain_Formal  : Node_Id;
+      Master_Formal : Node_Id;
 
    begin
       --  No such extra parameters are needed if there are no tasks
 
-      if not Has_Task (Etype (Function_Id)) then
+      if not Has_Task (Result_Subt) then
          return;
       end if;
 
-      --  The master
+      Actual := Master_Actual;
 
-      declare
-         Master_Formal : Node_Id;
-      begin
-         --  Locate implicit master parameter in the called function
+      --  Use a dummy _master actual in case of No_Task_Hierarchy
 
-         Master_Formal := Build_In_Place_Formal (Function_Id, BIP_Master);
+      if Restriction_Active (No_Task_Hierarchy) then
+         Actual := New_Occurrence_Of (RTE (RE_Library_Task_Level), Loc);
 
-         Analyze_And_Resolve (Master_Actual, Etype (Master_Formal));
+      --  In the case where we use the master associated with an access type,
+      --  the actual is an entity and requires an explicit reference.
 
-         --  Build the parameter association for the new actual and add it to
-         --  the end of the function's actuals.
+      elsif Nkind (Actual) = N_Defining_Identifier then
+         Actual := New_Reference_To (Actual, Loc);
+      end if;
 
-         Add_Extra_Actual_To_Call
-           (Function_Call, Master_Formal, Master_Actual);
-      end;
+      --  Locate the implicit master parameter in the called function
 
-      --  The activation chain
+      Master_Formal := Build_In_Place_Formal (Function_Id, BIP_Task_Master);
+      Analyze_And_Resolve (Actual, Etype (Master_Formal));
 
-      declare
-         Activation_Chain_Actual : Node_Id;
-         Activation_Chain_Formal : Node_Id;
+      --  Build the parameter association for the new actual and add it to the
+      --  end of the function's actuals.
 
-      begin
-         --  Locate implicit activation chain parameter in the called function
+      Add_Extra_Actual_To_Call (Function_Call, Master_Formal, Actual);
+
+      --  Locate the implicit activation chain parameter in the called function
 
-         Activation_Chain_Formal := Build_In_Place_Formal
-           (Function_Id, BIP_Activation_Chain);
+      Chain_Formal :=
+        Build_In_Place_Formal (Function_Id, BIP_Activation_Chain);
 
-         --  Create the actual which is a pointer to the current activation
-         --  chain
+      --  Create the actual which is a pointer to the current activation chain
 
-         Activation_Chain_Actual :=
-           Make_Attribute_Reference (Loc,
-             Prefix         => Make_Identifier (Loc, Name_uChain),
-             Attribute_Name => Name_Unrestricted_Access);
+      Chain_Actual :=
+        Make_Attribute_Reference (Loc,
+          Prefix         => Make_Identifier (Loc, Name_uChain),
+          Attribute_Name => Name_Unrestricted_Access);
 
-         Analyze_And_Resolve
-           (Activation_Chain_Actual, Etype (Activation_Chain_Formal));
+      Analyze_And_Resolve (Chain_Actual, Etype (Chain_Formal));
 
-         --  Build the parameter association for the new actual and add it to
-         --  the end of the function's actuals.
+      --  Build the parameter association for the new actual and add it to the
+      --  end of the function's actuals.
 
-         Add_Extra_Actual_To_Call
-           (Function_Call, Activation_Chain_Formal, Activation_Chain_Actual);
-      end;
+      Add_Extra_Actual_To_Call (Function_Call, Chain_Formal, Chain_Actual);
    end Add_Task_Actuals_To_Build_In_Place_Call;
 
    -----------------------
@@ -529,15 +545,17 @@ package body Exp_Ch6 is
    function BIP_Formal_Suffix (Kind : BIP_Formal_Kind) return String is
    begin
       case Kind is
-         when BIP_Alloc_Form       =>
+         when BIP_Alloc_Form          =>
             return "BIPalloc";
-         when BIP_Final_List       =>
-            return "BIPfinallist";
-         when BIP_Master           =>
-            return "BIPmaster";
-         when BIP_Activation_Chain =>
+         when BIP_Storage_Pool        =>
+            return "BIPstoragepool";
+         when BIP_Finalization_Master =>
+            return "BIPfinalizationmaster";
+         when BIP_Task_Master         =>
+            return "BIPtaskmaster";
+         when BIP_Activation_Chain    =>
             return "BIPactivationchain";
-         when BIP_Object_Access    =>
+         when BIP_Object_Access       =>
             return "BIPaccess";
       end case;
    end BIP_Formal_Suffix;
@@ -550,17 +568,29 @@ package body Exp_Ch6 is
      (Func : Entity_Id;
       Kind : BIP_Formal_Kind) return Entity_Id
    is
+      Formal_Name  : constant Name_Id :=
+                       New_External_Name
+                         (Chars (Func), BIP_Formal_Suffix (Kind));
       Extra_Formal : Entity_Id := Extra_Formals (Func);
 
    begin
       --  Maybe it would be better for each implicit formal of a build-in-place
       --  function to have a flag or a Uint attribute to identify it. ???
 
+      --  The return type in the function declaration may have been a limited
+      --  view, and the extra formals for the function were not generated at
+      --  that point. At the point of call the full view must be available and
+      --  the extra formals can be created.
+
+      if No (Extra_Formal) then
+         Create_Extra_Formals (Func);
+         Extra_Formal := Extra_Formals (Func);
+      end if;
+
       loop
          pragma Assert (Present (Extra_Formal));
-         exit when
-           Chars (Extra_Formal) =
-             New_External_Name (Chars (Func), BIP_Formal_Suffix (Kind));
+         exit when Chars (Extra_Formal) = Formal_Name;
+
          Next_Formal_With_Extras (Extra_Formal);
       end loop;
 
@@ -582,7 +612,7 @@ package body Exp_Ch6 is
       if Is_Derived_Type (Typ)
         and then not Is_Private_Type (Typ)
         and then In_Open_Scopes (Scope (Etype (Typ)))
-        and then Typ = Base_Type (Typ)
+        and then Is_Base_Type (Typ)
       then
          --  Subp overrides an inherited private operation if there is an
          --  inherited operation with a different name than Subp (see
@@ -1175,10 +1205,49 @@ package body Exp_Ch6 is
 
                Set_Assignment_OK (Lhs);
 
-               Append_To (Post_Call,
-                 Make_Assignment_Statement (Loc,
-                   Name       => Lhs,
-                   Expression => Expr));
+               if Is_Access_Type (E_Formal)
+                 and then Is_Entity_Name (Lhs)
+                 and then
+                   Present (Effective_Extra_Accessibility (Entity (Lhs)))
+               then
+                  --  Copyback target is an Ada 2012 stand-alone object
+                  --  of an anonymous access type
+
+                  pragma Assert (Ada_Version >= Ada_2012);
+
+                  if Type_Access_Level (E_Formal) >
+                     Object_Access_Level (Lhs)
+                  then
+                     Append_To (Post_Call,
+                       Make_Raise_Program_Error (Loc,
+                         Reason => PE_Accessibility_Check_Failed));
+                  end if;
+
+                  Append_To (Post_Call,
+                    Make_Assignment_Statement (Loc,
+                      Name       => Lhs,
+                      Expression => Expr));
+
+                  --  We would like to somehow suppress generation of the
+                  --  extra_accessibility assignment generated by the expansion
+                  --  of the above assignment statement. It's not a correctness
+                  --  issue because the following assignment renders it dead,
+                  --  but generating back-to-back assignments to the same
+                  --  target is undesirable. ???
+
+                  Append_To (Post_Call,
+                    Make_Assignment_Statement (Loc,
+                      Name       => New_Occurrence_Of (
+                        Effective_Extra_Accessibility (Entity (Lhs)), Loc),
+                      Expression => Make_Integer_Literal (Loc,
+                        Type_Access_Level (E_Formal))));
+
+               else
+                  Append_To (Post_Call,
+                    Make_Assignment_Statement (Loc,
+                      Name       => Lhs,
+                      Expression => Expr));
+               end if;
             end;
          end if;
       end Add_Call_By_Copy_Code;
@@ -1454,9 +1523,7 @@ package body Exp_Ch6 is
             --  functions that are treated as build-in-place to include other
             --  composite result types.
 
-            if Ada_Version >= Ada_05
-              and then Is_Build_In_Place_Function_Call (Actual)
-            then
+            if Is_Build_In_Place_Function_Call (Actual) then
                Make_Build_In_Place_Call_In_Anonymous_Context (Actual);
             end if;
 
@@ -1654,6 +1721,24 @@ package body Exp_Ch6 is
 
             elsif Is_Possibly_Unaligned_Slice (Actual) then
                Add_Call_By_Copy_Code;
+
+            --  An unusual case: a current instance of an enclosing task can be
+            --  an actual, and must be replaced by a reference to self.
+
+            elsif Is_Entity_Name (Actual)
+              and then Is_Task_Type (Entity (Actual))
+            then
+               if In_Open_Scopes (Entity (Actual)) then
+                  Rewrite (Actual,
+                    (Make_Function_Call (Loc,
+                     Name => New_Reference_To (RTE (RE_Self), Loc))));
+                  Analyze (Actual);
+
+               --  A task type cannot otherwise appear as an actual
+
+               else
+                  raise Program_Error;
+               end if;
             end if;
          end if;
 
@@ -1665,24 +1750,50 @@ package body Exp_Ch6 is
 
       if not Is_Empty_List (Post_Call) then
 
-         --  If call is not a list member, it must be the triggering statement
-         --  of a triggering alternative or an entry call alternative, and we
-         --  can add the post call stuff to the corresponding statement list.
+         --  Cases where the call is not a member of a statement list
 
          if not Is_List_Member (N) then
             declare
-               P : constant Node_Id := Parent (N);
+               P :  Node_Id := Parent (N);
 
             begin
-               pragma Assert (Nkind_In (P, N_Triggering_Alternative,
-                                           N_Entry_Call_Alternative));
+               --  In Ada 2012 the call may be a function call in an expression
+               --  (since OUT and IN OUT parameters are now allowed for such
+               --  calls. The write-back of (in)-out parameters is handled
+               --  by the back-end, but the constraint checks generated when
+               --  subtypes of formal and actual don't match must be inserted
+               --  in the form of assignments, at the nearest point after the
+               --  declaration or statement that contains the call.
+
+               if Ada_Version >= Ada_2012
+                 and then Nkind (N) = N_Function_Call
+               then
+                  while Nkind (P) not in N_Declaration
+                    and then
+                      Nkind (P) not in N_Statement_Other_Than_Procedure_Call
+                  loop
+                     P := Parent (P);
+                  end loop;
+
+                  Insert_Actions_After (P, Post_Call);
+
+               --  If not the special Ada 2012 case of a function call, then
+               --  we must have the triggering statement of a triggering
+               --  alternative or an entry call alternative, and we can add
+               --  the post call stuff to the corresponding statement list.
 
-               if Is_Non_Empty_List (Statements (P)) then
-                  Insert_List_Before_And_Analyze
-                    (First (Statements (P)), Post_Call);
                else
-                  Set_Statements (P, Post_Call);
+                  pragma Assert (Nkind_In (P, N_Triggering_Alternative,
+                                              N_Entry_Call_Alternative));
+
+                  if Is_Non_Empty_List (Statements (P)) then
+                     Insert_List_Before_And_Analyze
+                       (First (Statements (P)), Post_Call);
+                  else
+                     Set_Statements (P, Post_Call);
+                  end if;
                end if;
+
             end;
 
          --  Otherwise, normal case where N is in a statement sequence,
@@ -1720,6 +1831,7 @@ package body Exp_Ch6 is
 
    procedure Expand_Call (N : Node_Id) is
       Loc           : constant Source_Ptr := Sloc (N);
+      Call_Node     : Node_Id := N;
       Extra_Actuals : List_Id := No_List;
       Prev          : Node_Id := Empty;
 
@@ -1742,6 +1854,14 @@ package body Exp_Ch6 is
       --  convoluted tree traversal before setting the proper subprogram to be
       --  called.
 
+      function Is_Direct_Deep_Call (Subp : Entity_Id) return Boolean;
+      --  Determine if Subp denotes a non-dispatching call to a Deep routine
+
+      function New_Value (From : Node_Id) return Node_Id;
+      --  From is the original Expression. New_Value is equivalent to a call
+      --  to Duplicate_Subexpr with an explicit dereference when From is an
+      --  access parameter.
+
       --------------------------
       -- Add_Actual_Parameter --
       --------------------------
@@ -1756,14 +1876,17 @@ package body Exp_Ch6 is
          if No (Prev) or else
             Nkind (Parent (Prev)) /= N_Parameter_Association
          then
-            Set_Next_Named_Actual (Insert_Param, First_Named_Actual (N));
-            Set_First_Named_Actual (N, Actual_Expr);
+            Set_Next_Named_Actual
+              (Insert_Param, First_Named_Actual (Call_Node));
+            Set_First_Named_Actual (Call_Node, Actual_Expr);
 
             if No (Prev) then
-               if No (Parameter_Associations (N)) then
-                  Set_Parameter_Associations (N, New_List);
-                  Append (Insert_Param, Parameter_Associations (N));
+               if No (Parameter_Associations (Call_Node)) then
+                  Set_Parameter_Associations (Call_Node, New_List);
                end if;
+
+               Append (Insert_Param, Parameter_Associations (Call_Node));
+
             else
                Insert_After (Prev, Insert_Param);
             end if;
@@ -1774,7 +1897,7 @@ package body Exp_Ch6 is
             Set_Next_Named_Actual
               (Insert_Param, Next_Named_Actual (Parent (Prev)));
             Set_Next_Named_Actual (Parent (Prev), Actual_Expr);
-            Append (Insert_Param, Parameter_Associations (N));
+            Append (Insert_Param, Parameter_Associations (Call_Node));
          end if;
 
          Prev := Actual_Expr;
@@ -1790,18 +1913,17 @@ package body Exp_Ch6 is
       begin
          if Extra_Actuals = No_List then
             Extra_Actuals := New_List;
-            Set_Parent (Extra_Actuals, N);
+            Set_Parent (Extra_Actuals, Call_Node);
          end if;
 
          Append_To (Extra_Actuals,
            Make_Parameter_Association (Loc,
-             Explicit_Actual_Parameter => Expr,
-             Selector_Name =>
-               Make_Identifier (Loc, Chars (EF))));
+             Selector_Name             => Make_Identifier (Loc, Chars (EF)),
+             Explicit_Actual_Parameter => Expr));
 
          Analyze_And_Resolve (Expr, Etype (EF));
 
-         if Nkind (N) = N_Function_Call then
+         if Nkind (Call_Node) = N_Function_Call then
             Set_Is_Accessibility_Actual (Parent (Expr));
          end if;
       end Add_Extra_Actual;
@@ -1905,9 +2027,62 @@ package body Exp_Ch6 is
          raise Program_Error;
       end Inherited_From_Formal;
 
+      -------------------------
+      -- Is_Direct_Deep_Call --
+      -------------------------
+
+      function Is_Direct_Deep_Call (Subp : Entity_Id) return Boolean is
+      begin
+         if Is_TSS (Subp, TSS_Deep_Adjust)
+           or else Is_TSS (Subp, TSS_Deep_Finalize)
+           or else Is_TSS (Subp, TSS_Deep_Initialize)
+         then
+            declare
+               Actual : Node_Id;
+               Formal : Node_Id;
+
+            begin
+               Actual := First (Parameter_Associations (N));
+               Formal := First_Formal (Subp);
+               while Present (Actual)
+                 and then Present (Formal)
+               loop
+                  if Nkind (Actual) = N_Identifier
+                    and then Is_Controlling_Actual (Actual)
+                    and then Etype (Actual) = Etype (Formal)
+                  then
+                     return True;
+                  end if;
+
+                  Next (Actual);
+                  Next_Formal (Formal);
+               end loop;
+            end;
+         end if;
+
+         return False;
+      end Is_Direct_Deep_Call;
+
+      ---------------
+      -- New_Value --
+      ---------------
+
+      function New_Value (From : Node_Id) return Node_Id is
+         Res : constant Node_Id := Duplicate_Subexpr (From);
+      begin
+         if Is_Access_Type (Etype (From)) then
+            return
+              Make_Explicit_Dereference (Sloc (From),
+                Prefix => Res);
+         else
+            return Res;
+         end if;
+      end New_Value;
+
       --  Local variables
 
-      Remote        : constant Boolean := Is_Remote_Call (N);
+      Curr_S        : constant Entity_Id := Current_Scope;
+      Remote        : constant Boolean   := Is_Remote_Call (Call_Node);
       Actual        : Node_Id;
       Formal        : Entity_Id;
       Orig_Subp     : Entity_Id := Empty;
@@ -1930,35 +2105,37 @@ package body Exp_Ch6 is
    begin
       --  Ignore if previous error
 
-      if Nkind (N) in N_Has_Etype and then Etype (N) = Any_Type then
+      if Nkind (Call_Node) in N_Has_Etype
+        and then Etype (Call_Node) = Any_Type
+      then
          return;
       end if;
 
       --  Call using access to subprogram with explicit dereference
 
-      if Nkind (Name (N)) = N_Explicit_Dereference then
-         Subp        := Etype (Name (N));
+      if Nkind (Name (Call_Node)) = N_Explicit_Dereference then
+         Subp        := Etype (Name (Call_Node));
          Parent_Subp := Empty;
 
       --  Case of call to simple entry, where the Name is a selected component
       --  whose prefix is the task, and whose selector name is the entry name
 
-      elsif Nkind (Name (N)) = N_Selected_Component then
-         Subp        := Entity (Selector_Name (Name (N)));
+      elsif Nkind (Name (Call_Node)) = N_Selected_Component then
+         Subp        := Entity (Selector_Name (Name (Call_Node)));
          Parent_Subp := Empty;
 
       --  Case of call to member of entry family, where Name is an indexed
       --  component, with the prefix being a selected component giving the
       --  task and entry family name, and the index being the entry index.
 
-      elsif Nkind (Name (N)) = N_Indexed_Component then
-         Subp        := Entity (Selector_Name (Prefix (Name (N))));
+      elsif Nkind (Name (Call_Node)) = N_Indexed_Component then
+         Subp        := Entity (Selector_Name (Prefix (Name (Call_Node))));
          Parent_Subp := Empty;
 
       --  Normal case
 
       else
-         Subp        := Entity (Name (N));
+         Subp        := Entity (Name (Call_Node));
          Parent_Subp := Alias (Subp);
 
          --  Replace call to Raise_Exception by call to Raise_Exception_Always
@@ -1973,7 +2150,8 @@ package body Exp_Ch6 is
            and then RTE_Available (RE_Raise_Exception_Always)
          then
             declare
-               FA : constant Node_Id := Original_Node (First_Actual (N));
+               FA : constant Node_Id :=
+                      Original_Node (First_Actual (Call_Node));
 
             begin
                --  The case we catch is where the first argument is obtained
@@ -1984,7 +2162,7 @@ package body Exp_Ch6 is
                  and then Attribute_Name (FA) = Name_Identity
                then
                   Subp := RTE (RE_Raise_Exception_Always);
-                  Set_Name (N, New_Occurrence_Of (Subp, Loc));
+                  Set_Name (Call_Node, New_Occurrence_Of (Subp, Loc));
                end if;
             end;
          end if;
@@ -1994,19 +2172,65 @@ package body Exp_Ch6 is
          end if;
       end if;
 
+      --  Detect the following code in System.Finalization_Masters only on
+      --  .NET/JVM targets:
+      --
+      --    procedure Finalize (Master : in out Finalization_Master) is
+      --    begin
+      --       . . .
+      --       begin
+      --          Finalize (Curr_Ptr.all);
+      --
+      --  Since .NET/JVM compilers lack address arithmetic and Deep_Finalize
+      --  cannot be named in library or user code, the compiler has to install
+      --  a kludge and transform the call to Finalize into Deep_Finalize.
+
+      if VM_Target /= No_VM
+        and then Chars (Subp) = Name_Finalize
+        and then Ekind (Curr_S) = E_Block
+        and then Ekind (Scope (Curr_S)) = E_Procedure
+        and then Chars (Scope (Curr_S)) = Name_Finalize
+        and then Etype (First_Formal (Scope (Curr_S))) =
+                   RTE (RE_Finalization_Master)
+      then
+         declare
+            Deep_Fin : constant Entity_Id :=
+                         Find_Prim_Op (RTE (RE_Root_Controlled),
+                                       TSS_Deep_Finalize);
+         begin
+            --  Since Root_Controlled is a tagged type, the compiler should
+            --  always generate Deep_Finalize for it.
+
+            pragma Assert (Present (Deep_Fin));
+
+            --  Generate:
+            --    Deep_Finalize (Curr_Ptr.all);
+
+            Rewrite (N,
+              Make_Procedure_Call_Statement (Loc,
+                Name =>
+                  New_Reference_To (Deep_Fin, Loc),
+                Parameter_Associations =>
+                  New_Copy_List_Tree (Parameter_Associations (N))));
+
+            Analyze (N);
+            return;
+         end;
+      end if;
+
       --  Ada 2005 (AI-345): We have a procedure call as a triggering
       --  alternative in an asynchronous select or as an entry call in
       --  a conditional or timed select. Check whether the procedure call
       --  is a renaming of an entry and rewrite it as an entry call.
 
-      if Ada_Version >= Ada_05
-        and then Nkind (N) = N_Procedure_Call_Statement
+      if Ada_Version >= Ada_2005
+        and then Nkind (Call_Node) = N_Procedure_Call_Statement
         and then
-           ((Nkind (Parent (N)) = N_Triggering_Alternative
-               and then Triggering_Statement (Parent (N)) = N)
+           ((Nkind (Parent (Call_Node)) = N_Triggering_Alternative
+              and then Triggering_Statement (Parent (Call_Node)) = Call_Node)
           or else
-            (Nkind (Parent (N)) = N_Entry_Call_Alternative
-               and then Entry_Call_Statement (Parent (N)) = N))
+            (Nkind (Parent (Call_Node)) = N_Entry_Call_Alternative
+              and then Entry_Call_Statement (Parent (Call_Node)) = Call_Node))
       then
          declare
             Ren_Decl : Node_Id;
@@ -2023,12 +2247,13 @@ package body Exp_Ch6 is
                Ren_Decl := Original_Node (Parent (Parent (Ren_Root)));
 
                if Nkind (Ren_Decl) = N_Subprogram_Renaming_Declaration then
-                  Rewrite (N,
+                  Rewrite (Call_Node,
                     Make_Entry_Call_Statement (Loc,
                       Name =>
                         New_Copy_Tree (Name (Ren_Decl)),
                       Parameter_Associations =>
-                        New_Copy_List_Tree (Parameter_Associations (N))));
+                        New_Copy_List_Tree
+                          (Parameter_Associations (Call_Node))));
 
                   return;
                end if;
@@ -2045,8 +2270,8 @@ package body Exp_Ch6 is
       --  as we go through the loop, since this is a convenient place to do it.
       --  (Though it seems that this would be better done in Expand_Actuals???)
 
-      Formal      := First_Formal (Subp);
-      Actual      := First_Actual (N);
+      Formal := First_Formal (Subp);
+      Actual := First_Actual (Call_Node);
       Param_Count := 1;
       while Present (Formal) loop
 
@@ -2072,7 +2297,7 @@ package body Exp_Ch6 is
            CW_Interface_Formals_Present
              or else
                (Ekind (Etype (Formal)) = E_Class_Wide_Type
-                  and then Is_Interface (Etype (Etype (Formal))))
+                 and then Is_Interface (Etype (Etype (Formal))))
              or else
                (Ekind (Etype (Formal)) = E_Anonymous_Access_Type
                  and then Is_Interface (Directly_Designated_Type
@@ -2174,8 +2399,8 @@ package body Exp_Ch6 is
                Prev_Orig := Prev;
             end if;
 
-            --  Ada 2005 (AI-251): Thunks must propagate the extra actuals
-            --  of accessibility levels.
+            --  Ada 2005 (AI-251): Thunks must propagate the extra actuals of
+            --  accessibility levels.
 
             if Ekind (Current_Scope) in Subprogram_Kind
               and then Is_Thunk (Current_Scope)
@@ -2252,8 +2477,7 @@ package body Exp_Ch6 is
 
                else
                   Add_Extra_Actual
-                    (Make_Integer_Literal (Loc,
-                       Intval => Type_Access_Level (Etype (Prev_Orig))),
+                    (Dynamic_Accessibility_Level (Prev_Orig),
                      Extra_Accessibility (Formal));
                end if;
 
@@ -2282,12 +2506,40 @@ package body Exp_Ch6 is
                         --  For X'Access, pass on the level of the prefix X
 
                         when Attribute_Access =>
-                           Add_Extra_Actual
-                             (Make_Integer_Literal (Loc,
-                               Intval =>
-                                 Object_Access_Level
-                                   (Prefix (Prev_Orig))),
-                                    Extra_Accessibility (Formal));
+
+                           --  If this is an Access attribute applied to the
+                           --  the current instance object passed to a type
+                           --  initialization procedure, then use the level
+                           --  of the type itself. This is not really correct,
+                           --  as there should be an extra level parameter
+                           --  passed in with _init formals (only in the case
+                           --  where the type is immutably limited), but we
+                           --  don't have an easy way currently to create such
+                           --  an extra formal (init procs aren't ever frozen).
+                           --  For now we just use the level of the type,
+                           --  which may be too shallow, but that works better
+                           --  than passing Object_Access_Level of the type,
+                           --  which can be one level too deep in some cases.
+                           --  ???
+
+                           if Is_Entity_Name (Prefix (Prev_Orig))
+                             and then Is_Type (Entity (Prefix (Prev_Orig)))
+                           then
+                              Add_Extra_Actual
+                                (Make_Integer_Literal (Loc,
+                                   Intval =>
+                                     Type_Access_Level
+                                       (Entity (Prefix (Prev_Orig)))),
+                                 Extra_Accessibility (Formal));
+
+                           else
+                              Add_Extra_Actual
+                                (Make_Integer_Literal (Loc,
+                                   Intval =>
+                                     Object_Access_Level
+                                       (Prefix (Prev_Orig))),
+                                 Extra_Accessibility (Formal));
+                           end if;
 
                         --  Treat the unchecked attributes as library-level
 
@@ -2299,7 +2551,7 @@ package body Exp_Ch6 is
                               Extra_Accessibility (Formal));
 
                         --  No other cases of attributes returning access
-                        --  values that can be passed to access parameters
+                        --  values that can be passed to access parameters.
 
                         when others =>
                            raise Program_Error;
@@ -2316,40 +2568,45 @@ package body Exp_Ch6 is
                           Intval => Scope_Depth (Current_Scope) + 1),
                         Extra_Accessibility (Formal));
 
-                  --  For other cases we simply pass the level of the actual's
-                  --  access type. The type is retrieved from Prev rather than
-                  --  Prev_Orig, because in some cases Prev_Orig denotes an
-                  --  original expression that has not been analyzed.
+                  --  For most other cases we simply pass the level of the
+                  --  actual's access type. The type is retrieved from
+                  --  Prev rather than Prev_Orig, because in some cases
+                  --  Prev_Orig denotes an original expression that has
+                  --  not been analyzed.
 
                   when others =>
                      Add_Extra_Actual
-                       (Make_Integer_Literal (Loc,
-                          Intval => Type_Access_Level (Etype (Prev))),
+                       (Dynamic_Accessibility_Level (Prev),
                         Extra_Accessibility (Formal));
                end case;
             end if;
          end if;
 
          --  Perform the check of 4.6(49) that prevents a null value from being
-         --  passed as an actual to an access parameter. Note that the check is
-         --  elided in the common cases of passing an access attribute or
+         --  passed as an actual to an access parameter. Note that the check
+         --  is elided in the common cases of passing an access attribute or
          --  access parameter as an actual. Also, we currently don't enforce
          --  this check for expander-generated actuals and when -gnatdj is set.
 
-         if Ada_Version >= Ada_05 then
+         if Ada_Version >= Ada_2005 then
 
-            --  Ada 2005 (AI-231): Check null-excluding access types
+            --  Ada 2005 (AI-231): Check null-excluding access types. Note that
+            --  the intent of 6.4.1(13) is that null-exclusion checks should
+            --  not be done for 'out' parameters, even though it refers only
+            --  to constraint checks, and a null_exclusion is not a constraint.
+            --  Note that AI05-0196-1 corrects this mistake in the RM.
 
             if Is_Access_Type (Etype (Formal))
               and then Can_Never_Be_Null (Etype (Formal))
+              and then Ekind (Formal) /= E_Out_Parameter
               and then Nkind (Prev) /= N_Raise_Constraint_Error
               and then (Known_Null (Prev)
-                          or else not Can_Never_Be_Null (Etype (Prev)))
+                         or else not Can_Never_Be_Null (Etype (Prev)))
             then
                Install_Null_Excluding_Check (Prev);
             end if;
 
-         --  Ada_Version < Ada_05
+         --  Ada_Version < Ada_2005
 
          else
             if Ekind (Etype (Formal)) /= E_Anonymous_Access_Type
@@ -2390,10 +2647,10 @@ package body Exp_Ch6 is
 
          if Validity_Checks_On then
             if  (Ekind (Formal) = E_In_Parameter
-                   and then Validity_Check_In_Params)
+                  and then Validity_Check_In_Params)
               or else
                 (Ekind (Formal) = E_In_Out_Parameter
-                   and then Validity_Check_In_Out_Params)
+                  and then Validity_Check_In_Out_Params)
             then
                --  If the actual is an indexed component of a packed type (or
                --  is an indexed or selected component whose prefix recursively
@@ -2421,16 +2678,28 @@ package body Exp_Ch6 is
             end if;
          end if;
 
+         --  For Ada 2012, if a parameter is aliased, the actual must be a
+         --  tagged type or an aliased view of an object.
+
+         if Is_Aliased (Formal)
+           and then not Is_Aliased_View (Actual)
+           and then not Is_Tagged_Type (Etype (Formal))
+         then
+            Error_Msg_NE
+              ("actual for aliased formal& must be aliased object",
+               Actual, Formal);
+         end if;
+
          --  For IN OUT and OUT parameters, ensure that subscripts are valid
          --  since this is a left side reference. We only do this for calls
          --  from the source program since we assume that compiler generated
          --  calls explicitly generate any required checks. We also need it
-         --  only if we are doing standard validity checks, since clearly it
-         --  is not needed if validity checks are off, and in subscript
-         --  validity checking mode, all indexed components are checked with
-         --  a call directly from Expand_N_Indexed_Component.
+         --  only if we are doing standard validity checks, since clearly it is
+         --  not needed if validity checks are off, and in subscript validity
+         --  checking mode, all indexed components are checked with a call
+         --  directly from Expand_N_Indexed_Component.
 
-         if Comes_From_Source (N)
+         if Comes_From_Source (Call_Node)
            and then Ekind (Formal) /= E_In_Parameter
            and then Validity_Checks_On
            and then Validity_Check_Default
@@ -2472,9 +2741,7 @@ package body Exp_Ch6 is
                --  or IN OUT parameter! We do reset the Is_Known_Valid flag
                --  since the subprogram could have returned in invalid value.
 
-               if (Ekind (Formal) = E_Out_Parameter
-                     or else
-                   Ekind (Formal) = E_In_Out_Parameter)
+               if Ekind_In (Formal, E_Out_Parameter, E_In_Out_Parameter)
                  and then Is_Assignable (Ent)
                then
                   Sav := Last_Assignment (Ent);
@@ -2523,56 +2790,173 @@ package body Exp_Ch6 is
          Next_Formal (Formal);
       end loop;
 
+      --  If we are calling an Ada 2012 function which needs to have the
+      --  "accessibility level determined by the point of call" (AI05-0234)
+      --  passed in to it, then pass it in.
+
+      if Ekind_In (Subp, E_Function, E_Operator, E_Subprogram_Type)
+        and then
+          Present (Extra_Accessibility_Of_Result (Ultimate_Alias (Subp)))
+      then
+         declare
+            Ancestor : Node_Id := Parent (Call_Node);
+            Level    : Node_Id := Empty;
+            Defer    : Boolean := False;
+
+         begin
+            --  Unimplemented: if Subp returns an anonymous access type, then
+
+            --    a) if the call is the operand of an explict conversion, then
+            --       the target type of the conversion (a named access type)
+            --       determines the accessibility level pass in;
+
+            --    b) if the call defines an access discriminant of an object
+            --       (e.g., the discriminant of an object being created by an
+            --       allocator, or the discriminant of a function result),
+            --       then the accessibility level to pass in is that of the
+            --       discriminated object being initialized).
+
+            --  ???
+
+            while Nkind (Ancestor) = N_Qualified_Expression
+            loop
+               Ancestor := Parent (Ancestor);
+            end loop;
+
+            case Nkind (Ancestor) is
+               when N_Allocator =>
+
+                  --  At this point, we'd like to assign
+
+                  --    Level := Dynamic_Accessibility_Level (Ancestor);
+
+                  --  but Etype of Ancestor may not have been set yet,
+                  --  so that doesn't work.
+
+                  --  Handle this later in Expand_Allocator_Expression.
+
+                  Defer := True;
+
+               when N_Object_Declaration | N_Object_Renaming_Declaration =>
+                  declare
+                     Def_Id : constant Entity_Id :=
+                                Defining_Identifier (Ancestor);
+
+                  begin
+                     if Is_Return_Object (Def_Id) then
+                        if Present (Extra_Accessibility_Of_Result
+                                     (Return_Applies_To (Scope (Def_Id))))
+                        then
+                           --  Pass along value that was passed in if the
+                           --  routine we are returning from also has an
+                           --  Accessibility_Of_Result formal.
+
+                           Level :=
+                             New_Occurrence_Of
+                              (Extra_Accessibility_Of_Result
+                                (Return_Applies_To (Scope (Def_Id))), Loc);
+                        end if;
+                     else
+                        Level :=
+                          Make_Integer_Literal (Loc,
+                            Intval => Object_Access_Level (Def_Id));
+                     end if;
+                  end;
+
+               when N_Simple_Return_Statement =>
+                  if Present (Extra_Accessibility_Of_Result
+                               (Return_Applies_To
+                                 (Return_Statement_Entity (Ancestor))))
+                  then
+                     --  Pass along value that was passed in if the routine
+                     --  we are returning from also has an
+                     --  Accessibility_Of_Result formal.
+
+                     Level :=
+                       New_Occurrence_Of
+                         (Extra_Accessibility_Of_Result
+                            (Return_Applies_To
+                               (Return_Statement_Entity (Ancestor))), Loc);
+                  end if;
+
+               when others =>
+                  null;
+            end case;
+
+            if not Defer then
+               if not Present (Level) then
+
+                  --  The "innermost master that evaluates the function call".
+
+                  --  ??? - Should we use Integer'Last here instead in order
+                  --  to deal with (some of) the problems associated with
+                  --  calls to subps whose enclosing scope is unknown (e.g.,
+                  --  Anon_Access_To_Subp_Param.all)?
+
+                  Level := Make_Integer_Literal (Loc,
+                             Scope_Depth (Current_Scope) + 1);
+               end if;
+
+               Add_Extra_Actual
+                 (Level,
+                  Extra_Accessibility_Of_Result (Ultimate_Alias (Subp)));
+            end if;
+         end;
+      end if;
+
       --  If we are expanding a rhs of an assignment we need to check if tag
       --  propagation is needed. You might expect this processing to be in
       --  Analyze_Assignment but has to be done earlier (bottom-up) because the
       --  assignment might be transformed to a declaration for an unconstrained
       --  value if the expression is classwide.
 
-      if Nkind (N) = N_Function_Call
-        and then Is_Tag_Indeterminate (N)
-        and then Is_Entity_Name (Name (N))
+      if Nkind (Call_Node) = N_Function_Call
+        and then Is_Tag_Indeterminate (Call_Node)
+        and then Is_Entity_Name (Name (Call_Node))
       then
          declare
             Ass : Node_Id := Empty;
 
          begin
-            if Nkind (Parent (N)) = N_Assignment_Statement then
-               Ass := Parent (N);
+            if Nkind (Parent (Call_Node)) = N_Assignment_Statement then
+               Ass := Parent (Call_Node);
 
-            elsif Nkind (Parent (N)) = N_Qualified_Expression
-              and then Nkind (Parent (Parent (N))) = N_Assignment_Statement
+            elsif Nkind (Parent (Call_Node)) = N_Qualified_Expression
+              and then Nkind (Parent (Parent (Call_Node))) =
+                                                  N_Assignment_Statement
             then
-               Ass := Parent (Parent (N));
+               Ass := Parent (Parent (Call_Node));
 
-            elsif Nkind (Parent (N)) = N_Explicit_Dereference
-              and then Nkind (Parent (Parent (N))) = N_Assignment_Statement
+            elsif Nkind (Parent (Call_Node)) = N_Explicit_Dereference
+              and then Nkind (Parent (Parent (Call_Node))) =
+                                                  N_Assignment_Statement
             then
-               Ass := Parent (Parent (N));
+               Ass := Parent (Parent (Call_Node));
             end if;
 
             if Present (Ass)
               and then Is_Class_Wide_Type (Etype (Name (Ass)))
             then
-               if Is_Access_Type (Etype (N)) then
-                  if Designated_Type (Etype (N)) /=
+               if Is_Access_Type (Etype (Call_Node)) then
+                  if Designated_Type (Etype (Call_Node)) /=
                     Root_Type (Etype (Name (Ass)))
                   then
                      Error_Msg_NE
                        ("tag-indeterminate expression "
                          & " must have designated type& (RM 5.2 (6))",
-                           N, Root_Type (Etype (Name (Ass))));
+                         Call_Node, Root_Type (Etype (Name (Ass))));
                   else
-                     Propagate_Tag (Name (Ass), N);
+                     Propagate_Tag (Name (Ass), Call_Node);
                   end if;
 
-               elsif Etype (N) /= Root_Type (Etype (Name (Ass))) then
+               elsif Etype (Call_Node) /= Root_Type (Etype (Name (Ass))) then
                   Error_Msg_NE
                     ("tag-indeterminate expression must have type&"
-                     & "(RM 5.2 (6))", N, Root_Type (Etype (Name (Ass))));
+                     & "(RM 5.2 (6))",
+                     Call_Node, Root_Type (Etype (Name (Ass))));
 
                else
-                  Propagate_Tag (Name (Ass), N);
+                  Propagate_Tag (Name (Ass), Call_Node);
                end if;
 
                --  The call will be rewritten as a dispatching call, and
@@ -2586,50 +2970,113 @@ package body Exp_Ch6 is
       --  Ada 2005 (AI-251): If some formal is a class-wide interface, expand
       --  it to point to the correct secondary virtual table
 
-      if Nkind_In (N, N_Function_Call, N_Procedure_Call_Statement)
+      if Nkind_In (Call_Node, N_Function_Call, N_Procedure_Call_Statement)
         and then CW_Interface_Formals_Present
       then
-         Expand_Interface_Actuals (N);
+         Expand_Interface_Actuals (Call_Node);
       end if;
 
       --  Deals with Dispatch_Call if we still have a call, before expanding
       --  extra actuals since this will be done on the re-analysis of the
-      --  dispatching call. Note that we do not try to shorten the actual
-      --  list for a dispatching call, it would not make sense to do so.
-      --  Expansion of dispatching calls is suppressed when VM_Target, because
-      --  the VM back-ends directly handle the generation of dispatching
-      --  calls and would have to undo any expansion to an indirect call.
-
-      if Nkind_In (N, N_Function_Call, N_Procedure_Call_Statement)
-        and then Present (Controlling_Argument (N))
+      --  dispatching call. Note that we do not try to shorten the actual list
+      --  for a dispatching call, it would not make sense to do so. Expansion
+      --  of dispatching calls is suppressed when VM_Target, because the VM
+      --  back-ends directly handle the generation of dispatching calls and
+      --  would have to undo any expansion to an indirect call.
+
+      if Nkind_In (Call_Node, N_Function_Call, N_Procedure_Call_Statement)
+        and then Present (Controlling_Argument (Call_Node))
       then
-         if Tagged_Type_Expansion then
-            Expand_Dispatching_Call (N);
+         declare
+            Call_Typ   : constant Entity_Id := Etype (Call_Node);
+            Typ        : constant Entity_Id := Find_Dispatching_Type (Subp);
+            Eq_Prim_Op : Entity_Id := Empty;
+            New_Call   : Node_Id;
+            Param      : Node_Id;
+            Prev_Call  : Node_Id;
 
-            --  The following return is worrisome. Is it really OK to
-            --  skip all remaining processing in this procedure ???
+         begin
+            if not Is_Limited_Type (Typ) then
+               Eq_Prim_Op := Find_Prim_Op (Typ, Name_Op_Eq);
+            end if;
 
-            return;
+            if Tagged_Type_Expansion then
+               Expand_Dispatching_Call (Call_Node);
 
-         else
-            Apply_Tag_Checks (N);
+               --  The following return is worrisome. Is it really OK to skip
+               --  all remaining processing in this procedure ???
+
+               return;
 
-            --  Expansion of a dispatching call results in an indirect call,
-            --  which in turn causes current values to be killed (see
-            --  Resolve_Call), so on VM targets we do the call here to ensure
-            --  consistent warnings between VM and non-VM targets.
+            --  VM targets
 
-            Kill_Current_Values;
-         end if;
+            else
+               Apply_Tag_Checks (Call_Node);
+
+               --  If this is a dispatching "=", we must first compare the
+               --  tags so we generate: x.tag = y.tag and then x = y
+
+               if Subp = Eq_Prim_Op then
+
+                  --  Mark the node as analyzed to avoid reanalizing this
+                  --  dispatching call (which would cause a never-ending loop)
+
+                  Prev_Call := Relocate_Node (Call_Node);
+                  Set_Analyzed (Prev_Call);
+
+                  Param := First_Actual (Call_Node);
+                  New_Call :=
+                    Make_And_Then (Loc,
+                      Left_Opnd =>
+                           Make_Op_Eq (Loc,
+                             Left_Opnd =>
+                               Make_Selected_Component (Loc,
+                                 Prefix        => New_Value (Param),
+                                 Selector_Name =>
+                                   New_Reference_To (First_Tag_Component (Typ),
+                                                     Loc)),
+
+                             Right_Opnd =>
+                               Make_Selected_Component (Loc,
+                                 Prefix        =>
+                                   Unchecked_Convert_To (Typ,
+                                     New_Value (Next_Actual (Param))),
+                                 Selector_Name =>
+                                   New_Reference_To
+                                     (First_Tag_Component (Typ), Loc))),
+                      Right_Opnd => Prev_Call);
+
+                  Rewrite (Call_Node, New_Call);
+
+                  Analyze_And_Resolve
+                    (Call_Node, Call_Typ, Suppress => All_Checks);
+               end if;
+
+               --  Expansion of a dispatching call results in an indirect call,
+               --  which in turn causes current values to be killed (see
+               --  Resolve_Call), so on VM targets we do the call here to
+               --  ensure consistent warnings between VM and non-VM targets.
+
+               Kill_Current_Values;
+            end if;
+
+            --  If this is a dispatching "=" then we must update the reference
+            --  to the call node because we generated:
+            --     x.tag = y.tag and then x = y
+
+            if Subp = Eq_Prim_Op then
+               Call_Node := Right_Opnd (Call_Node);
+            end if;
+         end;
       end if;
 
       --  Similarly, expand calls to RCI subprograms on which pragma
       --  All_Calls_Remote applies. The rewriting will be reanalyzed
-      --  later. Do this only when the call comes from source since we do
-      --  not want such a rewriting to occur in expanded code.
+      --  later. Do this only when the call comes from source since we
+      --  do not want such a rewriting to occur in expanded code.
 
-      if Is_All_Remote_Call (N) then
-         Expand_All_Calls_Remote_Subprogram_Call (N);
+      if Is_All_Remote_Call (Call_Node) then
+         Expand_All_Calls_Remote_Subprogram_Call (Call_Node);
 
       --  Similarly, do not add extra actuals for an entry call whose entity
       --  is a protected procedure, or for an internal protected subprogram
@@ -2651,19 +3098,20 @@ package body Exp_Ch6 is
          end loop;
       end if;
 
-      --  At this point we have all the actuals, so this is the point at
-      --  which the various expansion activities for actuals is carried out.
+      --  At this point we have all the actuals, so this is the point at which
+      --  the various expansion activities for actuals is carried out.
 
-      Expand_Actuals (N, Subp);
+      Expand_Actuals (Call_Node, Subp);
 
-      --  If the subprogram is a renaming, or if it is inherited, replace it
-      --  in the call with the name of the actual subprogram being called.
-      --  If this is a dispatching call, the run-time decides what to call.
-      --  The Alias attribute does not apply to entries.
+      --  If the subprogram is a renaming, or if it is inherited, replace it in
+      --  the call with the name of the actual subprogram being called. If this
+      --  is a dispatching call, the run-time decides what to call. The Alias
+      --  attribute does not apply to entries.
 
-      if Nkind (N) /= N_Entry_Call_Statement
-        and then No (Controlling_Argument (N))
+      if Nkind (Call_Node) /= N_Entry_Call_Statement
+        and then No (Controlling_Argument (Call_Node))
         and then Present (Parent_Subp)
+        and then not Is_Direct_Deep_Call (Subp)
       then
          if Present (Inherited_From_Formal (Subp)) then
             Parent_Subp := Inherited_From_Formal (Subp);
@@ -2673,13 +3121,14 @@ package body Exp_Ch6 is
 
          --  The below setting of Entity is suspect, see F109-018 discussion???
 
-         Set_Entity (Name (N), Parent_Subp);
+         Set_Entity (Name (Call_Node), Parent_Subp);
 
          if Is_Abstract_Subprogram (Parent_Subp)
            and then not In_Instance
          then
             Error_Msg_NE
-              ("cannot call abstract subprogram &!", Name (N), Parent_Subp);
+              ("cannot call abstract subprogram &!",
+               Name (Call_Node), Parent_Subp);
          end if;
 
          --  Inspect all formals of derived subprogram Subp. Compare parameter
@@ -2715,7 +3164,7 @@ package body Exp_Ch6 is
                Parent_Typ : Entity_Id;
 
             begin
-               Actual := First_Actual (N);
+               Actual := First_Actual (Call_Node);
                Formal := First_Formal (Subp);
                Parent_Formal := First_Formal (Parent_Subp);
                while Present (Formal) loop
@@ -2802,12 +3251,15 @@ package body Exp_Ch6 is
 
       --  Check for violation of No_Abort_Statements
 
-      if Is_RTE (Subp, RE_Abort_Task) then
-         Check_Restriction (No_Abort_Statements, N);
+      if Restriction_Check_Required (No_Abort_Statements)
+        and then Is_RTE (Subp, RE_Abort_Task)
+      then
+         Check_Restriction (No_Abort_Statements, Call_Node);
 
       --  Check for violation of No_Dynamic_Attachment
 
-      elsif RTU_Loaded (Ada_Interrupts)
+      elsif Restriction_Check_Required (No_Dynamic_Attachment)
+        and then RTU_Loaded (Ada_Interrupts)
         and then (Is_RTE (Subp, RE_Is_Reserved)      or else
                   Is_RTE (Subp, RE_Is_Attached)      or else
                   Is_RTE (Subp, RE_Current_Handler)  or else
@@ -2816,29 +3268,29 @@ package body Exp_Ch6 is
                   Is_RTE (Subp, RE_Detach_Handler)   or else
                   Is_RTE (Subp, RE_Reference))
       then
-         Check_Restriction (No_Dynamic_Attachment, N);
+         Check_Restriction (No_Dynamic_Attachment, Call_Node);
       end if;
 
       --  Deal with case where call is an explicit dereference
 
-      if Nkind (Name (N)) = N_Explicit_Dereference then
+      if Nkind (Name (Call_Node)) = N_Explicit_Dereference then
 
       --  Handle case of access to protected subprogram type
 
          if Is_Access_Protected_Subprogram_Type
-              (Base_Type (Etype (Prefix (Name (N)))))
+              (Base_Type (Etype (Prefix (Name (Call_Node)))))
          then
-            --  If this is a call through an access to protected operation,
-            --  the prefix has the form (object'address, operation'access).
-            --  Rewrite as a for other protected calls: the object is the
-            --  first parameter of the list of actuals.
+            --  If this is a call through an access to protected operation, the
+            --  prefix has the form (object'address, operation'access). Rewrite
+            --  as a for other protected calls: the object is the 1st parameter
+            --  of the list of actuals.
 
             declare
                Call : Node_Id;
                Parm : List_Id;
                Nam  : Node_Id;
                Obj  : Node_Id;
-               Ptr  : constant Node_Id := Prefix (Name (N));
+               Ptr  : constant Node_Id := Prefix (Name (Call_Node));
 
                T : constant Entity_Id :=
                      Equivalent_Type (Base_Type (Etype (Ptr)));
@@ -2863,8 +3315,8 @@ package body Exp_Ch6 is
                  Make_Explicit_Dereference (Loc,
                    Prefix => Nam);
 
-               if Present (Parameter_Associations (N))  then
-                  Parm := Parameter_Associations (N);
+               if Present (Parameter_Associations (Call_Node))  then
+                  Parm := Parameter_Associations (Call_Node);
                else
                   Parm := New_List;
                end if;
@@ -2883,7 +3335,7 @@ package body Exp_Ch6 is
                       Parameter_Associations => Parm);
                end if;
 
-               Set_First_Named_Actual (Call, First_Named_Actual (N));
+               Set_First_Named_Actual (Call, First_Named_Actual (Call_Node));
                Set_Etype (Call, Etype (D_T));
 
                --  We do not re-analyze the call to avoid infinite recursion.
@@ -2891,7 +3343,7 @@ package body Exp_Ch6 is
                --  the checks on the prefix that would otherwise be emitted
                --  when resolving a call.
 
-               Rewrite (N, Call);
+               Rewrite (Call_Node, Call);
                Analyze (Nam);
                Apply_Access_Check (Nam);
                Analyze (Obj);
@@ -2906,20 +3358,20 @@ package body Exp_Ch6 is
 
       --  In the case where the intrinsic is to be processed by the back end,
       --  the call to Expand_Intrinsic_Call will do nothing, which is fine,
-      --  since the idea in this case is to pass the call unchanged.
-      --  If the intrinsic is an inherited unchecked conversion, and the
-      --  derived type is the target type of the conversion, we must retain
-      --  it as the return type of the expression. Otherwise the expansion
-      --  below, which uses the parent operation, will yield the wrong type.
+      --  since the idea in this case is to pass the call unchanged. If the
+      --  intrinsic is an inherited unchecked conversion, and the derived type
+      --  is the target type of the conversion, we must retain it as the return
+      --  type of the expression. Otherwise the expansion below, which uses the
+      --  parent operation, will yield the wrong type.
 
       if Is_Intrinsic_Subprogram (Subp) then
-         Expand_Intrinsic_Call (N, Subp);
+         Expand_Intrinsic_Call (Call_Node, Subp);
 
-         if Nkind (N) = N_Unchecked_Type_Conversion
+         if Nkind (Call_Node) = N_Unchecked_Type_Conversion
            and then Parent_Subp /= Orig_Subp
            and then Etype (Parent_Subp) /= Etype (Orig_Subp)
          then
-            Set_Etype (N, Etype (Orig_Subp));
+            Set_Etype (Call_Node, Etype (Orig_Subp));
          end if;
 
          return;
@@ -2941,13 +3393,13 @@ package body Exp_Ch6 is
          --  that tree generated is the same in both cases, for Inspector use.
 
          if Is_RTE (Subp, RE_To_Address) then
-            Rewrite (N,
+            Rewrite (Call_Node,
               Unchecked_Convert_To
-                (RTE (RE_Address), Relocate_Node (First_Actual (N))));
+                (RTE (RE_Address), Relocate_Node (First_Actual (Call_Node))));
             return;
 
          elsif Is_Null_Procedure (Subp)  then
-            Rewrite (N, Make_Null_Statement (Loc));
+            Rewrite (Call_Node, Make_Null_Statement (Loc));
             return;
          end if;
 
@@ -3021,8 +3473,8 @@ package body Exp_Ch6 is
                else
                   Bod := Body_To_Inline (Spec);
 
-                  if (In_Extended_Main_Code_Unit (N)
-                        or else In_Extended_Main_Code_Unit (Parent (N))
+                  if (In_Extended_Main_Code_Unit (Call_Node)
+                        or else In_Extended_Main_Code_Unit (Parent (Call_Node))
                         or else Has_Pragma_Inline_Always (Subp))
                     and then (not In_Same_Extended_Unit (Sloc (Bod), Loc)
                                or else
@@ -3042,7 +3494,7 @@ package body Exp_Ch6 is
                   --  visible a private entity in the body of the main unit,
                   --  that gigi will see before its sees its proper definition.
 
-                  elsif not (In_Extended_Main_Code_Unit (N))
+                  elsif not (In_Extended_Main_Code_Unit (Call_Node))
                     and then In_Package_Body
                   then
                      Must_Inline := not In_Extended_Main_Source_Unit (Subp);
@@ -3050,7 +3502,7 @@ package body Exp_Ch6 is
                end if;
 
                if Must_Inline then
-                  Expand_Inlined_Call (N, Subp, Orig_Subp);
+                  Expand_Inlined_Call (Call_Node, Subp, Orig_Subp);
 
                else
                   --  Let the back end handle it
@@ -3059,13 +3511,13 @@ package body Exp_Ch6 is
 
                   if Front_End_Inlining
                     and then Nkind (Spec) = N_Subprogram_Declaration
-                    and then (In_Extended_Main_Code_Unit (N))
+                    and then (In_Extended_Main_Code_Unit (Call_Node))
                     and then No (Body_To_Inline (Spec))
                     and then not Has_Completion (Subp)
                     and then In_Same_Extended_Unit (Sloc (Spec), Loc)
                   then
                      Cannot_Inline
-                      ("cannot inline& (body not seen yet)?", N, Subp);
+                      ("cannot inline& (body not seen yet)?", Call_Node, Subp);
                   end if;
                end if;
             end Inlined_Subprogram;
@@ -3083,7 +3535,7 @@ package body Exp_Ch6 is
 
       Scop := Scope (Subp);
 
-      if Nkind (N) /= N_Entry_Call_Statement
+      if Nkind (Call_Node) /= N_Entry_Call_Statement
         and then Is_Protected_Type (Scop)
         and then Ekind (Subp) /= E_Subprogram_Type
         and then not Is_Eliminated (Subp)
@@ -3091,24 +3543,40 @@ package body Exp_Ch6 is
          --  If the call is an internal one, it is rewritten as a call to the
          --  corresponding unprotected subprogram.
 
-         Expand_Protected_Subprogram_Call (N, Subp, Scop);
+         Expand_Protected_Subprogram_Call (Call_Node, Subp, Scop);
       end if;
 
-      --  Functions returning controlled objects need special attention:
-      --  if the return type is limited, the context is an initialization
-      --  and different processing applies. If the call is to a protected
-      --  function, the expansion above will call Expand_Call recusively.
-      --  To prevent a double attachment, check that the current call is
-      --  not a rewriting of a protected function call.
+      --  Functions returning controlled objects need special attention. If
+      --  the return type is limited, then the context is initialization and
+      --  different processing applies. If the call is to a protected function,
+      --  the expansion above will call Expand_Call recursively. Otherwise the
+      --  function call is transformed into a temporary which obtains the
+      --  result from the secondary stack.
 
-      if Needs_Finalization (Etype (Subp))
-        and then not Is_Inherently_Limited_Type (Etype (Subp))
-        and then
-          (No (First_Formal (Subp))
-            or else
-              not Is_Concurrent_Record_Type (Etype (First_Formal (Subp))))
-      then
-         Expand_Ctrl_Function_Call (N);
+      if Needs_Finalization (Etype (Subp)) then
+         if not Is_Immutably_Limited_Type (Etype (Subp))
+           and then
+             (No (First_Formal (Subp))
+                or else
+                  not Is_Concurrent_Record_Type (Etype (First_Formal (Subp))))
+         then
+            Expand_Ctrl_Function_Call (Call_Node);
+
+         --  Build-in-place function calls which appear in anonymous contexts
+         --  need a transient scope to ensure the proper finalization of the
+         --  intermediate result after its use.
+
+         elsif Is_Build_In_Place_Function_Call (Call_Node)
+           and then Nkind_In (Parent (Call_Node), N_Attribute_Reference,
+                                          N_Function_Call,
+                                          N_Indexed_Component,
+                                          N_Object_Renaming_Declaration,
+                                          N_Procedure_Call_Statement,
+                                          N_Selected_Component,
+                                          N_Slice)
+         then
+            Establish_Transient_Scope (Call_Node, Sec_Stack => True);
+         end if;
       end if;
 
       --  Test for First_Optional_Parameter, and if so, truncate parameter list
@@ -3132,7 +3600,7 @@ package body Exp_Ch6 is
             --  the validity of the parameter before setting it.
 
             Formal := First_Formal (Subp);
-            Actual := First_Actual (N);
+            Actual := First_Actual (Call_Node);
             while Formal /= First_Optional_Parameter (Subp) loop
                Last_Keep_Arg := Actual;
                Next_Formal (Formal);
@@ -3166,8 +3634,8 @@ package body Exp_Ch6 is
             --  If no arguments, delete entire list, this is the easy case
 
             if No (Last_Keep_Arg) then
-               Set_Parameter_Associations (N, No_List);
-               Set_First_Named_Actual (N, Empty);
+               Set_Parameter_Associations (Call_Node, No_List);
+               Set_First_Named_Actual (Call_Node, Empty);
 
             --  Case where at the last retained argument is positional. This
             --  is also an easy case, since the retained arguments are already
@@ -3179,7 +3647,7 @@ package body Exp_Ch6 is
                   Discard_Node (Remove_Next (Last_Keep_Arg));
                end loop;
 
-               Set_First_Named_Actual (N, Empty);
+               Set_First_Named_Actual (Call_Node, Empty);
 
             --  This is the annoying case where the last retained argument
             --  is a named parameter. Since the original arguments are not
@@ -3196,14 +3664,22 @@ package body Exp_Ch6 is
                   --  list (they are still chained using First_Named_Actual
                   --  and Next_Named_Actual, so we have not lost them!)
 
-                  Temp := First (Parameter_Associations (N));
+                  Temp := First (Parameter_Associations (Call_Node));
 
                   --  Case of all parameters named, remove them all
 
                   if Nkind (Temp) = N_Parameter_Association then
-                     while Is_Non_Empty_List (Parameter_Associations (N)) loop
-                        Temp := Remove_Head (Parameter_Associations (N));
+                     --  Suppress warnings to avoid warning on possible
+                     --  infinite loop (because Call_Node is not modified).
+
+                     pragma Warnings (Off);
+                     while Is_Non_Empty_List
+                             (Parameter_Associations (Call_Node))
+                     loop
+                        Temp :=
+                          Remove_Head (Parameter_Associations (Call_Node));
                      end loop;
+                     pragma Warnings (On);
 
                   --  Case of mixed positional/named, remove named parameters
 
@@ -3223,11 +3699,11 @@ package body Exp_Ch6 is
                   --  touched since we are only reordering them on the actual
                   --  parameter association list.
 
-                  Passoc := Parent (First_Named_Actual (N));
+                  Passoc := Parent (First_Named_Actual (Call_Node));
                   loop
                      Temp := Relocate_Node (Passoc);
                      Append_To
-                       (Parameter_Associations (N), Temp);
+                       (Parameter_Associations (Call_Node), Temp);
                      exit when
                        Last_Keep_Arg = Explicit_Actual_Parameter (Passoc);
                      Passoc := Parent (Next_Named_Actual (Passoc));
@@ -3248,6 +3724,33 @@ package body Exp_Ch6 is
       end if;
    end Expand_Call;
 
+   -------------------------------
+   -- Expand_Ctrl_Function_Call --
+   -------------------------------
+
+   procedure Expand_Ctrl_Function_Call (N : Node_Id) is
+   begin
+      --  Optimization, if the returned value (which is on the sec-stack) is
+      --  returned again, no need to copy/readjust/finalize, we can just pass
+      --  the value thru (see Expand_N_Simple_Return_Statement), and thus no
+      --  attachment is needed
+
+      if Nkind (Parent (N)) = N_Simple_Return_Statement then
+         return;
+      end if;
+
+      --  Resolution is now finished, make sure we don't start analysis again
+      --  because of the duplication.
+
+      Set_Analyzed (N);
+
+      --  A function which returns a controlled object uses the secondary
+      --  stack. Rewrite the call into a temporary which obtains the result of
+      --  the function using 'reference.
+
+      Remove_Side_Effects (N);
+   end Expand_Ctrl_Function_Call;
+
    --------------------------
    -- Expand_Inlined_Call --
    --------------------------
@@ -3276,8 +3779,15 @@ package body Exp_Ch6 is
       New_A    : Node_Id;
       Num_Ret  : Int := 0;
       Ret_Type : Entity_Id;
-      Targ     : Node_Id;
-      Targ1    : Node_Id;
+
+      Targ : Node_Id;
+      --  The target of the call. If context is an assignment statement then
+      --  this is the left-hand side of the assignment. else it is a temporary
+      --  to which the return value is assigned prior to rewriting the call.
+
+      Targ1 : Node_Id;
+      --  A separate target used when the return type is unconstrained
+
       Temp     : Entity_Id;
       Temp_Typ : Entity_Id;
 
@@ -3285,8 +3795,8 @@ package body Exp_Ch6 is
       --  Entity in declaration in an extended_return_statement
 
       Is_Unc : constant Boolean :=
-                    Is_Array_Type (Etype (Subp))
-                      and then not Is_Constrained (Etype (Subp));
+                 Is_Array_Type (Etype (Subp))
+                   and then not Is_Constrained (Etype (Subp));
       --  If the type returned by the function is unconstrained and the call
       --  can be inlined, special processing is required.
 
@@ -3377,6 +3887,7 @@ package body Exp_Ch6 is
                   Rewrite (N, New_Copy (A));
                end if;
             end if;
+
             return Skip;
 
          elsif Is_Entity_Name (N)
@@ -3427,8 +3938,8 @@ package body Exp_Ch6 is
                if Nkind_In (Expression (N), N_Aggregate, N_Null) then
                   Ret :=
                     Make_Qualified_Expression (Sloc (N),
-                       Subtype_Mark => New_Occurrence_Of (Ret_Type, Sloc (N)),
-                       Expression => Relocate_Node (Expression (N)));
+                      Subtype_Mark => New_Occurrence_Of (Ret_Type, Sloc (N)),
+                      Expression => Relocate_Node (Expression (N)));
                else
                   Ret :=
                     Unchecked_Convert_To
@@ -3438,12 +3949,12 @@ package body Exp_Ch6 is
                if Nkind (Targ) = N_Defining_Identifier then
                   Rewrite (N,
                     Make_Assignment_Statement (Loc,
-                      Name => New_Occurrence_Of (Targ, Loc),
+                      Name       => New_Occurrence_Of (Targ, Loc),
                       Expression => Ret));
                else
                   Rewrite (N,
                     Make_Assignment_Statement (Loc,
-                      Name => New_Copy (Targ),
+                      Name       => New_Copy (Targ),
                       Expression => Ret));
                end if;
 
@@ -3451,19 +3962,17 @@ package body Exp_Ch6 is
 
                if Present (Exit_Lab) then
                   Insert_After (N,
-                    Make_Goto_Statement (Loc,
-                      Name => New_Copy (Lab_Id)));
+                    Make_Goto_Statement (Loc, Name => New_Copy (Lab_Id)));
                end if;
             end if;
 
             return OK;
 
-         elsif Nkind (N) = N_Extended_Return_Statement then
-
-            --  An extended return becomes a block whose first statement is
-            --  the assignment of the initial expression of the return object
-            --  to the target of the call itself.
+         --  An extended return becomes a block whose first statement is the
+         --  assignment of the initial expression of the return object to the
+         --  target of the call itself.
 
+         elsif Nkind (N) = N_Extended_Return_Statement then
             declare
                Return_Decl : constant Entity_Id :=
                                First (Return_Object_Declarations (N));
@@ -3476,12 +3985,12 @@ package body Exp_Ch6 is
                   if Nkind (Targ) = N_Defining_Identifier then
                      Assign :=
                        Make_Assignment_Statement (Loc,
-                         Name => New_Occurrence_Of (Targ, Loc),
+                         Name       => New_Occurrence_Of (Targ, Loc),
                          Expression => Expression (Return_Decl));
                   else
                      Assign :=
                        Make_Assignment_Statement (Loc,
-                         Name => New_Copy (Targ),
+                         Name       => New_Copy (Targ),
                          Expression => Expression (Return_Decl));
                   end if;
 
@@ -3547,7 +4056,6 @@ package body Exp_Ch6 is
            and then Nkind (Fst) = N_Assignment_Statement
            and then No (Next (Fst))
          then
-
             --  The function call may have been rewritten as the temporary
             --  that holds the result of the call, in which case remove the
             --  now useless declaration.
@@ -3567,12 +4075,20 @@ package body Exp_Ch6 is
 
             Insert_After (Parent (Entity (N)), Blk);
 
+         --  If the context is an assignment, and the left-hand side is free of
+         --  side-effects, the replacement is also safe.
+         --  Can this be generalized further???
+
          elsif Nkind (Parent (N)) = N_Assignment_Statement
            and then
             (Is_Entity_Name (Name (Parent (N)))
-               or else
-                  (Nkind (Name (Parent (N))) = N_Explicit_Dereference
-                    and then Is_Entity_Name (Prefix (Name (Parent (N))))))
+              or else
+                (Nkind (Name (Parent (N))) = N_Explicit_Dereference
+                  and then Is_Entity_Name (Prefix (Name (Parent (N)))))
+
+              or else
+                (Nkind (Name (Parent (N))) = N_Selected_Component
+                  and then Is_Entity_Name (Prefix (Name (Parent (N))))))
          then
             --  Replace assignment with the block
 
@@ -3608,6 +4124,7 @@ package body Exp_Ch6 is
 
       procedure Rewrite_Procedure_Call (N : Node_Id; Blk : Node_Id) is
          HSS  : constant Node_Id := Handled_Statement_Sequence (Blk);
+
       begin
          --  If there is a transient scope for N, this will be the scope of the
          --  actions for N, and the statements in Blk need to be within this
@@ -3689,7 +4206,6 @@ package body Exp_Ch6 is
    --  Start of processing for Expand_Inlined_Call
 
    begin
-
       --  Check for an illegal attempt to inline a recursive procedure. If the
       --  subprogram has parameters this is detected when trying to supply a
       --  binding for parameters that already have one. For parameterless
@@ -3737,22 +4253,27 @@ package body Exp_Ch6 is
          Set_Declarations (Blk, New_List);
       end if;
 
-      --  For the unconstrained case, capture the name of the local
-      --  variable that holds the result. This must be the first declaration
-      --  in the block, because its bounds cannot depend on local variables.
-      --  Otherwise there is no way to declare the result outside of the
-      --  block. Needless to say, in general the bounds will depend on the
-      --  actuals in the call.
+      --  For the unconstrained case, capture the name of the local variable
+      --  that holds the result. This must be the first declaration in the
+      --  block, because its bounds cannot depend on local variables. Otherwise
+      --  there is no way to declare the result outside of the block. Needless
+      --  to say, in general the bounds will depend on the actuals in the call.
+
+      --  If the context is an assignment statement, as is the case for the
+      --  expansion of an extended return, the left-hand side provides bounds
+      --  even if the return type is unconstrained.
 
       if Is_Unc then
-         Targ1 := Defining_Identifier (First (Declarations (Blk)));
+         if Nkind (Parent (N)) /= N_Assignment_Statement then
+            Targ1 := Defining_Identifier (First (Declarations (Blk)));
+         else
+            Targ1 := Name (Parent (N));
+         end if;
       end if;
 
       --  If this is a derived function, establish the proper return type
 
-      if Present (Orig_Subp)
-        and then Orig_Subp /= Subp
-      then
+      if Present (Orig_Subp) and then Orig_Subp /= Subp then
          Ret_Type := Etype (Orig_Subp);
       else
          Ret_Type := Etype (Subp);
@@ -3777,8 +4298,7 @@ package body Exp_Ch6 is
 
          if Is_Class_Wide_Type (Etype (F))
            or else (Is_Access_Type (Etype (F))
-                      and then
-                    Is_Class_Wide_Type (Designated_Type (Etype (F))))
+                     and then Is_Class_Wide_Type (Designated_Type (Etype (F))))
          then
             Temp_Typ := Etype (F);
 
@@ -3786,7 +4306,6 @@ package body Exp_Ch6 is
            and then Etype (F) /= Base_Type (Etype (F))
          then
             Temp_Typ := Etype (F);
-
          else
             Temp_Typ := Etype (A);
          end if;
@@ -3812,13 +4331,13 @@ package body Exp_Ch6 is
 
            or else
              (Nkind_In (A, N_Real_Literal,
-                            N_Integer_Literal,
-                            N_Character_Literal)
-                and then not Address_Taken (F))
+                           N_Integer_Literal,
+                           N_Character_Literal)
+               and then not Address_Taken (F))
          then
             if Etype (F) /= Etype (A) then
                Set_Renamed_Object
-                (F, Unchecked_Convert_To (Etype (F), Relocate_Node (A)));
+                 (F, Unchecked_Convert_To (Etype (F), Relocate_Node (A)));
             else
                Set_Renamed_Object (F, A);
             end if;
@@ -3862,19 +4381,18 @@ package body Exp_Ch6 is
             --  code will have the same semantics.
 
             if Ekind (F) = E_In_Parameter
-              and then not Is_Limited_Type (Etype (A))
-              and then not Is_Tagged_Type  (Etype (A))
+              and then not Is_By_Reference_Type (Etype (A))
               and then
-               (not Is_Array_Type (Etype (A))
-                 or else not Is_Object_Reference (A)
-                 or else Is_Bit_Packed_Array (Etype (A)))
+                (not Is_Array_Type (Etype (A))
+                  or else not Is_Object_Reference (A)
+                  or else Is_Bit_Packed_Array (Etype (A)))
             then
                Decl :=
                  Make_Object_Declaration (Loc,
                    Defining_Identifier => Temp,
-                   Constant_Present => True,
-                   Object_Definition => New_Occurrence_Of (Temp_Typ, Loc),
-                   Expression => New_A);
+                   Constant_Present    => True,
+                   Object_Definition   => New_Occurrence_Of (Temp_Typ, Loc),
+                   Expression          => New_A);
             else
                Decl :=
                  Make_Object_Renaming_Declaration (Loc,
@@ -3892,10 +4410,10 @@ package body Exp_Ch6 is
       end loop;
 
       --  Establish target of function call. If context is not assignment or
-      --  declaration, create a temporary as a target. The declaration for
-      --  the temporary may be subsequently optimized away if the body is a
-      --  single expression, or if the left-hand side of the assignment is
-      --  simple enough, i.e. an entity or an explicit dereference of one.
+      --  declaration, create a temporary as a target. The declaration for the
+      --  temporary may be subsequently optimized away if the body is a single
+      --  expression, or if the left-hand side of the assignment is simple
+      --  enough, i.e. an entity or an explicit dereference of one.
 
       if Ekind (Subp) = E_Function then
          if Nkind (Parent (N)) = N_Assignment_Statement
@@ -3909,6 +4427,12 @@ package body Exp_Ch6 is
          then
             Targ := Name (Parent (N));
 
+         elsif Nkind (Parent (N)) = N_Assignment_Statement
+           and then Nkind (Name (Parent (N))) = N_Selected_Component
+           and then Is_Entity_Name (Prefix (Name (Parent (N))))
+         then
+            Targ := New_Copy_Tree (Name (Parent (N)));
+
          elsif Nkind (Parent (N)) = N_Object_Declaration
            and then Is_Limited_Type (Etype (Subp))
          then
@@ -3925,11 +4449,13 @@ package body Exp_Ch6 is
             --  eventually be possible to remove that temporary and use the
             --  result variable directly.
 
-            if Is_Unc then
+            if Is_Unc
+              and then Nkind (Parent (N)) /= N_Assignment_Statement
+            then
                Decl :=
                  Make_Object_Declaration (Loc,
                    Defining_Identifier => Temp,
-                   Object_Definition =>
+                   Object_Definition   =>
                      New_Copy_Tree (Object_Definition (Parent (Targ1))));
 
                Replace_Formals (Decl);
@@ -3938,8 +4464,7 @@ package body Exp_Ch6 is
                Decl :=
                  Make_Object_Declaration (Loc,
                    Defining_Identifier => Temp,
-                   Object_Definition =>
-                     New_Occurrence_Of (Ret_Type, Loc));
+                   Object_Definition   => New_Occurrence_Of (Ret_Type, Loc));
 
                Set_Etype (Temp, Ret_Type);
             end if;
@@ -3959,9 +4484,7 @@ package body Exp_Ch6 is
       Replace_Formals (Blk);
       Set_Parent (Blk, N);
 
-      if not Comes_From_Source (Subp)
-        or else Is_Predef
-      then
+      if not Comes_From_Source (Subp) or else Is_Predef then
          Reset_Slocs (Blk);
       end if;
 
@@ -3973,7 +4496,7 @@ package body Exp_Ch6 is
          if Num_Ret = 1
            and then
              Nkind (Last (Statements (Handled_Statement_Sequence (Blk)))) =
-               N_Goto_Statement
+                                                            N_Goto_Statement
          then
             Remove (Last (Statements (Handled_Statement_Sequence (Blk))));
          else
@@ -4011,6 +4534,7 @@ package body Exp_Ch6 is
 
       if Ekind (Subp) = E_Procedure then
          Rewrite_Procedure_Call (N, Blk);
+
       else
          Rewrite_Function_Call (N, Blk);
 
@@ -4038,217 +4562,1206 @@ package body Exp_Ch6 is
       end loop;
    end Expand_Inlined_Call;
 
-   ----------------------------
-   -- Expand_N_Function_Call --
-   ----------------------------
-
-   procedure Expand_N_Function_Call (N : Node_Id) is
-   begin
-      Expand_Call (N);
+   ----------------------------------------
+   -- Expand_N_Extended_Return_Statement --
+   ----------------------------------------
 
-      --  If the return value of a foreign compiled function is VAX Float, then
-      --  expand the return (adjusts the location of the return value on
-      --  Alpha/VMS, no-op everywhere else).
-      --  Comes_From_Source intercepts recursive expansion.
+   --  If there is a Handled_Statement_Sequence, we rewrite this:
 
-      if Vax_Float (Etype (N))
-        and then Nkind (N) = N_Function_Call
-        and then Present (Name (N))
-        and then Present (Entity (Name (N)))
-        and then Has_Foreign_Convention (Entity (Name (N)))
-        and then Comes_From_Source (Parent (N))
-      then
-         Expand_Vax_Foreign_Return (N);
-      end if;
-   end Expand_N_Function_Call;
+   --     return Result : T := <expression> do
+   --        <handled_seq_of_stms>
+   --     end return;
 
-   ---------------------------------------
-   -- Expand_N_Procedure_Call_Statement --
-   ---------------------------------------
+   --  to be:
 
-   procedure Expand_N_Procedure_Call_Statement (N : Node_Id) is
-   begin
-      Expand_Call (N);
-   end Expand_N_Procedure_Call_Statement;
+   --     declare
+   --        Result : T := <expression>;
+   --     begin
+   --        <handled_seq_of_stms>
+   --        return Result;
+   --     end;
 
-   ------------------------------
-   -- Expand_N_Subprogram_Body --
-   ------------------------------
+   --  Otherwise (no Handled_Statement_Sequence), we rewrite this:
 
-   --  Add poll call if ATC polling is enabled, unless the body will be inlined
-   --  by the back-end.
+   --     return Result : T := <expression>;
 
-   --  Add dummy push/pop label nodes at start and end to clear any local
-   --  exception indications if local-exception-to-goto optimization is active.
+   --  to be:
 
-   --  Add return statement if last statement in body is not a return statement
-   --  (this makes things easier on Gigi which does not want to have to handle
-   --  a missing return).
+   --     return <expression>;
 
-   --  Add call to Activate_Tasks if body is a task activator
+   --  unless it's build-in-place or there's no <expression>, in which case
+   --  we generate:
 
-   --  Deal with possible detection of infinite recursion
+   --     declare
+   --        Result : T := <expression>;
+   --     begin
+   --        return Result;
+   --     end;
 
-   --  Eliminate body completely if convention stubbed
+   --  Note that this case could have been written by the user as an extended
+   --  return statement, or could have been transformed to this from a simple
+   --  return statement.
 
-   --  Encode entity names within body, since we will not need to reference
-   --  these entities any longer in the front end.
+   --  That is, we need to have a reified return object if there are statements
+   --  (which might refer to it) or if we're doing build-in-place (so we can
+   --  set its address to the final resting place or if there is no expression
+   --  (in which case default initial values might need to be set).
 
-   --  Initialize scalar out parameters if Initialize/Normalize_Scalars
+   procedure Expand_N_Extended_Return_Statement (N : Node_Id) is
+      Loc : constant Source_Ptr := Sloc (N);
 
-   --  Reset Pure indication if any parameter has root type System.Address
+      Par_Func     : constant Entity_Id :=
+                       Return_Applies_To (Return_Statement_Entity (N));
+      Result_Subt  : constant Entity_Id := Etype (Par_Func);
+      Ret_Obj_Id   : constant Entity_Id :=
+                       First_Entity (Return_Statement_Entity (N));
+      Ret_Obj_Decl : constant Node_Id := Parent (Ret_Obj_Id);
+
+      Is_Build_In_Place : constant Boolean :=
+                            Is_Build_In_Place_Function (Par_Func);
+
+      Exp         : Node_Id;
+      HSS         : Node_Id;
+      Result      : Node_Id;
+      Return_Stmt : Node_Id;
+      Stmts       : List_Id;
+
+      function Build_Heap_Allocator
+        (Temp_Id    : Entity_Id;
+         Temp_Typ   : Entity_Id;
+         Func_Id    : Entity_Id;
+         Ret_Typ    : Entity_Id;
+         Alloc_Expr : Node_Id) return Node_Id;
+      --  Create the statements necessary to allocate a return object on the
+      --  caller's master. The master is available through implicit parameter
+      --  BIPfinalizationmaster.
+      --
+      --    if BIPfinalizationmaster /= null then
+      --       declare
+      --          type Ptr_Typ is access Ret_Typ;
+      --          for Ptr_Typ'Storage_Pool use
+      --                Base_Pool (BIPfinalizationmaster.all).all;
+      --          Local : Ptr_Typ;
+      --
+      --       begin
+      --          procedure Allocate (...) is
+      --          begin
+      --             System.Storage_Pools.Subpools.Allocate_Any (...);
+      --          end Allocate;
+      --
+      --          Local := <Alloc_Expr>;
+      --          Temp_Id := Temp_Typ (Local);
+      --       end;
+      --    end if;
+      --
+      --  Temp_Id is the temporary which is used to reference the internally
+      --  created object in all allocation forms. Temp_Typ is the type of the
+      --  temporary. Func_Id is the enclosing function. Ret_Typ is the return
+      --  type of Func_Id. Alloc_Expr is the actual allocator.
+
+      function Move_Activation_Chain return Node_Id;
+      --  Construct a call to System.Tasking.Stages.Move_Activation_Chain
+      --  with parameters:
+      --    From         current activation chain
+      --    To           activation chain passed in by the caller
+      --    New_Master   master passed in by the caller
 
-   --  Wrap thread body
+      --------------------------
+      -- Build_Heap_Allocator --
+      --------------------------
 
-   procedure Expand_N_Subprogram_Body (N : Node_Id) is
-      Loc      : constant Source_Ptr := Sloc (N);
-      H        : constant Node_Id    := Handled_Statement_Sequence (N);
-      Body_Id  : Entity_Id;
-      Except_H : Node_Id;
-      L        : List_Id;
-      Spec_Id  : Entity_Id;
+      function Build_Heap_Allocator
+        (Temp_Id    : Entity_Id;
+         Temp_Typ   : Entity_Id;
+         Func_Id    : Entity_Id;
+         Ret_Typ    : Entity_Id;
+         Alloc_Expr : Node_Id) return Node_Id
+      is
+      begin
+         pragma Assert (Is_Build_In_Place_Function (Func_Id));
 
-      procedure Add_Return (S : List_Id);
-      --  Append a return statement to the statement sequence S if the last
-      --  statement is not already a return or a goto statement. Note that
-      --  the latter test is not critical, it does not matter if we add a few
-      --  extra returns, since they get eliminated anyway later on.
+         --  Processing for build-in-place object allocation. This is disabled
+         --  on .NET/JVM because the targets do not support pools.
 
-      ----------------
-      -- Add_Return --
-      ----------------
+         if VM_Target = No_VM
+           and then Needs_Finalization (Ret_Typ)
+         then
+            declare
+               Decls      : constant List_Id := New_List;
+               Fin_Mas_Id : constant Entity_Id :=
+                              Build_In_Place_Formal
+                                (Func_Id, BIP_Finalization_Master);
+               Stmts      : constant List_Id := New_List;
+               Desig_Typ  : Entity_Id;
+               Local_Id   : Entity_Id;
+               Pool_Id    : Entity_Id;
+               Ptr_Typ    : Entity_Id;
 
-      procedure Add_Return (S : List_Id) is
-         Last_Stm : Node_Id;
-         Loc      : Source_Ptr;
+            begin
+               --  Generate:
+               --    Pool_Id renames Base_Pool (BIPfinalizationmaster.all).all;
 
-      begin
-         --  Get last statement, ignoring any Pop_xxx_Label nodes, which are
-         --  not relevant in this context since they are not executable.
+               Pool_Id := Make_Temporary (Loc, 'P');
 
-         Last_Stm := Last (S);
-         while Nkind (Last_Stm) in N_Pop_xxx_Label loop
-            Prev (Last_Stm);
-         end loop;
+               Append_To (Decls,
+                 Make_Object_Renaming_Declaration (Loc,
+                   Defining_Identifier => Pool_Id,
+                   Subtype_Mark        =>
+                     New_Reference_To (RTE (RE_Root_Storage_Pool), Loc),
+                   Name                =>
+                     Make_Explicit_Dereference (Loc,
+                       Prefix =>
+                         Make_Function_Call (Loc,
+                           Name                   =>
+                             New_Reference_To (RTE (RE_Base_Pool), Loc),
+                           Parameter_Associations => New_List (
+                             Make_Explicit_Dereference (Loc,
+                               Prefix =>
+                                 New_Reference_To (Fin_Mas_Id, Loc)))))));
+
+               --  Create an access type which uses the storage pool of the
+               --  caller's master. This additional type is necessary because
+               --  the finalization master cannot be associated with the type
+               --  of the temporary. Otherwise the secondary stack allocation
+               --  will fail.
+
+               Desig_Typ := Ret_Typ;
+
+               --  Ensure that the build-in-place machinery uses a fat pointer
+               --  when allocating an unconstrained array on the heap. In this
+               --  case the result object type is a constrained array type even
+               --  though the function type is unconstrained.
+
+               if Ekind (Desig_Typ) = E_Array_Subtype then
+                  Desig_Typ := Base_Type (Desig_Typ);
+               end if;
 
-         --  Now insert return unless last statement is a transfer
+               --  Generate:
+               --    type Ptr_Typ is access Desig_Typ;
 
-         if not Is_Transfer (Last_Stm) then
+               Ptr_Typ := Make_Temporary (Loc, 'P');
 
-            --  The source location for the return is the end label of the
-            --  procedure if present. Otherwise use the sloc of the last
-            --  statement in the list. If the list comes from a generated
-            --  exception handler and we are not debugging generated code,
-            --  all the statements within the handler are made invisible
-            --  to the debugger.
+               Append_To (Decls,
+                 Make_Full_Type_Declaration (Loc,
+                   Defining_Identifier => Ptr_Typ,
+                   Type_Definition     =>
+                     Make_Access_To_Object_Definition (Loc,
+                       Subtype_Indication =>
+                         New_Reference_To (Desig_Typ, Loc))));
 
-            if Nkind (Parent (S)) = N_Exception_Handler
-              and then not Comes_From_Source (Parent (S))
-            then
-               Loc := Sloc (Last_Stm);
+               --  Perform minor decoration in order to set the master and the
+               --  storage pool attributes.
 
-            elsif Present (End_Label (H)) then
-               Loc := Sloc (End_Label (H));
+               Set_Ekind (Ptr_Typ, E_Access_Type);
+               Set_Finalization_Master     (Ptr_Typ, Fin_Mas_Id);
+               Set_Associated_Storage_Pool (Ptr_Typ, Pool_Id);
 
-            else
-               Loc := Sloc (Last_Stm);
-            end if;
+               --  Create the temporary, generate:
+               --    Local_Id : Ptr_Typ;
 
-            declare
-               Rtn : constant Node_Id := Make_Simple_Return_Statement (Loc);
+               Local_Id := Make_Temporary (Loc, 'T');
 
-            begin
-               --  Append return statement, and set analyzed manually. We can't
-               --  call Analyze on this return since the scope is wrong.
+               Append_To (Decls,
+                 Make_Object_Declaration (Loc,
+                   Defining_Identifier => Local_Id,
+                   Object_Definition   =>
+                     New_Reference_To (Ptr_Typ, Loc)));
 
-               --  Note: it almost works to push the scope and then do the
-               --  Analyze call, but something goes wrong in some weird cases
-               --  and it is not worth worrying about ???
+               --  Allocate the object, generate:
+               --    Local_Id := <Alloc_Expr>;
 
-               Append_To (S, Rtn);
-               Set_Analyzed (Rtn);
+               Append_To (Stmts,
+                 Make_Assignment_Statement (Loc,
+                   Name       => New_Reference_To (Local_Id, Loc),
+                   Expression => Alloc_Expr));
 
-               --  Call _Postconditions procedure if appropriate. We need to
-               --  do this explicitly because we did not analyze the generated
-               --  return statement above, so the call did not get inserted.
+               --  Generate:
+               --    Temp_Id := Temp_Typ (Local_Id);
 
-               if Ekind (Spec_Id) = E_Procedure
-                 and then Has_Postconditions (Spec_Id)
-               then
-                  pragma Assert (Present (Postcondition_Proc (Spec_Id)));
-                  Insert_Action (Rtn,
-                    Make_Procedure_Call_Statement (Loc,
-                      Name =>
-                        New_Reference_To (Postcondition_Proc (Spec_Id), Loc)));
-               end if;
+               Append_To (Stmts,
+                 Make_Assignment_Statement (Loc,
+                   Name       => New_Reference_To (Temp_Id, Loc),
+                   Expression =>
+                     Unchecked_Convert_To (Temp_Typ,
+                       New_Reference_To (Local_Id, Loc))));
+
+               --  Wrap the allocation in a block. This is further conditioned
+               --  by checking the caller finalization master at runtime. A
+               --  null value indicates a non-existent master, most likely due
+               --  to a Finalize_Storage_Only allocation.
+
+               --  Generate:
+               --    if BIPfinalizationmaster /= null then
+               --       declare
+               --          <Decls>
+               --       begin
+               --          <Stmts>
+               --       end;
+               --    end if;
+
+               return
+                 Make_If_Statement (Loc,
+                   Condition       =>
+                     Make_Op_Ne (Loc,
+                       Left_Opnd  => New_Reference_To (Fin_Mas_Id, Loc),
+                       Right_Opnd => Make_Null (Loc)),
+
+                   Then_Statements => New_List (
+                     Make_Block_Statement (Loc,
+                       Declarations               => Decls,
+                       Handled_Statement_Sequence =>
+                         Make_Handled_Sequence_Of_Statements (Loc,
+                           Statements => Stmts))));
             end;
+
+         --  For all other cases, generate:
+         --    Temp_Id := <Alloc_Expr>;
+
+         else
+            return
+              Make_Assignment_Statement (Loc,
+                Name       => New_Reference_To (Temp_Id, Loc),
+                Expression => Alloc_Expr);
          end if;
-      end Add_Return;
+      end Build_Heap_Allocator;
 
-   --  Start of processing for Expand_N_Subprogram_Body
+      ---------------------------
+      -- Move_Activation_Chain --
+      ---------------------------
 
-   begin
-      --  Set L to either the list of declarations if present, or to the list
-      --  of statements if no declarations are present. This is used to insert
-      --  new stuff at the start.
+      function Move_Activation_Chain return Node_Id is
+      begin
+         return
+           Make_Procedure_Call_Statement (Loc,
+             Name                   =>
+               New_Reference_To (RTE (RE_Move_Activation_Chain), Loc),
 
-      if Is_Non_Empty_List (Declarations (N)) then
-         L := Declarations (N);
+             Parameter_Associations => New_List (
+
+               --  Source chain
+
+               Make_Attribute_Reference (Loc,
+                 Prefix         => Make_Identifier (Loc, Name_uChain),
+                 Attribute_Name => Name_Unrestricted_Access),
+
+               --  Destination chain
+
+               New_Reference_To
+                 (Build_In_Place_Formal (Par_Func, BIP_Activation_Chain), Loc),
+
+               --  New master
+
+               New_Reference_To
+                 (Build_In_Place_Formal (Par_Func, BIP_Task_Master), Loc)));
+      end Move_Activation_Chain;
+
+   --  Start of processing for Expand_N_Extended_Return_Statement
+
+   begin
+      if Nkind (Ret_Obj_Decl) = N_Object_Declaration then
+         Exp := Expression (Ret_Obj_Decl);
       else
-         L := Statements (H);
+         Exp := Empty;
       end if;
 
-      --  If local-exception-to-goto optimization active, insert dummy push
-      --  statements at start, and dummy pop statements at end.
+      HSS := Handled_Statement_Sequence (N);
 
-      if (Debug_Flag_Dot_G
-           or else Restriction_Active (No_Exception_Propagation))
-        and then Is_Non_Empty_List (L)
+      --  If the returned object needs finalization actions, the function must
+      --  perform the appropriate cleanup should it fail to return. The state
+      --  of the function itself is tracked through a flag which is coupled
+      --  with the scope finalizer. There is one flag per each return object
+      --  in case of multiple returns.
+
+      if Is_Build_In_Place
+        and then Needs_Finalization (Etype (Ret_Obj_Id))
       then
          declare
-            FS  : constant Node_Id    := First (L);
-            FL  : constant Source_Ptr := Sloc (FS);
-            LS  : Node_Id;
-            LL  : Source_Ptr;
+            Flag_Decl : Node_Id;
+            Flag_Id   : Entity_Id;
+            Func_Bod  : Node_Id;
 
          begin
-            --  LS points to either last statement, if statements are present
-            --  or to the last declaration if there are no statements present.
-            --  It is the node after which the pop's are generated.
+            --  Recover the function body
 
-            if Is_Non_Empty_List (Statements (H)) then
-               LS := Last (Statements (H));
-            else
-               LS := Last (L);
+            Func_Bod := Unit_Declaration_Node (Par_Func);
+
+            if Nkind (Func_Bod) = N_Subprogram_Declaration then
+               Func_Bod := Parent (Parent (Corresponding_Body (Func_Bod)));
             end if;
 
-            LL := Sloc (LS);
+            --  Create a flag to track the function state
 
-            Insert_List_Before_And_Analyze (FS, New_List (
-              Make_Push_Constraint_Error_Label (FL),
-              Make_Push_Program_Error_Label    (FL),
-              Make_Push_Storage_Error_Label    (FL)));
+            Flag_Id := Make_Temporary (Loc, 'F');
+            Set_Return_Flag_Or_Transient_Decl (Ret_Obj_Id, Flag_Id);
 
-            Insert_List_After_And_Analyze (LS, New_List (
-              Make_Pop_Constraint_Error_Label  (LL),
-              Make_Pop_Program_Error_Label     (LL),
-              Make_Pop_Storage_Error_Label     (LL)));
+            --  Insert the flag at the beginning of the function declarations,
+            --  generate:
+            --    Fnn : Boolean := False;
+
+            Flag_Decl :=
+              Make_Object_Declaration (Loc,
+                Defining_Identifier => Flag_Id,
+                  Object_Definition =>
+                    New_Reference_To (Standard_Boolean, Loc),
+                  Expression        => New_Reference_To (Standard_False, Loc));
+
+            Prepend_To (Declarations (Func_Bod), Flag_Decl);
+            Analyze (Flag_Decl);
          end;
       end if;
 
-      --  Find entity for subprogram
+      --  Build a simple_return_statement that returns the return object when
+      --  there is a statement sequence, or no expression, or the result will
+      --  be built in place. Note however that we currently do this for all
+      --  composite cases, even though nonlimited composite results are not yet
+      --  built in place (though we plan to do so eventually).
 
-      Body_Id := Defining_Entity (N);
+      if Present (HSS)
+        or else Is_Composite_Type (Result_Subt)
+        or else No (Exp)
+      then
+         if No (HSS) then
+            Stmts := New_List;
 
-      if Present (Corresponding_Spec (N)) then
-         Spec_Id := Corresponding_Spec (N);
-      else
-         Spec_Id := Body_Id;
-      end if;
+         --  If the extended return has a handled statement sequence, then wrap
+         --  it in a block and use the block as the first statement.
 
-      --  Need poll on entry to subprogram if polling enabled. We only do this
-      --  for non-empty subprograms, since it does not seem necessary to poll
-      --  for a dummy null subprogram.
+         else
+            Stmts := New_List (
+              Make_Block_Statement (Loc,
+                Declarations               => New_List,
+                Handled_Statement_Sequence => HSS));
+         end if;
+
+         --  If the result type contains tasks, we call Move_Activation_Chain.
+         --  Later, the cleanup code will call Complete_Master, which will
+         --  terminate any unactivated tasks belonging to the return statement
+         --  master. But Move_Activation_Chain updates their master to be that
+         --  of the caller, so they will not be terminated unless the return
+         --  statement completes unsuccessfully due to exception, abort, goto,
+         --  or exit. As a formality, we test whether the function requires the
+         --  result to be built in place, though that's necessarily true for
+         --  the case of result types with task parts.
+
+         if Is_Build_In_Place
+           and then Has_Task (Result_Subt)
+         then
+            --  The return expression is an aggregate for a complex type which
+            --  contains tasks. This particular case is left unexpanded since
+            --  the regular expansion would insert all temporaries and
+            --  initialization code in the wrong block.
+
+            if Nkind (Exp) = N_Aggregate then
+               Expand_N_Aggregate (Exp);
+            end if;
+
+            --  Do not move the activation chain if the return object does not
+            --  contain tasks.
+
+            if Has_Task (Etype (Ret_Obj_Id)) then
+               Append_To (Stmts, Move_Activation_Chain);
+            end if;
+         end if;
+
+         --  Update the state of the function right before the object is
+         --  returned.
+
+         if Is_Build_In_Place
+           and then Needs_Finalization (Etype (Ret_Obj_Id))
+         then
+            declare
+               Flag_Id : constant Entity_Id :=
+                           Return_Flag_Or_Transient_Decl (Ret_Obj_Id);
+
+            begin
+               --  Generate:
+               --    Fnn := True;
+
+               Append_To (Stmts,
+                 Make_Assignment_Statement (Loc,
+                   Name       => New_Reference_To (Flag_Id, Loc),
+                   Expression => New_Reference_To (Standard_True, Loc)));
+            end;
+         end if;
+
+         --  Build a simple_return_statement that returns the return object
+
+         Return_Stmt :=
+           Make_Simple_Return_Statement (Loc,
+             Expression => New_Occurrence_Of (Ret_Obj_Id, Loc));
+         Append_To (Stmts, Return_Stmt);
+
+         HSS := Make_Handled_Sequence_Of_Statements (Loc, Stmts);
+      end if;
+
+      --  Case where we build a return statement block
+
+      if Present (HSS) then
+         Result :=
+           Make_Block_Statement (Loc,
+             Declarations               => Return_Object_Declarations (N),
+             Handled_Statement_Sequence => HSS);
+
+         --  We set the entity of the new block statement to be that of the
+         --  return statement. This is necessary so that various fields, such
+         --  as Finalization_Chain_Entity carry over from the return statement
+         --  to the block. Note that this block is unusual, in that its entity
+         --  is an E_Return_Statement rather than an E_Block.
+
+         Set_Identifier
+           (Result, New_Occurrence_Of (Return_Statement_Entity (N), Loc));
+
+         --  If the object decl was already rewritten as a renaming, then we
+         --  don't want to do the object allocation and transformation of of
+         --  the return object declaration to a renaming. This case occurs
+         --  when the return object is initialized by a call to another
+         --  build-in-place function, and that function is responsible for
+         --  the allocation of the return object.
+
+         if Is_Build_In_Place
+           and then Nkind (Ret_Obj_Decl) = N_Object_Renaming_Declaration
+         then
+            pragma Assert
+              (Nkind (Original_Node (Ret_Obj_Decl)) = N_Object_Declaration
+                and then Is_Build_In_Place_Function_Call
+                           (Expression (Original_Node (Ret_Obj_Decl))));
+
+            --  Return the build-in-place result by reference
+
+            Set_By_Ref (Return_Stmt);
+
+         elsif Is_Build_In_Place then
+
+            --  Locate the implicit access parameter associated with the
+            --  caller-supplied return object and convert the return
+            --  statement's return object declaration to a renaming of a
+            --  dereference of the access parameter. If the return object's
+            --  declaration includes an expression that has not already been
+            --  expanded as separate assignments, then add an assignment
+            --  statement to ensure the return object gets initialized.
+
+            --    declare
+            --       Result : T [:= <expression>];
+            --    begin
+            --       ...
+
+            --  is converted to
+
+            --    declare
+            --       Result : T renames FuncRA.all;
+            --       [Result := <expression;]
+            --    begin
+            --       ...
+
+            declare
+               Return_Obj_Id    : constant Entity_Id :=
+                                    Defining_Identifier (Ret_Obj_Decl);
+               Return_Obj_Typ   : constant Entity_Id := Etype (Return_Obj_Id);
+               Return_Obj_Expr  : constant Node_Id :=
+                                    Expression (Ret_Obj_Decl);
+               Constr_Result    : constant Boolean :=
+                                    Is_Constrained (Result_Subt);
+               Obj_Alloc_Formal : Entity_Id;
+               Object_Access    : Entity_Id;
+               Obj_Acc_Deref    : Node_Id;
+               Init_Assignment  : Node_Id := Empty;
+
+            begin
+               --  Build-in-place results must be returned by reference
+
+               Set_By_Ref (Return_Stmt);
+
+               --  Retrieve the implicit access parameter passed by the caller
+
+               Object_Access :=
+                 Build_In_Place_Formal (Par_Func, BIP_Object_Access);
+
+               --  If the return object's declaration includes an expression
+               --  and the declaration isn't marked as No_Initialization, then
+               --  we need to generate an assignment to the object and insert
+               --  it after the declaration before rewriting it as a renaming
+               --  (otherwise we'll lose the initialization). The case where
+               --  the result type is an interface (or class-wide interface)
+               --  is also excluded because the context of the function call
+               --  must be unconstrained, so the initialization will always
+               --  be done as part of an allocator evaluation (storage pool
+               --  or secondary stack), never to a constrained target object
+               --  passed in by the caller. Besides the assignment being
+               --  unneeded in this case, it avoids problems with trying to
+               --  generate a dispatching assignment when the return expression
+               --  is a nonlimited descendant of a limited interface (the
+               --  interface has no assignment operation).
+
+               if Present (Return_Obj_Expr)
+                 and then not No_Initialization (Ret_Obj_Decl)
+                 and then not Is_Interface (Return_Obj_Typ)
+               then
+                  Init_Assignment :=
+                    Make_Assignment_Statement (Loc,
+                      Name       => New_Reference_To (Return_Obj_Id, Loc),
+                      Expression => Relocate_Node (Return_Obj_Expr));
+
+                  Set_Etype (Name (Init_Assignment), Etype (Return_Obj_Id));
+                  Set_Assignment_OK (Name (Init_Assignment));
+                  Set_No_Ctrl_Actions (Init_Assignment);
+
+                  Set_Parent (Name (Init_Assignment), Init_Assignment);
+                  Set_Parent (Expression (Init_Assignment), Init_Assignment);
+
+                  Set_Expression (Ret_Obj_Decl, Empty);
+
+                  if Is_Class_Wide_Type (Etype (Return_Obj_Id))
+                    and then not Is_Class_Wide_Type
+                                   (Etype (Expression (Init_Assignment)))
+                  then
+                     Rewrite (Expression (Init_Assignment),
+                       Make_Type_Conversion (Loc,
+                         Subtype_Mark =>
+                           New_Occurrence_Of (Etype (Return_Obj_Id), Loc),
+                         Expression   =>
+                           Relocate_Node (Expression (Init_Assignment))));
+                  end if;
+
+                  --  In the case of functions where the calling context can
+                  --  determine the form of allocation needed, initialization
+                  --  is done with each part of the if statement that handles
+                  --  the different forms of allocation (this is true for
+                  --  unconstrained and tagged result subtypes).
+
+                  if Constr_Result
+                    and then not Is_Tagged_Type (Underlying_Type (Result_Subt))
+                  then
+                     Insert_After (Ret_Obj_Decl, Init_Assignment);
+                  end if;
+               end if;
+
+               --  When the function's subtype is unconstrained, a run-time
+               --  test is needed to determine the form of allocation to use
+               --  for the return object. The function has an implicit formal
+               --  parameter indicating this. If the BIP_Alloc_Form formal has
+               --  the value one, then the caller has passed access to an
+               --  existing object for use as the return object. If the value
+               --  is two, then the return object must be allocated on the
+               --  secondary stack. Otherwise, the object must be allocated in
+               --  a storage pool (currently only supported for the global
+               --  heap, user-defined storage pools TBD ???). We generate an
+               --  if statement to test the implicit allocation formal and
+               --  initialize a local access value appropriately, creating
+               --  allocators in the secondary stack and global heap cases.
+               --  The special formal also exists and must be tested when the
+               --  function has a tagged result, even when the result subtype
+               --  is constrained, because in general such functions can be
+               --  called in dispatching contexts and must be handled similarly
+               --  to functions with a class-wide result.
+
+               if not Constr_Result
+                 or else Is_Tagged_Type (Underlying_Type (Result_Subt))
+               then
+                  Obj_Alloc_Formal :=
+                    Build_In_Place_Formal (Par_Func, BIP_Alloc_Form);
+
+                  declare
+                     Pool_Id        : constant Entity_Id :=
+                                        Make_Temporary (Loc, 'P');
+                     Alloc_Obj_Id   : Entity_Id;
+                     Alloc_Obj_Decl : Node_Id;
+                     Alloc_If_Stmt  : Node_Id;
+                     Heap_Allocator : Node_Id;
+                     Pool_Decl      : Node_Id;
+                     Pool_Allocator : Node_Id;
+                     Ptr_Type_Decl  : Node_Id;
+                     Ref_Type       : Entity_Id;
+                     SS_Allocator   : Node_Id;
+
+                  begin
+                     --  Reuse the itype created for the function's implicit
+                     --  access formal. This avoids the need to create a new
+                     --  access type here, plus it allows assigning the access
+                     --  formal directly without applying a conversion.
+
+                     --    Ref_Type := Etype (Object_Access);
+
+                     --  Create an access type designating the function's
+                     --  result subtype.
+
+                     Ref_Type := Make_Temporary (Loc, 'A');
+
+                     Ptr_Type_Decl :=
+                       Make_Full_Type_Declaration (Loc,
+                         Defining_Identifier => Ref_Type,
+                         Type_Definition     =>
+                           Make_Access_To_Object_Definition (Loc,
+                             All_Present        => True,
+                             Subtype_Indication =>
+                               New_Reference_To (Return_Obj_Typ, Loc)));
+
+                     Insert_Before (Ret_Obj_Decl, Ptr_Type_Decl);
+
+                     --  Create an access object that will be initialized to an
+                     --  access value denoting the return object, either coming
+                     --  from an implicit access value passed in by the caller
+                     --  or from the result of an allocator.
+
+                     Alloc_Obj_Id := Make_Temporary (Loc, 'R');
+                     Set_Etype (Alloc_Obj_Id, Ref_Type);
+
+                     Alloc_Obj_Decl :=
+                       Make_Object_Declaration (Loc,
+                         Defining_Identifier => Alloc_Obj_Id,
+                         Object_Definition   =>
+                           New_Reference_To (Ref_Type, Loc));
+
+                     Insert_Before (Ret_Obj_Decl, Alloc_Obj_Decl);
+
+                     --  Create allocators for both the secondary stack and
+                     --  global heap. If there's an initialization expression,
+                     --  then create these as initialized allocators.
+
+                     if Present (Return_Obj_Expr)
+                       and then not No_Initialization (Ret_Obj_Decl)
+                     then
+                        --  Always use the type of the expression for the
+                        --  qualified expression, rather than the result type.
+                        --  In general we cannot always use the result type
+                        --  for the allocator, because the expression might be
+                        --  of a specific type, such as in the case of an
+                        --  aggregate or even a nonlimited object when the
+                        --  result type is a limited class-wide interface type.
+
+                        Heap_Allocator :=
+                          Make_Allocator (Loc,
+                            Expression =>
+                              Make_Qualified_Expression (Loc,
+                                Subtype_Mark =>
+                                  New_Reference_To
+                                    (Etype (Return_Obj_Expr), Loc),
+                                Expression   =>
+                                  New_Copy_Tree (Return_Obj_Expr)));
+
+                     else
+                        --  If the function returns a class-wide type we cannot
+                        --  use the return type for the allocator. Instead we
+                        --  use the type of the expression, which must be an
+                        --  aggregate of a definite type.
+
+                        if Is_Class_Wide_Type (Return_Obj_Typ) then
+                           Heap_Allocator :=
+                             Make_Allocator (Loc,
+                               Expression =>
+                                 New_Reference_To
+                                   (Etype (Return_Obj_Expr), Loc));
+                        else
+                           Heap_Allocator :=
+                             Make_Allocator (Loc,
+                               Expression =>
+                                 New_Reference_To (Return_Obj_Typ, Loc));
+                        end if;
+
+                        --  If the object requires default initialization then
+                        --  that will happen later following the elaboration of
+                        --  the object renaming. If we don't turn it off here
+                        --  then the object will be default initialized twice.
+
+                        Set_No_Initialization (Heap_Allocator);
+                     end if;
+
+                     --  The Pool_Allocator is just like the Heap_Allocator,
+                     --  except we set Storage_Pool and Procedure_To_Call so
+                     --  it will use the user-defined storage pool.
+
+                     Pool_Allocator := New_Copy_Tree (Heap_Allocator);
+
+                     --  Do not generate the renaming of the build-in-place
+                     --  pool parameter on .NET/JVM/ZFP because the parameter
+                     --  is not created in the first place.
+
+                     if VM_Target = No_VM
+                       and then RTE_Available (RE_Root_Storage_Pool_Ptr)
+                     then
+                        Pool_Decl :=
+                          Make_Object_Renaming_Declaration (Loc,
+                            Defining_Identifier => Pool_Id,
+                            Subtype_Mark        =>
+                              New_Reference_To
+                                (RTE (RE_Root_Storage_Pool), Loc),
+                            Name                =>
+                              Make_Explicit_Dereference (Loc,
+                                New_Reference_To
+                                  (Build_In_Place_Formal
+                                     (Par_Func, BIP_Storage_Pool), Loc)));
+                        Set_Storage_Pool (Pool_Allocator, Pool_Id);
+                        Set_Procedure_To_Call
+                          (Pool_Allocator, RTE (RE_Allocate_Any));
+                     else
+                        Pool_Decl := Make_Null_Statement (Loc);
+                     end if;
+
+                     --  If the No_Allocators restriction is active, then only
+                     --  an allocator for secondary stack allocation is needed.
+                     --  It's OK for such allocators to have Comes_From_Source
+                     --  set to False, because gigi knows not to flag them as
+                     --  being a violation of No_Implicit_Heap_Allocations.
+
+                     if Restriction_Active (No_Allocators) then
+                        SS_Allocator   := Heap_Allocator;
+                        Heap_Allocator := Make_Null (Loc);
+                        Pool_Allocator := Make_Null (Loc);
+
+                     --  Otherwise the heap and pool allocators may be needed,
+                     --  so we make another allocator for secondary stack
+                     --  allocation.
+
+                     else
+                        SS_Allocator := New_Copy_Tree (Heap_Allocator);
+
+                        --  The heap and pool allocators are marked as
+                        --  Comes_From_Source since they correspond to an
+                        --  explicit user-written allocator (that is, it will
+                        --  only be executed on behalf of callers that call the
+                        --  function as initialization for such an allocator).
+                        --  Prevents errors when No_Implicit_Heap_Allocations
+                        --  is in force.
+
+                        Set_Comes_From_Source (Heap_Allocator, True);
+                        Set_Comes_From_Source (Pool_Allocator, True);
+                     end if;
+
+                     --  The allocator is returned on the secondary stack. We
+                     --  don't do this on VM targets, since the SS is not used.
+
+                     if VM_Target = No_VM then
+                        Set_Storage_Pool (SS_Allocator, RTE (RE_SS_Pool));
+                        Set_Procedure_To_Call
+                          (SS_Allocator, RTE (RE_SS_Allocate));
+
+                        --  The allocator is returned on the secondary stack,
+                        --  so indicate that the function return, as well as
+                        --  the block that encloses the allocator, must not
+                        --  release it. The flags must be set now because
+                        --  the decision to use the secondary stack is done
+                        --  very late in the course of expanding the return
+                        --  statement, past the point where these flags are
+                        --  normally set.
+
+                        Set_Sec_Stack_Needed_For_Return (Par_Func);
+                        Set_Sec_Stack_Needed_For_Return
+                          (Return_Statement_Entity (N));
+                        Set_Uses_Sec_Stack (Par_Func);
+                        Set_Uses_Sec_Stack (Return_Statement_Entity (N));
+                     end if;
+
+                     --  Create an if statement to test the BIP_Alloc_Form
+                     --  formal and initialize the access object to either the
+                     --  BIP_Object_Access formal (BIP_Alloc_Form =
+                     --  Caller_Allocation), the result of allocating the
+                     --  object in the secondary stack (BIP_Alloc_Form =
+                     --  Secondary_Stack), or else an allocator to create the
+                     --  return object in the heap or user-defined pool
+                     --  (BIP_Alloc_Form = Global_Heap or User_Storage_Pool).
+
+                     --  ??? An unchecked type conversion must be made in the
+                     --  case of assigning the access object formal to the
+                     --  local access object, because a normal conversion would
+                     --  be illegal in some cases (such as converting access-
+                     --  to-unconstrained to access-to-constrained), but the
+                     --  the unchecked conversion will presumably fail to work
+                     --  right in just such cases. It's not clear at all how to
+                     --  handle this. ???
+
+                     Alloc_If_Stmt :=
+                       Make_If_Statement (Loc,
+                         Condition =>
+                           Make_Op_Eq (Loc,
+                             Left_Opnd  =>
+                               New_Reference_To (Obj_Alloc_Formal, Loc),
+                             Right_Opnd =>
+                               Make_Integer_Literal (Loc,
+                                 UI_From_Int (BIP_Allocation_Form'Pos
+                                                (Caller_Allocation)))),
+
+                         Then_Statements => New_List (
+                           Make_Assignment_Statement (Loc,
+                             Name       =>
+                               New_Reference_To (Alloc_Obj_Id, Loc),
+                             Expression =>
+                               Make_Unchecked_Type_Conversion (Loc,
+                                 Subtype_Mark =>
+                                   New_Reference_To (Ref_Type, Loc),
+                                 Expression   =>
+                                   New_Reference_To (Object_Access, Loc)))),
+
+                         Elsif_Parts => New_List (
+                           Make_Elsif_Part (Loc,
+                             Condition =>
+                               Make_Op_Eq (Loc,
+                                 Left_Opnd  =>
+                                   New_Reference_To (Obj_Alloc_Formal, Loc),
+                                 Right_Opnd =>
+                                   Make_Integer_Literal (Loc,
+                                     UI_From_Int (BIP_Allocation_Form'Pos
+                                                    (Secondary_Stack)))),
+
+                             Then_Statements => New_List (
+                               Make_Assignment_Statement (Loc,
+                                 Name       =>
+                                   New_Reference_To (Alloc_Obj_Id, Loc),
+                                 Expression => SS_Allocator))),
+
+                           Make_Elsif_Part (Loc,
+                             Condition =>
+                               Make_Op_Eq (Loc,
+                                 Left_Opnd  =>
+                                   New_Reference_To (Obj_Alloc_Formal, Loc),
+                                 Right_Opnd =>
+                                   Make_Integer_Literal (Loc,
+                                     UI_From_Int (BIP_Allocation_Form'Pos
+                                                    (Global_Heap)))),
+
+                             Then_Statements => New_List (
+                               Build_Heap_Allocator
+                                 (Temp_Id    => Alloc_Obj_Id,
+                                  Temp_Typ   => Ref_Type,
+                                  Func_Id    => Par_Func,
+                                  Ret_Typ    => Return_Obj_Typ,
+                                  Alloc_Expr => Heap_Allocator)))),
+
+                         Else_Statements => New_List (
+                           Pool_Decl,
+                           Build_Heap_Allocator
+                             (Temp_Id    => Alloc_Obj_Id,
+                              Temp_Typ   => Ref_Type,
+                              Func_Id    => Par_Func,
+                              Ret_Typ    => Return_Obj_Typ,
+                              Alloc_Expr => Pool_Allocator)));
+
+                     --  If a separate initialization assignment was created
+                     --  earlier, append that following the assignment of the
+                     --  implicit access formal to the access object, to ensure
+                     --  that the return object is initialized in that case. In
+                     --  this situation, the target of the assignment must be
+                     --  rewritten to denote a dereference of the access to the
+                     --  return object passed in by the caller.
+
+                     if Present (Init_Assignment) then
+                        Rewrite (Name (Init_Assignment),
+                          Make_Explicit_Dereference (Loc,
+                            Prefix => New_Reference_To (Alloc_Obj_Id, Loc)));
+
+                        Set_Etype
+                          (Name (Init_Assignment), Etype (Return_Obj_Id));
+
+                        Append_To
+                          (Then_Statements (Alloc_If_Stmt), Init_Assignment);
+                     end if;
+
+                     Insert_Before (Ret_Obj_Decl, Alloc_If_Stmt);
+
+                     --  Remember the local access object for use in the
+                     --  dereference of the renaming created below.
+
+                     Object_Access := Alloc_Obj_Id;
+                  end;
+               end if;
+
+               --  Replace the return object declaration with a renaming of a
+               --  dereference of the access value designating the return
+               --  object.
+
+               Obj_Acc_Deref :=
+                 Make_Explicit_Dereference (Loc,
+                   Prefix => New_Reference_To (Object_Access, Loc));
+
+               Rewrite (Ret_Obj_Decl,
+                 Make_Object_Renaming_Declaration (Loc,
+                   Defining_Identifier => Return_Obj_Id,
+                   Access_Definition   => Empty,
+                   Subtype_Mark        =>
+                     New_Occurrence_Of (Return_Obj_Typ, Loc),
+                   Name                => Obj_Acc_Deref));
+
+               Set_Renamed_Object (Return_Obj_Id, Obj_Acc_Deref);
+            end;
+         end if;
+
+      --  Case where we do not build a block
+
+      else
+         --  We're about to drop Return_Object_Declarations on the floor, so
+         --  we need to insert it, in case it got expanded into useful code.
+         --  Remove side effects from expression, which may be duplicated in
+         --  subsequent checks (see Expand_Simple_Function_Return).
+
+         Insert_List_Before (N, Return_Object_Declarations (N));
+         Remove_Side_Effects (Exp);
+
+         --  Build simple_return_statement that returns the expression directly
+
+         Return_Stmt := Make_Simple_Return_Statement (Loc, Expression => Exp);
+         Result := Return_Stmt;
+      end if;
+
+      --  Set the flag to prevent infinite recursion
+
+      Set_Comes_From_Extended_Return_Statement (Return_Stmt);
+
+      Rewrite (N, Result);
+      Analyze (N);
+   end Expand_N_Extended_Return_Statement;
+
+   ----------------------------
+   -- Expand_N_Function_Call --
+   ----------------------------
+
+   procedure Expand_N_Function_Call (N : Node_Id) is
+   begin
+      Expand_Call (N);
+
+      --  If the return value of a foreign compiled function is VAX Float, then
+      --  expand the return (adjusts the location of the return value on
+      --  Alpha/VMS, no-op everywhere else).
+      --  Comes_From_Source intercepts recursive expansion.
+
+      if Vax_Float (Etype (N))
+        and then Nkind (N) = N_Function_Call
+        and then Present (Name (N))
+        and then Present (Entity (Name (N)))
+        and then Has_Foreign_Convention (Entity (Name (N)))
+        and then Comes_From_Source (Parent (N))
+      then
+         Expand_Vax_Foreign_Return (N);
+      end if;
+   end Expand_N_Function_Call;
+
+   ---------------------------------------
+   -- Expand_N_Procedure_Call_Statement --
+   ---------------------------------------
+
+   procedure Expand_N_Procedure_Call_Statement (N : Node_Id) is
+   begin
+      Expand_Call (N);
+   end Expand_N_Procedure_Call_Statement;
+
+   --------------------------------------
+   -- Expand_N_Simple_Return_Statement --
+   --------------------------------------
+
+   procedure Expand_N_Simple_Return_Statement (N : Node_Id) is
+   begin
+      --  Defend against previous errors (i.e. the return statement calls a
+      --  function that is not available in configurable runtime).
+
+      if Present (Expression (N))
+        and then Nkind (Expression (N)) = N_Empty
+      then
+         return;
+      end if;
+
+      --  Distinguish the function and non-function cases:
+
+      case Ekind (Return_Applies_To (Return_Statement_Entity (N))) is
+
+         when E_Function          |
+              E_Generic_Function  =>
+            Expand_Simple_Function_Return (N);
+
+         when E_Procedure         |
+              E_Generic_Procedure |
+              E_Entry             |
+              E_Entry_Family      |
+              E_Return_Statement =>
+            Expand_Non_Function_Return (N);
+
+         when others =>
+            raise Program_Error;
+      end case;
+
+   exception
+      when RE_Not_Available =>
+         return;
+   end Expand_N_Simple_Return_Statement;
+
+   ------------------------------
+   -- Expand_N_Subprogram_Body --
+   ------------------------------
+
+   --  Add poll call if ATC polling is enabled, unless the body will be inlined
+   --  by the back-end.
+
+   --  Add dummy push/pop label nodes at start and end to clear any local
+   --  exception indications if local-exception-to-goto optimization is active.
+
+   --  Add return statement if last statement in body is not a return statement
+   --  (this makes things easier on Gigi which does not want to have to handle
+   --  a missing return).
+
+   --  Add call to Activate_Tasks if body is a task activator
+
+   --  Deal with possible detection of infinite recursion
+
+   --  Eliminate body completely if convention stubbed
+
+   --  Encode entity names within body, since we will not need to reference
+   --  these entities any longer in the front end.
+
+   --  Initialize scalar out parameters if Initialize/Normalize_Scalars
+
+   --  Reset Pure indication if any parameter has root type System.Address
+   --  or has any parameters of limited types, where limited means that the
+   --  run-time view is limited (i.e. the full type is limited).
+
+   --  Wrap thread body
+
+   procedure Expand_N_Subprogram_Body (N : Node_Id) is
+      Loc      : constant Source_Ptr := Sloc (N);
+      H        : constant Node_Id    := Handled_Statement_Sequence (N);
+      Body_Id  : Entity_Id;
+      Except_H : Node_Id;
+      L        : List_Id;
+      Spec_Id  : Entity_Id;
+
+      procedure Add_Return (S : List_Id);
+      --  Append a return statement to the statement sequence S if the last
+      --  statement is not already a return or a goto statement. Note that
+      --  the latter test is not critical, it does not matter if we add a few
+      --  extra returns, since they get eliminated anyway later on.
+
+      ----------------
+      -- Add_Return --
+      ----------------
+
+      procedure Add_Return (S : List_Id) is
+         Last_Stm : Node_Id;
+         Loc      : Source_Ptr;
+
+      begin
+         --  Get last statement, ignoring any Pop_xxx_Label nodes, which are
+         --  not relevant in this context since they are not executable.
+
+         Last_Stm := Last (S);
+         while Nkind (Last_Stm) in N_Pop_xxx_Label loop
+            Prev (Last_Stm);
+         end loop;
+
+         --  Now insert return unless last statement is a transfer
+
+         if not Is_Transfer (Last_Stm) then
+
+            --  The source location for the return is the end label of the
+            --  procedure if present. Otherwise use the sloc of the last
+            --  statement in the list. If the list comes from a generated
+            --  exception handler and we are not debugging generated code,
+            --  all the statements within the handler are made invisible
+            --  to the debugger.
+
+            if Nkind (Parent (S)) = N_Exception_Handler
+              and then not Comes_From_Source (Parent (S))
+            then
+               Loc := Sloc (Last_Stm);
+            elsif Present (End_Label (H)) then
+               Loc := Sloc (End_Label (H));
+            else
+               Loc := Sloc (Last_Stm);
+            end if;
+
+            declare
+               Rtn : constant Node_Id := Make_Simple_Return_Statement (Loc);
+
+            begin
+               --  Append return statement, and set analyzed manually. We can't
+               --  call Analyze on this return since the scope is wrong.
+
+               --  Note: it almost works to push the scope and then do the
+               --  Analyze call, but something goes wrong in some weird cases
+               --  and it is not worth worrying about ???
+
+               Append_To (S, Rtn);
+               Set_Analyzed (Rtn);
+
+               --  Call _Postconditions procedure if appropriate. We need to
+               --  do this explicitly because we did not analyze the generated
+               --  return statement above, so the call did not get inserted.
+
+               if Ekind (Spec_Id) = E_Procedure
+                 and then Has_Postconditions (Spec_Id)
+               then
+                  pragma Assert (Present (Postcondition_Proc (Spec_Id)));
+                  Insert_Action (Rtn,
+                    Make_Procedure_Call_Statement (Loc,
+                      Name =>
+                        New_Reference_To (Postcondition_Proc (Spec_Id), Loc)));
+               end if;
+            end;
+         end if;
+      end Add_Return;
+
+   --  Start of processing for Expand_N_Subprogram_Body
+
+   begin
+      --  Set L to either the list of declarations if present, or to the list
+      --  of statements if no declarations are present. This is used to insert
+      --  new stuff at the start.
+
+      if Is_Non_Empty_List (Declarations (N)) then
+         L := Declarations (N);
+      else
+         L := Statements (H);
+      end if;
+
+      --  If local-exception-to-goto optimization active, insert dummy push
+      --  statements at start, and dummy pop statements at end, but inhibit
+      --  this if we have No_Exception_Handlers, since they are useless and
+      --  intefere with analysis, e.g. by codepeer.
+
+      if (Debug_Flag_Dot_G
+           or else Restriction_Active (No_Exception_Propagation))
+        and then not Restriction_Active (No_Exception_Handlers)
+        and then not CodePeer_Mode
+        and then Is_Non_Empty_List (L)
+      then
+         declare
+            FS  : constant Node_Id    := First (L);
+            FL  : constant Source_Ptr := Sloc (FS);
+            LS  : Node_Id;
+            LL  : Source_Ptr;
+
+         begin
+            --  LS points to either last statement, if statements are present
+            --  or to the last declaration if there are no statements present.
+            --  It is the node after which the pop's are generated.
+
+            if Is_Non_Empty_List (Statements (H)) then
+               LS := Last (Statements (H));
+            else
+               LS := Last (L);
+            end if;
+
+            LL := Sloc (LS);
+
+            Insert_List_Before_And_Analyze (FS, New_List (
+              Make_Push_Constraint_Error_Label (FL),
+              Make_Push_Program_Error_Label    (FL),
+              Make_Push_Storage_Error_Label    (FL)));
+
+            Insert_List_After_And_Analyze (LS, New_List (
+              Make_Pop_Constraint_Error_Label  (LL),
+              Make_Pop_Program_Error_Label     (LL),
+              Make_Pop_Storage_Error_Label     (LL)));
+         end;
+      end if;
+
+      --  Find entity for subprogram
+
+      Body_Id := Defining_Entity (N);
+
+      if Present (Corresponding_Spec (N)) then
+         Spec_Id := Corresponding_Spec (N);
+      else
+         Spec_Id := Body_Id;
+      end if;
+
+      --  Need poll on entry to subprogram if polling enabled. We only do this
+      --  for non-empty subprograms, since it does not seem necessary to poll
+      --  for a dummy null subprogram.
 
       if Is_Non_Empty_List (L) then
 
@@ -4288,7 +5801,14 @@ package body Exp_Ch6 is
          begin
             F := First_Formal (Spec_Id);
             while Present (F) loop
-               if Is_Descendent_Of_Address (Etype (F)) then
+               if Is_Descendent_Of_Address (Etype (F))
+
+                 --  Note that this test is being made in the body of the
+                 --  subprogram, not the spec, so we are testing the full
+                 --  type for being limited here, as required.
+
+                 or else Is_Limited_Type (Etype (F))
+               then
                   Set_Is_Pure (Spec_Id, False);
 
                   if Spec_Id /= Body_Id then
@@ -4346,8 +5866,7 @@ package body Exp_Ch6 is
             Set_Declarations (N, Empty_List);
             Set_Handled_Statement_Sequence (N,
               Make_Handled_Sequence_Of_Statements (Loc,
-                Statements => New_List (
-                  Make_Null_Statement (Loc))));
+                Statements => New_List (Make_Null_Statement (Loc))));
             return;
          end if;
       end if;
@@ -4376,7 +5895,7 @@ package body Exp_Ch6 is
          then
             null;
 
-         elsif Is_Inherently_Limited_Type (Typ) then
+         elsif Is_Immutably_Limited_Type (Typ) then
             Set_Returns_By_Ref (Spec_Id);
 
          elsif Present (Utyp) and then CW_Or_Has_Controlled_Part (Utyp) then
@@ -4494,6 +6013,30 @@ package body Exp_Ch6 is
       Prot_Id   : Entity_Id;
 
    begin
+      --  In SPARK, subprogram declarations are only allowed in package
+      --  specifications.
+
+      if Nkind (Parent (N)) /= N_Package_Specification then
+         if Nkind (Parent (N)) = N_Compilation_Unit then
+            Check_SPARK_Restriction
+              ("subprogram declaration is not a library item", N);
+
+         elsif Present (Next (N))
+           and then Nkind (Next (N)) = N_Pragma
+           and then Get_Pragma_Id (Pragma_Name (Next (N))) = Pragma_Import
+         then
+            --  In SPARK, subprogram declarations are also permitted in
+            --  declarative parts when immediately followed by a corresponding
+            --  pragma Import. We only check here that there is some pragma
+            --  Import.
+
+            null;
+         else
+            Check_SPARK_Restriction
+              ("subprogram declaration is not allowed here", N);
+         end if;
+      end if;
+
       --  Deal with case of protected subprogram. Do not generate protected
       --  operation if operation is flagged as eliminated.
 
@@ -4531,7 +6074,7 @@ package body Exp_Ch6 is
 
             Push_Scope (Scope (Scop));
             Analyze (Prot_Decl);
-            Insert_Actions (N, Freeze_Entity (Prot_Id, Loc));
+            Freeze_Before (N, Prot_Id);
             Set_Protected_Body_Subprogram (Subp, Prot_Id);
 
             --  Create protected operation as well. Even though the operation
@@ -4549,10 +6092,10 @@ package body Exp_Ch6 is
             Pop_Scope;
          end if;
 
-      --  Ada 2005 (AI-348): Generate body for a null procedure.
-      --  In most cases this is superfluous because calls to it
-      --  will be automatically inlined, but we definitely need
-      --  the body if preconditions for the procedure are present.
+      --  Ada 2005 (AI-348): Generate body for a null procedure. In most
+      --  cases this is superfluous because calls to it will be automatically
+      --  inlined, but we definitely need the body if preconditions for the
+      --  procedure are present.
 
       elsif Nkind (Specification (N)) = N_Procedure_Specification
         and then Null_Present (Specification (N))
@@ -4572,6 +6115,121 @@ package body Exp_Ch6 is
       end if;
    end Expand_N_Subprogram_Declaration;
 
+   --------------------------------
+   -- Expand_Non_Function_Return --
+   --------------------------------
+
+   procedure Expand_Non_Function_Return (N : Node_Id) is
+      pragma Assert (No (Expression (N)));
+
+      Loc         : constant Source_Ptr := Sloc (N);
+      Scope_Id    : Entity_Id :=
+                      Return_Applies_To (Return_Statement_Entity (N));
+      Kind        : constant Entity_Kind := Ekind (Scope_Id);
+      Call        : Node_Id;
+      Acc_Stat    : Node_Id;
+      Goto_Stat   : Node_Id;
+      Lab_Node    : Node_Id;
+
+   begin
+      --  Call _Postconditions procedure if procedure with active
+      --  postconditions. Here, we use the Postcondition_Proc attribute,
+      --  which is needed for implicitly-generated returns. Functions
+      --  never have implicitly-generated returns, and there's no
+      --  room for Postcondition_Proc in E_Function, so we look up the
+      --  identifier Name_uPostconditions for function returns (see
+      --  Expand_Simple_Function_Return).
+
+      if Ekind (Scope_Id) = E_Procedure
+        and then Has_Postconditions (Scope_Id)
+      then
+         pragma Assert (Present (Postcondition_Proc (Scope_Id)));
+         Insert_Action (N,
+           Make_Procedure_Call_Statement (Loc,
+             Name => New_Reference_To (Postcondition_Proc (Scope_Id), Loc)));
+      end if;
+
+      --  If it is a return from a procedure do no extra steps
+
+      if Kind = E_Procedure or else Kind = E_Generic_Procedure then
+         return;
+
+      --  If it is a nested return within an extended one, replace it with a
+      --  return of the previously declared return object.
+
+      elsif Kind = E_Return_Statement then
+         Rewrite (N,
+           Make_Simple_Return_Statement (Loc,
+             Expression =>
+               New_Occurrence_Of (First_Entity (Scope_Id), Loc)));
+         Set_Comes_From_Extended_Return_Statement (N);
+         Set_Return_Statement_Entity (N, Scope_Id);
+         Expand_Simple_Function_Return (N);
+         return;
+      end if;
+
+      pragma Assert (Is_Entry (Scope_Id));
+
+      --  Look at the enclosing block to see whether the return is from an
+      --  accept statement or an entry body.
+
+      for J in reverse 0 .. Scope_Stack.Last loop
+         Scope_Id := Scope_Stack.Table (J).Entity;
+         exit when Is_Concurrent_Type (Scope_Id);
+      end loop;
+
+      --  If it is a return from accept statement it is expanded as call to
+      --  RTS Complete_Rendezvous and a goto to the end of the accept body.
+
+      --  (cf : Expand_N_Accept_Statement, Expand_N_Selective_Accept,
+      --  Expand_N_Accept_Alternative in exp_ch9.adb)
+
+      if Is_Task_Type (Scope_Id) then
+
+         Call :=
+           Make_Procedure_Call_Statement (Loc,
+             Name => New_Reference_To (RTE (RE_Complete_Rendezvous), Loc));
+         Insert_Before (N, Call);
+         --  why not insert actions here???
+         Analyze (Call);
+
+         Acc_Stat := Parent (N);
+         while Nkind (Acc_Stat) /= N_Accept_Statement loop
+            Acc_Stat := Parent (Acc_Stat);
+         end loop;
+
+         Lab_Node := Last (Statements
+           (Handled_Statement_Sequence (Acc_Stat)));
+
+         Goto_Stat := Make_Goto_Statement (Loc,
+           Name => New_Occurrence_Of
+             (Entity (Identifier (Lab_Node)), Loc));
+
+         Set_Analyzed (Goto_Stat);
+
+         Rewrite (N, Goto_Stat);
+         Analyze (N);
+
+      --  If it is a return from an entry body, put a Complete_Entry_Body call
+      --  in front of the return.
+
+      elsif Is_Protected_Type (Scope_Id) then
+         Call :=
+           Make_Procedure_Call_Statement (Loc,
+             Name =>
+               New_Reference_To (RTE (RE_Complete_Entry_Body), Loc),
+             Parameter_Associations => New_List (
+               Make_Attribute_Reference (Loc,
+                 Prefix         =>
+                   New_Reference_To
+                     (Find_Protection_Object (Current_Scope), Loc),
+                 Attribute_Name => Name_Unchecked_Access)));
+
+         Insert_Before (N, Call);
+         Analyze (Call);
+      end if;
+   end Expand_Non_Function_Return;
+
    ---------------------------------------
    -- Expand_Protected_Object_Reference --
    ---------------------------------------
@@ -4587,9 +6245,7 @@ package body Exp_Ch6 is
       Proc  : Entity_Id;
 
    begin
-      Rec :=
-        Make_Identifier (Loc,
-          Chars => Name_uObject);
+      Rec := Make_Identifier (Loc, Name_uObject);
       Set_Etype (Rec, Corresponding_Record_Type (Scop));
 
       --  Find enclosing protected operation, and retrieve its first parameter,
@@ -4648,19 +6304,20 @@ package body Exp_Ch6 is
             Decls := New_List (
               Make_Full_Type_Declaration (Loc,
                 Defining_Identifier => Obj_Ptr,
-                  Type_Definition =>
+                  Type_Definition   =>
                      Make_Access_To_Object_Definition (Loc,
                        Subtype_Indication =>
                          New_Reference_To
                            (Corresponding_Record_Type (Scop), Loc))));
 
             Insert_Actions (N, Decls);
-            Insert_Actions (N, Freeze_Entity (Obj_Ptr, Sloc (N)));
+            Freeze_Before (N, Obj_Ptr);
 
             Rec :=
               Make_Explicit_Dereference (Loc,
-                Unchecked_Convert_To (Obj_Ptr,
-                  New_Occurrence_Of (Param, Loc)));
+                Prefix =>
+                  Unchecked_Convert_To (Obj_Ptr,
+                    New_Occurrence_Of (Param, Loc)));
 
             --  Analyze new actual. Other actuals in calls are already analyzed
             --  and the list of actuals is not reanalyzed after rewriting.
@@ -4685,14 +6342,13 @@ package body Exp_Ch6 is
       Rec   : Node_Id;
 
    begin
-      --  If the protected object is not an enclosing scope, this is
-      --  an inter-object function call. Inter-object procedure
-      --  calls are expanded by Exp_Ch9.Build_Simple_Entry_Call.
-      --  The call is intra-object only if the subprogram being
-      --  called is in the protected body being compiled, and if the
-      --  protected object in the call is statically the enclosing type.
-      --  The object may be an component of some other data structure,
-      --  in which case this must be handled as an inter-object call.
+      --  If the protected object is not an enclosing scope, this is an inter-
+      --  object function call. Inter-object procedure calls are expanded by
+      --  Exp_Ch9.Build_Simple_Entry_Call. The call is intra-object only if the
+      --  subprogram being called is in the protected body being compiled, and
+      --  if the protected object in the call is statically the enclosing type.
+      --  The object may be an component of some other data structure, in which
+      --  case this must be handled as an inter-object call.
 
       if not In_Open_Scopes (Scop)
         or else not Is_Entity_Name (Name (N))
@@ -4700,47 +6356,900 @@ package body Exp_Ch6 is
          if Nkind (Name (N)) = N_Selected_Component then
             Rec := Prefix (Name (N));
 
-         else
-            pragma Assert (Nkind (Name (N)) = N_Indexed_Component);
-            Rec := Prefix (Prefix (Name (N)));
-         end if;
+         else
+            pragma Assert (Nkind (Name (N)) = N_Indexed_Component);
+            Rec := Prefix (Prefix (Name (N)));
+         end if;
+
+         Build_Protected_Subprogram_Call (N,
+           Name     => New_Occurrence_Of (Subp, Sloc (N)),
+           Rec      => Convert_Concurrent (Rec, Etype (Rec)),
+           External => True);
+
+      else
+         Rec := Expand_Protected_Object_Reference (N, Scop);
+
+         if No (Rec) then
+            return;
+         end if;
+
+         Build_Protected_Subprogram_Call (N,
+           Name     => Name (N),
+           Rec      => Rec,
+           External => False);
+
+      end if;
+
+      --  If it is a function call it can appear in elaboration code and
+      --  the called entity must be frozen here.
+
+      if Ekind (Subp) = E_Function then
+         Freeze_Expression (Name (N));
+      end if;
+
+      --  Analyze and resolve the new call. The actuals have already been
+      --  resolved, but expansion of a function call will add extra actuals
+      --  if needed. Analysis of a procedure call already includes resolution.
+
+      Analyze (N);
+
+      if Ekind (Subp) = E_Function then
+         Resolve (N, Etype (Subp));
+      end if;
+   end Expand_Protected_Subprogram_Call;
+
+   --------------------------------------------
+   -- Has_Unconstrained_Access_Discriminants --
+   --------------------------------------------
+
+   function Has_Unconstrained_Access_Discriminants
+     (Subtyp : Entity_Id) return Boolean
+   is
+      Discr : Entity_Id;
+
+   begin
+      if Has_Discriminants (Subtyp)
+        and then not Is_Constrained (Subtyp)
+      then
+         Discr := First_Discriminant (Subtyp);
+         while Present (Discr) loop
+            if Ekind (Etype (Discr)) = E_Anonymous_Access_Type then
+               return True;
+            end if;
+
+            Next_Discriminant (Discr);
+         end loop;
+      end if;
+
+      return False;
+   end Has_Unconstrained_Access_Discriminants;
+
+   -----------------------------------
+   -- Expand_Simple_Function_Return --
+   -----------------------------------
+
+   --  The "simple" comes from the syntax rule simple_return_statement. The
+   --  semantics are not at all simple!
+
+   procedure Expand_Simple_Function_Return (N : Node_Id) is
+      Loc : constant Source_Ptr := Sloc (N);
+
+      Scope_Id : constant Entity_Id :=
+                   Return_Applies_To (Return_Statement_Entity (N));
+      --  The function we are returning from
+
+      R_Type : constant Entity_Id := Etype (Scope_Id);
+      --  The result type of the function
+
+      Utyp : constant Entity_Id := Underlying_Type (R_Type);
+
+      Exp : constant Node_Id := Expression (N);
+      pragma Assert (Present (Exp));
+
+      Exptyp : constant Entity_Id := Etype (Exp);
+      --  The type of the expression (not necessarily the same as R_Type)
+
+      Subtype_Ind : Node_Id;
+      --  If the result type of the function is class-wide and the expression
+      --  has a specific type, then we use the expression's type as the type of
+      --  the return object. In cases where the expression is an aggregate that
+      --  is built in place, this avoids the need for an expensive conversion
+      --  of the return object to the specific type on assignments to the
+      --  individual components.
+
+   begin
+      if Is_Class_Wide_Type (R_Type)
+        and then not Is_Class_Wide_Type (Etype (Exp))
+      then
+         Subtype_Ind := New_Occurrence_Of (Etype (Exp), Loc);
+      else
+         Subtype_Ind := New_Occurrence_Of (R_Type, Loc);
+      end if;
+
+      --  For the case of a simple return that does not come from an extended
+      --  return, in the case of Ada 2005 where we are returning a limited
+      --  type, we rewrite "return <expression>;" to be:
+
+      --    return _anon_ : <return_subtype> := <expression>
+
+      --  The expansion produced by Expand_N_Extended_Return_Statement will
+      --  contain simple return statements (for example, a block containing
+      --  simple return of the return object), which brings us back here with
+      --  Comes_From_Extended_Return_Statement set. The reason for the barrier
+      --  checking for a simple return that does not come from an extended
+      --  return is to avoid this infinite recursion.
+
+      --  The reason for this design is that for Ada 2005 limited returns, we
+      --  need to reify the return object, so we can build it "in place", and
+      --  we need a block statement to hang finalization and tasking stuff.
+
+      --  ??? In order to avoid disruption, we avoid translating to extended
+      --  return except in the cases where we really need to (Ada 2005 for
+      --  inherently limited). We might prefer to do this translation in all
+      --  cases (except perhaps for the case of Ada 95 inherently limited),
+      --  in order to fully exercise the Expand_N_Extended_Return_Statement
+      --  code. This would also allow us to do the build-in-place optimization
+      --  for efficiency even in cases where it is semantically not required.
+
+      --  As before, we check the type of the return expression rather than the
+      --  return type of the function, because the latter may be a limited
+      --  class-wide interface type, which is not a limited type, even though
+      --  the type of the expression may be.
+
+      if not Comes_From_Extended_Return_Statement (N)
+        and then Is_Immutably_Limited_Type (Etype (Expression (N)))
+        and then Ada_Version >= Ada_2005
+        and then not Debug_Flag_Dot_L
+      then
+         declare
+            Return_Object_Entity : constant Entity_Id :=
+                                     Make_Temporary (Loc, 'R', Exp);
+            Obj_Decl : constant Node_Id :=
+                         Make_Object_Declaration (Loc,
+                           Defining_Identifier => Return_Object_Entity,
+                           Object_Definition   => Subtype_Ind,
+                           Expression          => Exp);
+
+            Ext : constant Node_Id := Make_Extended_Return_Statement (Loc,
+                    Return_Object_Declarations => New_List (Obj_Decl));
+            --  Do not perform this high-level optimization if the result type
+            --  is an interface because the "this" pointer must be displaced.
+
+         begin
+            Rewrite (N, Ext);
+            Analyze (N);
+            return;
+         end;
+      end if;
+
+      --  Here we have a simple return statement that is part of the expansion
+      --  of an extended return statement (either written by the user, or
+      --  generated by the above code).
+
+      --  Always normalize C/Fortran boolean result. This is not always needed,
+      --  but it seems a good idea to minimize the passing around of non-
+      --  normalized values, and in any case this handles the processing of
+      --  barrier functions for protected types, which turn the condition into
+      --  a return statement.
+
+      if Is_Boolean_Type (Exptyp)
+        and then Nonzero_Is_True (Exptyp)
+      then
+         Adjust_Condition (Exp);
+         Adjust_Result_Type (Exp, Exptyp);
+      end if;
+
+      --  Do validity check if enabled for returns
+
+      if Validity_Checks_On
+        and then Validity_Check_Returns
+      then
+         Ensure_Valid (Exp);
+      end if;
+
+      --  Check the result expression of a scalar function against the subtype
+      --  of the function by inserting a conversion. This conversion must
+      --  eventually be performed for other classes of types, but for now it's
+      --  only done for scalars.
+      --  ???
+
+      if Is_Scalar_Type (Exptyp) then
+         Rewrite (Exp, Convert_To (R_Type, Exp));
+
+         --  The expression is resolved to ensure that the conversion gets
+         --  expanded to generate a possible constraint check.
+
+         Analyze_And_Resolve (Exp, R_Type);
+      end if;
+
+      --  Deal with returning variable length objects and controlled types
+
+      --  Nothing to do if we are returning by reference, or this is not a
+      --  type that requires special processing (indicated by the fact that
+      --  it requires a cleanup scope for the secondary stack case).
+
+      if Is_Immutably_Limited_Type (Exptyp)
+        or else Is_Limited_Interface (Exptyp)
+      then
+         null;
+
+      elsif not Requires_Transient_Scope (R_Type) then
+
+         --  Mutable records with no variable length components are not
+         --  returned on the sec-stack, so we need to make sure that the
+         --  backend will only copy back the size of the actual value, and not
+         --  the maximum size. We create an actual subtype for this purpose.
+
+         declare
+            Ubt  : constant Entity_Id := Underlying_Type (Base_Type (Exptyp));
+            Decl : Node_Id;
+            Ent  : Entity_Id;
+         begin
+            if Has_Discriminants (Ubt)
+              and then not Is_Constrained (Ubt)
+              and then not Has_Unchecked_Union (Ubt)
+            then
+               Decl := Build_Actual_Subtype (Ubt, Exp);
+               Ent := Defining_Identifier (Decl);
+               Insert_Action (Exp, Decl);
+               Rewrite (Exp, Unchecked_Convert_To (Ent, Exp));
+               Analyze_And_Resolve (Exp);
+            end if;
+         end;
+
+      --  Here if secondary stack is used
+
+      else
+         --  Make sure that no surrounding block will reclaim the secondary
+         --  stack on which we are going to put the result. Not only may this
+         --  introduce secondary stack leaks but worse, if the reclamation is
+         --  done too early, then the result we are returning may get
+         --  clobbered.
+
+         declare
+            S : Entity_Id;
+         begin
+            S := Current_Scope;
+            while Ekind (S) = E_Block or else Ekind (S) = E_Loop loop
+               Set_Sec_Stack_Needed_For_Return (S, True);
+               S := Enclosing_Dynamic_Scope (S);
+            end loop;
+         end;
+
+         --  Optimize the case where the result is a function call. In this
+         --  case either the result is already on the secondary stack, or is
+         --  already being returned with the stack pointer depressed and no
+         --  further processing is required except to set the By_Ref flag
+         --  to ensure that gigi does not attempt an extra unnecessary copy.
+         --  (actually not just unnecessary but harmfully wrong in the case
+         --  of a controlled type, where gigi does not know how to do a copy).
+         --  To make up for a gcc 2.8.1 deficiency (???), we perform the copy
+         --  for array types if the constrained status of the target type is
+         --  different from that of the expression.
+
+         if Requires_Transient_Scope (Exptyp)
+           and then
+              (not Is_Array_Type (Exptyp)
+                or else Is_Constrained (Exptyp) = Is_Constrained (R_Type)
+                or else CW_Or_Has_Controlled_Part (Utyp))
+           and then Nkind (Exp) = N_Function_Call
+         then
+            Set_By_Ref (N);
+
+            --  Remove side effects from the expression now so that other parts
+            --  of the expander do not have to reanalyze this node without this
+            --  optimization
+
+            Rewrite (Exp, Duplicate_Subexpr_No_Checks (Exp));
+
+         --  For controlled types, do the allocation on the secondary stack
+         --  manually in order to call adjust at the right time:
+
+         --    type Anon1 is access R_Type;
+         --    for Anon1'Storage_pool use ss_pool;
+         --    Anon2 : anon1 := new R_Type'(expr);
+         --    return Anon2.all;
+
+         --  We do the same for classwide types that are not potentially
+         --  controlled (by the virtue of restriction No_Finalization) because
+         --  gigi is not able to properly allocate class-wide types.
+
+         elsif CW_Or_Has_Controlled_Part (Utyp) then
+            declare
+               Loc        : constant Source_Ptr := Sloc (N);
+               Acc_Typ    : constant Entity_Id := Make_Temporary (Loc, 'A');
+               Alloc_Node : Node_Id;
+               Temp       : Entity_Id;
+
+            begin
+               Set_Ekind (Acc_Typ, E_Access_Type);
+
+               Set_Associated_Storage_Pool (Acc_Typ, RTE (RE_SS_Pool));
+
+               --  This is an allocator for the secondary stack, and it's fine
+               --  to have Comes_From_Source set False on it, as gigi knows not
+               --  to flag it as a violation of No_Implicit_Heap_Allocations.
+
+               Alloc_Node :=
+                 Make_Allocator (Loc,
+                   Expression =>
+                     Make_Qualified_Expression (Loc,
+                       Subtype_Mark => New_Reference_To (Etype (Exp), Loc),
+                       Expression   => Relocate_Node (Exp)));
+
+               --  We do not want discriminant checks on the declaration,
+               --  given that it gets its value from the allocator.
+
+               Set_No_Initialization (Alloc_Node);
+
+               Temp := Make_Temporary (Loc, 'R', Alloc_Node);
+
+               Insert_List_Before_And_Analyze (N, New_List (
+                 Make_Full_Type_Declaration (Loc,
+                   Defining_Identifier => Acc_Typ,
+                   Type_Definition     =>
+                     Make_Access_To_Object_Definition (Loc,
+                       Subtype_Indication => Subtype_Ind)),
+
+                 Make_Object_Declaration (Loc,
+                   Defining_Identifier => Temp,
+                   Object_Definition   => New_Reference_To (Acc_Typ, Loc),
+                   Expression          => Alloc_Node)));
+
+               Rewrite (Exp,
+                 Make_Explicit_Dereference (Loc,
+                 Prefix => New_Reference_To (Temp, Loc)));
+
+               --  Ada 2005 (AI-251): If the type of the returned object is
+               --  an interface then add an implicit type conversion to force
+               --  displacement of the "this" pointer.
+
+               if Is_Interface (R_Type) then
+                  Rewrite (Exp, Convert_To (R_Type, Relocate_Node (Exp)));
+               end if;
+
+               Analyze_And_Resolve (Exp, R_Type);
+            end;
+
+         --  Otherwise use the gigi mechanism to allocate result on the
+         --  secondary stack.
+
+         else
+            Check_Restriction (No_Secondary_Stack, N);
+            Set_Storage_Pool (N, RTE (RE_SS_Pool));
+
+            --  If we are generating code for the VM do not use
+            --  SS_Allocate since everything is heap-allocated anyway.
+
+            if VM_Target = No_VM then
+               Set_Procedure_To_Call (N, RTE (RE_SS_Allocate));
+            end if;
+         end if;
+      end if;
+
+      --  Implement the rules of 6.5(8-10), which require a tag check in
+      --  the case of a limited tagged return type, and tag reassignment for
+      --  nonlimited tagged results. These actions are needed when the return
+      --  type is a specific tagged type and the result expression is a
+      --  conversion or a formal parameter, because in that case the tag of
+      --  the expression might differ from the tag of the specific result type.
+
+      if Is_Tagged_Type (Utyp)
+        and then not Is_Class_Wide_Type (Utyp)
+        and then (Nkind_In (Exp, N_Type_Conversion,
+                                 N_Unchecked_Type_Conversion)
+                    or else (Is_Entity_Name (Exp)
+                               and then Ekind (Entity (Exp)) in Formal_Kind))
+      then
+         --  When the return type is limited, perform a check that the tag of
+         --  the result is the same as the tag of the return type.
+
+         if Is_Limited_Type (R_Type) then
+            Insert_Action (Exp,
+              Make_Raise_Constraint_Error (Loc,
+                Condition =>
+                  Make_Op_Ne (Loc,
+                    Left_Opnd  =>
+                      Make_Selected_Component (Loc,
+                        Prefix        => Duplicate_Subexpr (Exp),
+                        Selector_Name => Make_Identifier (Loc, Name_uTag)),
+                    Right_Opnd =>
+                      Make_Attribute_Reference (Loc,
+                        Prefix         =>
+                          New_Occurrence_Of (Base_Type (Utyp), Loc),
+                        Attribute_Name => Name_Tag)),
+                Reason    => CE_Tag_Check_Failed));
+
+         --  If the result type is a specific nonlimited tagged type, then we
+         --  have to ensure that the tag of the result is that of the result
+         --  type. This is handled by making a copy of the expression in
+         --  the case where it might have a different tag, namely when the
+         --  expression is a conversion or a formal parameter. We create a new
+         --  object of the result type and initialize it from the expression,
+         --  which will implicitly force the tag to be set appropriately.
+
+         else
+            declare
+               ExpR       : constant Node_Id   := Relocate_Node (Exp);
+               Result_Id  : constant Entity_Id :=
+                              Make_Temporary (Loc, 'R', ExpR);
+               Result_Exp : constant Node_Id   :=
+                              New_Reference_To (Result_Id, Loc);
+               Result_Obj : constant Node_Id   :=
+                              Make_Object_Declaration (Loc,
+                                Defining_Identifier => Result_Id,
+                                Object_Definition   =>
+                                  New_Reference_To (R_Type, Loc),
+                                Constant_Present    => True,
+                                Expression          => ExpR);
+
+            begin
+               Set_Assignment_OK (Result_Obj);
+               Insert_Action (Exp, Result_Obj);
+
+               Rewrite (Exp, Result_Exp);
+               Analyze_And_Resolve (Exp, R_Type);
+            end;
+         end if;
+
+      --  Ada 2005 (AI-344): If the result type is class-wide, then insert
+      --  a check that the level of the return expression's underlying type
+      --  is not deeper than the level of the master enclosing the function.
+      --  Always generate the check when the type of the return expression
+      --  is class-wide, when it's a type conversion, or when it's a formal
+      --  parameter. Otherwise, suppress the check in the case where the
+      --  return expression has a specific type whose level is known not to
+      --  be statically deeper than the function's result type.
+
+      --  Note: accessibility check is skipped in the VM case, since there
+      --  does not seem to be any practical way to implement this check.
+
+      elsif Ada_Version >= Ada_2005
+        and then Tagged_Type_Expansion
+        and then Is_Class_Wide_Type (R_Type)
+        and then not Scope_Suppress (Accessibility_Check)
+        and then
+          (Is_Class_Wide_Type (Etype (Exp))
+            or else Nkind_In (Exp, N_Type_Conversion,
+                                   N_Unchecked_Type_Conversion)
+            or else (Is_Entity_Name (Exp)
+                      and then Ekind (Entity (Exp)) in Formal_Kind)
+            or else Scope_Depth (Enclosing_Dynamic_Scope (Etype (Exp))) >
+                      Scope_Depth (Enclosing_Dynamic_Scope (Scope_Id)))
+      then
+         declare
+            Tag_Node : Node_Id;
+
+         begin
+            --  Ada 2005 (AI-251): In class-wide interface objects we displace
+            --  "this" to reference the base of the object. This is required to
+            --  get access to the TSD of the object.
+
+            if Is_Class_Wide_Type (Etype (Exp))
+              and then Is_Interface (Etype (Exp))
+              and then Nkind (Exp) = N_Explicit_Dereference
+            then
+               Tag_Node :=
+                 Make_Explicit_Dereference (Loc,
+                   Prefix =>
+                     Unchecked_Convert_To (RTE (RE_Tag_Ptr),
+                       Make_Function_Call (Loc,
+                         Name                   =>
+                           New_Reference_To (RTE (RE_Base_Address), Loc),
+                         Parameter_Associations => New_List (
+                           Unchecked_Convert_To (RTE (RE_Address),
+                             Duplicate_Subexpr (Prefix (Exp)))))));
+            else
+               Tag_Node :=
+                 Make_Attribute_Reference (Loc,
+                   Prefix         => Duplicate_Subexpr (Exp),
+                   Attribute_Name => Name_Tag);
+            end if;
+
+            Insert_Action (Exp,
+              Make_Raise_Program_Error (Loc,
+                Condition =>
+                  Make_Op_Gt (Loc,
+                    Left_Opnd  => Build_Get_Access_Level (Loc, Tag_Node),
+                    Right_Opnd =>
+                      Make_Integer_Literal (Loc,
+                        Scope_Depth (Enclosing_Dynamic_Scope (Scope_Id)))),
+                Reason => PE_Accessibility_Check_Failed));
+         end;
+
+      --  AI05-0073: If function has a controlling access result, check that
+      --  the tag of the return value, if it is not null, matches designated
+      --  type of return type.
+      --  The return expression is referenced twice in the code below, so
+      --  it must be made free of side effects. Given that different compilers
+      --  may evaluate these parameters in different order, both occurrences
+      --  perform a copy.
+
+      elsif Ekind (R_Type) = E_Anonymous_Access_Type
+        and then Has_Controlling_Result (Scope_Id)
+      then
+         Insert_Action (N,
+           Make_Raise_Constraint_Error (Loc,
+             Condition =>
+               Make_And_Then (Loc,
+                 Left_Opnd  =>
+                   Make_Op_Ne (Loc,
+                     Left_Opnd  => Duplicate_Subexpr (Exp),
+                     Right_Opnd => Make_Null (Loc)),
+
+                 Right_Opnd => Make_Op_Ne (Loc,
+                   Left_Opnd  =>
+                     Make_Selected_Component (Loc,
+                       Prefix        => Duplicate_Subexpr (Exp),
+                       Selector_Name => Make_Identifier (Loc, Name_uTag)),
+
+                   Right_Opnd =>
+                     Make_Attribute_Reference (Loc,
+                       Prefix         =>
+                         New_Occurrence_Of (Designated_Type (R_Type), Loc),
+                       Attribute_Name => Name_Tag))),
+
+             Reason    => CE_Tag_Check_Failed),
+             Suppress  => All_Checks);
+      end if;
+
+      --  AI05-0234: RM 6.5(21/3). Check access discriminants to
+      --  ensure that the function result does not outlive an
+      --  object designated by one of it discriminants.
+
+      if Present (Extra_Accessibility_Of_Result (Scope_Id))
+        and then Has_Unconstrained_Access_Discriminants (R_Type)
+      then
+         declare
+            Discrim_Source : Node_Id;
+
+            procedure Check_Against_Result_Level (Level : Node_Id);
+            --  Check the given accessibility level against the level
+            --  determined by the point of call. (AI05-0234).
+
+            --------------------------------
+            -- Check_Against_Result_Level --
+            --------------------------------
+
+            procedure Check_Against_Result_Level (Level : Node_Id) is
+            begin
+               Insert_Action (N,
+                 Make_Raise_Program_Error (Loc,
+                   Condition =>
+                     Make_Op_Gt (Loc,
+                       Left_Opnd  => Level,
+                       Right_Opnd =>
+                         New_Occurrence_Of
+                           (Extra_Accessibility_Of_Result (Scope_Id), Loc)),
+                       Reason => PE_Accessibility_Check_Failed));
+            end Check_Against_Result_Level;
+
+         begin
+            Discrim_Source := Exp;
+            while Nkind (Discrim_Source) = N_Qualified_Expression loop
+               Discrim_Source := Expression (Discrim_Source);
+            end loop;
+
+            if Nkind (Discrim_Source) = N_Identifier
+              and then Is_Return_Object (Entity (Discrim_Source))
+            then
+               Discrim_Source := Entity (Discrim_Source);
+
+               if Is_Constrained (Etype (Discrim_Source)) then
+                  Discrim_Source := Etype (Discrim_Source);
+               else
+                  Discrim_Source := Expression (Parent (Discrim_Source));
+               end if;
+
+            elsif Nkind (Discrim_Source) = N_Identifier
+              and then Nkind_In (Original_Node (Discrim_Source),
+                                 N_Aggregate, N_Extension_Aggregate)
+            then
+               Discrim_Source := Original_Node (Discrim_Source);
+
+            elsif Nkind (Discrim_Source) = N_Explicit_Dereference and then
+              Nkind (Original_Node (Discrim_Source)) = N_Function_Call
+            then
+               Discrim_Source := Original_Node (Discrim_Source);
+            end if;
+
+            while Nkind_In (Discrim_Source, N_Qualified_Expression,
+                                            N_Type_Conversion,
+                                            N_Unchecked_Type_Conversion)
+            loop
+               Discrim_Source := Expression (Discrim_Source);
+            end loop;
+
+            case Nkind (Discrim_Source) is
+               when N_Defining_Identifier =>
+
+                  pragma Assert (Is_Composite_Type (Discrim_Source)
+                                  and then Has_Discriminants (Discrim_Source)
+                                  and then Is_Constrained (Discrim_Source));
+
+                  declare
+                     Discrim   : Entity_Id :=
+                                   First_Discriminant (Base_Type (R_Type));
+                     Disc_Elmt : Elmt_Id   :=
+                                   First_Elmt (Discriminant_Constraint
+                                                 (Discrim_Source));
+                  begin
+                     loop
+                        if Ekind (Etype (Discrim)) =
+                             E_Anonymous_Access_Type
+                        then
+                           Check_Against_Result_Level
+                             (Dynamic_Accessibility_Level (Node (Disc_Elmt)));
+                        end if;
+
+                        Next_Elmt (Disc_Elmt);
+                        Next_Discriminant (Discrim);
+                        exit when not Present (Discrim);
+                     end loop;
+                  end;
+
+               when N_Aggregate | N_Extension_Aggregate =>
+
+                  --  Unimplemented: extension aggregate case where discrims
+                  --  come from ancestor part, not extension part.
+
+                  declare
+                     Discrim  : Entity_Id :=
+                                  First_Discriminant (Base_Type (R_Type));
+
+                     Disc_Exp : Node_Id   := Empty;
+
+                     Positionals_Exhausted
+                              : Boolean   := not Present (Expressions
+                                                            (Discrim_Source));
+
+                     function Associated_Expr
+                       (Comp_Id : Entity_Id;
+                        Associations : List_Id) return Node_Id;
+
+                     --  Given a component and a component associations list,
+                     --  locate the expression for that component; returns
+                     --  Empty if no such expression is found.
+
+                     ---------------------
+                     -- Associated_Expr --
+                     ---------------------
+
+                     function Associated_Expr
+                       (Comp_Id : Entity_Id;
+                        Associations : List_Id) return Node_Id
+                     is
+                        Assoc  : Node_Id;
+                        Choice : Node_Id;
+
+                     begin
+                        --  Simple linear search seems ok here
+
+                        Assoc := First (Associations);
+                        while Present (Assoc) loop
+                           Choice := First (Choices (Assoc));
+                           while Present (Choice) loop
+                              if (Nkind (Choice) = N_Identifier
+                                   and then Chars (Choice) = Chars (Comp_Id))
+                                or else (Nkind (Choice) = N_Others_Choice)
+                              then
+                                 return Expression (Assoc);
+                              end if;
+
+                              Next (Choice);
+                           end loop;
+
+                           Next (Assoc);
+                        end loop;
+
+                        return Empty;
+                     end Associated_Expr;
+
+                  --  Start of processing for Expand_Simple_Function_Return
+
+                  begin
+                     if not Positionals_Exhausted then
+                        Disc_Exp := First (Expressions (Discrim_Source));
+                     end if;
+
+                     loop
+                        if Positionals_Exhausted then
+                           Disc_Exp :=
+                             Associated_Expr
+                               (Discrim,
+                                Component_Associations (Discrim_Source));
+                        end if;
+
+                        if Ekind (Etype (Discrim)) =
+                             E_Anonymous_Access_Type
+                        then
+                           Check_Against_Result_Level
+                             (Dynamic_Accessibility_Level (Disc_Exp));
+                        end if;
+
+                        Next_Discriminant (Discrim);
+                        exit when not Present (Discrim);
+
+                        if not Positionals_Exhausted then
+                           Next (Disc_Exp);
+                           Positionals_Exhausted := not Present (Disc_Exp);
+                        end if;
+                     end loop;
+                  end;
+
+               when N_Function_Call =>
+
+                  --  No check needed (check performed by callee)
+
+                  null;
+
+               when others =>
+
+                  declare
+                     Level : constant Node_Id :=
+                               Make_Integer_Literal (Loc,
+                                 Object_Access_Level (Discrim_Source));
+
+                  begin
+                     --  Unimplemented: check for name prefix that includes
+                     --  a dereference of an access value with a dynamic
+                     --  accessibility level (e.g., an access param or a
+                     --  saooaaat) and use dynamic level in that case. For
+                     --  example:
+                     --    return Access_Param.all(Some_Index).Some_Component;
+                     --  ???
+
+                     Set_Etype (Level, Standard_Natural);
+                     Check_Against_Result_Level (Level);
+                  end;
+
+            end case;
+         end;
+      end if;
+
+      --  If we are returning an object that may not be bit-aligned, then copy
+      --  the value into a temporary first. This copy may need to expand to a
+      --  loop of component operations.
+
+      if Is_Possibly_Unaligned_Slice (Exp)
+        or else Is_Possibly_Unaligned_Object (Exp)
+      then
+         declare
+            ExpR : constant Node_Id   := Relocate_Node (Exp);
+            Tnn  : constant Entity_Id := Make_Temporary (Loc, 'T', ExpR);
+         begin
+            Insert_Action (Exp,
+              Make_Object_Declaration (Loc,
+                Defining_Identifier => Tnn,
+                Constant_Present    => True,
+                Object_Definition   => New_Occurrence_Of (R_Type, Loc),
+                Expression          => ExpR),
+              Suppress => All_Checks);
+            Rewrite (Exp, New_Occurrence_Of (Tnn, Loc));
+         end;
+      end if;
+
+      --  Generate call to postcondition checks if they are present
 
-         Build_Protected_Subprogram_Call (N,
-           Name => New_Occurrence_Of (Subp, Sloc (N)),
-           Rec =>  Convert_Concurrent (Rec, Etype (Rec)),
-           External => True);
+      if Ekind (Scope_Id) = E_Function
+        and then Has_Postconditions (Scope_Id)
+      then
+         --  We are going to reference the returned value twice in this case,
+         --  once in the call to _Postconditions, and once in the actual return
+         --  statement, but we can't have side effects happening twice, and in
+         --  any case for efficiency we don't want to do the computation twice.
+
+         --  If the returned expression is an entity name, we don't need to
+         --  worry since it is efficient and safe to reference it twice, that's
+         --  also true for literals other than string literals, and for the
+         --  case of X.all where X is an entity name.
+
+         if Is_Entity_Name (Exp)
+           or else Nkind_In (Exp, N_Character_Literal,
+                                  N_Integer_Literal,
+                                  N_Real_Literal)
+           or else (Nkind (Exp) = N_Explicit_Dereference
+                     and then Is_Entity_Name (Prefix (Exp)))
+         then
+            null;
 
-      else
-         Rec := Expand_Protected_Object_Reference (N, Scop);
+         --  Otherwise we are going to need a temporary to capture the value
 
-         if No (Rec) then
-            return;
-         end if;
+         else
+            declare
+               ExpR : constant Node_Id   := Relocate_Node (Exp);
+               Tnn  : constant Entity_Id := Make_Temporary (Loc, 'T', ExpR);
 
-         Build_Protected_Subprogram_Call (N,
-           Name     => Name (N),
-           Rec      => Rec,
-           External => False);
+            begin
+               --  For a complex expression of an elementary type, capture
+               --  value in the temporary and use it as the reference.
+
+               if Is_Elementary_Type (R_Type) then
+                  Insert_Action (Exp,
+                    Make_Object_Declaration (Loc,
+                      Defining_Identifier => Tnn,
+                      Constant_Present    => True,
+                      Object_Definition   => New_Occurrence_Of (R_Type, Loc),
+                      Expression          => ExpR),
+                    Suppress => All_Checks);
+
+                  Rewrite (Exp, New_Occurrence_Of (Tnn, Loc));
+
+               --  If we have something we can rename, generate a renaming of
+               --  the object and replace the expression with a reference
+
+               elsif Is_Object_Reference (Exp) then
+                  Insert_Action (Exp,
+                    Make_Object_Renaming_Declaration (Loc,
+                      Defining_Identifier => Tnn,
+                      Subtype_Mark        => New_Occurrence_Of (R_Type, Loc),
+                      Name                => ExpR),
+                    Suppress => All_Checks);
+
+                  Rewrite (Exp, New_Occurrence_Of (Tnn, Loc));
+
+               --  Otherwise we have something like a string literal or an
+               --  aggregate. We could copy the value, but that would be
+               --  inefficient. Instead we make a reference to the value and
+               --  capture this reference with a renaming, the expression is
+               --  then replaced by a dereference of this renaming.
 
-      end if;
+               else
+                  --  For now, copy the value, since the code below does not
+                  --  seem to work correctly ???
+
+                  Insert_Action (Exp,
+                    Make_Object_Declaration (Loc,
+                      Defining_Identifier => Tnn,
+                      Constant_Present    => True,
+                      Object_Definition   => New_Occurrence_Of (R_Type, Loc),
+                      Expression          => Relocate_Node (Exp)),
+                    Suppress => All_Checks);
+
+                  Rewrite (Exp, New_Occurrence_Of (Tnn, Loc));
+
+                  --  Insert_Action (Exp,
+                  --    Make_Object_Renaming_Declaration (Loc,
+                  --      Defining_Identifier => Tnn,
+                  --      Access_Definition =>
+                  --        Make_Access_Definition (Loc,
+                  --          All_Present  => True,
+                  --          Subtype_Mark => New_Occurrence_Of (R_Type, Loc)),
+                  --      Name =>
+                  --        Make_Reference (Loc,
+                  --          Prefix => Relocate_Node (Exp))),
+                  --    Suppress => All_Checks);
+
+                  --  Rewrite (Exp,
+                  --    Make_Explicit_Dereference (Loc,
+                  --      Prefix => New_Occurrence_Of (Tnn, Loc)));
+               end if;
+            end;
+         end if;
 
-      --  If it is a function call it can appear in elaboration code and
-      --  the called entity must be frozen here.
+         --  Generate call to _postconditions
 
-      if Ekind (Subp) = E_Function then
-         Freeze_Expression (Name (N));
+         Insert_Action (Exp,
+           Make_Procedure_Call_Statement (Loc,
+             Name => Make_Identifier (Loc, Name_uPostconditions),
+             Parameter_Associations => New_List (Duplicate_Subexpr (Exp))));
       end if;
 
-      --  Analyze and resolve the new call. The actuals have already been
-      --  resolved, but expansion of a function call will add extra actuals
-      --  if needed. Analysis of a procedure call already includes resolution.
-
-      Analyze (N);
+      --  Ada 2005 (AI-251): If this return statement corresponds with an
+      --  simple return statement associated with an extended return statement
+      --  and the type of the returned object is an interface then generate an
+      --  implicit conversion to force displacement of the "this" pointer.
 
-      if Ekind (Subp) = E_Function then
-         Resolve (N, Etype (Subp));
+      if Ada_Version >= Ada_2005
+        and then Comes_From_Extended_Return_Statement (N)
+        and then Nkind (Expression (N)) = N_Identifier
+        and then Is_Interface (Utyp)
+        and then Utyp /= Underlying_Type (Exptyp)
+      then
+         Rewrite (Exp, Convert_To (Utyp, Relocate_Node (Exp)));
+         Analyze_And_Resolve (Exp);
       end if;
-   end Expand_Protected_Subprogram_Call;
+   end Expand_Simple_Function_Return;
 
    --------------------------------
    -- Is_Build_In_Place_Function --
@@ -4781,8 +7290,8 @@ package body Exp_Ch6 is
          --  may return objects of nonlimited descendants.
 
          else
-            return Is_Inherently_Limited_Type (Etype (E))
-              and then Ada_Version >= Ada_05
+            return Is_Immutably_Limited_Type (Etype (E))
+              and then Ada_Version >= Ada_2005
               and then not Debug_Flag_Dot_L;
          end if;
 
@@ -4800,11 +7309,23 @@ package body Exp_Ch6 is
       Function_Id : Entity_Id;
 
    begin
+      --  Return False when the expander is inactive, since awareness of
+      --  build-in-place treatment is only relevant during expansion. Note that
+      --  Is_Build_In_Place_Function, which is called as part of this function,
+      --  is also conditioned this way, but we need to check here as well to
+      --  avoid blowing up on processing protected calls when expansion is
+      --  disabled (such as with -gnatc) since those would trip over the raise
+      --  of Program_Error below.
+
+      if not Expander_Active then
+         return False;
+      end if;
+
       --  Step past qualification or unchecked conversion (the latter can occur
       --  in cases of calls to 'Input).
 
-      if Nkind_In
-           (Exp_Node, N_Qualified_Expression, N_Unchecked_Type_Conversion)
+      if Nkind_In (Exp_Node, N_Qualified_Expression,
+                             N_Unchecked_Type_Conversion)
       then
          Exp_Node := Expression (N);
       end if;
@@ -4813,11 +7334,24 @@ package body Exp_Ch6 is
          return False;
 
       else
-         if Is_Entity_Name (Name (Exp_Node)) then
+         --  In Alfa mode, build-in-place calls are not expanded, so that we
+         --  may end up with a call that is neither resolved to an entity, nor
+         --  an indirect call.
+
+         if Alfa_Mode then
+            return False;
+
+         elsif Is_Entity_Name (Name (Exp_Node)) then
             Function_Id := Entity (Name (Exp_Node));
 
+         --  In the case of an explicitly dereferenced call, use the subprogram
+         --  type generated for the dereference.
+
          elsif Nkind (Name (Exp_Node)) = N_Explicit_Dereference then
             Function_Id := Etype (Name (Exp_Node));
+
+         else
+            raise Program_Error;
          end if;
 
          return Is_Build_In_Place_Function (Function_Id);
@@ -4866,7 +7400,7 @@ package body Exp_Ch6 is
            Next_Elmt (Next_Elmt (First_Elmt (Access_Disp_Table (Tagged_Typ))));
 
          while Present (Iface_DT_Ptr)
-            and then Ekind (Node (Iface_DT_Ptr)) = E_Constant
+           and then Ekind (Node (Iface_DT_Ptr)) = E_Constant
          loop
             pragma Assert (Has_Thunks (Node (Iface_DT_Ptr)));
             Expand_Interface_Thunk (Prim, Thunk_Id, Thunk_Code);
@@ -4876,9 +7410,9 @@ package body Exp_Ch6 is
                  Thunk_Code,
 
                  Build_Set_Predefined_Prim_Op_Address (Loc,
-                   Tag_Node =>
+                   Tag_Node     =>
                      New_Reference_To (Node (Next_Elmt (Iface_DT_Ptr)), Loc),
-                   Position => DT_Position (Prim),
+                   Position     => DT_Position (Prim),
                    Address_Node =>
                      Unchecked_Convert_To (RTE (RE_Prim_Ptr),
                        Make_Attribute_Reference (Loc,
@@ -4886,11 +7420,11 @@ package body Exp_Ch6 is
                          Attribute_Name => Name_Unrestricted_Access))),
 
                  Build_Set_Predefined_Prim_Op_Address (Loc,
-                   Tag_Node =>
+                   Tag_Node     =>
                      New_Reference_To
                       (Node (Next_Elmt (Next_Elmt (Next_Elmt (Iface_DT_Ptr)))),
                        Loc),
-                   Position => DT_Position (Prim),
+                   Position     => DT_Position (Prim),
                    Address_Node =>
                      Unchecked_Convert_To (RTE (RE_Prim_Ptr),
                        Make_Attribute_Reference (Loc,
@@ -4903,13 +7437,12 @@ package body Exp_Ch6 is
             Next_Elmt (Iface_DT_Ptr);
             pragma Assert (Has_Thunks (Node (Iface_DT_Ptr)));
 
-            --  Skip the tag of the no-thunks dispatch table
+            --  Skip tag of the no-thunks dispatch table
 
             Next_Elmt (Iface_DT_Ptr);
             pragma Assert (not Has_Thunks (Node (Iface_DT_Ptr)));
 
-            --  Skip the tag of the predefined primitives no-thunks dispatch
-            --  table
+            --  Skip tag of predefined primitives no-thunks dispatch table
 
             Next_Elmt (Iface_DT_Ptr);
             pragma Assert (not Has_Thunks (Node (Iface_DT_Ptr)));
@@ -4920,7 +7453,7 @@ package body Exp_Ch6 is
 
       --  Local variables
 
-      Subp : constant Entity_Id := Entity (N);
+      Subp : constant Entity_Id  := Entity (N);
 
    --  Start of processing for Freeze_Subprogram
 
@@ -4961,18 +7494,16 @@ package body Exp_Ch6 is
             --  slots.
 
             elsif Is_Imported (Subp)
-                    and then (Convention (Subp) = Convention_CPP
-                                or else Convention (Subp) = Convention_C)
+               and then (Convention (Subp) = Convention_CPP
+                           or else Convention (Subp) = Convention_C)
             then
                null;
 
             --  Generate code to register the primitive in non statically
             --  allocated dispatch tables
 
-            elsif not Static_Dispatch_Tables
-              or else not
-                Is_Library_Level_Tagged_Type (Scope (DTC_Entity (Subp)))
-            then
+            elsif not Building_Static_DT (Scope (DTC_Entity (Subp))) then
+
                --  When a primitive is frozen, enter its name in its dispatch
                --  table slot.
 
@@ -4998,7 +7529,7 @@ package body Exp_Ch6 is
          Typ  : constant Entity_Id := Etype (Subp);
          Utyp : constant Entity_Id := Underlying_Type (Typ);
       begin
-         if Is_Inherently_Limited_Type (Typ) then
+         if Is_Immutably_Limited_Type (Typ) then
             Set_Returns_By_Ref (Subp);
          elsif Present (Utyp) and then CW_Or_Has_Controlled_Part (Utyp) then
             Set_Returns_By_Ref (Subp);
@@ -5073,11 +7604,11 @@ package body Exp_Ch6 is
      (Allocator     : Node_Id;
       Function_Call : Node_Id)
    is
+      Acc_Type          : constant Entity_Id := Etype (Allocator);
       Loc               : Source_Ptr;
       Func_Call         : Node_Id := Function_Call;
       Function_Id       : Entity_Id;
       Result_Subt       : Entity_Id;
-      Acc_Type          : constant Entity_Id := Etype (Allocator);
       New_Allocator     : Node_Id;
       Return_Obj_Access : Entity_Id;
 
@@ -5116,7 +7647,14 @@ package body Exp_Ch6 is
          raise Program_Error;
       end if;
 
-      Result_Subt := Etype (Function_Id);
+      Result_Subt := Available_View (Etype (Function_Id));
+
+      --  Check whether return type includes tasks. This may not have been done
+      --  previously, if the type was a limited view.
+
+      if Has_Task (Result_Subt) then
+         Build_Activation_Chain_Entity (Allocator);
+      end if;
 
       --  When the result subtype is constrained, the return object must be
       --  allocated on the caller side, and access to it is passed to the
@@ -5170,10 +7708,10 @@ package body Exp_Ch6 is
          --  called as a dispatching operation and must be treated similarly
          --  to functions with unconstrained result subtypes.
 
-         Add_Alloc_Form_Actual_To_Build_In_Place_Call
+         Add_Unconstrained_Actuals_To_Build_In_Place_Call
            (Func_Call, Function_Id, Alloc_Form => Caller_Allocation);
 
-         Add_Final_List_Actual_To_Build_In_Place_Call
+         Add_Finalization_Master_Actual_To_Build_In_Place_Call
            (Func_Call, Function_Id, Acc_Type);
 
          Add_Task_Actuals_To_Build_In_Place_Call
@@ -5201,14 +7739,32 @@ package body Exp_Ch6 is
       --  operations. ???
 
       else
+         --  Case of a user-defined storage pool. Pass an allocation parameter
+         --  indicating that the function should allocate its result in the
+         --  pool, and pass the pool. Use 'Unrestricted_Access because the
+         --  pool may not be aliased.
 
-         --  Pass an allocation parameter indicating that the function should
-         --  allocate its result on the heap.
+         if VM_Target = No_VM
+           and then Present (Associated_Storage_Pool (Acc_Type))
+         then
+            Add_Unconstrained_Actuals_To_Build_In_Place_Call
+              (Func_Call, Function_Id, Alloc_Form => User_Storage_Pool,
+               Pool_Actual =>
+                 Make_Attribute_Reference (Loc,
+                   Prefix         =>
+                     New_Reference_To
+                       (Associated_Storage_Pool (Acc_Type), Loc),
+                   Attribute_Name => Name_Unrestricted_Access));
+
+         --  No user-defined pool; pass an allocation parameter indicating that
+         --  the function should allocate its result on the heap.
 
-         Add_Alloc_Form_Actual_To_Build_In_Place_Call
-           (Func_Call, Function_Id, Alloc_Form => Global_Heap);
+         else
+            Add_Unconstrained_Actuals_To_Build_In_Place_Call
+              (Func_Call, Function_Id, Alloc_Form => Global_Heap);
+         end if;
 
-         Add_Final_List_Actual_To_Build_In_Place_Call
+         Add_Finalization_Master_Actual_To_Build_In_Place_Call
            (Func_Call, Function_Id, Acc_Type);
 
          Add_Task_Actuals_To_Build_In_Place_Call
@@ -5221,11 +7777,51 @@ package body Exp_Ch6 is
            (Func_Call, Function_Id, Return_Object => Empty);
       end if;
 
+      --  If the build-in-place function call returns a controlled object,
+      --  the finalization master will require a reference to routine
+      --  Finalize_Address of the designated type. Setting this attribute
+      --  is done in the same manner to expansion of allocators.
+
+      if Needs_Finalization (Result_Subt) then
+
+         --  Controlled types with supressed finalization do not need to
+         --  associate the address of their Finalize_Address primitives with
+         --  a master since they do not need a master to begin with.
+
+         if Is_Library_Level_Entity (Acc_Type)
+           and then Finalize_Storage_Only (Result_Subt)
+         then
+            null;
+
+         --  Do not generate the call to Set_Finalize_Address in Alfa mode
+         --  because it is not necessary and results in unwanted expansion.
+         --  This expansion is also not carried out in CodePeer mode because
+         --  Finalize_Address is never built.
+
+         elsif not Alfa_Mode
+           and then not CodePeer_Mode
+         then
+            Insert_Action (Allocator,
+              Make_Set_Finalize_Address_Call (Loc,
+                Typ     => Etype (Function_Id),
+                Ptr_Typ => Acc_Type));
+         end if;
+      end if;
+
       --  Finally, replace the allocator node with a reference to the result
       --  of the function call itself (which will effectively be an access
       --  to the object created by the allocator).
 
       Rewrite (Allocator, Make_Reference (Loc, Relocate_Node (Function_Call)));
+
+      --  Ada 2005 (AI-251): If the type of the allocator is an interface then
+      --  generate an implicit conversion to force displacement of the "this"
+      --  pointer.
+
+      if Is_Interface (Designated_Type (Acc_Type)) then
+         Rewrite (Allocator, Convert_To (Acc_Type, Relocate_Node (Allocator)));
+      end if;
+
       Analyze_And_Resolve (Allocator, Acc_Type);
    end Make_Build_In_Place_Call_In_Allocator;
 
@@ -5281,10 +7877,47 @@ package body Exp_Ch6 is
 
       Result_Subt := Etype (Function_Id);
 
+      --  If the build-in-place function returns a controlled object, then the
+      --  object needs to be finalized immediately after the context. Since
+      --  this case produces a transient scope, the servicing finalizer needs
+      --  to name the returned object. Create a temporary which is initialized
+      --  with the function call:
+      --
+      --    Temp_Id : Func_Type := BIP_Func_Call;
+      --
+      --  The initialization expression of the temporary will be rewritten by
+      --  the expander using the appropriate mechanism in Make_Build_In_Place_
+      --  Call_In_Object_Declaration.
+
+      if Needs_Finalization (Result_Subt) then
+         declare
+            Temp_Id   : constant Entity_Id := Make_Temporary (Loc, 'R');
+            Temp_Decl : Node_Id;
+
+         begin
+            --  Reset the guard on the function call since the following does
+            --  not perform actual call expansion.
+
+            Set_Is_Expanded_Build_In_Place_Call (Func_Call, False);
+
+            Temp_Decl :=
+              Make_Object_Declaration (Loc,
+                Defining_Identifier => Temp_Id,
+                Object_Definition =>
+                  New_Reference_To (Result_Subt, Loc),
+                Expression =>
+                  New_Copy_Tree (Function_Call));
+
+            Insert_Action (Function_Call, Temp_Decl);
+
+            Rewrite (Function_Call, New_Reference_To (Temp_Id, Loc));
+            Analyze (Function_Call);
+         end;
+
       --  When the result subtype is constrained, an object of the subtype is
       --  declared and an access value designating it is passed as an actual.
 
-      if Is_Constrained (Underlying_Type (Result_Subt)) then
+      elsif Is_Constrained (Underlying_Type (Result_Subt)) then
 
          --  Create a temporary object to hold the function result
 
@@ -5307,11 +7940,11 @@ package body Exp_Ch6 is
          --  called as a dispatching operation and must be treated similarly
          --  to functions with unconstrained result subtypes.
 
-         Add_Alloc_Form_Actual_To_Build_In_Place_Call
+         Add_Unconstrained_Actuals_To_Build_In_Place_Call
            (Func_Call, Function_Id, Alloc_Form => Caller_Allocation);
 
-         Add_Final_List_Actual_To_Build_In_Place_Call
-           (Func_Call, Function_Id, Acc_Type => Empty);
+         Add_Finalization_Master_Actual_To_Build_In_Place_Call
+           (Func_Call, Function_Id);
 
          Add_Task_Actuals_To_Build_In_Place_Call
            (Func_Call, Function_Id, Make_Identifier (Loc, Name_uMaster));
@@ -5328,15 +7961,14 @@ package body Exp_Ch6 is
       --  scope is established to ensure eventual cleanup of the result.
 
       else
-
          --  Pass an allocation parameter indicating that the function should
          --  allocate its result on the secondary stack.
 
-         Add_Alloc_Form_Actual_To_Build_In_Place_Call
+         Add_Unconstrained_Actuals_To_Build_In_Place_Call
            (Func_Call, Function_Id, Alloc_Form => Secondary_Stack);
 
-         Add_Final_List_Actual_To_Build_In_Place_Call
-           (Func_Call, Function_Id, Acc_Type => Empty);
+         Add_Finalization_Master_Actual_To_Build_In_Place_Call
+           (Func_Call, Function_Id);
 
          Add_Task_Actuals_To_Build_In_Place_Call
            (Func_Call, Function_Id, Make_Identifier (Loc, Name_uMaster));
@@ -5346,8 +7978,6 @@ package body Exp_Ch6 is
 
          Add_Access_Actual_To_Build_In_Place_Call
            (Func_Call, Function_Id, Empty);
-
-         Establish_Transient_Scope (Func_Call, Sec_Stack => True);
       end if;
    end Make_Build_In_Place_Call_In_Anonymous_Context;
 
@@ -5367,6 +7997,7 @@ package body Exp_Ch6 is
       Obj_Id       : Entity_Id;
       Ptr_Typ      : Entity_Id;
       Ptr_Typ_Decl : Node_Id;
+      New_Expr     : Node_Id;
       Result_Subt  : Entity_Id;
       Target       : Node_Id;
 
@@ -5412,19 +8043,11 @@ package body Exp_Ch6 is
       --  controlling result, because dispatching calls to the function needs
       --  to be treated effectively the same as calls to class-wide functions.
 
-      Add_Alloc_Form_Actual_To_Build_In_Place_Call
+      Add_Unconstrained_Actuals_To_Build_In_Place_Call
         (Func_Call, Func_Id, Alloc_Form => Caller_Allocation);
 
-      --  If Lhs is a selected component, then pass it along so that its prefix
-      --  object will be used as the source of the finalization list.
-
-      if Nkind (Lhs) = N_Selected_Component then
-         Add_Final_List_Actual_To_Build_In_Place_Call
-           (Func_Call, Func_Id, Acc_Type => Empty, Sel_Comp => Lhs);
-      else
-         Add_Final_List_Actual_To_Build_In_Place_Call
-           (Func_Call, Func_Id, Acc_Type => Empty);
-      end if;
+      Add_Finalization_Master_Actual_To_Build_In_Place_Call
+        (Func_Call, Func_Id);
 
       Add_Task_Actuals_To_Build_In_Place_Call
         (Func_Call, Func_Id, Make_Identifier (Loc, Name_uMaster));
@@ -5446,27 +8069,28 @@ package body Exp_Ch6 is
       Ptr_Typ_Decl :=
         Make_Full_Type_Declaration (Loc,
           Defining_Identifier => Ptr_Typ,
-          Type_Definition =>
+          Type_Definition     =>
             Make_Access_To_Object_Definition (Loc,
-              All_Present => True,
+              All_Present        => True,
               Subtype_Indication =>
                 New_Reference_To (Result_Subt, Loc)));
       Insert_After_And_Analyze (Assign, Ptr_Typ_Decl);
 
       --  Finally, create an access object initialized to a reference to the
-      --  function call.
+      --  function call. We know this access value is non-null, so mark the
+      --  entity accordingly to suppress junk access checks.
+
+      New_Expr := Make_Reference (Loc, Relocate_Node (Func_Call));
 
-      Obj_Id := Make_Temporary (Loc, 'R');
+      Obj_Id := Make_Temporary (Loc, 'R', New_Expr);
       Set_Etype (Obj_Id, Ptr_Typ);
+      Set_Is_Known_Non_Null (Obj_Id);
 
       Obj_Decl :=
         Make_Object_Declaration (Loc,
           Defining_Identifier => Obj_Id,
-          Object_Definition =>
-            New_Reference_To (Ptr_Typ, Loc),
-          Expression =>
-            Make_Reference (Loc,
-              Prefix => Relocate_Node (Func_Call)));
+          Object_Definition   => New_Reference_To (Ptr_Typ, Loc),
+          Expression          => New_Expr);
       Insert_After_And_Analyze (Ptr_Typ_Decl, Obj_Decl);
 
       Rewrite (Assign, Make_Null_Statement (Loc));
@@ -5490,58 +8114,6 @@ package body Exp_Ch6 is
       else
          return;
       end if;
-
-      --  When the target of the assignment is a return object of an enclosing
-      --  build-in-place function and also requires finalization, the list
-      --  generated for the assignment must be moved to that of the enclosing
-      --  function.
-
-      --    function Enclosing_BIP_Function return Ctrl_Typ is
-      --    begin
-      --       return (Ctrl_Parent_Part => BIP_Function with ...);
-      --    end Enclosing_BIP_Function;
-
-      if Is_Return_Object (Target)
-        and then Needs_Finalization (Etype (Target))
-        and then Needs_Finalization (Result_Subt)
-      then
-         declare
-            Obj_List  : constant Node_Id := Find_Final_List (Obj_Id);
-            Encl_List : Node_Id;
-            Encl_Scop : Entity_Id;
-
-         begin
-            Encl_Scop := Scope (Target);
-
-            --  Locate the scope of the extended return statement
-
-            while Present (Encl_Scop)
-              and then Ekind (Encl_Scop) /= E_Return_Statement
-            loop
-               Encl_Scop := Scope (Encl_Scop);
-            end loop;
-
-            --  A return object should always be enclosed by a return statement
-            --  scope at some level.
-
-            pragma Assert (Present (Encl_Scop));
-
-            Encl_List :=
-              Make_Attribute_Reference (Loc,
-                Prefix =>
-                  New_Reference_To (
-                    Finalization_Chain_Entity (Encl_Scop), Loc),
-                Attribute_Name => Name_Unrestricted_Access);
-
-            --  Generate a call to move final list
-
-            Insert_After_And_Analyze (Obj_Decl,
-              Make_Procedure_Call_Statement (Loc,
-                Name =>
-                  New_Reference_To (RTE (RE_Move_Final_List), Loc),
-                Parameter_Associations => New_List (Obj_List, Encl_List)));
-         end;
-      end if;
    end Make_Build_In_Place_Call_In_Assignment;
 
    ----------------------------------------------------
@@ -5555,18 +8127,20 @@ package body Exp_Ch6 is
       Loc             : Source_Ptr;
       Obj_Def_Id      : constant Entity_Id :=
                           Defining_Identifier (Object_Decl);
-
+      Enclosing_Func  : constant Entity_Id :=
+                          Enclosing_Subprogram (Obj_Def_Id);
+      Call_Deref      : Node_Id;
+      Caller_Object   : Node_Id;
+      Def_Id          : Entity_Id;
+      Fmaster_Actual  : Node_Id := Empty;
       Func_Call       : Node_Id := Function_Call;
       Function_Id     : Entity_Id;
-      Result_Subt     : Entity_Id;
-      Caller_Object   : Node_Id;
-      Call_Deref      : Node_Id;
-      Ref_Type        : Entity_Id;
+      Pool_Actual     : Node_Id;
       Ptr_Typ_Decl    : Node_Id;
-      Def_Id          : Entity_Id;
-      New_Expr        : Node_Id;
-      Enclosing_Func  : Entity_Id;
       Pass_Caller_Acc : Boolean := False;
+      New_Expr        : Node_Id;
+      Ref_Type        : Entity_Id;
+      Result_Subt     : Entity_Id;
 
    begin
       --  Step past qualification or unchecked conversion (the latter can occur
@@ -5604,61 +8178,59 @@ package body Exp_Ch6 is
 
       Result_Subt := Etype (Function_Id);
 
-      --  In the constrained case, add an implicit actual to the function call
-      --  that provides access to the declared object. An unchecked conversion
-      --  to the (specific) result type of the function is inserted to handle
-      --  the case where the object is declared with a class-wide type.
-
-      if Is_Constrained (Underlying_Type (Result_Subt)) then
-         Caller_Object :=
-            Make_Unchecked_Type_Conversion (Loc,
-              Subtype_Mark => New_Reference_To (Result_Subt, Loc),
-              Expression   => New_Reference_To (Obj_Def_Id, Loc));
-
-         --  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_Alloc_Form_Actual_To_Build_In_Place_Call
-           (Func_Call, Function_Id, Alloc_Form => Caller_Allocation);
-
-      --  If the function's result subtype is unconstrained and the object is
-      --  a return object of an enclosing build-in-place function, then the
-      --  implicit build-in-place parameters of the enclosing function must be
-      --  passed along to the called function. (Unfortunately, this won't cover
-      --  the case of extension aggregates where the ancestor part is a build-
-      --  in-place unconstrained function call that should be passed along the
-      --  caller's parameters. Currently those get mishandled by reassigning
-      --  the result of the call to the aggregate return object, when the call
-      --  result should really be directly built in place in the aggregate and
-      --  not built in a temporary. ???)
-
-      elsif Is_Return_Object (Defining_Identifier (Object_Decl)) then
+      --  If the the object is a return object of an enclosing build-in-place
+      --  function, then the implicit build-in-place parameters of the
+      --  enclosing function are simply passed along to the called function.
+      --  (Unfortunately, this won't cover the case of extension aggregates
+      --  where the ancestor part is a build-in-place unconstrained function
+      --  call that should be passed along the caller's parameters. Currently
+      --  those get mishandled by reassigning the result of the call to the
+      --  aggregate return object, when the call result should really be
+      --  directly built in place in the aggregate and not in a temporary. ???)
+
+      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).
 
-         --  If the enclosing function has a constrained result type, then
-         --  caller allocation will be used.
+         if Needs_BIP_Alloc_Form (Enclosing_Func) then
+            if VM_Target = No_VM and then
+              RTE_Available (RE_Root_Storage_Pool_Ptr)
+            then
+               Pool_Actual :=
+                 New_Reference_To (Build_In_Place_Formal
+                   (Enclosing_Func, BIP_Storage_Pool), Loc);
 
-         if Is_Constrained (Etype (Enclosing_Func)) then
-            Add_Alloc_Form_Actual_To_Build_In_Place_Call
-              (Func_Call, Function_Id, Alloc_Form => Caller_Allocation);
+            --  The build-in-place pool formal is not built on .NET/JVM
 
-         --  Otherwise, when the enclosing function has an unconstrained result
-         --  type, the BIP_Alloc_Form formal of the enclosing function must be
-         --  passed along to the callee.
+            else
+               Pool_Actual := Empty;
+            end if;
 
-         else
-            Add_Alloc_Form_Actual_To_Build_In_Place_Call
+            Add_Unconstrained_Actuals_To_Build_In_Place_Call
               (Func_Call,
                Function_Id,
                Alloc_Form_Exp =>
                  New_Reference_To
                    (Build_In_Place_Formal (Enclosing_Func, BIP_Alloc_Form),
-                    Loc));
+                    Loc),
+               Pool_Actual => Pool_Actual);
+
+         --  Otherwise, if enclosing function has a constrained result subtype,
+         --  then caller allocation will be used.
+
+         else
+            Add_Unconstrained_Actuals_To_Build_In_Place_Call
+              (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
@@ -5676,37 +8248,59 @@ package body Exp_Ch6 is
                   (Build_In_Place_Formal (Enclosing_Func, BIP_Object_Access),
                    Loc));
 
+      --  In the constrained case, add an implicit actual to the function call
+      --  that provides access to the declared object. An unchecked conversion
+      --  to the (specific) result type of the function is inserted to handle
+      --  the case where the object is declared with a class-wide type.
+
+      elsif Is_Constrained (Underlying_Type (Result_Subt)) then
+         Caller_Object :=
+            Make_Unchecked_Type_Conversion (Loc,
+              Subtype_Mark => New_Reference_To (Result_Subt, Loc),
+              Expression   => New_Reference_To (Obj_Def_Id, Loc));
+
+         --  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_Unconstrained_Actuals_To_Build_In_Place_Call
+           (Func_Call, Function_Id, Alloc_Form => Caller_Allocation);
+
       --  In other unconstrained cases, pass an indication to do the allocation
       --  on the secondary stack and set Caller_Object to Empty so that a null
       --  value will be passed for the caller's object address. A transient
       --  scope is established to ensure eventual cleanup of the result.
 
       else
-         Add_Alloc_Form_Actual_To_Build_In_Place_Call
-           (Func_Call,
-            Function_Id,
-            Alloc_Form => Secondary_Stack);
+         Add_Unconstrained_Actuals_To_Build_In_Place_Call
+           (Func_Call, Function_Id, Alloc_Form => Secondary_Stack);
          Caller_Object := Empty;
 
          Establish_Transient_Scope (Object_Decl, Sec_Stack => True);
       end if;
 
-      Add_Final_List_Actual_To_Build_In_Place_Call
-        (Func_Call, Function_Id, Acc_Type => Empty);
+      --  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  => 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.
 
          Add_Task_Actuals_To_Build_In_Place_Call
            (Func_Call, Function_Id,
             Master_Actual =>
-              New_Reference_To
-                (Build_In_Place_Formal (Enclosing_Func, BIP_Master), Loc));
+              New_Reference_To (Build_In_Place_Formal
+                (Enclosing_Func, BIP_Task_Master), Loc));
 
       else
          Add_Task_Actuals_To_Build_In_Place_Call
@@ -5726,34 +8320,37 @@ package body Exp_Ch6 is
       Ptr_Typ_Decl :=
         Make_Full_Type_Declaration (Loc,
           Defining_Identifier => Ref_Type,
-          Type_Definition =>
+          Type_Definition     =>
             Make_Access_To_Object_Definition (Loc,
-              All_Present => True,
+              All_Present        => True,
               Subtype_Indication =>
                 New_Reference_To (Etype (Function_Call), Loc)));
 
       --  The access type and its accompanying object must be inserted after
       --  the object declaration in the constrained case, so that the function
       --  call can be passed access to the object. In the unconstrained case,
-      --  the access type and object must be inserted before the object, since
-      --  the object declaration is rewritten to be a renaming of a dereference
-      --  of the access object.
+      --  or if the object declaration is for a return object, the access type
+      --  and object must be inserted before the object, since the object
+      --  declaration is rewritten to be a renaming of a dereference of the
+      --  access object.
 
-      if Is_Constrained (Underlying_Type (Result_Subt)) then
+      if Is_Constrained (Underlying_Type (Result_Subt))
+        and then not Is_Return_Object (Defining_Identifier (Object_Decl))
+      then
          Insert_After_And_Analyze (Object_Decl, Ptr_Typ_Decl);
       else
          Insert_Action (Object_Decl, Ptr_Typ_Decl);
       end if;
 
       --  Finally, create an access object initialized to a reference to the
-      --  function call.
+      --  function call. We know this access value cannot be null, so mark the
+      --  entity accordingly to suppress the access check.
 
-      New_Expr :=
-        Make_Reference (Loc,
-          Prefix => Relocate_Node (Func_Call));
+      New_Expr := Make_Reference (Loc, Relocate_Node (Func_Call));
 
       Def_Id := Make_Temporary (Loc, 'R', New_Expr);
       Set_Etype (Def_Id, Ref_Type);
+      Set_Is_Known_Non_Null (Def_Id);
 
       Insert_After_And_Analyze (Ptr_Typ_Decl,
         Make_Object_Declaration (Loc,
@@ -5761,11 +8358,18 @@ package body Exp_Ch6 is
           Object_Definition   => New_Reference_To (Ref_Type, Loc),
           Expression          => New_Expr));
 
-      if Is_Constrained (Underlying_Type (Result_Subt)) then
+      --  If the result subtype of the called function is constrained and
+      --  is not itself the return expression of an enclosing BIP function,
+      --  then mark the object as having no initialization.
+
+      if Is_Constrained (Underlying_Type (Result_Subt))
+        and then not Is_Return_Object (Defining_Identifier (Object_Decl))
+      then
          Set_Expression (Object_Decl, Empty);
          Set_No_Initialization (Object_Decl);
 
-      --  In case of an unconstrained result subtype, rewrite the object
+      --  In case of an unconstrained result subtype, or if the call is the
+      --  return expression of an enclosing BIP function, rewrite the object
       --  declaration as an object renaming where the renamed object is a
       --  dereference of <function_Call>'reference:
       --
@@ -5776,6 +8380,7 @@ package body Exp_Ch6 is
            Make_Explicit_Dereference (Loc,
              Prefix => New_Reference_To (Def_Id, Loc));
 
+         Loc := Sloc (Object_Decl);
          Rewrite (Object_Decl,
            Make_Object_Renaming_Declaration (Loc,
              Defining_Identifier => Make_Temporary (Loc, 'D'),
@@ -5813,6 +8418,17 @@ package body Exp_Ch6 is
             Set_Homonym     (Renaming_Def_Id, Homonym (Obj_Def_Id));
 
             Exchange_Entities (Renaming_Def_Id, Obj_Def_Id);
+
+            --  Preserve source indication of original declaration, so that
+            --  xref information is properly generated for the right entity.
+
+            Preserve_Comes_From_Source
+              (Object_Decl, Original_Node (Object_Decl));
+
+            Preserve_Comes_From_Source
+              (Obj_Def_Id, Original_Node (Object_Decl));
+
+            Set_Comes_From_Source (Renaming_Def_Id, False);
          end;
       end if;
 
@@ -5829,24 +8445,156 @@ package body Exp_Ch6 is
       end if;
    end Make_Build_In_Place_Call_In_Object_Declaration;
 
+   -----------------------------------
+   -- Needs_BIP_Finalization_Master --
+   -----------------------------------
+
+   function Needs_BIP_Finalization_Master
+     (Func_Id : Entity_Id) return Boolean
+   is
+      pragma Assert (Is_Build_In_Place_Function (Func_Id));
+      Func_Typ : constant Entity_Id := Underlying_Type (Etype (Func_Id));
+   begin
+      return
+        not Restriction_Active (No_Finalization)
+          and then Needs_Finalization (Func_Typ);
+   end Needs_BIP_Finalization_Master;
+
    --------------------------
-   -- Needs_BIP_Final_List --
+   -- Needs_BIP_Alloc_Form --
    --------------------------
 
-   function Needs_BIP_Final_List (E : Entity_Id) return Boolean is
-      pragma Assert (Is_Build_In_Place_Function (E));
-      Result_Subt : constant Entity_Id := Underlying_Type (Etype (E));
+   function Needs_BIP_Alloc_Form (Func_Id : Entity_Id) return Boolean is
+      pragma Assert (Is_Build_In_Place_Function (Func_Id));
+      Func_Typ : constant Entity_Id := Underlying_Type (Etype (Func_Id));
+   begin
+      return not Is_Constrained (Func_Typ) or else Is_Tagged_Type (Func_Typ);
+   end Needs_BIP_Alloc_Form;
+
+   --------------------------------------
+   -- Needs_Result_Accessibility_Level --
+   --------------------------------------
+
+   function Needs_Result_Accessibility_Level
+     (Func_Id : Entity_Id) return Boolean
+   is
+      Func_Typ : constant Entity_Id := Underlying_Type (Etype (Func_Id));
+
+      function Has_Unconstrained_Access_Discriminant_Component
+        (Comp_Typ : Entity_Id) return Boolean;
+      --  Returns True if any component of the type has an unconstrained access
+      --  discriminant.
+
+      -----------------------------------------------------
+      -- Has_Unconstrained_Access_Discriminant_Component --
+      -----------------------------------------------------
+
+      function Has_Unconstrained_Access_Discriminant_Component
+        (Comp_Typ :  Entity_Id) return Boolean
+      is
+      begin
+         if not Is_Limited_Type (Comp_Typ) then
+            return False;
+
+            --  Only limited types can have access discriminants with
+            --  defaults.
+
+         elsif Has_Unconstrained_Access_Discriminants (Comp_Typ) then
+            return True;
+
+         elsif Is_Array_Type (Comp_Typ) then
+            return Has_Unconstrained_Access_Discriminant_Component
+                     (Underlying_Type (Component_Type (Comp_Typ)));
+
+         elsif Is_Record_Type (Comp_Typ) then
+            declare
+               Comp : Entity_Id;
+
+            begin
+               Comp := First_Component (Comp_Typ);
+               while Present (Comp) loop
+                  if Has_Unconstrained_Access_Discriminant_Component
+                       (Underlying_Type (Etype (Comp)))
+                  then
+                     return True;
+                  end if;
+
+                  Next_Component (Comp);
+               end loop;
+            end;
+         end if;
+
+         return False;
+      end Has_Unconstrained_Access_Discriminant_Component;
+
+      Feature_Disabled : constant Boolean := True;
+      --  Temporary
+
+   --  Start of processing for Needs_Result_Accessibility_Level
 
    begin
-      --  We need the BIP_Final_List if the result type needs finalization. We
-      --  also need it for tagged types, even if not class-wide, because some
-      --  type extension might need finalization, and all overriding functions
-      --  must have the same calling conventions. However, if there is a
-      --  pragma Restrictions (No_Finalization), we never need this parameter.
-
-      return (Needs_Finalization (Result_Subt)
-               or else Is_Tagged_Type (Underlying_Type (Result_Subt)))
-        and then not Restriction_Active (No_Finalization);
-   end Needs_BIP_Final_List;
+      --  False if completion unavailable (how does this happen???)
+
+      if not Present (Func_Typ) then
+         return False;
+
+      elsif Feature_Disabled then
+         return False;
+
+      --  False if not a function, also handle enum-lit renames case
+
+      elsif Func_Typ = Standard_Void_Type
+        or else Is_Scalar_Type (Func_Typ)
+      then
+         return False;
+
+      --  Handle a corner case, a cross-dialect subp renaming. For example,
+      --  an Ada 2012 renaming of an Ada 2005 subprogram. This can occur when
+      --  an Ada 2005 (or earlier) unit references predefined run-time units.
+
+      elsif Present (Alias (Func_Id)) then
+
+         --  Unimplemented: a cross-dialect subp renaming which does not set
+         --  the Alias attribute (e.g., a rename of a dereference of an access
+         --  to subprogram value). ???
+
+         return Present (Extra_Accessibility_Of_Result (Alias (Func_Id)));
+
+      --  Remaining cases require Ada 2012 mode
+
+      elsif Ada_Version < Ada_2012 then
+         return False;
+
+      elsif Ekind (Func_Typ) = E_Anonymous_Access_Type
+        or else Is_Tagged_Type (Func_Typ)
+      then
+         --  In the case of, say, a null tagged record result type, the need
+         --  for this extra parameter might not be obvious. This function
+         --  returns True for all tagged types for compatibility reasons.
+         --  A function with, say, a tagged null controlling result type might
+         --  be overridden by a primitive of an extension having an access
+         --  discriminant and the overrider and overridden must have compatible
+         --  calling conventions (including implicitly declared parameters).
+         --  Similarly, values of one access-to-subprogram type might designate
+         --  both a primitive subprogram of a given type and a function
+         --  which is, for example, not a primitive subprogram of any type.
+         --  Again, this requires calling convention compatibility.
+         --  It might be possible to solve these issues by introducing
+         --  wrappers, but that is not the approach that was chosen.
+
+         return True;
+
+      elsif Has_Unconstrained_Access_Discriminants (Func_Typ) then
+         return True;
+
+      elsif Has_Unconstrained_Access_Discriminant_Component (Func_Typ) then
+         return True;
+
+      --  False for all other cases
+
+      else
+         return False;
+      end if;
+   end Needs_Result_Accessibility_Level;
 
 end Exp_Ch6;