diff --git a/gcc/ada/exp_ch3.adb b/gcc/ada/exp_ch3.adb
index 13a0c8e7500f79a8fe294b08d5b10ff9573c2b1a..5764b22b80027ae106b682a2cf3464aef171bfb7 100644
--- a/gcc/ada/exp_ch3.adb
+++ b/gcc/ada/exp_ch3.adb
@@ -1176,11 +1176,13 @@ package body Exp_Ch3 is
          end if;
       end if;
 
-      --  Build an abort block to protect the initialization calls
+      --  Build an abort block to protect the initialization calls, except for
+      --  a finalization collection, which does not need any protection.
 
       if Abort_Allowed
         and then Present (Comp_Init)
         and then Present (Obj_Init)
+        and then not Is_RTE (Typ, RE_Finalization_Collection)
       then
          --  Generate:
          --    Abort_Defer;
@@ -6955,6 +6957,7 @@ package body Exp_Ch3 is
                    Defining_Identifier => Local_Id,
                    Object_Definition   =>
                      New_Occurrence_Of (Ptr_Typ, Loc)));
+               Set_No_Initialization (Last (Decls));
 
                --  Allocate the object, generate:
                --    Local_Id := <Alloc_Expr>;
diff --git a/gcc/ada/exp_ch4.adb b/gcc/ada/exp_ch4.adb
index 342828aa6724d527d669836666c72d64023ea7e8..b1f7593de2ac109c2f858aa85c2f0ee50bc0049d 100644
--- a/gcc/ada/exp_ch4.adb
+++ b/gcc/ada/exp_ch4.adb
@@ -592,11 +592,10 @@ package body Exp_Ch4 is
 
          Preserve_Comes_From_Source (Expression (Temp_Decl), N);
 
-         --  Insert declaration, assignment and build the allocation procedure
+         --  Insert the declaration and generate the in-place assignment
 
          Insert_Action (N, Temp_Decl);
          Convert_Aggr_In_Allocator (N, Exp, Temp);
-         Build_Allocate_Deallocate_Proc (Temp_Decl);
       end Build_Aggregate_In_Place;
 
       --  Local variables
@@ -806,7 +805,6 @@ package body Exp_Ch4 is
                    Expression          => Node);
 
                Insert_Action (N, Temp_Decl);
-               Build_Allocate_Deallocate_Proc (Temp_Decl);
             end if;
 
          --  Ada 2005 (AI-251): Handle allocators whose designated type is an
@@ -859,7 +857,6 @@ package body Exp_Ch4 is
                       Expression          => Node);
 
                   Insert_Action (N, Temp_Decl);
-                  Build_Allocate_Deallocate_Proc (Temp_Decl);
                end if;
 
                --  Generate an additional object containing the address of the
@@ -968,6 +965,7 @@ package body Exp_Ch4 is
 
          Apply_Accessibility_Check_For_Allocator (N, Exp, Temp);
 
+         Build_Allocate_Deallocate_Proc (Declaration_Node (Temp), Mark => N);
          Rewrite (N, New_Occurrence_Of (Temp, Loc));
          Analyze_And_Resolve (N, PtrT);
 
@@ -991,6 +989,7 @@ package body Exp_Ch4 is
       then
          Temp := Make_Temporary (Loc, 'P', N);
          Build_Aggregate_In_Place (Temp, PtrT);
+         Build_Allocate_Deallocate_Proc (Declaration_Node (Temp), Mark => N);
          Rewrite (N, New_Occurrence_Of (Temp, Loc));
          Analyze_And_Resolve (N, PtrT);
 
@@ -4600,10 +4599,15 @@ package body Exp_Ch4 is
          Expand_Allocator_Expression (N);
 
       --  If no initialization is necessary, just create a custom Allocate if
-      --  the context requires it.
+      --  the context requires it; that is the case only for allocators built
+      --  for the special return objects because, in other cases, the custom
+      --  Allocate will be created later during the expansion of the original
+      --  allocator without the No_Initialization flag.
 
       elsif No_Initialization (N) then
-         Build_Allocate_Deallocate_Proc (N);
+         if For_Special_Return_Object (N) then
+            Build_Allocate_Deallocate_Proc (Parent (N));
+         end if;
 
       --  If the allocator is for a type which requires initialization, and
       --  there is no initial value (i.e. operand is a subtype indication
@@ -4662,7 +4666,6 @@ package body Exp_Ch4 is
                    Expression          => Relocate_Node (N));
 
                Insert_Action (N, Temp_Decl, Suppress => All_Checks);
-               Build_Allocate_Deallocate_Proc (Temp_Decl);
 
                --  Generate:
                --    Temp.all := ...
@@ -4682,6 +4685,7 @@ package body Exp_Ch4 is
                Set_Assignment_OK (Name (Stmt));
 
                Insert_Action (N, Stmt, Suppress => All_Checks);
+               Build_Allocate_Deallocate_Proc (Temp_Decl);
                Rewrite (N, New_Occurrence_Of (Temp, Loc));
                Analyze_And_Resolve (N, PtrT);
             end;
@@ -4799,7 +4803,6 @@ package body Exp_Ch4 is
                    Expression          => Relocate_Node (N));
 
                Insert_Action (N, Temp_Decl, Suppress => All_Checks);
-               Build_Allocate_Deallocate_Proc (Temp_Decl);
 
                --  If the designated type is a task type or contains tasks,
                --  create a specific block to activate the created tasks.
@@ -4818,6 +4821,7 @@ package body Exp_Ch4 is
                   Insert_Actions (N, Init_Stmts, Suppress => All_Checks);
                end if;
 
+               Build_Allocate_Deallocate_Proc (Temp_Decl);
                Rewrite (N, New_Occurrence_Of (Temp, Loc));
                Analyze_And_Resolve (N, PtrT);
 
diff --git a/gcc/ada/exp_ch7.adb b/gcc/ada/exp_ch7.adb
index a62c7441a488e0fce3eed920e2a1ee838b6f8904..e978a778f1e5029bc4849ad251d09c6ff9608918 100644
--- a/gcc/ada/exp_ch7.adb
+++ b/gcc/ada/exp_ch7.adb
@@ -245,6 +245,34 @@ package body Exp_Ch7 is
    --    at end
    --       _Finalizer;
 
+   --  Here is the version with a dynamically allocated object:
+
+   --    declare
+   --       X : P_Ctrl := new Ctrl;
+
+   --    begin
+   --       null;
+   --    end;
+   --
+   --  is expanded into:
+
+   --    declare
+   --       Cnn : System.Finalization_Primitives.Finalization_Collection_Ptr :=
+   --               P_CtrlFC'unrestricted_access;
+   --       [...]
+   --       Pnn : constant P_Ctrl := new Ctrl[...][...];
+   --       Bnn : begin
+   --          Abort_Defer;
+   --          Initialize (Pnn.all);
+   --          System.Finalization_Primitives.Attach_To_Collection
+   --            (Pnn.all'address,
+   --             CtrlFD'unrestricted_access,
+   --             Cnn.all);
+   --       at end
+   --          Abort_Undefer;
+   --       end Bnn;
+   --       X : P_Ctrl := Pnn;
+
    --  The implementation uses two different strategies for the finalization
    --  of (statically) declared objects and of dynamically allocated objects.
 
@@ -274,11 +302,10 @@ package body Exp_Ch7 is
    --  recognized by Requires_Cleanup_Actions and picked up by Build_Finalizer.
 
    --  For dynamically allocated objects, there is no post-processing phase and
-   --  the objects are automatically attached and detached when they are being
-   --  allocated or deallocated. In other words, there are no direct attachment
-   --  or detachment actions generated by the compiler; instead they are fully
-   --  carried out by the run-time library when it is invoked by the allocation
-   --  and deallocation actions generated by the compiler.
+   --  the attachment to the finalization chain of the access type, as well the
+   --  the detachment from this chain for unchecked deallocation, are generated
+   --  directly by the compiler during the expansion of allocators and calls to
+   --  instances of the Unchecked_Deallocation procedure.
 
    type Final_Primitives is
      (Initialize_Case, Adjust_Case, Finalize_Case, Address_Case);
@@ -514,13 +541,6 @@ package body Exp_Ch7 is
    --  of the formal of Proc, or force a conversion to the class-wide type in
    --  the case where the operation is abstract.
 
-   function Make_Address_For_Finalize
-     (Loc     : Source_Ptr;
-      Obj_Ref : Node_Id;
-      Obj_Typ : Entity_Id) return Node_Id;
-   --  Build the address of an object denoted by Obj_Ref and Obj_Typ for use as
-   --  the actual parameter in a call to a Finalize_Address procedure.
-
    function Make_Call
      (Loc       : Source_Ptr;
       Proc_Id   : Entity_Id;
@@ -2528,306 +2548,6 @@ package body Exp_Ch7 is
          Obj_Id : constant Entity_Id := Defining_Identifier (Decl);
          Loc    : constant Source_Ptr := Sloc (Decl);
 
-         Init_Typ : Entity_Id;
-         --  The initialization type of the related object declaration. Note
-         --  that this is not necessarily the same type as Obj_Typ because of
-         --  possible type derivations.
-
-         Obj_Typ : Entity_Id;
-         --  The type of the related object declaration
-
-         procedure Find_Last_Init
-           (Last_Init   : out Node_Id;
-            Body_Insert : out Node_Id);
-         --  Find the last initialization call related to object declaration
-         --  Decl. Last_Init denotes the last initialization call which follows
-         --  Decl. Body_Insert denotes a node where the finalizer body could be
-         --  potentially inserted after (if blocks are involved).
-
-         --------------------
-         -- Find_Last_Init --
-         --------------------
-
-         procedure Find_Last_Init
-           (Last_Init   : out Node_Id;
-            Body_Insert : out Node_Id)
-         is
-            function Find_Last_Init_In_Block (Blk : Node_Id) return Node_Id;
-            --  Find the last initialization call within the statements of
-            --  block Blk.
-
-            function Is_Init_Call (N : Node_Id) return Boolean;
-            --  Determine whether node N denotes one of the initialization
-            --  procedures of types Init_Typ or Obj_Typ.
-
-            function Next_Suitable_Statement (Stmt : Node_Id) return Node_Id;
-            --  Obtain the next statement which follows list member Stmt while
-            --  ignoring artifacts related to access-before-elaboration checks.
-
-            -----------------------------
-            -- Find_Last_Init_In_Block --
-            -----------------------------
-
-            function Find_Last_Init_In_Block (Blk : Node_Id) return Node_Id is
-               HSS  : constant Node_Id := Handled_Statement_Sequence (Blk);
-               Stmt : Node_Id;
-
-            begin
-               --  Examine the individual statements of the block in reverse to
-               --  locate the last initialization call.
-
-               if Present (HSS) and then Present (Statements (HSS)) then
-                  Stmt := Last (Statements (HSS));
-                  while Present (Stmt) loop
-
-                     --  Peek inside nested blocks in case aborts are allowed
-
-                     if Nkind (Stmt) = N_Block_Statement then
-                        return Find_Last_Init_In_Block (Stmt);
-
-                     elsif Is_Init_Call (Stmt) then
-                        return Stmt;
-                     end if;
-
-                     Prev (Stmt);
-                  end loop;
-               end if;
-
-               return Empty;
-            end Find_Last_Init_In_Block;
-
-            ------------------
-            -- Is_Init_Call --
-            ------------------
-
-            function Is_Init_Call (N : Node_Id) return Boolean is
-               function Is_Init_Proc_Of
-                 (Subp_Id : Entity_Id;
-                  Typ     : Entity_Id) return Boolean;
-               --  Determine whether subprogram Subp_Id is a valid init proc of
-               --  type Typ.
-
-               ---------------------
-               -- Is_Init_Proc_Of --
-               ---------------------
-
-               function Is_Init_Proc_Of
-                 (Subp_Id : Entity_Id;
-                  Typ     : Entity_Id) return Boolean
-               is
-                  Deep_Init : Entity_Id := Empty;
-                  Prim_Init : Entity_Id := Empty;
-                  Type_Init : Entity_Id := Empty;
-
-               begin
-                  --  Obtain all possible initialization routines of the
-                  --  related type and try to match the subprogram entity
-                  --  against one of them.
-
-                  --  Deep_Initialize
-
-                  Deep_Init := TSS (Typ, TSS_Deep_Initialize);
-
-                  --  Primitive Initialize
-
-                  if Is_Controlled (Typ) then
-                     Prim_Init := Find_Optional_Prim_Op (Typ, Name_Initialize);
-
-                     if Present (Prim_Init) then
-                        Prim_Init := Ultimate_Alias (Prim_Init);
-                     end if;
-                  end if;
-
-                  --  Type initialization routine
-
-                  if Has_Non_Null_Base_Init_Proc (Typ) then
-                     Type_Init := Base_Init_Proc (Typ);
-                  end if;
-
-                  return
-                    (Present (Deep_Init) and then Subp_Id = Deep_Init)
-                      or else
-                    (Present (Prim_Init) and then Subp_Id = Prim_Init)
-                      or else
-                    (Present (Type_Init) and then Subp_Id = Type_Init);
-               end Is_Init_Proc_Of;
-
-               --  Local variables
-
-               Call_Id : Entity_Id;
-
-            --  Start of processing for Is_Init_Call
-
-            begin
-               if Nkind (N) = N_Procedure_Call_Statement
-                 and then Nkind (Name (N)) = N_Identifier
-               then
-                  Call_Id := Entity (Name (N));
-
-                  --  Consider both the type of the object declaration and its
-                  --  related initialization type.
-
-                  return
-                    Is_Init_Proc_Of (Call_Id, Init_Typ)
-                      or else
-                    Is_Init_Proc_Of (Call_Id, Obj_Typ);
-               end if;
-
-               return False;
-            end Is_Init_Call;
-
-            -----------------------------
-            -- Next_Suitable_Statement --
-            -----------------------------
-
-            function Next_Suitable_Statement (Stmt : Node_Id) return Node_Id is
-               Result : Node_Id;
-
-            begin
-               --  Skip call markers and Program_Error raises installed by the
-               --  ABE mechanism.
-
-               Result := Next (Stmt);
-               while Present (Result) loop
-                  exit when Nkind (Result) not in
-                              N_Call_Marker | N_Raise_Program_Error;
-
-                  Next (Result);
-               end loop;
-
-               return Result;
-            end Next_Suitable_Statement;
-
-            --  Local variables
-
-            Call   : Node_Id;
-            Stmt   : Node_Id;
-            Stmt_2 : Node_Id;
-
-            Deep_Init_Found : Boolean := False;
-            --  A flag set when a call to [Deep_]Initialize has been found
-
-         --  Start of processing for Find_Last_Init
-
-         begin
-            Last_Init   := Decl;
-            Body_Insert := Empty;
-
-            --  Objects that capture controlled function results do not require
-            --  initialization.
-
-            if Nkind (Decl) = N_Object_Declaration
-              and then Nkind (Expression (Decl)) = N_Reference
-            then
-               return;
-            end if;
-
-            if Present (Freeze_Node (Obj_Id)) then
-               Stmt := First (Actions (Freeze_Node (Obj_Id)));
-               Body_Insert := Freeze_Node (Obj_Id);
-            else
-               Stmt := Next_Suitable_Statement (Decl);
-            end if;
-
-            --  For an object with suppressed initialization, we check whether
-            --  there is in fact no initialization expression. If there is not,
-            --  then this is an object declaration that has been turned into a
-            --  different object declaration that calls the build-in-place
-            --  function in a 'Reference attribute, as in "F(...)'Reference".
-            --  We search for that later object declaration, so that the
-            --  attachment will be inserted after the call. Otherwise, if the
-            --  call raises an exception, we will finalize the (uninitialized)
-            --  object, which is wrong.
-
-            if Nkind (Decl) = N_Object_Declaration
-              and then No_Initialization (Decl)
-            then
-               if No (Expression (Last_Init)) then
-                  loop
-                     Next (Last_Init);
-                     exit when No (Last_Init);
-                     exit when Nkind (Last_Init) = N_Object_Declaration
-                       and then Nkind (Expression (Last_Init)) = N_Reference
-                       and then Nkind (Prefix (Expression (Last_Init))) =
-                                  N_Function_Call
-                       and then Is_Expanded_Build_In_Place_Call
-                                  (Prefix (Expression (Last_Init)));
-                  end loop;
-               end if;
-
-               return;
-
-            --  If the initialization is in the declaration, we're done, so
-            --  early return if we have no more statements or they have been
-            --  rewritten, which means that they were in the source code.
-
-            elsif No (Stmt) or else Original_Node (Stmt) /= Stmt then
-               return;
-
-            --  In all other cases the initialization calls follow the related
-            --  object. The general structure of object initialization built by
-            --  routine Default_Initialize_Object is as follows:
-
-            --   [begin                                --  aborts allowed
-            --       Abort_Defer;]
-            --       Type_Init_Proc (Obj);
-            --      [begin]                            --  exceptions allowed
-            --          Deep_Initialize (Obj);
-            --      [exception                         --  exceptions allowed
-            --          when others =>
-            --             Deep_Finalize (Obj, Self => False);
-            --             raise;
-            --       end;]
-            --   [at end                               --  aborts allowed
-            --       Abort_Undefer;
-            --    end;]
-
-            --  When aborts are allowed, the initialization calls are housed
-            --  within a block.
-
-            elsif Nkind (Stmt) = N_Block_Statement then
-               Last_Init   := Find_Last_Init_In_Block (Stmt);
-               Body_Insert := Stmt;
-
-            --  Otherwise the initialization calls follow the related object
-
-            else
-               Stmt_2 := Next_Suitable_Statement (Stmt);
-
-               --  Check for an optional call to Deep_Initialize which may
-               --  appear within a block depending on whether the object has
-               --  controlled components.
-
-               if Present (Stmt_2) then
-                  if Nkind (Stmt_2) = N_Block_Statement then
-                     Call := Find_Last_Init_In_Block (Stmt_2);
-
-                     if Present (Call) then
-                        Deep_Init_Found := True;
-                        Last_Init       := Call;
-                        Body_Insert     := Stmt_2;
-                     end if;
-
-                  elsif Is_Init_Call (Stmt_2) then
-                     Deep_Init_Found := True;
-                     Last_Init       := Stmt_2;
-                     Body_Insert     := Last_Init;
-                  end if;
-               end if;
-
-               --  If the object lacks a call to Deep_Initialize, then it must
-               --  have a call to its related type init proc.
-
-               if not Deep_Init_Found and then Is_Init_Call (Stmt) then
-                  Last_Init   := Stmt;
-                  Body_Insert := Last_Init;
-               end if;
-            end if;
-         end Find_Last_Init;
-
-         --  Local variables
-
-         Body_Ins           : Node_Id;
          Fin_Call           : Node_Id;
          Fin_Id             : Entity_Id;
          Master_Node_Attach : Node_Id;
@@ -2836,6 +2556,7 @@ package body Exp_Ch7 is
          Master_Node_Ins    : Node_Id;
          Master_Node_Loc    : Source_Ptr;
          Obj_Ref            : Node_Id;
+         Obj_Typ            : Entity_Id;
 
       --  Start of processing for Process_Object_Declaration
 
@@ -2855,23 +2576,6 @@ package body Exp_Ch7 is
             Obj_Typ := Available_View (Designated_Type (Obj_Typ));
          end if;
 
-         --  Handle the initialization type of the object declaration
-
-         Init_Typ := Obj_Typ;
-         loop
-            if Is_Private_Type (Init_Typ)
-              and then Present (Full_View (Init_Typ))
-            then
-               Init_Typ := Full_View (Init_Typ);
-
-            elsif Is_Untagged_Derivation (Init_Typ) then
-               Init_Typ := Root_Type (Init_Typ);
-
-            else
-               exit;
-            end if;
-         end loop;
-
          --  If the object is a Master_Node, then nothing to do, except if it
          --  is the only object, in which case we move its declaration, call
          --  marker (if any) and initialization call, as well as mark it to
@@ -2936,27 +2640,25 @@ package body Exp_Ch7 is
 
             if Present (BIP_Initialization_Call (Obj_Id)) then
                Master_Node_Ins := BIP_Initialization_Call (Obj_Id);
-               Body_Ins  := Empty;
 
             --  The object is initialized by an aggregate. The Master_Node
             --  insertion point is after the last aggregate assignment.
 
             elsif Present (Last_Aggregate_Assignment (Obj_Id)) then
                Master_Node_Ins := Last_Aggregate_Assignment (Obj_Id);
-               Body_Ins  := Empty;
 
             --  In other cases the Master_Node is inserted after the last call
             --  to either [Deep_]Initialize or the type-specific init proc.
 
             else
-               Find_Last_Init (Master_Node_Ins, Body_Ins);
+               Master_Node_Ins := Find_Last_Init (Decl);
             end if;
 
          --  In all other cases the Master_Node is inserted after the last call
          --  to either [Deep_]Initialize or the type-specific init proc.
 
          else
-            Find_Last_Init (Master_Node_Ins, Body_Ins);
+            Master_Node_Ins := Find_Last_Init (Decl);
          end if;
 
          --  If the Initialize function is null or trivial, the call will have
@@ -3096,6 +2798,7 @@ package body Exp_Ch7 is
 
             if CodePeer_Mode or else Obj_Id = Master_Node_Id then
                Master_Node_Attach := Make_Null_Statement (Loc);
+
             else
                Master_Node_Attach :=
                  Make_Procedure_Call_Statement (Loc,
@@ -3163,6 +2866,7 @@ package body Exp_Ch7 is
 
             elsif CodePeer_Mode then
                Master_Node_Attach := Make_Null_Statement (Loc);
+
             else
                Master_Node_Attach :=
                  Make_Procedure_Call_Statement (Loc,
diff --git a/gcc/ada/exp_ch7.ads b/gcc/ada/exp_ch7.ads
index 73a822b4806c32efcbf4a2441a185b652121d70b..712671a427e057612349e0b81b30e98a3ed9cc5e 100644
--- a/gcc/ada/exp_ch7.ads
+++ b/gcc/ada/exp_ch7.ads
@@ -189,6 +189,13 @@ package Exp_Ch7 is
    --  one of N_Block_Statement, N_Subprogram_Body, N_Task_Body, N_Entry_Body,
    --  or N_Extended_Return_Statement.
 
+   function Make_Address_For_Finalize
+     (Loc     : Source_Ptr;
+      Obj_Ref : Node_Id;
+      Obj_Typ : Entity_Id) return Node_Id;
+   --  Build the address of an object denoted by Obj_Ref and Obj_Typ for use as
+   --  the actual parameter in a call to a Finalize_Address procedure.
+
    function Make_Adjust_Call
      (Obj_Ref   : Node_Id;
       Typ       : Entity_Id;
diff --git a/gcc/ada/exp_util.adb b/gcc/ada/exp_util.adb
index d3d0132cfd8b158db441458dc72307215e05effb..057cf3ebc48008aee77e683c58649c7edc9cfeb9 100644
--- a/gcc/ada/exp_util.adb
+++ b/gcc/ada/exp_util.adb
@@ -721,7 +721,10 @@ package body Exp_Util is
    -- Build_Allocate_Deallocate_Proc --
    ------------------------------------
 
-   procedure Build_Allocate_Deallocate_Proc (N : Node_Id) is
+   procedure Build_Allocate_Deallocate_Proc
+     (N    : Node_Id;
+      Mark : Node_Id := Empty)
+   is
       Is_Allocate : constant Boolean := Nkind (N) /= N_Free_Statement;
 
       function Find_Object (E : Node_Id) return Node_Id;
@@ -829,12 +832,18 @@ package body Exp_Util is
       --  Obtain the attributes of the allocation
 
       if Is_Allocate then
-         if Nkind (N) = N_Object_Declaration then
+         if Nkind (N) in N_Assignment_Statement | N_Object_Declaration then
             Expr := Expression (N);
          else
             Expr := N;
          end if;
 
+         --  Deal with type conversions created for interface types
+
+         if Nkind (Expr) = N_Unchecked_Type_Conversion then
+            Expr := Expression (Expr);
+         end if;
+
          --  In certain cases, an allocator with a qualified expression may be
          --  relocated and used as the initialization expression of a temporary
          --  and the analysis of the declaration of this temporary may in turn
@@ -856,7 +865,7 @@ package body Exp_Util is
            and then Nkind (Parent (Entity (Expr))) = N_Object_Declaration
            and then Nkind (Expression (Parent (Entity (Expr)))) = N_Allocator
          then
-            Build_Allocate_Deallocate_Proc (Parent (Entity (Expr)));
+            Build_Allocate_Deallocate_Proc (Parent (Entity (Expr)), Mark);
             return;
          end if;
 
@@ -970,10 +979,9 @@ package body Exp_Util is
 
          Actuals      : List_Id;
          Alloc_Expr   : Node_Id := Empty;
-         Fin_Addr_Id  : Entity_Id;
-         Fin_Coll_Act : Node_Id;
          Fin_Coll_Id  : Entity_Id;
          Proc_To_Call : Entity_Id;
+         Ptr_Coll_Id  : Entity_Id;
          Subpool      : Node_Id := Empty;
 
       begin
@@ -1015,46 +1023,41 @@ package body Exp_Util is
 
             --  c) Finalization collection
 
-            if Needs_Fin then
-               Fin_Coll_Id  := Finalization_Collection (Ptr_Typ);
-               Fin_Coll_Act := New_Occurrence_Of (Fin_Coll_Id, Loc);
-
-               --  Handle the case where the collection is actually a pointer
-               --  to a collection. This arises in build-in-place functions.
+            Fin_Coll_Id := Make_Temporary (Loc, 'C');
+            Ptr_Coll_Id := Finalization_Collection (Ptr_Typ);
 
-               if Is_Access_Type (Etype (Fin_Coll_Id)) then
-                  Append_To (Actuals, Fin_Coll_Act);
-               else
-                  Append_To (Actuals,
-                    Make_Attribute_Reference (Loc,
-                      Prefix         => Fin_Coll_Act,
-                      Attribute_Name => Name_Unrestricted_Access));
-               end if;
-            else
-               Append_To (Actuals, Make_Null (Loc));
-            end if;
-
-            --  d) Finalize_Address
-
-            --  Primitive Finalize_Address is never generated in CodePeer mode
-            --  since it contains an Unchecked_Conversion.
+            --  Create the temporary which represents the collection of
+            --  the expression. Generate:
+            --
+            --    C : Finalization_Collection_Ptr :=
+            --          Finalization_Collection (Ptr_Typ)'Access
+            --
+            --  Handle the case where a collection is actually a pointer
+            --  to a collection. This arises in build-in-place functions.
 
-            if Needs_Fin and then not CodePeer_Mode then
-               Fin_Addr_Id := Finalize_Address (Desig_Typ);
-               pragma Assert (Present (Fin_Addr_Id));
+            Insert_Action (N,
+              Make_Object_Declaration (Loc,
+                Defining_Identifier => Fin_Coll_Id,
+                Object_Definition   =>
+                  New_Occurrence_Of
+                    (RTE (RE_Finalization_Collection_Ptr), Loc),
+                  Expression        =>
+                    (if not Needs_Fin
+                      then Make_Null (Loc)
+                      elsif Is_Access_Type (Etype (Ptr_Coll_Id))
+                      then New_Occurrence_Of (Ptr_Coll_Id, Loc)
+                      else
+                        Make_Attribute_Reference (Loc,
+                          Prefix         =>
+                            New_Occurrence_Of (Ptr_Coll_Id, Loc),
+                          Attribute_Name => Name_Unrestricted_Access))));
 
-               Append_To (Actuals,
-                 Make_Attribute_Reference (Loc,
-                   Prefix         => New_Occurrence_Of (Fin_Addr_Id, Loc),
-                   Attribute_Name => Name_Unrestricted_Access));
-            else
-               Append_To (Actuals, Make_Null (Loc));
-            end if;
+            Append_To (Actuals, New_Occurrence_Of (Fin_Coll_Id, Loc));
          end if;
 
-         --  e) Address
-         --  f) Storage_Size
-         --  g) Alignment
+         --  d) Address
+         --  e) Storage_Size
+         --  f) Alignment
 
          Append_To (Actuals, New_Occurrence_Of (Addr_Id, Loc));
          Append_To (Actuals, New_Occurrence_Of (Size_Id, Loc));
@@ -1094,11 +1097,12 @@ package body Exp_Util is
                   Attribute_Name => Name_Alignment)));
          end if;
 
-         --  h) Is_Controlled
+         --  g) Is_Controlled
 
          if Needs_Fin then
             Is_Controlled : declare
                Flag_Id   : constant Entity_Id := Make_Temporary (Loc, 'F');
+
                Flag_Expr : Node_Id;
                Param     : Node_Id;
                Pref      : Node_Id;
@@ -1206,6 +1210,112 @@ package body Exp_Util is
                     Expression          => Flag_Expr));
 
                Append_To (Actuals, New_Occurrence_Of (Flag_Id, Loc));
+
+               --  Finalize_Address is not generated in CodePeer mode because
+               --  the body contains address arithmetic. So we don't want to
+               --  generate the attach or detach in this case.
+
+               if CodePeer_Mode then
+                  null;
+
+               --  Nothing to generate if the flag is statically false
+
+               elsif Is_Entity_Name (Flag_Expr)
+                 and then Entity (Flag_Expr) = Standard_False
+               then
+                  null;
+
+               --  Generate:
+               --    if F then
+               --       Attach_Object_To_Collection
+               --         (Temp.all'Address,
+               --          Desig_Typ_FD'Access,
+               --          Fin_Coll_Id.all);
+               --    end if;
+
+               elsif Is_Allocate then
+                  declare
+                     Stmt : Node_Id;
+                     Temp : Entity_Id;
+
+                  begin
+                     --  The original allocator must have been rewritten by
+                     --  the caller at this point and a temporary introduced.
+
+                     case Nkind (N) is
+                        when N_Assignment_Statement =>
+                           Temp := New_Copy_Tree (Name (N));
+
+                        when N_Object_Declaration =>
+                           Temp :=
+                             New_Occurrence_Of (Defining_Identifier (N), Loc);
+
+                        when others =>
+                           raise Program_Error;
+                     end case;
+
+                     Stmt :=
+                       Make_If_Statement (Loc,
+                         Condition       =>
+                           New_Occurrence_Of (Flag_Id, Loc),
+                         Then_Statements => New_List (
+                           Make_Procedure_Call_Statement (Loc,
+                             Name =>
+                               New_Occurrence_Of
+                                 (RTE (RE_Attach_Object_To_Collection), Loc),
+                             Parameter_Associations => New_List (
+                               Make_Address_For_Finalize (Loc,
+                                 Make_Explicit_Dereference (Loc, Temp),
+                                 Desig_Typ),
+                               Make_Attribute_Reference (Loc,
+                                 Prefix =>
+                                   New_Occurrence_Of
+                                    (Finalize_Address (Desig_Typ), Loc),
+                                 Attribute_Name => Name_Unrestricted_Access),
+                               Make_Explicit_Dereference (Loc,
+                                 New_Occurrence_Of (Fin_Coll_Id, Loc))))));
+
+                     --  If we have a mark past the initialization, then insert
+                     --  the statement there, otherwise insert after either the
+                     --  assignment or the last initialization statement of the
+                     --  declaration of the temporary.
+
+                     if Present (Mark) then
+                        Insert_Action (Mark, Stmt, Suppress => All_Checks);
+
+                     elsif Nkind (N) = N_Assignment_Statement then
+                        Insert_After_And_Analyze
+                          (N, Stmt, Suppress => All_Checks);
+
+                     else
+                        Insert_After_And_Analyze
+                          (Find_Last_Init (N), Stmt, Suppress => All_Checks);
+                     end if;
+                  end;
+
+               --  Generate:
+               --    if F then
+               --       Detach_Object_From_Collection (Temp.all'Address);
+               --    end if;
+
+               else
+                  Insert_Action (N,
+                    Make_If_Statement (Loc,
+                      Condition       => New_Occurrence_Of (Flag_Id, Loc),
+                      Then_Statements => New_List (
+                        Make_Procedure_Call_Statement (Loc,
+                          Name =>
+                            New_Occurrence_Of
+                              (RTE (RE_Detach_Object_From_Collection), Loc),
+                          Parameter_Associations => New_List (
+                            Make_Address_For_Finalize (Loc,
+                              Make_Explicit_Dereference (Loc,
+                                New_Occurrence_Of
+                                  (Entity (Expression (N)), Loc)),
+                                Desig_Typ))))),
+                    Suppress => All_Checks);
+               end if;
+
             end Is_Controlled;
 
          --  The object is not controlled
@@ -1214,7 +1324,7 @@ package body Exp_Util is
             Append_To (Actuals, New_Occurrence_Of (Standard_False, Loc));
          end if;
 
-         --  i) On_Subpool
+         --  h) On_Subpool
 
          if Is_Allocate then
             Append_To (Actuals,
@@ -6130,6 +6240,332 @@ package body Exp_Util is
       end if;
    end Find_Interface_Tag;
 
+   --------------------
+   -- Find_Last_Init --
+   --------------------
+
+   function Find_Last_Init (Decl : Node_Id) return Node_Id is
+      Obj_Id : constant Entity_Id := Defining_Identifier (Decl);
+
+      Init_Typ : Entity_Id;
+      --  The initialization type of the related object declaration. Note
+      --  that this is not necessarily the same type as Obj_Typ because of
+      --  possible type derivations.
+
+      Obj_Typ : Entity_Id;
+      --  The (designated) type of the object declaration
+
+      function Find_Last_Init_In_Block (Blk : Node_Id) return Node_Id;
+      --  Find the last initialization call within the statements of block Blk
+
+      function Is_Init_Call (N : Node_Id) return Boolean;
+      --  Determine whether node N denotes one of the initialization procedures
+      --  of types Init_Typ or Typ.
+
+      function Next_Suitable_Statement (Stmt : Node_Id) return Node_Id;
+      --  Obtain the next statement which follows list member Stmt while
+      --  ignoring artifacts related to access-before-elaboration checks.
+
+      -----------------------------
+      -- Find_Last_Init_In_Block --
+      -----------------------------
+
+      function Find_Last_Init_In_Block (Blk : Node_Id) return Node_Id is
+         HSS  : constant Node_Id := Handled_Statement_Sequence (Blk);
+
+         Stmt : Node_Id;
+
+      begin
+         --  Examine the individual statements of the block in reverse to
+         --  locate the last initialization call.
+
+         if Present (HSS) and then Present (Statements (HSS)) then
+            Stmt := Last (Statements (HSS));
+
+            while Present (Stmt) loop
+               --  Peek inside nested blocks in case aborts are allowed
+
+               if Nkind (Stmt) = N_Block_Statement then
+                  return Find_Last_Init_In_Block (Stmt);
+
+               elsif Is_Init_Call (Stmt) then
+                  return Stmt;
+               end if;
+
+               Prev (Stmt);
+            end loop;
+         end if;
+
+         return Empty;
+      end Find_Last_Init_In_Block;
+
+      ------------------
+      -- Is_Init_Call --
+      ------------------
+
+      function Is_Init_Call (N : Node_Id) return Boolean is
+         function Is_Init_Proc_Of
+           (Subp : Entity_Id;
+            Typ  : Entity_Id) return Boolean;
+         --  Determine whether subprogram Subp_Id is a valid init proc of
+         --  type Typ.
+
+         ---------------------
+         -- Is_Init_Proc_Of --
+         ---------------------
+
+         function Is_Init_Proc_Of
+           (Subp : Entity_Id;
+            Typ  : Entity_Id) return Boolean
+         is
+            Deep_Init : Entity_Id := Empty;
+            Prim_Init : Entity_Id := Empty;
+            Type_Init : Entity_Id := Empty;
+
+         begin
+            --  Obtain all possible initialization routines of the
+            --  related type and try to match the subprogram entity
+            --  against one of them.
+
+            --  Deep_Initialize
+
+            Deep_Init := TSS (Typ, TSS_Deep_Initialize);
+
+            --  Primitive Initialize
+
+            if Is_Controlled (Typ) then
+               Prim_Init := Find_Optional_Prim_Op (Typ, Name_Initialize);
+
+               if Present (Prim_Init) then
+                  Prim_Init := Ultimate_Alias (Prim_Init);
+               end if;
+            end if;
+
+            --  Type initialization routine
+
+            if Has_Non_Null_Base_Init_Proc (Typ) then
+               Type_Init := Base_Init_Proc (Typ);
+            end if;
+
+            return
+              (Present (Deep_Init) and then Subp = Deep_Init)
+                or else
+              (Present (Prim_Init) and then Subp = Prim_Init)
+                or else
+              (Present (Type_Init) and then Subp = Type_Init);
+         end Is_Init_Proc_Of;
+
+         --  Local variables
+
+         Call_Id : Entity_Id;
+
+      --  Start of processing for Is_Init_Call
+
+      begin
+         if Nkind (N) = N_Procedure_Call_Statement
+           and then Is_Entity_Name (Name (N))
+         then
+            Call_Id := Entity (Name (N));
+
+            --  Consider both the type of the object declaration and its
+            --  related initialization type.
+
+            return
+              Is_Init_Proc_Of (Call_Id, Init_Typ)
+                or else
+              Is_Init_Proc_Of (Call_Id, Obj_Typ);
+         end if;
+
+         return False;
+      end Is_Init_Call;
+
+      -----------------------------
+      -- Next_Suitable_Statement --
+      -----------------------------
+
+      function Next_Suitable_Statement (Stmt : Node_Id) return Node_Id is
+         Result : Node_Id;
+
+      begin
+         --  Skip call markers and Program_Error raises installed by the
+         --  ABE mechanism.
+
+         Result := Next (Stmt);
+         while Present (Result) loop
+            exit when Nkind (Result) not in
+                        N_Call_Marker | N_Raise_Program_Error;
+
+            Next (Result);
+         end loop;
+
+         return Result;
+      end Next_Suitable_Statement;
+
+      --  Local variables
+
+      Call      : Node_Id;
+      Last_Init : Node_Id;
+      Stmt      : Node_Id;
+      Stmt_2    : Node_Id;
+
+      Deep_Init_Found : Boolean := False;
+      --  A flag set when a call to [Deep_]Initialize has been found
+
+   --  Start of processing for Find_Last_Init
+
+   begin
+      Last_Init := Decl;
+
+      --  Objects that capture controlled function results do not require
+      --  initialization.
+
+      if Nkind (Decl) = N_Object_Declaration
+        and then Nkind (Expression (Decl)) = N_Reference
+      then
+         return Last_Init;
+      end if;
+
+      Obj_Typ := Base_Type (Etype (Obj_Id));
+
+      if Is_Access_Type (Obj_Typ) then
+         Obj_Typ := Available_View (Designated_Type (Obj_Typ));
+      end if;
+
+      --  Handle the initialization type of the object declaration
+
+      if Is_Class_Wide_Type (Obj_Typ)
+        and then Nkind (Decl) = N_Object_Declaration
+        and then Nkind (Expression (Decl)) = N_Allocator
+      then
+         Init_Typ := Base_Type (Etype (Expression (Expression (Decl))));
+      else
+         Init_Typ := Obj_Typ;
+      end if;
+
+      loop
+         if Is_Private_Type (Init_Typ)
+           and then Present (Full_View (Init_Typ))
+         then
+            Init_Typ := Base_Type (Full_View (Init_Typ));
+
+         elsif Is_Concurrent_Type (Init_Typ)
+           and then Present (Corresponding_Record_Type (Init_Typ))
+         then
+            Init_Typ := Corresponding_Record_Type (Init_Typ);
+
+         elsif Is_Untagged_Derivation (Init_Typ) then
+            Init_Typ := Root_Type (Init_Typ);
+
+         else
+            exit;
+         end if;
+      end loop;
+
+      if Present (Freeze_Node (Obj_Id)) then
+         Stmt := First (Actions (Freeze_Node (Obj_Id)));
+      else
+         Stmt := Next_Suitable_Statement (Decl);
+      end if;
+
+      --  For an object with suppressed initialization, we check whether
+      --  there is in fact no initialization expression. If there is not,
+      --  then this is an object declaration that has been turned into a
+      --  different object declaration that calls the build-in-place
+      --  function in a 'Reference attribute, as in "F(...)'Reference".
+      --  We search for that later object declaration, so that the
+      --  attachment will be inserted after the call. Otherwise, if the
+      --  call raises an exception, we will finalize the (uninitialized)
+      --  object, which is wrong.
+
+      if Nkind (Decl) = N_Object_Declaration
+        and then No_Initialization (Decl)
+      then
+         if No (Expression (Last_Init)) then
+            loop
+               Next (Last_Init);
+
+               exit when No (Last_Init);
+               exit when Nkind (Last_Init) = N_Object_Declaration
+                 and then Nkind (Expression (Last_Init)) = N_Reference
+                 and then Nkind (Prefix (Expression (Last_Init))) =
+                            N_Function_Call
+                 and then Is_Expanded_Build_In_Place_Call
+                            (Prefix (Expression (Last_Init)));
+            end loop;
+         end if;
+
+         return Last_Init;
+
+      --  If the initialization is in the declaration, we're done, so
+      --  early return if we have no more statements or they have been
+      --  rewritten, which means that they were in the source code.
+
+      elsif No (Stmt) or else Original_Node (Stmt) /= Stmt then
+         return Last_Init;
+
+      --  In all other cases the initialization calls follow the related
+      --  object. The general structure of object initialization built by
+      --  routine Default_Initialize_Object is as follows:
+
+      --   [begin                                --  aborts allowed
+      --       Abort_Defer;]
+      --       Type_Init_Proc (Obj);
+      --      [begin]                            --  exceptions allowed
+      --          Deep_Initialize (Obj);
+      --      [exception                         --  exceptions allowed
+      --          when others =>
+      --             Deep_Finalize (Obj, Self => False);
+      --             raise;
+      --       end;]
+      --   [at end                               --  aborts allowed
+      --       Abort_Undefer;
+      --    end;]
+
+      --  When aborts are allowed, the initialization calls are housed
+      --  within a block.
+
+      elsif Nkind (Stmt) = N_Block_Statement then
+         Call := Find_Last_Init_In_Block (Stmt);
+
+         if Present (Call) then
+            Last_Init := Call;
+         end if;
+
+      --  Otherwise the initialization calls follow the related object
+
+      else
+         Stmt_2 := Next_Suitable_Statement (Stmt);
+
+         --  Check for an optional call to Deep_Initialize which may
+         --  appear within a block depending on whether the object has
+         --  controlled components.
+
+         if Present (Stmt_2) then
+            if Nkind (Stmt_2) = N_Block_Statement then
+               Call := Find_Last_Init_In_Block (Stmt_2);
+
+               if Present (Call) then
+                  Deep_Init_Found := True;
+                  Last_Init       := Call;
+               end if;
+
+            elsif Is_Init_Call (Stmt_2) then
+               Deep_Init_Found := True;
+               Last_Init       := Stmt_2;
+            end if;
+         end if;
+
+         --  If the object lacks a call to Deep_Initialize, then it must
+         --  have a call to its related type init proc.
+
+         if not Deep_Init_Found and then Is_Init_Call (Stmt) then
+            Last_Init := Stmt;
+         end if;
+      end if;
+
+      return Last_Init;
+   end Find_Last_Init;
+
    ---------------------------
    -- Find_Optional_Prim_Op --
    ---------------------------
diff --git a/gcc/ada/exp_util.ads b/gcc/ada/exp_util.ads
index 4e7a4bba2cf1ab24beda7ce80f324ecbf656ccf1..3c7e70ed13b70481eb0848cc86a26391b1873e82 100644
--- a/gcc/ada/exp_util.ads
+++ b/gcc/ada/exp_util.ads
@@ -234,17 +234,27 @@ package Exp_Util is
    --  Return the static value of a statically known attribute reference
    --  Pref'Constrained.
 
-   procedure Build_Allocate_Deallocate_Proc (N : Node_Id);
+   procedure Build_Allocate_Deallocate_Proc
+     (N    : Node_Id;
+      Mark : Node_Id := Empty);
    --  Create a custom Allocate/Deallocate to be associated with an allocation
-   --  or deallocation:
+   --  or deallocation for:
    --
    --    1) controlled objects
    --    2) class-wide objects
-   --    3) any kind of object on a subpool
+   --    3) any kind of objects on a subpool
    --
-   --  N must be an allocator or the declaration of a temporary variable which
-   --  represents the expression of the original allocator node, otherwise N
-   --  must be a free statement.
+   --  Moreover, for objects that need finalization, generate the attachment
+   --  actions to resp. detachment actions from the appropriate collection.
+   --
+   --  N must be an allocator or the declaration of a temporary initialized by
+   --  an allocator or an assignment of an allocator to a temporary, otherwise
+   --  N must be a free statement of a temporary.
+   --
+   --  Mark must be set to a mark past the initialization of the allocator if
+   --  it is initialized (the allocator itself is OK) or left empty otherwise.
+   --  It is used to determine the place where objects that need finalization
+   --  can be attached to the appropriate collection.
 
    function Build_Abort_Undefer_Block
      (Loc     : Source_Ptr;
@@ -564,6 +574,9 @@ package Exp_Util is
 
    --  WARNING: There is a matching C declaration of this subprogram in fe.h
 
+   function Find_Last_Init (Decl : Node_Id) return Node_Id;
+   --  Find the last initialization call related to object declaration Decl
+
    function Find_Prim_Op (T : Entity_Id; Name : Name_Id) return Entity_Id;
    --  Find the first primitive operation of a tagged type T with name Name.
    --  This function allows the use of a primitive operation which is not
diff --git a/gcc/ada/libgnat/s-finpri.adb b/gcc/ada/libgnat/s-finpri.adb
index 1fbd391c66c9b7a897c95a505d387512b6b7dfba..8026b3fb284bbffe8974abd18fd9e529a68ae6c6 100644
--- a/gcc/ada/libgnat/s-finpri.adb
+++ b/gcc/ada/libgnat/s-finpri.adb
@@ -29,7 +29,8 @@
 --                                                                          --
 ------------------------------------------------------------------------------
 
-with Ada.Exceptions; use Ada.Exceptions;
+with Ada.Exceptions;           use Ada.Exceptions;
+with Ada.Unchecked_Conversion;
 
 with System.Soft_Links; use System.Soft_Links;
 
@@ -37,6 +38,12 @@ package body System.Finalization_Primitives is
 
    use type System.Storage_Elements.Storage_Offset;
 
+   function To_Collection_Node_Ptr is
+     new Ada.Unchecked_Conversion (Address, Collection_Node_Ptr);
+
+   procedure Detach_Node_From_Collection (Node : not null Collection_Node_Ptr);
+   --  Removes a collection node from its associated finalization collection
+
    ---------------------------
    -- Add_Offset_To_Address --
    ---------------------------
@@ -49,23 +56,57 @@ package body System.Finalization_Primitives is
       return System.Storage_Elements."+" (Addr, Offset);
    end Add_Offset_To_Address;
 
-   -------------------------------
-   -- Attach_Node_To_Collection --
-   -------------------------------
+   ---------------------------------
+   -- Attach_Object_To_Collection --
+   ---------------------------------
 
-   procedure Attach_Node_To_Collection
-     (Node             : not null Collection_Node_Ptr;
+   procedure Attach_Object_To_Collection
+     (Object_Address   : System.Address;
       Finalize_Address : not null Finalize_Address_Ptr;
       Collection       : in out Finalization_Collection)
    is
+      Node : constant Collection_Node_Ptr :=
+               To_Collection_Node_Ptr (Object_Address - Header_Size);
+
    begin
+      Lock_Task.all;
+
+      --  Do not allow the attachment of controlled objects while the
+      --  associated collection is being finalized.
+
+      --  Synchronization:
+      --    Read  - attachment, finalization
+      --    Write - finalization
+
+      if Collection.Finalization_Started then
+         raise Program_Error with "attachment after finalization started";
+      end if;
+
+      --  Check whether primitive Finalize_Address is available. If it is
+      --  not, then either the expansion of the designated type failed or
+      --  the expansion of the allocator failed. This is a compiler bug.
+
+      pragma Assert
+        (Finalize_Address /= null, "primitive Finalize_Address not available");
+
       Node.Finalize_Address := Finalize_Address;
       Node.Prev             := Collection.Head'Unchecked_Access;
       Node.Next             := Collection.Head.Next;
 
       Collection.Head.Next.Prev := Node;
       Collection.Head.Next      := Node;
-   end Attach_Node_To_Collection;
+
+      Unlock_Task.all;
+
+   exception
+      when others =>
+
+         --  Unlock the task in case the attachment failed and reraise the
+         --  exception.
+
+         Unlock_Task.all;
+         raise;
+   end Attach_Object_To_Collection;
 
    -----------------------------
    -- Attach_Object_To_Master --
@@ -128,16 +169,23 @@ package body System.Finalization_Primitives is
       end if;
    end Detach_Node_From_Collection;
 
-   --------------------------
-   -- Finalization_Started --
-   --------------------------
+   -----------------------------------
+   -- Detach_Object_From_Collection --
+   -----------------------------------
 
-   function Finalization_Started
-     (Master : Finalization_Collection) return Boolean
+   procedure Detach_Object_From_Collection
+     (Object_Address : System.Address)
    is
+      Node : constant Collection_Node_Ptr :=
+               To_Collection_Node_Ptr (Object_Address - Header_Size);
+
    begin
-      return Master.Finalization_Started;
-   end Finalization_Started;
+      Lock_Task.all;
+
+      Detach_Node_From_Collection (Node);
+
+      Unlock_Task.all;
+   end Detach_Object_From_Collection;
 
    --------------
    -- Finalize --
@@ -168,7 +216,7 @@ package body System.Finalization_Primitives is
       Lock_Task.all;
 
       --  Synchronization:
-      --    Read  - allocation, finalization
+      --    Read  - attachment, finalization
       --    Write - finalization
 
       if Collection.Finalization_Started then
@@ -180,13 +228,13 @@ package body System.Finalization_Primitives is
          return;
       end if;
 
-      --  Lock the collection to prevent any allocation while the objects are
+      --  Lock the collection to prevent any attachment while the objects are
       --  being finalized. The collection remains locked because either it is
       --  explicitly deallocated or the associated access type is about to go
       --  out of scope.
 
       --  Synchronization:
-      --    Read  - allocation, finalization
+      --    Read  - attachment, finalization
       --    Write - finalization
 
       Collection.Finalization_Started := True;
@@ -201,7 +249,7 @@ package body System.Finalization_Primitives is
          Curr_Ptr := Collection.Head.Next;
 
          --  Synchronization:
-         --    Write - allocation, deallocation, finalization
+         --    Write - attachment, detachment, finalization
 
          Detach_Node_From_Collection (Curr_Ptr);
 
diff --git a/gcc/ada/libgnat/s-finpri.ads b/gcc/ada/libgnat/s-finpri.ads
index 9fe9ef47eb7618dc2cf0244f24d16df70c982569..874a82f53499d1a8c1a94e125aa1aa5993911c13 100644
--- a/gcc/ada/libgnat/s-finpri.ads
+++ b/gcc/ada/libgnat/s-finpri.ads
@@ -143,10 +143,6 @@ package System.Finalization_Primitives with Preelaborate is
    --  collection, in some arbitrary order. Calls to this procedure with
    --  a collection that has already been finalized have no effect.
 
-   function Finalization_Started
-     (Master : Finalization_Collection) return Boolean;
-   --  Return the finalization status of a collection
-
    type Collection_Node is private;
    --  Each controlled object associated with a finalization collection has
    --  an associated object of this type.
@@ -157,17 +153,20 @@ package System.Finalization_Primitives with Preelaborate is
    --  A reference to a collection node. Since this type may not be used to
    --  allocate objects, its storage size is zero.
 
-   procedure Attach_Node_To_Collection
-     (Node             : not null Collection_Node_Ptr;
+   procedure Attach_Object_To_Collection
+     (Object_Address   : System.Address;
       Finalize_Address : not null Finalize_Address_Ptr;
       Collection       : in out Finalization_Collection);
-   --  Associates a collection node with a finalization collection. The node
+   --  Associates a controlled object allocated for some access type with a
+   --  given finalization collection. Finalize_Address denotes the operation
+   --  to be called to finalize the object (which could be a user-declared
+   --  Finalize procedure or a procedure generated by the compiler). An object
    --  can be associated with at most one finalization collection.
 
-   procedure Detach_Node_From_Collection (Node : not null Collection_Node_Ptr);
-   --  Removes a collection node from its associated finalization collection.
-   --  Calls to the procedure with a Node that has already been detached have
-   --  no effects.
+   procedure Detach_Object_From_Collection (Object_Address : System.Address);
+   --  Removes a controlled object from its associated finalization collection.
+   --  Calls to the procedure with an object that has already been detached
+   --  have no effects.
 
    function Header_Size return System.Storage_Elements.Storage_Count;
    --  Return the size of type Collection_Node as Storage_Count
@@ -231,10 +230,13 @@ private
       --  The head of the circular doubly-linked list of Collection_Nodes
 
       Finalization_Started : Boolean := False;
-      pragma Atomic (Finalization_Started);
       --  A flag used to detect allocations which occur during the finalization
       --  of a collection. The allocations must raise Program_Error. This may
       --  arise in a multitask environment.
    end record;
 
+   --  This operation is very simple and thus can be performed in line
+
+   pragma Inline (Initialize);
+
 end System.Finalization_Primitives;
diff --git a/gcc/ada/libgnat/s-stposu.adb b/gcc/ada/libgnat/s-stposu.adb
index 8d232fa0d61eec35d516c4a791a6218450ac8912..38dc69f976a1a7f384a8bc99184c6b2a9b48a522 100644
--- a/gcc/ada/libgnat/s-stposu.adb
+++ b/gcc/ada/libgnat/s-stposu.adb
@@ -29,23 +29,18 @@
 --                                                                          --
 ------------------------------------------------------------------------------
 
-with Ada.Exceptions;           use Ada.Exceptions;
-with Ada.Unchecked_Conversion;
+with Ada.Exceptions; use Ada.Exceptions;
 
 with System.Address_Image;
-with System.Finalization_Primitives; use System.Finalization_Primitives;
-with System.IO;                      use System.IO;
-with System.Soft_Links;              use System.Soft_Links;
-with System.Storage_Elements;        use System.Storage_Elements;
+with System.IO;               use System.IO;
+with System.Soft_Links;       use System.Soft_Links;
+with System.Storage_Elements; use System.Storage_Elements;
 
 with System.Storage_Pools.Subpools.Finalization;
 use  System.Storage_Pools.Subpools.Finalization;
 
 package body System.Storage_Pools.Subpools is
 
-   function To_Collection_Node_Ptr is
-     new Ada.Unchecked_Conversion (Address, Collection_Node_Ptr);
-
    procedure Attach (N : not null SP_Node_Ptr; L : not null SP_Node_Ptr);
    --  Attach a subpool node to a pool
 
@@ -99,25 +94,24 @@ package body System.Storage_Pools.Subpools is
    -----------------------------
 
    procedure Allocate_Any_Controlled
-     (Pool               : in out Root_Storage_Pool'Class;
-      Context_Subpool    : Subpool_Handle;
-      Context_Collection : Finalization_Primitives.Finalization_Collection_Ptr;
-      Fin_Address        : Finalization_Primitives.Finalize_Address_Ptr;
-      Addr               : out System.Address;
-      Storage_Size       : System.Storage_Elements.Storage_Count;
-      Alignment          : System.Storage_Elements.Storage_Count;
-      Is_Controlled      : Boolean;
-      On_Subpool         : Boolean)
+     (Pool          : in out Root_Storage_Pool'Class;
+      Named_Subpool : Subpool_Handle;
+      Collection    : in out
+                        Finalization_Primitives.Finalization_Collection_Ptr;
+      Addr          : out System.Address;
+      Storage_Size  : System.Storage_Elements.Storage_Count;
+      Alignment     : System.Storage_Elements.Storage_Count;
+      Is_Controlled : Boolean;
+      On_Subpool    : Boolean)
    is
+      use type System.Finalization_Primitives.Finalization_Collection_Ptr;
+
       Is_Subpool_Allocation : constant Boolean :=
                                 Pool in Root_Storage_Pool_With_Subpools'Class;
 
-      Collection : Finalization_Collection_Ptr := null;
-      N_Addr     : Address;
-      N_Ptr      : Collection_Node_Ptr;
-      N_Size     : Storage_Count;
-      Subpool    : Subpool_Handle := null;
-      Lock_Taken : Boolean := False;
+      N_Addr  : Address;
+      N_Size  : Storage_Count;
+      Subpool : Subpool_Handle;
 
       Header_And_Padding : Storage_Offset;
       --  This offset includes the size of a collection node plus an additional
@@ -134,7 +128,7 @@ package body System.Storage_Pools.Subpools is
          --  Case of an allocation without a Subpool_Handle. Dispatch to the
          --  implementation of Default_Subpool_For_Pool.
 
-         if Context_Subpool = null then
+         if Named_Subpool = null then
             Subpool :=
               Default_Subpool_For_Pool
                 (Root_Storage_Pool_With_Subpools'Class (Pool));
@@ -142,7 +136,7 @@ package body System.Storage_Pools.Subpools is
          --  Allocation with a Subpool_Handle
 
          else
-            Subpool := Context_Subpool;
+            Subpool := Named_Subpool;
          end if;
 
          --  Ensure proper ownership and chaining of the subpool
@@ -166,13 +160,13 @@ package body System.Storage_Pools.Subpools is
          --  type has failed to create one. This is a compiler bug.
 
          pragma Assert
-           (Context_Collection /= null, "no collection in pool allocation");
+           (Collection /= null, "no collection in pool allocation");
 
          --  If a subpool is present, then this is the result of erroneous
          --  allocator expansion. This is not a serious error, but it should
          --  still be detected.
 
-         if Context_Subpool /= null then
+         if Named_Subpool /= null then
             raise Program_Error
               with "subpool not required in pool allocation";
          end if;
@@ -185,38 +179,14 @@ package body System.Storage_Pools.Subpools is
             raise Program_Error
               with "pool of access type does not support subpools";
          end if;
-
-         Collection := Context_Collection;
       end if;
 
-      --  Step 2: Collection, Finalize_Address-related runtime checks and size
-      --  calculations.
+      --  Step 2: Size calculation
 
       --  Allocation of a descendant from [Limited_]Controlled, a class-wide
       --  object or a record with controlled components.
 
       if Is_Controlled then
-         Lock_Taken := True;
-         Lock_Task.all;
-
-         --  Do not allow the allocation of controlled objects while the
-         --  associated collection is being finalized.
-
-         --  Synchronization:
-         --    Read  - allocation, finalization
-         --    Write - finalization
-
-         if Finalization_Started (Collection.all) then
-            raise Program_Error with "allocation after finalization started";
-         end if;
-
-         --  Check whether primitive Finalize_Address is available. If it is
-         --  not, then either the expansion of the designated type failed or
-         --  the expansion of the allocator failed. This is a compiler bug.
-
-         pragma Assert
-           (Fin_Address /= null, "primitive Finalize_Address not available");
-
          --  The size must account for the hidden header preceding the object.
          --  Account for possible padding space before the header due to a
          --  larger alignment.
@@ -248,62 +218,35 @@ package body System.Storage_Pools.Subpools is
          Allocate (Pool, N_Addr, N_Size, Alignment);
       end if;
 
-      --  Step 4: Attachment
+      --  Step 4: Displacement of address
 
       if Is_Controlled then
 
-         --  Note that we already did "Lock_Task.all;" in Step 2 above
-
          --  Map the allocated memory into a collection node. This converts the
          --  top of the allocated bits into a list header. If there is padding
          --  due to larger alignment, the padding is placed at the beginning:
 
-         --     N_Addr  N_Ptr
-         --     |       |
-         --     V       V
-         --     +-------+---------------+----------------------+
-         --     |Padding|    Header     |        Object        |
-         --     +-------+---------------+----------------------+
-         --     ^       ^               ^
-         --     |       +- Header_Size -+
-         --     |                       |
-         --     +- Header_And_Padding --+
-
-         N_Ptr :=
-           To_Collection_Node_Ptr (N_Addr + Header_And_Padding - Header_Size);
-
-         --  Attach the allocated object to the finalization collection
-
-         --  Synchronization:
-         --    Write - allocation, deallocation, finalization
-
-         Attach_Node_To_Collection (N_Ptr, Fin_Address, Collection.all);
+         --    N_Addr                  Addr
+         --    |                       |
+         --    V                       V
+         --    +-------+---------------+----------------------+
+         --    |Padding|    Header     |        Object        |
+         --    +-------+---------------+----------------------+
+         --    ^       ^               ^
+         --    |       +- Header_Size -+
+         --    |                       |
+         --    +- Header_And_Padding --+
 
          --  Move the address from the hidden list header to the start of the
          --  object. This operation effectively hides the list header.
 
          Addr := N_Addr + Header_And_Padding;
 
-         Unlock_Task.all;
-         Lock_Taken := False;
-
       --  Non-controlled allocation
 
       else
          Addr := N_Addr;
       end if;
-
-   exception
-      when others =>
-
-         --  Unlock the task in case the allocation step failed and reraise the
-         --  exception.
-
-         if Lock_Taken then
-            Unlock_Task.all;
-         end if;
-
-         raise;
    end Allocate_Any_Controlled;
 
    ------------
@@ -341,7 +284,6 @@ package body System.Storage_Pools.Subpools is
       Is_Controlled : Boolean)
    is
       N_Addr : Address;
-      N_Ptr  : Collection_Node_Ptr;
       N_Size : Storage_Count;
 
       Header_And_Padding : Storage_Offset;
@@ -349,68 +291,39 @@ package body System.Storage_Pools.Subpools is
       --  padding due to a larger alignment.
 
    begin
-      --  Step 1: Detachment
+      --  Step 1: Displacement of address
 
       if Is_Controlled then
-         Lock_Task.all;
-
-         begin
-            --  Account for possible padding space before the header due to a
-            --  larger alignment.
-
-            Header_And_Padding := Header_Size_With_Padding (Alignment);
-
-            --    N_Addr  N_Ptr           Addr (from input)
-            --    |       |               |
-            --    V       V               V
-            --    +-------+---------------+----------------------+
-            --    |Padding|    Header     |        Object        |
-            --    +-------+---------------+----------------------+
-            --    ^       ^               ^
-            --    |       +- Header_Size -+
-            --    |                       |
-            --    +- Header_And_Padding --+
-
-            --  Convert the bits preceding the object into a list header
-
-            N_Ptr := To_Collection_Node_Ptr (Addr - Header_Size);
-
-            --  Detach the object from the related finalization collection.
-            --  This action does not need to know the context used during
-            --  allocation.
-
-            --  Synchronization:
-            --    Write - allocation, deallocation, finalization
-
-            Detach_Node_From_Collection (N_Ptr);
-
-            --  Move the address from the object to the beginning of the list
-            --  header.
+         --  Account for possible padding space before the header due to a
+         --  larger alignment.
 
-            N_Addr := Addr - Header_And_Padding;
+         Header_And_Padding := Header_Size_With_Padding (Alignment);
 
-            --  The size of the deallocated object must include the size of the
-            --  hidden list header.
+         --    N_Addr                  Addr
+         --    |                       |
+         --    V                       V
+         --    +-------+---------------+----------------------+
+         --    |Padding|    Header     |        Object        |
+         --    +-------+---------------+----------------------+
+         --    ^       ^               ^
+         --    |       +- Header_Size -+
+         --    |                       |
+         --    +- Header_And_Padding --+
 
-            N_Size := Storage_Size + Header_And_Padding;
+         --  Move the address from the object to the beginning of the header
 
-            Unlock_Task.all;
+         N_Addr := Addr - Header_And_Padding;
 
-         exception
-            when others =>
+         --  The size of the deallocated object must include that of the header
 
-               --  Unlock the task in case the computations performed above
-               --  fail for some reason.
+         N_Size := Storage_Size + Header_And_Padding;
 
-               Unlock_Task.all;
-               raise;
-         end;
       else
          N_Addr := Addr;
          N_Size := Storage_Size;
       end if;
 
-      --  Step 2: Deallocation
+      --  Step 2: Deallocation of object
 
       --  Dispatch to the proper implementation of Deallocate. This action
       --  covers both Root_Storage_Pool and Root_Storage_Pool_With_Subpools
@@ -542,7 +455,8 @@ package body System.Storage_Pools.Subpools is
      (Alignment : System.Storage_Elements.Storage_Count)
       return System.Storage_Elements.Storage_Count
    is
-      Size : constant Storage_Count := Header_Size;
+      Size : constant Storage_Count :=
+               System.Finalization_Primitives.Header_Size;
 
    begin
       if Size mod Alignment = 0 then
diff --git a/gcc/ada/libgnat/s-stposu.ads b/gcc/ada/libgnat/s-stposu.ads
index f3b908d53e499a8924d7c9b11be3d8f7b9fef34b..a2f306a0c9359ddec6e2a51ba5c40a719e3aeca8 100644
--- a/gcc/ada/libgnat/s-stposu.ads
+++ b/gcc/ada/libgnat/s-stposu.ads
@@ -242,15 +242,15 @@ private
    --  to Allocate_Any.
 
    procedure Allocate_Any_Controlled
-     (Pool               : in out Root_Storage_Pool'Class;
-      Context_Subpool    : Subpool_Handle;
-      Context_Collection : Finalization_Primitives.Finalization_Collection_Ptr;
-      Fin_Address        : Finalization_Primitives.Finalize_Address_Ptr;
-      Addr               : out System.Address;
-      Storage_Size       : System.Storage_Elements.Storage_Count;
-      Alignment          : System.Storage_Elements.Storage_Count;
-      Is_Controlled      : Boolean;
-      On_Subpool         : Boolean);
+     (Pool          : in out Root_Storage_Pool'Class;
+      Named_Subpool : Subpool_Handle;
+      Collection    : in out
+                        Finalization_Primitives.Finalization_Collection_Ptr;
+      Addr          : out System.Address;
+      Storage_Size  : System.Storage_Elements.Storage_Count;
+      Alignment     : System.Storage_Elements.Storage_Count;
+      Is_Controlled : Boolean;
+      On_Subpool    : Boolean);
    --  Compiler interface. This version of Allocate handles all possible cases,
    --  either on a pool or a pool_with_subpools, regardless of the controlled
    --  status of the allocated object. Parameter usage:
@@ -258,16 +258,13 @@ private
    --    * Pool - The pool associated with the access type. Pool can be any
    --    derivation from Root_Storage_Pool, including a pool_with_subpools.
    --
-   --    * Context_Subpool - The subpool handle name of an allocator. If no
-   --    subpool handle is present at the point of allocation, the actual
-   --    would be null.
-   --
-   --    * Context_Collection - The finalization collection associated with the
-   --    access type. If the access type's designated type is not controlled,
-   --    the actual would be null.
+   --    * Named_Subpool - The subpool identified by the handle name of an
+   --    allocator. If no handle name is present, the actual would be null.
    --
-   --    * Fin_Address - TSS routine Finalize_Address of the designated type.
-   --    If the designated type is not controlled, the actual would be null.
+   --    * Collection - The finalization collection associated with the access
+   --    type if its designated type is controlled. If it is not, the actual
+   --    would be null. If the object is allocated on a subpool, the parameter
+   --    is updated to the collection of the subpool.
    --
    --    * Addr - The address of the allocated object.
    --
@@ -276,8 +273,8 @@ private
    --    * Alignment - The alignment of the allocated object.
    --
    --    * Is_Controlled - A flag which determines whether the allocated object
-   --    is controlled. When set to True, the machinery generates additional
-   --    data.
+   --    is controlled. When set to True, the machinery allocates more space
+   --    and returns a displaced address.
    --
    --    * On_Subpool - A flag which determines whether the a subpool handle
    --    name is present at the point of allocation. This is used for error
@@ -303,8 +300,7 @@ private
    --    * Alignment - The alignment of the allocated object.
    --
    --    * Is_Controlled - A flag which determines whether the allocated object
-   --    is controlled. When set to True, the machinery generates additional
-   --    data.
+   --    is controlled. When set to True, the address must be displaced.
 
    procedure Detach (N : not null SP_Node_Ptr);
    --  Unhook a subpool node from an arbitrary subpool list
diff --git a/gcc/ada/rtsfind.ads b/gcc/ada/rtsfind.ads
index d67dc0e678370ef0953435bb1fbe228d4f47af22..50c77867dcdc70298f9c21c3e5d22707852cba4f 100644
--- a/gcc/ada/rtsfind.ads
+++ b/gcc/ada/rtsfind.ads
@@ -918,9 +918,11 @@ package Rtsfind is
      RE_Attr_Long_Long_Float,            -- System.Fat_LLF
 
      RE_Add_Offset_To_Address,           -- System.Finalization_Primitives
+     RE_Attach_Object_To_Collection,     -- System.Finalization_Primitives
      RE_Attach_Object_To_Master,         -- System.Finalization_Primitives
      RE_Attach_Object_To_Node,           -- System.Finalization_Primitives
      RE_Chain_Node_To_Master,            -- System.Finalization_Primitives
+     RE_Detach_Object_From_Collection,   -- System.Finalization_Primitives
      RE_Finalization_Collection,         -- System.Finalization_Primitives
      RE_Finalization_Collection_Ptr,     -- System.Finalization_Primitives
      RE_Finalization_Master,             -- System.Finalization_Primitives
@@ -2567,9 +2569,11 @@ package Rtsfind is
      RE_Attr_Long_Long_Float             => System_Fat_LLF,
 
      RE_Add_Offset_To_Address            => System_Finalization_Primitives,
+     RE_Attach_Object_To_Collection      => System_Finalization_Primitives,
      RE_Attach_Object_To_Master          => System_Finalization_Primitives,
      RE_Attach_Object_To_Node            => System_Finalization_Primitives,
      RE_Chain_Node_To_Master             => System_Finalization_Primitives,
+     RE_Detach_Object_From_Collection    => System_Finalization_Primitives,
      RE_Finalization_Collection          => System_Finalization_Primitives,
      RE_Finalization_Collection_Ptr      => System_Finalization_Primitives,
      RE_Finalization_Master              => System_Finalization_Primitives,