OSDN Git Service

2011-08-03 Robert Dewar <dewar@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / exp_ch5.adb
index 4de1074..51ae183 100644 (file)
@@ -6,7 +6,7 @@
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 1992-2007, 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- --
@@ -27,8 +27,6 @@ with Atree;    use Atree;
 with Checks;   use Checks;
 with Debug;    use Debug;
 with Einfo;    use Einfo;
-with Elists;   use Elists;
-with Exp_Atag; use Exp_Atag;
 with Exp_Aggr; use Exp_Aggr;
 with Exp_Ch6;  use Exp_Ch6;
 with Exp_Ch7;  use Exp_Ch7;
@@ -46,6 +44,7 @@ with Rident;   use Rident;
 with Rtsfind;  use Rtsfind;
 with Sinfo;    use Sinfo;
 with Sem;      use Sem;
+with Sem_Aux;  use Sem_Aux;
 with Sem_Ch3;  use Sem_Ch3;
 with Sem_Ch8;  use Sem_Ch8;
 with Sem_Ch13; use Sem_Ch13;
@@ -100,25 +99,23 @@ package body Exp_Ch5 is
    --  N is an assignment of a non-tagged record value. This routine handles
    --  the case where the assignment must be made component by component,
    --  either because the target is not byte aligned, or there is a change
-   --  of representation.
+   --  of representation, or when we have a tagged type with a representation
+   --  clause (this last case is required because holes in the tagged type
+   --  might be filled with components from child types).
 
-   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.
+   procedure Expand_Iterator_Loop (N : Node_Id);
+   --  Expand loop over arrays and containers that uses the form "for X of C"
+   --  with an optional subtype mark, or "for Y in C".
 
-   procedure Expand_Simple_Function_Return (N : Node_Id);
-   --  Expand simple return from function. Called by
-   --  Expand_N_Simple_Return_Statement in case we're returning from a function
-   --  body.
+   procedure Expand_Predicated_Loop (N : Node_Id);
+   --  Expand for loop over predicated subtype
 
    function Make_Tag_Ctrl_Assignment (N : Node_Id) return List_Id;
-   --  Generate the necessary code for controlled and tagged assignment,
-   --  that is to say, finalization of the target before, adjustement of
-   --  the target after and save and restore of the tag and finalization
-   --  pointers which are not 'part of the value' and must not be changed
-   --  upon assignment. N is the original Assignment node.
+   --  Generate the necessary code for controlled and tagged assignment, that
+   --  is to say, finalization of the target before, adjustment of the target
+   --  after and save and restore of the tag and finalization pointers which
+   --  are not 'part of the value' and must not be changed upon assignment. N
+   --  is the original Assignment node.
 
    ------------------------------
    -- Change_Of_Representation --
@@ -308,6 +305,18 @@ package body Exp_Ch5 is
          --  can be performed directly.
       end if;
 
+      --  If either operand has an address clause clear Backwards_OK and
+      --  Forwards_OK, since we cannot tell if the operands overlap. We
+      --  exclude this treatment when Rhs is an aggregate, since we know
+      --  that overlap can't occur.
+
+      if (Has_Address_Clause (Lhs) and then Nkind (Rhs) /= N_Aggregate)
+        or else Has_Address_Clause (Rhs)
+      then
+         Set_Forwards_OK  (N, False);
+         Set_Backwards_OK (N, False);
+      end if;
+
       --  We certainly must use a loop for change of representation and also
       --  we use the operand of the conversion on the right hand side as the
       --  effective right hand side (the component types must match in this
@@ -364,8 +373,8 @@ package body Exp_Ch5 is
          --  do this, we get the wrong length computed for the array to be
          --  moved. The two cases we need to worry about are:
 
-         --  Explicit deference of an unconstrained packed array type as in the
-         --  following example:
+         --  Explicit dereference of an unconstrained packed array type as in
+         --  the following example:
 
          --    procedure C52 is
          --       type BITS is array(INTEGER range <>) of BOOLEAN;
@@ -502,8 +511,7 @@ package body Exp_Ch5 is
 
       if Nkind (Rhs) = N_String_Literal then
          declare
-            Temp : constant Entity_Id :=
-                     Make_Defining_Identifier (Loc, New_Internal_Name ('T'));
+            Temp : constant Entity_Id := Make_Temporary (Loc, 'T', Rhs);
             Decl : Node_Id;
 
          begin
@@ -561,15 +569,23 @@ package body Exp_Ch5 is
          --  cannot assign to elements of the array without this extra
          --  unchecked conversion.
 
+         --  Note: We propagate Parent to the conversion nodes to generate
+         --  a well-formed subtree.
+
          if Nkind (Act_Lhs) = N_Slice then
             Larray := Prefix (Act_Lhs);
          else
             Larray := Act_Lhs;
 
             if Is_Private_Type (Etype (Larray)) then
-               Larray :=
-                 Unchecked_Convert_To
-                   (Underlying_Type (Etype (Larray)), Larray);
+               declare
+                  Par : constant Node_Id := Parent (Larray);
+               begin
+                  Larray :=
+                    Unchecked_Convert_To
+                      (Underlying_Type (Etype (Larray)), Larray);
+                  Set_Parent (Larray, Par);
+               end;
             end if;
          end if;
 
@@ -579,9 +595,14 @@ package body Exp_Ch5 is
             Rarray := Act_Rhs;
 
             if Is_Private_Type (Etype (Rarray)) then
-               Rarray :=
-                 Unchecked_Convert_To
-                   (Underlying_Type (Etype (Rarray)), Rarray);
+               declare
+                  Par : constant Node_Id := Parent (Rarray);
+               begin
+                  Rarray :=
+                    Unchecked_Convert_To
+                      (Underlying_Type (Etype (Rarray)), Rarray);
+                  Set_Parent (Rarray, Par);
+               end;
             end if;
          end if;
 
@@ -615,10 +636,14 @@ package body Exp_Ch5 is
             --  or upper bounds at compile time and compare them.
 
             else
-               Cresult := Compile_Time_Compare (Left_Lo, Right_Lo);
+               Cresult :=
+                 Compile_Time_Compare
+                   (Left_Lo, Right_Lo, Assume_Valid => True);
 
                if Cresult = Unknown then
-                  Cresult := Compile_Time_Compare (Left_Hi, Right_Hi);
+                  Cresult :=
+                    Compile_Time_Compare
+                      (Left_Hi, Right_Hi, Assume_Valid => True);
                end if;
 
                case Cresult is
@@ -630,16 +655,21 @@ package body Exp_Ch5 is
             end if;
          end if;
 
-         --  If after that analysis, Forwards_OK is still True, and
-         --  Loop_Required is False, meaning that we have not discovered some
-         --  non-overlap reason for requiring a loop, then we can still let
-         --  gigi handle it.
+         --  If after that analysis Loop_Required is False, meaning that we
+         --  have not discovered some non-overlap reason for requiring a loop,
+         --  then the outcome depends on the capabilities of the back end.
 
          if not Loop_Required then
 
-            --  Assume gigi can handle it if Forwards_OK is set
+            --  The GCC back end can deal with all cases of overlap by falling
+            --  back to memmove if it cannot use a more efficient approach.
+
+            if VM_Target = No_VM and not AAMP_On_Target then
+               return;
+
+            --  Assume other back ends can handle it if Forwards_OK is set
 
-            if Forwards_OK (N) then
+            elsif Forwards_OK (N) then
                return;
 
             --  If Forwards_OK is not set, the back end will need something
@@ -729,14 +759,14 @@ package body Exp_Ch5 is
          --  Cases where either Forwards_OK or Backwards_OK is true
 
          if Forwards_OK (N) or else Backwards_OK (N) then
-            if Controlled_Type (Component_Type (L_Type))
+            if Needs_Finalization (Component_Type (L_Type))
               and then Base_Type (L_Type) = Base_Type (R_Type)
               and then Ndim = 1
               and then not No_Ctrl_Actions (N)
             then
                declare
-                  Proc : constant Entity_Id :=
-                           TSS (Base_Type (L_Type), TSS_Slice_Assign);
+                  Proc    : constant Entity_Id :=
+                              TSS (Base_Type (L_Type), TSS_Slice_Assign);
                   Actuals : List_Id;
 
                begin
@@ -805,7 +835,7 @@ package body Exp_Ch5 is
             Ensure_Defined (R_Type, N);
 
             --  We normally compare addresses to find out which way round to
-            --  do the loop, since this is realiable, and handles the cases of
+            --  do the loop, since this is reliable, and handles the cases of
             --  parameters, conversions etc. But we can't do that in the bit
             --  packed case or the VM case, because addresses don't work there.
 
@@ -848,12 +878,23 @@ package body Exp_Ch5 is
             --  conversions ???
 
             else
-               --  Copy the bounds and reset the Analyzed flag, because the
-               --  bounds of the index type itself may be universal, and must
-               --  must be reaanalyzed to acquire the proper type for Gigi.
+               --  Copy the bounds
 
                Cleft_Lo  := New_Copy_Tree (Left_Lo);
                Cright_Lo := New_Copy_Tree (Right_Lo);
+
+               --  If the types do not match we add an implicit conversion
+               --  here to ensure proper match
+
+               if Etype (Left_Lo) /= Etype (Right_Lo) then
+                  Cright_Lo :=
+                    Unchecked_Convert_To (Etype (Left_Lo), Cright_Lo);
+               end if;
+
+               --  Reset the Analyzed flag, because the bounds of the index
+               --  type itself may be universal, and must must be reanalyzed
+               --  to acquire the proper type for the back end.
+
                Set_Analyzed (Cleft_Lo, False);
                Set_Analyzed (Cright_Lo, False);
 
@@ -863,17 +904,17 @@ package body Exp_Ch5 is
                    Right_Opnd => Cright_Lo);
             end if;
 
-            if Controlled_Type (Component_Type (L_Type))
+            if Needs_Finalization (Component_Type (L_Type))
               and then Base_Type (L_Type) = Base_Type (R_Type)
               and then Ndim = 1
               and then not No_Ctrl_Actions (N)
             then
 
-               --  Call TSS procedure for array assignment, passing the the
+               --  Call TSS procedure for array assignment, passing the
                --  explicit bounds of right and left hand sides.
 
                declare
-                  Proc    : constant Node_Id :=
+                  Proc    : constant Entity_Id :=
                               TSS (Base_Type (L_Type), TSS_Slice_Assign);
                   Actuals : List_Id;
 
@@ -974,6 +1015,62 @@ package body Exp_Ch5 is
       F_Or_L : Name_Id;
       S_Or_P : Name_Id;
 
+      function Build_Step (J : Nat) return Node_Id;
+      --  The increment step for the index of the right-hand side is written
+      --  as an attribute reference (Succ or Pred). This function returns
+      --  the corresponding node, which is placed at the end of the loop body.
+
+      ----------------
+      -- Build_Step --
+      ----------------
+
+      function Build_Step (J : Nat) return Node_Id is
+         Step : Node_Id;
+         Lim  : Name_Id;
+
+      begin
+         if Rev then
+            Lim := Name_First;
+         else
+            Lim := Name_Last;
+         end if;
+
+         Step :=
+            Make_Assignment_Statement (Loc,
+               Name => New_Occurrence_Of (Rnn (J), Loc),
+               Expression =>
+                 Make_Attribute_Reference (Loc,
+                   Prefix =>
+                     New_Occurrence_Of (R_Index_Type (J), Loc),
+                   Attribute_Name => S_Or_P,
+                   Expressions => New_List (
+                     New_Occurrence_Of (Rnn (J), Loc))));
+
+      --  Note that on the last iteration of the loop, the index is increased
+      --  (or decreased) past the corresponding bound. This is consistent with
+      --  the C semantics of the back-end, where such an off-by-one value on a
+      --  dead index variable is OK. However, in CodePeer mode this leads to
+      --  spurious warnings, and thus we place a guard around the attribute
+      --  reference. For obvious reasons we only do this for CodePeer.
+
+         if CodePeer_Mode then
+            Step :=
+              Make_If_Statement (Loc,
+                 Condition =>
+                    Make_Op_Ne (Loc,
+                       Left_Opnd  => New_Occurrence_Of (Lnn (J), Loc),
+                       Right_Opnd =>
+                         Make_Attribute_Reference (Loc,
+                           Prefix => New_Occurrence_Of (L_Index_Type (J), Loc),
+                           Attribute_Name => Lim)),
+                 Then_Statements => New_List (Step));
+         end if;
+
+         return Step;
+      end Build_Step;
+
+   --  Start of processing for Expand_Assign_Array_Loop
+
    begin
       if Rev then
          F_Or_L := Name_Last;
@@ -994,13 +1091,8 @@ package body Exp_Ch5 is
          R_Index := First_Index (R_Type);
 
          for J in 1 .. Ndim loop
-            Lnn (J) :=
-              Make_Defining_Identifier (Loc,
-                Chars => New_Internal_Name ('L'));
-
-            Rnn (J) :=
-              Make_Defining_Identifier (Loc,
-                Chars => New_Internal_Name ('R'));
+            Lnn (J) := Make_Temporary (Loc, 'L');
+            Rnn (J) := Make_Temporary (Loc, 'R');
 
             L_Index_Type (J) := Etype (L_Index);
             R_Index_Type (J) := Etype (R_Index);
@@ -1075,18 +1167,7 @@ package body Exp_Ch5 is
                            Discrete_Subtype_Definition =>
                              New_Reference_To (L_Index_Type (J), Loc))),
 
-                   Statements => New_List (
-                     Assign,
-
-                     Make_Assignment_Statement (Loc,
-                       Name => New_Occurrence_Of (Rnn (J), Loc),
-                       Expression =>
-                         Make_Attribute_Reference (Loc,
-                           Prefix =>
-                             New_Occurrence_Of (R_Index_Type (J), Loc),
-                           Attribute_Name => S_Or_P,
-                           Expressions => New_List (
-                             New_Occurrence_Of (Rnn (J), Loc)))))))));
+                   Statements => New_List (Assign, Build_Step (J))))));
       end loop;
 
       return Assign;
@@ -1096,13 +1177,10 @@ package body Exp_Ch5 is
    -- Expand_Assign_Record --
    --------------------------
 
-   --  The only processing required is in the change of representation case,
-   --  where we must expand the assignment to a series of field by field
-   --  assignments.
-
    procedure Expand_Assign_Record (N : Node_Id) is
-      Lhs : constant Node_Id := Name (N);
-      Rhs : Node_Id          := Expression (N);
+      Lhs   : constant Node_Id    := Name (N);
+      Rhs   : Node_Id             := Expression (N);
+      L_Typ : constant Entity_Id  := Base_Type (Etype (Lhs));
 
    begin
       --  If change of representation, then extract the real right hand side
@@ -1124,6 +1202,14 @@ package body Exp_Ch5 is
       then
          null;
 
+      --  If we have a tagged type that has a complete record representation
+      --  clause, we must do we must do component-wise assignments, since child
+      --  types may have used gaps for their components, and we might be
+      --  dealing with a view conversion.
+
+      elsif Is_Fully_Repped_Tagged_Type (L_Typ) then
+         null;
+
       --  If neither condition met, then nothing special to do, the back end
       --  can handle assignment of the entire component as a single entity.
 
@@ -1136,7 +1222,6 @@ package body Exp_Ch5 is
       declare
          Loc   : constant Source_Ptr := Sloc (N);
          R_Typ : constant Entity_Id  := Base_Type (Etype (Rhs));
-         L_Typ : constant Entity_Id  := Base_Type (Etype (Lhs));
          Decl  : constant Node_Id    := Declaration_Node (R_Typ);
          RDef  : Node_Id;
          F     : Entity_Id;
@@ -1157,7 +1242,7 @@ package body Exp_Ch5 is
          --  part expression as the switch for the generated case statement.
 
          function Make_Field_Assign
-           (C : Entity_Id;
+           (C   : Entity_Id;
             U_U : Boolean := False) return Node_Id;
          --  Given C, the entity for a discriminant or component, build an
          --  assignment for the corresponding field values. The flag U_U
@@ -1182,11 +1267,11 @@ package body Exp_Ch5 is
 
          begin
             C := First_Entity (Utyp);
-
             while Present (C) loop
                if Chars (C) = Chars (Comp) then
                   return C;
                end if;
+
                Next_Entity (C);
             end loop;
 
@@ -1215,11 +1300,9 @@ package body Exp_Ch5 is
             Result := Make_Field_Assigns (CI);
 
             if Present (VP) then
-
                V := First_Non_Pragma (Variants (VP));
                Alts := New_List;
                while Present (V) loop
-
                   DCH := New_List;
                   DC := First (Discrete_Choices (V));
                   while Present (DC) loop
@@ -1249,7 +1332,7 @@ package body Exp_Ch5 is
                else
                   Expr :=
                     Make_Selected_Component (Loc,
-                      Prefix => Duplicate_Subexpr (Rhs),
+                      Prefix        => Duplicate_Subexpr (Rhs),
                       Selector_Name =>
                         Make_Identifier (Loc, Chars (Name (VP))));
                end if;
@@ -1268,7 +1351,7 @@ package body Exp_Ch5 is
          -----------------------
 
          function Make_Field_Assign
-           (C : Entity_Id;
+           (C   : Entity_Id;
             U_U : Boolean := False) return Node_Id
          is
             A    : Node_Id;
@@ -1286,7 +1369,7 @@ package body Exp_Ch5 is
             else
                Expr :=
                  Make_Selected_Component (Loc,
-                   Prefix => Duplicate_Subexpr (Rhs),
+                   Prefix        => Duplicate_Subexpr (Rhs),
                    Selector_Name => New_Occurrence_Of (C, Loc));
             end if;
 
@@ -1294,7 +1377,7 @@ package body Exp_Ch5 is
               Make_Assignment_Statement (Loc,
                 Name =>
                   Make_Selected_Component (Loc,
-                    Prefix => Duplicate_Subexpr (Lhs),
+                    Prefix        => Duplicate_Subexpr (Lhs),
                     Selector_Name =>
                       New_Occurrence_Of (Find_Component (L_Typ, C), Loc)),
                 Expression => Expr);
@@ -1302,6 +1385,14 @@ package body Exp_Ch5 is
             --  Set Assignment_OK, so discriminants can be assigned
 
             Set_Assignment_OK (Name (A), True);
+
+            if Componentwise_Assignment (N)
+              and then Nkind (Name (A)) = N_Selected_Component
+              and then Chars (Selector_Name (Name (A))) = Name_uParent
+            then
+               Set_Componentwise_Assignment (A);
+            end if;
+
             return A;
          end Make_Field_Assign;
 
@@ -1316,8 +1407,16 @@ package body Exp_Ch5 is
          begin
             Item := First (CI);
             Result := New_List;
+
             while Present (Item) loop
-               if Nkind (Item) = N_Component_Declaration then
+
+               --  Look for components, but exclude _tag field assignment if
+               --  the special Componentwise_Assignment flag is set.
+
+               if Nkind (Item) = N_Component_Declaration
+                 and then not (Is_Tag (Defining_Identifier (Item))
+                                 and then Componentwise_Assignment (N))
+               then
                   Append_To
                     (Result, Make_Field_Assign (Defining_Identifier (Item)));
                end if;
@@ -1346,20 +1445,38 @@ package body Exp_Ch5 is
             F := First_Discriminant (R_Typ);
             while Present (F) loop
 
-               if Is_Unchecked_Union (Base_Type (R_Typ)) then
-                  Insert_Action (N, Make_Field_Assign (F, True));
-               else
-                  Insert_Action (N, Make_Field_Assign (F));
-               end if;
+               --  If we are expanding the initialization of a derived record
+               --  that constrains or renames discriminants of the parent, we
+               --  must use the corresponding discriminant in the parent.
+
+               declare
+                  CF : Entity_Id;
+
+               begin
+                  if Inside_Init_Proc
+                    and then Present (Corresponding_Discriminant (F))
+                  then
+                     CF := Corresponding_Discriminant (F);
+                  else
+                     CF := F;
+                  end if;
+
+                  if Is_Unchecked_Union (Base_Type (R_Typ)) then
+                     Insert_Action (N, Make_Field_Assign (CF, True));
+                  else
+                     Insert_Action (N, Make_Field_Assign (CF));
+                  end if;
 
-               Next_Discriminant (F);
+                  Next_Discriminant (F);
+               end;
             end loop;
          end if;
 
          --  We know the underlying type is a record, but its current view
          --  may be private. We must retrieve the usable record declaration.
 
-         if Nkind (Decl) = N_Private_Type_Declaration
+         if Nkind_In (Decl, N_Private_Type_Declaration,
+                            N_Private_Extension_Declaration)
            and then Present (Full_View (R_Typ))
          then
             RDef := Type_Definition (Declaration_Node (Full_View (R_Typ)));
@@ -1367,10 +1484,13 @@ package body Exp_Ch5 is
             RDef := Type_Definition (Decl);
          end if;
 
+         if Nkind (RDef) = N_Derived_Type_Definition then
+            RDef := Record_Extension_Part (RDef);
+         end if;
+
          if Nkind (RDef) = N_Record_Definition
            and then Present (Component_List (RDef))
          then
-
             if Is_Unchecked_Union (R_Typ) then
                Insert_Actions (N,
                  Make_Component_List_Assign (Component_List (RDef), True));
@@ -1381,7 +1501,6 @@ package body Exp_Ch5 is
 
             Rewrite (N, Make_Null_Statement (Loc));
          end if;
-
       end;
    end Expand_Assign_Record;
 
@@ -1400,6 +1519,32 @@ package body Exp_Ch5 is
       Exp  : Node_Id;
 
    begin
+      --  Special case to check right away, if the Componentwise_Assignment
+      --  flag is set, this is a reanalysis from the expansion of the primitive
+      --  assignment procedure for a tagged type, and all we need to do is to
+      --  expand to assignment of components, because otherwise, we would get
+      --  infinite recursion (since this looks like a tagged assignment which
+      --  would normally try to *call* the primitive assignment procedure).
+
+      if Componentwise_Assignment (N) then
+         Expand_Assign_Record (N);
+         return;
+      end if;
+
+      --  Defend against invalid subscripts on left side if we are in standard
+      --  validity checking mode. No need to do this if we are checking all
+      --  subscripts.
+
+      --  Note that we do this right away, because there are some early return
+      --  paths in this procedure, and this is required on all paths.
+
+      if Validity_Checks_On
+        and then Validity_Check_Default
+        and then not Validity_Check_Subscripts
+      then
+         Check_Valid_Lvalue_Subscripts (Lhs);
+      end if;
+
       --  Ada 2005 (AI-327): Handle assignment to priority of protected object
 
       --  Rewrite an assignment to X'Priority into a run-time call
@@ -1413,7 +1558,7 @@ package body Exp_Ch5 is
       --  about complications that would other arise from X'Priority'Access,
       --  which is illegal, because of the lack of aliasing.
 
-      if Ada_Version >= Ada_05 then
+      if Ada_Version >= Ada_2005 then
          declare
             Call           : Node_Id;
             Conctyp        : Entity_Id;
@@ -1481,14 +1626,20 @@ package body Exp_Ch5 is
          end;
       end if;
 
-      --  First deal with generation of range check if required. For now we do
-      --  this only for discrete types.
+      --  Deal with assignment checks unless suppressed
 
-      if Do_Range_Check (Rhs)
-        and then Is_Discrete_Type (Typ)
-      then
-         Set_Do_Range_Check (Rhs, False);
-         Generate_Range_Check (Rhs, Typ, CE_Range_Check_Failed);
+      if not Suppress_Assignment_Checks (N) then
+
+         --  First deal with generation of range check if required
+
+         if Do_Range_Check (Rhs) then
+            Set_Do_Range_Check (Rhs, False);
+            Generate_Range_Check (Rhs, Typ, CE_Range_Check_Failed);
+         end if;
+
+         --  Then generate predicate check if required
+
+         Apply_Predicate_Check (Rhs, Typ);
       end if;
 
       --  Check for a special case where a high level transformation is
@@ -1523,17 +1674,14 @@ package body Exp_Ch5 is
       --  Since P is going to be evaluated more than once, any subscripts
       --  in P must have their evaluation forced.
 
-      if (Nkind (Lhs) = N_Indexed_Component
-           or else
-          Nkind (Lhs) = N_Selected_Component)
+      if Nkind_In (Lhs, N_Indexed_Component, N_Selected_Component)
         and then Is_Ref_To_Bit_Packed_Array (Prefix (Lhs))
       then
          declare
             BPAR_Expr : constant Node_Id   := Relocate_Node (Prefix (Lhs));
             BPAR_Typ  : constant Entity_Id := Etype (BPAR_Expr);
             Tnn       : constant Entity_Id :=
-                          Make_Defining_Identifier (Loc,
-                            Chars => New_Internal_Name ('T'));
+                          Make_Temporary (Loc, 'T', BPAR_Expr);
 
          begin
             --  Insert the post assignment first, because we want to copy the
@@ -1562,9 +1710,8 @@ package body Exp_Ch5 is
             loop
                Set_Analyzed (Exp, False);
 
-               if Nkind (Exp) = N_Selected_Component
-                    or else
-                  Nkind (Exp) = N_Indexed_Component
+               if Nkind_In
+                   (Exp, N_Selected_Component, N_Indexed_Component)
                then
                   Exp := Prefix (Exp);
                else
@@ -1643,6 +1790,7 @@ package body Exp_Ch5 is
       --  has discriminants (necessarily with defaults) a check may still be
       --  necessary if the Lhs is aliased. The private determinants must be
       --  visible to build the discriminant constraints.
+      --  What is a "determinant"???
 
       --  Only an explicit dereference that comes from source indicates
       --  aliasing. Access to formals of protected operations and entries
@@ -1749,7 +1897,7 @@ package body Exp_Ch5 is
       --  build-in-place for user-written assignment statements (the assignment
       --  here came from an aggregate.)
 
-      elsif Ada_Version >= Ada_05
+      elsif Ada_Version >= Ada_2005
         and then Is_Build_In_Place_Function_Call (Rhs)
       then
          Make_Build_In_Place_Call_In_Assignment (N, Rhs);
@@ -1762,17 +1910,16 @@ package body Exp_Ch5 is
          return;
 
       elsif Is_Tagged_Type (Typ)
-        or else (Controlled_Type (Typ) and then not Is_Array_Type (Typ))
+        or else (Needs_Finalization (Typ) and then not Is_Array_Type (Typ))
       then
          Tagged_Case : declare
             L                   : List_Id := No_List;
             Expand_Ctrl_Actions : constant Boolean := not No_Ctrl_Actions (N);
 
          begin
-            --  In the controlled case, we need to make sure that function
-            --  calls are evaluated before finalizing the target. In all cases,
-            --  it makes the expansion easier if the side-effects are removed
-            --  first.
+            --  In the controlled case, we ensure that function calls are
+            --  evaluated before finalizing the target. In all cases, it makes
+            --  the expansion easier if the side-effects are removed first.
 
             Remove_Side_Effects (Lhs);
             Remove_Side_Effects (Rhs);
@@ -1787,27 +1934,25 @@ package body Exp_Ch5 is
 
                --  If the type is tagged, we may as well use the predefined
                --  primitive assignment. This avoids inlining a lot of code
-               --  and in the class-wide case, the assignment is replaced by
-               --  dispatch call to _assign. Note that this cannot be done when
-               --  discriminant checks are locally suppressed (as in extension
-               --  aggregate expansions) because otherwise the discriminant
-               --  check will be performed within the _assign call. It is also
-               --  suppressed for assignmments created by the expander that
-               --  correspond to initializations, where we do want to copy the
-               --  tag (No_Ctrl_Actions flag set True). by the expander and we
-               --  do not need to mess with tags ever (Expand_Ctrl_Actions flag
-               --  is set True in this case).
+               --  and in the class-wide case, the assignment is replaced
+               --  by a dispatching call to _assign. It is suppressed in the
+               --  case of assignments created by the expander that correspond
+               --  to initializations, where we do want to copy the tag
+               --  (Expand_Ctrl_Actions flag is set True in this case). It is
+               --  also suppressed if restriction No_Dispatching_Calls is in
+               --  force because in that case predefined primitives are not
+               --  generated.
 
                or else (Is_Tagged_Type (Typ)
-                          and then not Is_Value_Type (Etype (Lhs))
-                          and then Chars (Current_Scope) /= Name_uAssign
-                          and then Expand_Ctrl_Actions
-                          and then not Discriminant_Checks_Suppressed (Empty))
+                         and then not Is_Value_Type (Etype (Lhs))
+                         and then Chars (Current_Scope) /= Name_uAssign
+                         and then Expand_Ctrl_Actions
+                         and then
+                           not Restriction_Active (No_Dispatching_Calls))
             then
                --  Fetch the primitive op _assign and proper type to call it.
-               --  Because of possible conflits between private and full view
-               --  the proper type is fetched directly from the operation
-               --  profile.
+               --  Because of possible conflicts between private and full view,
+               --  fetch the proper type directly from the operation profile.
 
                declare
                   Op    : constant Entity_Id :=
@@ -1840,25 +1985,38 @@ package body Exp_Ch5 is
                                  Make_Selected_Component (Loc,
                                    Prefix        => Duplicate_Subexpr (Lhs),
                                    Selector_Name =>
-                                     Make_Identifier (Loc,
-                                       Chars => Name_uTag)),
+                                     Make_Identifier (Loc, Name_uTag)),
                                Right_Opnd =>
                                  Make_Selected_Component (Loc,
                                    Prefix        => Duplicate_Subexpr (Rhs),
                                    Selector_Name =>
-                                     Make_Identifier (Loc,
-                                       Chars => Name_uTag))),
+                                     Make_Identifier (Loc, Name_uTag))),
                          Reason => CE_Tag_Check_Failed));
                   end if;
 
-                  Append_To (L,
-                    Make_Procedure_Call_Statement (Loc,
-                      Name => New_Reference_To (Op, Loc),
-                      Parameter_Associations => New_List (
-                        Unchecked_Convert_To (F_Typ,
-                          Duplicate_Subexpr (Lhs)),
-                        Unchecked_Convert_To (F_Typ,
-                          Duplicate_Subexpr (Rhs)))));
+                  declare
+                     Left_N  : Node_Id := Duplicate_Subexpr (Lhs);
+                     Right_N : Node_Id := Duplicate_Subexpr (Rhs);
+
+                  begin
+                     --  In order to dispatch the call to _assign the type of
+                     --  the actuals must match. Add conversion (if required).
+
+                     if Etype (Lhs) /= F_Typ then
+                        Left_N := Unchecked_Convert_To (F_Typ, Left_N);
+                     end if;
+
+                     if Etype (Rhs) /= F_Typ then
+                        Right_N := Unchecked_Convert_To (F_Typ, Right_N);
+                     end if;
+
+                     Append_To (L,
+                       Make_Procedure_Call_Statement (Loc,
+                         Name => New_Reference_To (Op, Loc),
+                         Parameter_Associations => New_List (
+                           Node1 => Left_N,
+                           Node2 => Right_N)));
+                  end;
                end;
 
             else
@@ -1873,8 +2031,11 @@ package body Exp_Ch5 is
                --       <code for controlled and/or tagged assignment>
                --    end if;
 
+               --  Skip this if Restriction (No_Finalization) is active
+
                if not Statically_Different (Lhs, Rhs)
                  and then Expand_Ctrl_Actions
+                 and then not Restriction_Active (No_Finalization)
                then
                   L := New_List (
                     Make_Implicit_If_Statement (N,
@@ -1918,10 +2079,10 @@ package body Exp_Ch5 is
                 Handled_Statement_Sequence =>
                   Make_Handled_Sequence_Of_Statements (Loc, Statements => L)));
 
-            --  If no restrictions on aborts, protect the whole assignement
+            --  If no restrictions on aborts, protect the whole assignment
             --  for controlled objects as per 9.8(11).
 
-            if Controlled_Type (Typ)
+            if Needs_Finalization (Typ)
               and then Expand_Ctrl_Actions
               and then Abort_Allowed
             then
@@ -1958,9 +2119,8 @@ package body Exp_Ch5 is
             Actual_Rhs : Node_Id := Rhs;
 
          begin
-            while Nkind (Actual_Rhs) = N_Type_Conversion
-              or else
-                  Nkind (Actual_Rhs) = N_Qualified_Expression
+            while Nkind_In (Actual_Rhs, N_Type_Conversion,
+                                        N_Qualified_Expression)
             loop
                Actual_Rhs := Expression (Actual_Rhs);
             end loop;
@@ -1988,14 +2148,31 @@ package body Exp_Ch5 is
             --  Here the right side is valid, so it is fine. The case to deal
             --  with is when the left side is a local variable reference whose
             --  value is not currently known to be valid. If this is the case,
-            --  and the assignment appears in an unconditional context, then we
-            --  can mark the left side as now being valid.
+            --  and the assignment appears in an unconditional context, then
+            --  we can mark the left side as now being valid if one of these
+            --  conditions holds:
+
+            --    The expression of the right side has Do_Range_Check set so
+            --    that we know a range check will be performed. Note that it
+            --    can be the case that a range check is omitted because we
+            --    make the assumption that we can assume validity for operands
+            --    appearing in the right side in determining whether a range
+            --    check is required
+
+            --    The subtype of the right side matches the subtype of the
+            --    left side. In this case, even though we have not checked
+            --    the range of the right side, we know it is in range of its
+            --    subtype if the expression is valid.
 
             if Is_Local_Variable_Reference (Lhs)
               and then not Is_Known_Valid (Entity (Lhs))
               and then In_Unconditional_Context (N)
             then
-               Set_Is_Known_Valid (Entity (Lhs), True);
+               if Do_Range_Check (Rhs)
+                 or else Etype (Lhs) = Etype (Rhs)
+               then
+                  Set_Is_Known_Valid (Entity (Lhs), True);
+               end if;
             end if;
 
          --  Case where right side may be invalid in the sense of the RM
@@ -2017,9 +2194,7 @@ package body Exp_Ch5 is
                --  Skip this if left hand side is an array or record component
                --  and elementary component validity checks are suppressed.
 
-               if (Nkind (Lhs) = N_Selected_Component
-                    or else
-                   Nkind (Lhs) = N_Indexed_Component)
+               if Nkind_In (Lhs, N_Selected_Component, N_Indexed_Component)
                  and then not Validity_Check_Components
                then
                   null;
@@ -2070,17 +2245,6 @@ package body Exp_Ch5 is
          end if;
       end if;
 
-      --  Defend against invalid subscripts on left side if we are in standard
-      --  validity checking mode. No need to do this if we are checking all
-      --  subscripts.
-
-      if Validity_Checks_On
-        and then Validity_Check_Default
-        and then not Validity_Check_Subscripts
-      then
-         Check_Valid_Lvalue_Subscripts (Lhs);
-      end if;
-
    exception
       when RE_Not_Available =>
          return;
@@ -2207,7 +2371,7 @@ package body Exp_Ch5 is
 
          --  An optimization. If there are only two alternatives, and only
          --  a single choice, then rewrite the whole case statement as an
-         --  if statement, since this can result in susbequent optimizations.
+         --  if statement, since this can result in subsequent optimizations.
          --  This helps not only with case statements in the source of a
          --  simple form, but also with generated code (discriminant check
          --  functions in particular)
@@ -2304,657 +2468,6 @@ package body Exp_Ch5 is
       Adjust_Condition (Condition (N));
    end Expand_N_Exit_Statement;
 
-   ----------------------------------------
-   -- Expand_N_Extended_Return_Statement --
-   ----------------------------------------
-
-   --  If there is a Handled_Statement_Sequence, we rewrite this:
-
-   --     return Result : T := <expression> do
-   --        <handled_seq_of_stms>
-   --     end return;
-
-   --  to be:
-
-   --     declare
-   --        Result : T := <expression>;
-   --     begin
-   --        <handled_seq_of_stms>
-   --        return Result;
-   --     end;
-
-   --  Otherwise (no Handled_Statement_Sequence), we rewrite this:
-
-   --     return Result : T := <expression>;
-
-   --  to be:
-
-   --     return <expression>;
-
-   --  unless it's build-in-place or there's no <expression>, in which case
-   --  we generate:
-
-   --     declare
-   --        Result : T := <expression>;
-   --     begin
-   --        return Result;
-   --     end;
-
-   --  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.
-
-   --  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).
-
-   procedure Expand_N_Extended_Return_Statement (N : Node_Id) is
-      Loc : constant Source_Ptr := Sloc (N);
-
-      Return_Object_Entity : constant Entity_Id :=
-                               First_Entity (Return_Statement_Entity (N));
-      Return_Object_Decl   : constant Node_Id :=
-                               Parent (Return_Object_Entity);
-      Parent_Function      : constant Entity_Id :=
-                               Return_Applies_To (Return_Statement_Entity (N));
-      Is_Build_In_Place    : constant Boolean :=
-                               Is_Build_In_Place_Function (Parent_Function);
-
-      Return_Stm      : Node_Id;
-      Statements      : List_Id;
-      Handled_Stm_Seq : Node_Id;
-      Result          : Node_Id;
-      Exp             : Node_Id;
-
-      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
-
-      function Move_Final_List return Node_Id;
-      --  Construct call to System.Finalization_Implementation.Move_Final_List
-      --  with parameters:
-      --
-      --    From         finalization list of the return statement
-      --    To           finalization list passed in by the caller
-
-      ---------------------------
-      -- Move_Activation_Chain --
-      ---------------------------
-
-      function Move_Activation_Chain return Node_Id is
-         Activation_Chain_Formal : constant Entity_Id :=
-                                     Build_In_Place_Formal
-                                       (Parent_Function, BIP_Activation_Chain);
-         To                      : constant Node_Id :=
-                                     New_Reference_To
-                                       (Activation_Chain_Formal, Loc);
-         Master_Formal           : constant Entity_Id :=
-                                     Build_In_Place_Formal
-                                       (Parent_Function, BIP_Master);
-         New_Master              : constant Node_Id :=
-                                     New_Reference_To (Master_Formal, Loc);
-
-         Chain_Entity : Entity_Id;
-         From         : Node_Id;
-
-      begin
-         Chain_Entity := First_Entity (Return_Statement_Entity (N));
-         while Chars (Chain_Entity) /= Name_uChain loop
-            Chain_Entity := Next_Entity (Chain_Entity);
-         end loop;
-
-         From :=
-           Make_Attribute_Reference (Loc,
-             Prefix         => New_Reference_To (Chain_Entity, Loc),
-             Attribute_Name => Name_Unrestricted_Access);
-         --  ??? Not clear why "Make_Identifier (Loc, Name_uChain)" doesn't
-         --  work, instead of "New_Reference_To (Chain_Entity, Loc)" above.
-
-         return
-           Make_Procedure_Call_Statement (Loc,
-             Name => New_Reference_To (RTE (RE_Move_Activation_Chain), Loc),
-             Parameter_Associations => New_List (From, To, New_Master));
-      end Move_Activation_Chain;
-
-      ---------------------
-      -- Move_Final_List --
-      ---------------------
-
-      function Move_Final_List return Node_Id is
-         Flist : constant Entity_Id  :=
-                   Finalization_Chain_Entity (Return_Statement_Entity (N));
-
-         From : constant Node_Id := New_Reference_To (Flist, Loc);
-
-         Caller_Final_List : constant Entity_Id :=
-                               Build_In_Place_Formal
-                                 (Parent_Function, BIP_Final_List);
-
-         To : constant Node_Id := New_Reference_To (Caller_Final_List, Loc);
-
-      begin
-         --  Catch cases where a finalization chain entity has not been
-         --  associated with the return statement entity.
-
-         pragma Assert (Present (Flist));
-
-         --  Build required call
-
-         return
-           Make_If_Statement (Loc,
-             Condition =>
-               Make_Op_Ne (Loc,
-                 Left_Opnd  => New_Copy (From),
-                 Right_Opnd => New_Node (N_Null, Loc)),
-             Then_Statements =>
-               New_List (
-                 Make_Procedure_Call_Statement (Loc,
-                   Name => New_Reference_To (RTE (RE_Move_Final_List), Loc),
-                   Parameter_Associations => New_List (From, To))));
-      end Move_Final_List;
-
-   --  Start of processing for Expand_N_Extended_Return_Statement
-
-   begin
-      if Nkind (Return_Object_Decl) = N_Object_Declaration then
-         Exp := Expression (Return_Object_Decl);
-      else
-         Exp := Empty;
-      end if;
-
-      Handled_Stm_Seq := Handled_Statement_Sequence (N);
-
-      --  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).
-
-      if Present (Handled_Stm_Seq)
-        or else Is_Composite_Type (Etype (Parent_Function))
-        or else No (Exp)
-      then
-         if No (Handled_Stm_Seq) then
-            Statements := New_List;
-
-         --  If the extended return has a handled statement sequence, then wrap
-         --  it in a block and use the block as the first statement.
-
-         else
-            Statements :=
-              New_List (Make_Block_Statement (Loc,
-                          Declarations => New_List,
-                          Handled_Statement_Sequence => Handled_Stm_Seq));
-         end if;
-
-         --  If control gets past the above Statements, we have successfully
-         --  completed the return statement. If the result type has controlled
-         --  parts and the return is for a build-in-place function, then we
-         --  call Move_Final_List to transfer responsibility for finalization
-         --  of the return object to the caller. An alternative would be to
-         --  declare a Success flag in the function, initialize it to False,
-         --  and set it to True here. Then move the Move_Final_List call into
-         --  the cleanup code, and check Success. If Success then make a call
-         --  to Move_Final_List else do finalization. Then we can remove the
-         --  abort-deferral and the nulling-out of the From parameter from
-         --  Move_Final_List. Note that the current method is not quite correct
-         --  in the rather obscure case of a select-then-abort statement whose
-         --  abortable part contains the return statement.
-
-         --  We test the type of the expression as well as the return type
-         --  of the function, because the latter may be a class-wide type
-         --  which is always treated as controlled, while the expression itself
-         --  has to have a definite type. The expression may be absent if a
-         --  constrained aggregate has been expanded into component assignments
-         --  so we have to check for this as well.
-
-         if Is_Build_In_Place
-           and then Controlled_Type (Etype (Parent_Function))
-         then
-            if not Is_Class_Wide_Type (Etype (Parent_Function))
-              or else
-               (Present (Exp)
-                 and then Controlled_Type (Etype (Exp)))
-            then
-               Append_To (Statements, Move_Final_List);
-            end if;
-         end if;
-
-         --  Similarly to the above Move_Final_List, 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 Has_Task (Etype (Parent_Function)) then
-            Append_To (Statements, Move_Activation_Chain);
-         end if;
-
-         --  Build a simple_return_statement that returns the return object
-
-         Return_Stm :=
-           Make_Simple_Return_Statement (Loc,
-             Expression => New_Occurrence_Of (Return_Object_Entity, Loc));
-         Append_To (Statements, Return_Stm);
-
-         Handled_Stm_Seq :=
-           Make_Handled_Sequence_Of_Statements (Loc, Statements);
-      end if;
-
-      --  Case where we build a block
-
-      if Present (Handled_Stm_Seq) then
-         Result :=
-           Make_Block_Statement (Loc,
-             Declarations => Return_Object_Declarations (N),
-             Handled_Statement_Sequence => Handled_Stm_Seq);
-
-         --  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 (Return_Object_Decl) = N_Object_Renaming_Declaration
-         then
-            Set_By_Ref (Return_Stm);  -- Return build-in-place results by ref
-
-         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 (Return_Object_Decl);
-               Return_Obj_Typ   : constant Entity_Id := Etype (Return_Obj_Id);
-               Return_Obj_Expr  : constant Node_Id :=
-                                    Expression (Return_Object_Decl);
-               Result_Subt      : constant Entity_Id :=
-                                    Etype (Parent_Function);
-               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_Stm);
-
-               --  Retrieve the implicit access parameter passed by the caller
-
-               Object_Access :=
-                 Build_In_Place_Formal (Parent_Function, 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).
-
-               if Present (Return_Obj_Expr)
-                 and then not No_Initialization (Return_Object_Decl)
-               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 (Return_Object_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 (Return_Object_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 (Parent_Function, BIP_Alloc_Form);
-
-                  declare
-                     Ref_Type       : Entity_Id;
-                     Ptr_Type_Decl  : Node_Id;
-                     Alloc_Obj_Id   : Entity_Id;
-                     Alloc_Obj_Decl : Node_Id;
-                     Alloc_If_Stmt  : Node_Id;
-                     SS_Allocator   : Node_Id;
-                     Heap_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_Defining_Identifier (Loc, New_Internal_Name ('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 (Return_Object_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_Defining_Identifier (Loc,
-                         Chars => New_Internal_Name ('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 (Return_Object_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 (Return_Object_Decl)
-                     then
-                        Heap_Allocator :=
-                          Make_Allocator (Loc,
-                            Expression =>
-                              Make_Qualified_Expression (Loc,
-                                Subtype_Mark =>
-                                  New_Reference_To (Return_Obj_Typ, Loc),
-                                Expression =>
-                                  New_Copy_Tree (Return_Obj_Expr)));
-
-                        SS_Allocator := New_Copy_Tree (Heap_Allocator);
-
-                     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,
-                               New_Reference_To
-                                 (Etype (Return_Obj_Expr), Loc));
-                        else
-                           Heap_Allocator :=
-                             Make_Allocator (Loc,
-                               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);
-
-                        SS_Allocator := New_Copy_Tree (Heap_Allocator);
-                     end if;
-
-                     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 (Parent_Function);
-                     Set_Sec_Stack_Needed_For_Return
-                       (Return_Statement_Entity (N));
-                     Set_Uses_Sec_Stack (Parent_Function);
-                     Set_Uses_Sec_Stack (Return_Statement_Entity (N));
-
-                     --  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 = 0), the
-                     --  result of allocating the object in the secondary stack
-                     --  (BIP_Alloc_Form = 1), or else an allocator to create
-                     --  the return object in the heap (BIP_Alloc_Form = 2).
-
-                     --  ??? 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)))),
-                         Else_Statements =>
-                           New_List (Make_Assignment_Statement (Loc,
-                                        Name       =>
-                                          New_Reference_To
-                                            (Alloc_Obj_Id, Loc),
-                                        Expression =>
-                                          Heap_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 derference 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 (Return_Object_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 (Return_Object_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.
-
-         Insert_List_Before (N, Return_Object_Declarations (N));
-
-         --  Build simple_return_statement that returns the expression directly
-
-         Return_Stm := Make_Simple_Return_Statement (Loc, Expression => Exp);
-
-         Result := Return_Stm;
-      end if;
-
-      --  Set the flag to prevent infinite recursion
-
-      Set_Comes_From_Extended_Return_Statement (Return_Stm);
-
-      Rewrite (N, Result);
-      Analyze (N);
-   end Expand_N_Extended_Return_Statement;
-
    -----------------------------
    -- Expand_N_Goto_Statement --
    -----------------------------
@@ -2976,8 +2489,8 @@ package body Exp_Ch5 is
    --  Second, we deal with the obvious rewriting for the cases where the
    --  condition of the IF is known at compile time to be True or False.
 
-   --  Third, we remove elsif parts which have non-empty Condition_Actions
-   --  and rewrite as independent if statements. For example:
+   --  Third, we remove elsif parts which have non-empty Condition_Actions and
+   --  rewrite as independent if statements. For example:
 
    --     if x then xs
    --     elsif y then ys
@@ -3184,75 +2697,378 @@ package body Exp_Ch5 is
 
       --     return not (expression);
 
-      if Nkind (N) = N_If_Statement
-         and then No (Elsif_Parts (N))
-         and then Present (Else_Statements (N))
-         and then List_Length (Then_Statements (N)) = 1
-         and then List_Length (Else_Statements (N)) = 1
+      --  Only do these optimizations if we are at least at -O1 level and
+      --  do not do them if control flow optimizations are suppressed.
+
+      if Optimization_Level > 0
+        and then not Opt.Suppress_Control_Flow_Optimizations
       then
+         if Nkind (N) = N_If_Statement
+           and then No (Elsif_Parts (N))
+           and then Present (Else_Statements (N))
+           and then List_Length (Then_Statements (N)) = 1
+           and then List_Length (Else_Statements (N)) = 1
+         then
+            declare
+               Then_Stm : constant Node_Id := First (Then_Statements (N));
+               Else_Stm : constant Node_Id := First (Else_Statements (N));
+
+            begin
+               if Nkind (Then_Stm) = N_Simple_Return_Statement
+                    and then
+                  Nkind (Else_Stm) = N_Simple_Return_Statement
+               then
+                  declare
+                     Then_Expr : constant Node_Id := Expression (Then_Stm);
+                     Else_Expr : constant Node_Id := Expression (Else_Stm);
+
+                  begin
+                     if Nkind (Then_Expr) = N_Identifier
+                          and then
+                        Nkind (Else_Expr) = N_Identifier
+                     then
+                        if Entity (Then_Expr) = Standard_True
+                          and then Entity (Else_Expr) = Standard_False
+                        then
+                           Rewrite (N,
+                             Make_Simple_Return_Statement (Loc,
+                               Expression => Relocate_Node (Condition (N))));
+                           Analyze (N);
+                           return;
+
+                        elsif Entity (Then_Expr) = Standard_False
+                          and then Entity (Else_Expr) = Standard_True
+                        then
+                           Rewrite (N,
+                             Make_Simple_Return_Statement (Loc,
+                               Expression =>
+                                 Make_Op_Not (Loc,
+                                   Right_Opnd =>
+                                     Relocate_Node (Condition (N)))));
+                           Analyze (N);
+                           return;
+                        end if;
+                     end if;
+                  end;
+               end if;
+            end;
+         end if;
+      end if;
+   end Expand_N_If_Statement;
+
+   --------------------------
+   -- Expand_Iterator_Loop --
+   --------------------------
+
+   procedure Expand_Iterator_Loop (N : Node_Id) is
+      Isc    : constant Node_Id    := Iteration_Scheme (N);
+      I_Spec : constant Node_Id    := Iterator_Specification (Isc);
+      Id     : constant Entity_Id  := Defining_Identifier (I_Spec);
+      Loc    : constant Source_Ptr := Sloc (N);
+
+      Container     : constant Node_Id   := Name (I_Spec);
+      Container_Typ : constant Entity_Id := Etype (Container);
+      Cursor        : Entity_Id;
+      New_Loop      : Node_Id;
+      Stats         : List_Id := Statements (N);
+
+   begin
+      --  Processing for arrays
+
+      if Is_Array_Type (Container_Typ) then
+
+         --  for Element of Array loop
+         --
+         --  This case requires an internally generated cursor to iterate over
+         --  the array.
+
+         if Of_Present (I_Spec) then
+            Cursor := Make_Temporary (Loc, 'C');
+
+            --  Generate:
+            --    Element : Component_Type renames Container (Cursor);
+
+            Prepend_To (Stats,
+              Make_Object_Renaming_Declaration (Loc,
+                Defining_Identifier => Id,
+                Subtype_Mark =>
+                  New_Reference_To (Component_Type (Container_Typ), Loc),
+                Name =>
+                  Make_Indexed_Component (Loc,
+                    Prefix => Relocate_Node (Container),
+                    Expressions => New_List (
+                      New_Reference_To (Cursor, Loc)))));
+
+         --  for Index in Array loop
+         --
+         --  This case utilizes the already given cursor name
+
+         else
+            Cursor := Id;
+         end if;
+
+         --  Generate:
+         --    for Cursor in [reverse] Container'Range loop
+         --       Element : Component_Type renames Container (Cursor);
+         --       --  for the "of" form
+         --
+         --       <original loop statements>
+         --    end loop;
+
+         New_Loop :=
+           Make_Loop_Statement (Loc,
+             Iteration_Scheme =>
+               Make_Iteration_Scheme (Loc,
+                 Loop_Parameter_Specification =>
+                   Make_Loop_Parameter_Specification (Loc,
+                     Defining_Identifier => Cursor,
+                       Discrete_Subtype_Definition =>
+                         Make_Attribute_Reference (Loc,
+                           Prefix => Relocate_Node (Container),
+                           Attribute_Name => Name_Range),
+                      Reverse_Present => Reverse_Present (I_Spec))),
+              Statements => Stats,
+              End_Label  => Empty);
+
+      --  Processing for containers
+
+      else
+         --  The for loop is expanded into a while loop which uses a container
+         --  specific cursor to examine each element.
+
+         --    Cursor : Pack.Cursor := Container.First;
+         --    while Cursor /= Pack.No_Element loop
+         --       declare
+         --       --  the block is added when Element_Type is controlled
+
+         --          Obj : Pack.Element_Type := Element (Cursor);
+         --          --  for the "of" loop form
+         --       begin
+         --          <original loop statements>
+         --       end;
+
+         --       Pack.Next (Cursor);
+         --    end loop;
+
+         --  If "reverse" is present, then the initialization of the cursor
+         --  uses Last and the step becomes Prev. Pack is the name of the
+         --  package which instantiates the container.
+
          declare
-            Then_Stm : constant Node_Id := First (Then_Statements (N));
-            Else_Stm : constant Node_Id := First (Else_Statements (N));
+            Element_Type : constant Entity_Id := Etype (Id);
+            Pack         : constant Entity_Id :=
+                             Scope (Base_Type (Container_Typ));
+            Decl         : Node_Id;
+            Cntr         : Node_Id;
+            Name_Init    : Name_Id;
+            Name_Step    : Name_Id;
 
          begin
-            if Nkind (Then_Stm) = N_Simple_Return_Statement
-                 and then
-               Nkind (Else_Stm) = N_Simple_Return_Statement
-            then
+            --  The "of" case uses an internally generated cursor
+
+            if Of_Present (I_Spec) then
+               Cursor := Make_Temporary (Loc, 'C');
+            else
+               Cursor := Id;
+            end if;
+
+            --  The code below only handles containers where Element is not a
+            --  primitive operation of the container. This excludes for now the
+            --  Hi-Lite formal containers.
+
+            if Of_Present (I_Spec) then
+
+               --  Generate:
+               --    Id : Element_Type := Pack.Element (Cursor);
+
+               Decl :=
+                 Make_Object_Renaming_Declaration (Loc,
+                   Defining_Identifier => Id,
+                   Subtype_Mark =>
+                     New_Reference_To (Element_Type, Loc),
+                   Name =>
+                     Make_Indexed_Component (Loc,
+                       Prefix =>
+                         Make_Selected_Component (Loc,
+                           Prefix =>
+                             New_Reference_To (Pack, Loc),
+                           Selector_Name =>
+                             Make_Identifier (Loc, Chars => Name_Element)),
+                       Expressions => New_List (
+                         New_Reference_To (Cursor, Loc))));
+
+               --  When the container holds controlled objects, wrap the loop
+               --  statements and element renaming declaration with a block.
+               --  This ensures that the transient result of Element (Cursor)
+               --  is cleaned up after each iteration of the loop.
+
+               if Needs_Finalization (Element_Type) then
+
+                  --  Generate:
+                  --    declare
+                  --       Id : Element_Type := Pack.Element (Cursor);
+                  --    begin
+                  --       <original loop statments>
+                  --    end;
+
+                  Stats := New_List (
+                    Make_Block_Statement (Loc,
+                      Declarations => New_List (Decl),
+                      Handled_Statement_Sequence =>
+                        Make_Handled_Sequence_Of_Statements (Loc,
+                          Statements => Stats)));
+               else
+                  Prepend_To (Stats, Decl);
+               end if;
+            end if;
+
+            --  Determine the advancement and initialization steps for the
+            --  cursor.
+
+            --  Must verify that the container has a reverse iterator ???
+
+            if Reverse_Present (I_Spec) then
+               Name_Init := Name_Last;
+               Name_Step := Name_Previous;
+            else
+               Name_Init := Name_First;
+               Name_Step := Name_Next;
+            end if;
+
+            --  For both iterator forms, add a call to the step operation to
+            --  advance the cursor. Generate:
+            --
+            --    Pack.[Next | Prev] (Cursor);
+
+            Append_To (Stats,
+              Make_Procedure_Call_Statement (Loc,
+                Name =>
+                  Make_Selected_Component (Loc,
+                    Prefix =>
+                      New_Reference_To (Pack, Loc),
+                    Selector_Name =>
+                      Make_Identifier (Loc, Name_Step)),
+
+                Parameter_Associations => New_List (
+                  New_Reference_To (Cursor, Loc))));
+
+            --  Generate:
+            --    while Cursor /= Pack.No_Element loop
+            --       <Stats>
+            --    end loop;
+
+            New_Loop :=
+              Make_Loop_Statement (Loc,
+                Iteration_Scheme =>
+                  Make_Iteration_Scheme (Loc,
+                    Condition =>
+                      Make_Op_Ne (Loc,
+                        Left_Opnd =>
+                          New_Reference_To (Cursor, Loc),
+                        Right_Opnd =>
+                          Make_Selected_Component (Loc,
+                            Prefix =>
+                              New_Reference_To (Pack, Loc),
+                            Selector_Name =>
+                              Make_Identifier (Loc, Name_No_Element)))),
+                Statements => Stats,
+                End_Label  => Empty);
+
+            Cntr := Relocate_Node (Container);
+
+            --  When the container is provided by a function call, create an
+            --  explicit renaming of the function result. Generate:
+            --
+            --    Cnn : Container_Typ renames Func_Call (...);
+            --
+            --  The renaming avoids the generation of a transient scope when
+            --  initializing the cursor and the premature finalization of the
+            --  container.
+
+            if Nkind (Cntr) = N_Function_Call then
                declare
-                  Then_Expr : constant Node_Id := Expression (Then_Stm);
-                  Else_Expr : constant Node_Id := Expression (Else_Stm);
+                  Ren_Id : constant Entity_Id := Make_Temporary (Loc, 'C');
 
                begin
-                  if Nkind (Then_Expr) = N_Identifier
-                       and then
-                     Nkind (Else_Expr) = N_Identifier
-                  then
-                     if Entity (Then_Expr) = Standard_True
-                       and then Entity (Else_Expr) = Standard_False
-                     then
-                        Rewrite (N,
-                          Make_Simple_Return_Statement (Loc,
-                            Expression => Relocate_Node (Condition (N))));
-                        Analyze (N);
-                        return;
-
-                     elsif Entity (Then_Expr) = Standard_False
-                       and then Entity (Else_Expr) = Standard_True
-                     then
-                        Rewrite (N,
-                          Make_Simple_Return_Statement (Loc,
-                            Expression =>
-                              Make_Op_Not (Loc,
-                                Right_Opnd => Relocate_Node (Condition (N)))));
-                        Analyze (N);
-                        return;
-                     end if;
-                  end if;
+                  Insert_Action (N,
+                    Make_Object_Renaming_Declaration (Loc,
+                      Defining_Identifier => Ren_Id,
+                      Subtype_Mark =>
+                        New_Reference_To (Container_Typ, Loc),
+                      Name => Cntr));
+
+                  Cntr := New_Reference_To (Ren_Id, Loc);
                end;
             end if;
+
+            --  Create the declaration of the cursor and insert it before the
+            --  source loop. Generate:
+            --
+            --    C : Pack.Cursor_Type := Container.[First | Last];
+
+            Insert_Action (N,
+              Make_Object_Declaration (Loc,
+                Defining_Identifier => Cursor,
+                Object_Definition =>
+                  Make_Selected_Component (Loc,
+                    Prefix =>
+                      New_Reference_To (Pack, Loc),
+                    Selector_Name =>
+                      Make_Identifier (Loc, Name_Cursor)),
+
+                Expression =>
+                  Make_Selected_Component (Loc,
+                    Prefix => Cntr,
+                    Selector_Name =>
+                      Make_Identifier (Loc, Name_Init))));
+
+            --  If the range of iteration is given by a function call that
+            --  returns a container, the finalization actions have been saved
+            --  in the Condition_Actions of the iterator. Insert them now at
+            --  the head of the loop.
+
+            if Present (Condition_Actions (Isc)) then
+               Insert_List_Before (N, Condition_Actions (Isc));
+            end if;
          end;
       end if;
-   end Expand_N_If_Statement;
+
+      Rewrite (N, New_Loop);
+      Analyze (N);
+   end Expand_Iterator_Loop;
 
    -----------------------------
    -- Expand_N_Loop_Statement --
    -----------------------------
 
-   --  1. Deal with while condition for C/Fortran boolean
-   --  2. Deal with loops with a non-standard enumeration type range
-   --  3. Deal with while loops where Condition_Actions is set
-   --  4. Insert polling call if required
+   --  1. Remove null loop entirely
+   --  2. Deal with while condition for C/Fortran boolean
+   --  3. Deal with loops with a non-standard enumeration type range
+   --  4. Deal with while loops where Condition_Actions is set
+   --  5. Deal with loops over predicated subtypes
+   --  6. Deal with loops with iterators over arrays and containers
+   --  7. Insert polling call if required
 
    procedure Expand_N_Loop_Statement (N : Node_Id) is
       Loc  : constant Source_Ptr := Sloc (N);
       Isc  : constant Node_Id    := Iteration_Scheme (N);
 
    begin
+      --  Delete null loop
+
+      if Is_Null_Loop (N) then
+         Rewrite (N, Make_Null_Statement (Loc));
+         return;
+      end if;
+
+      --  Deal with condition for C/Fortran Boolean
+
       if Present (Isc) then
          Adjust_Condition (Condition (Isc));
       end if;
 
+      --  Generate polling call
+
       if Is_Non_Empty_List (Statements (N)) then
          Generate_Poll_Call (First (Statements (N)));
       end if;
@@ -3260,33 +3076,15 @@ package body Exp_Ch5 is
       --  Nothing more to do for plain loop with no iteration scheme
 
       if No (Isc) then
-         return;
-      end if;
+         null;
 
-      --  Note: we do not have to worry about validity chekcing of the for loop
+      --  Case of for loop (Loop_Parameter_Specification present)
+
+      --  Note: we do not have to worry about validity checking of the for loop
       --  range bounds here, since they were frozen with constant declarations
       --  and it is during that process that the validity checking is done.
 
-      --  Handle the case where we have a for loop with the range type being an
-      --  enumeration type with non-standard representation. In this case we
-      --  expand:
-
-      --    for x in [reverse] a .. b loop
-      --       ...
-      --    end loop;
-
-      --  to
-
-      --    for xP in [reverse] integer
-      --                          range etype'Pos (a) .. etype'Pos (b) loop
-      --       declare
-      --          x : constant etype := Pos_To_Rep (xP);
-      --       begin
-      --          ...
-      --       end;
-      --    end loop;
-
-      if Present (Loop_Parameter_Specification (Isc)) then
+      elsif Present (Loop_Parameter_Specification (Isc)) then
          declare
             LPS     : constant Node_Id   := Loop_Parameter_Specification (Isc);
             Loop_Id : constant Entity_Id := Defining_Identifier (LPS);
@@ -3296,95 +3094,129 @@ package body Exp_Ch5 is
             New_Id  : Entity_Id;
 
          begin
-            if not Is_Enumeration_Type (Btype)
-              or else No (Enum_Pos_To_Rep (Btype))
+            --  Deal with loop over predicates
+
+            if Is_Discrete_Type (Ltype)
+              and then Present (Predicate_Function (Ltype))
             then
-               return;
-            end if;
+               Expand_Predicated_Loop (N);
+
+            --  Handle the case where we have a for loop with the range type
+            --  being an enumeration type with non-standard representation.
+            --  In this case we expand:
+
+            --    for x in [reverse] a .. b loop
+            --       ...
+            --    end loop;
+
+            --  to
+
+            --    for xP in [reverse] integer
+            --      range etype'Pos (a) .. etype'Pos (b)
+            --    loop
+            --       declare
+            --          x : constant etype := Pos_To_Rep (xP);
+            --       begin
+            --          ...
+            --       end;
+            --    end loop;
+
+            elsif Is_Enumeration_Type (Btype)
+              and then Present (Enum_Pos_To_Rep (Btype))
+            then
+               New_Id :=
+                 Make_Defining_Identifier (Loc,
+                   Chars => New_External_Name (Chars (Loop_Id), 'P'));
 
-            New_Id :=
-              Make_Defining_Identifier (Loc,
-                Chars => New_External_Name (Chars (Loop_Id), 'P'));
+               --  If the type has a contiguous representation, successive
+               --  values can be generated as offsets from the first literal.
 
-            --  If the type has a contiguous representation, successive values
-            --  can be generated as offsets from the first literal.
+               if Has_Contiguous_Rep (Btype) then
+                  Expr :=
+                     Unchecked_Convert_To (Btype,
+                       Make_Op_Add (Loc,
+                         Left_Opnd =>
+                            Make_Integer_Literal (Loc,
+                              Enumeration_Rep (First_Literal (Btype))),
+                         Right_Opnd => New_Reference_To (New_Id, Loc)));
+               else
+                  --  Use the constructed array Enum_Pos_To_Rep
 
-            if Has_Contiguous_Rep (Btype) then
-               Expr :=
-                  Unchecked_Convert_To (Btype,
-                    Make_Op_Add (Loc,
-                      Left_Opnd =>
-                         Make_Integer_Literal (Loc,
-                           Enumeration_Rep (First_Literal (Btype))),
-                      Right_Opnd => New_Reference_To (New_Id, Loc)));
-            else
-               --  Use the constructed array Enum_Pos_To_Rep
+                  Expr :=
+                    Make_Indexed_Component (Loc,
+                      Prefix      =>
+                        New_Reference_To (Enum_Pos_To_Rep (Btype), Loc),
+                      Expressions =>
+                        New_List (New_Reference_To (New_Id, Loc)));
+               end if;
 
-               Expr :=
-                 Make_Indexed_Component (Loc,
-                   Prefix => New_Reference_To (Enum_Pos_To_Rep (Btype), Loc),
-                   Expressions => New_List (New_Reference_To (New_Id, Loc)));
-            end if;
+               Rewrite (N,
+                 Make_Loop_Statement (Loc,
+                   Identifier => Identifier (N),
 
-            Rewrite (N,
-              Make_Loop_Statement (Loc,
-                Identifier => Identifier (N),
+                   Iteration_Scheme =>
+                     Make_Iteration_Scheme (Loc,
+                       Loop_Parameter_Specification =>
+                         Make_Loop_Parameter_Specification (Loc,
+                           Defining_Identifier => New_Id,
+                           Reverse_Present => Reverse_Present (LPS),
 
-                Iteration_Scheme =>
-                  Make_Iteration_Scheme (Loc,
-                    Loop_Parameter_Specification =>
-                      Make_Loop_Parameter_Specification (Loc,
-                        Defining_Identifier => New_Id,
-                        Reverse_Present => Reverse_Present (LPS),
+                           Discrete_Subtype_Definition =>
+                             Make_Subtype_Indication (Loc,
 
-                        Discrete_Subtype_Definition =>
-                          Make_Subtype_Indication (Loc,
+                               Subtype_Mark =>
+                                 New_Reference_To (Standard_Natural, Loc),
 
-                            Subtype_Mark =>
-                              New_Reference_To (Standard_Natural, Loc),
+                               Constraint =>
+                                 Make_Range_Constraint (Loc,
+                                   Range_Expression =>
+                                     Make_Range (Loc,
 
-                            Constraint =>
-                              Make_Range_Constraint (Loc,
-                                Range_Expression =>
-                                  Make_Range (Loc,
+                                       Low_Bound =>
+                                         Make_Attribute_Reference (Loc,
+                                           Prefix =>
+                                             New_Reference_To (Btype, Loc),
 
-                                    Low_Bound =>
-                                      Make_Attribute_Reference (Loc,
-                                        Prefix =>
-                                          New_Reference_To (Btype, Loc),
+                                           Attribute_Name => Name_Pos,
 
-                                        Attribute_Name => Name_Pos,
+                                           Expressions => New_List (
+                                             Relocate_Node
+                                               (Type_Low_Bound (Ltype)))),
 
-                                        Expressions => New_List (
-                                          Relocate_Node
-                                            (Type_Low_Bound (Ltype)))),
+                                       High_Bound =>
+                                         Make_Attribute_Reference (Loc,
+                                           Prefix =>
+                                             New_Reference_To (Btype, Loc),
 
-                                    High_Bound =>
-                                      Make_Attribute_Reference (Loc,
-                                        Prefix =>
-                                          New_Reference_To (Btype, Loc),
+                                           Attribute_Name => Name_Pos,
 
-                                        Attribute_Name => Name_Pos,
+                                           Expressions => New_List (
+                                             Relocate_Node
+                                               (Type_High_Bound
+                                                  (Ltype))))))))),
 
-                                        Expressions => New_List (
-                                          Relocate_Node
-                                            (Type_High_Bound (Ltype))))))))),
+                   Statements => New_List (
+                     Make_Block_Statement (Loc,
+                       Declarations => New_List (
+                         Make_Object_Declaration (Loc,
+                           Defining_Identifier => Loop_Id,
+                           Constant_Present    => True,
+                           Object_Definition   =>
+                             New_Reference_To (Ltype, Loc),
+                           Expression          => Expr)),
 
-                Statements => New_List (
-                  Make_Block_Statement (Loc,
-                    Declarations => New_List (
-                      Make_Object_Declaration (Loc,
-                        Defining_Identifier => Loop_Id,
-                        Constant_Present    => True,
-                        Object_Definition   => New_Reference_To (Ltype, Loc),
-                        Expression          => Expr)),
+                       Handled_Statement_Sequence =>
+                         Make_Handled_Sequence_Of_Statements (Loc,
+                           Statements => Statements (N)))),
 
-                    Handled_Statement_Sequence =>
-                      Make_Handled_Sequence_Of_Statements (Loc,
-                        Statements => Statements (N)))),
+                   End_Label => End_Label (N)));
+               Analyze (N);
 
-                End_Label => End_Label (N)));
-            Analyze (N);
+            --  Nothing to do with other cases of for loops
+
+            else
+               null;
+            end if;
          end;
 
       --  Second case, if we have a while loop with Condition_Actions set, then
@@ -3404,6 +3236,7 @@ package body Exp_Ch5 is
 
       elsif Present (Isc)
         and then Present (Condition_Actions (Isc))
+        and then Present (Condition (Isc))
       then
          declare
             ES : Node_Id;
@@ -3431,540 +3264,218 @@ package body Exp_Ch5 is
 
             Analyze (N);
          end;
-      end if;
-   end Expand_N_Loop_Statement;
-
-   --------------------------------------
-   -- Expand_N_Simple_Return_Statement --
-   --------------------------------------
-
-   procedure Expand_N_Simple_Return_Statement (N : Node_Id) is
-   begin
-      --  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;
+      --  Here to deal with iterator case
 
-   exception
-      when RE_Not_Available =>
-         return;
-   end Expand_N_Simple_Return_Statement;
-
-   --------------------------------
-   -- 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
-      --  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
-                     (Object_Ref
-                        (Corresponding_Body (Parent (Scope_Id))),
-                     Loc),
-                 Attribute_Name => Name_Unchecked_Access)));
-
-         Insert_Before (N, Call);
-         Analyze (Call);
-      end if;
-   end Expand_Non_Function_Return;
-
-   -----------------------------------
-   -- 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)
-
-   begin
-      --  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. To avoid infinite
-      --  recursion, we do not transform into an extended return if
-      --  Comes_From_Extended_Return_Statement is True.
-
-      --  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
-      --  inherently limited). We would prefer eventually to do this
-      --  translation in all cases except perhaps for the case of Ada 95
-      --  inherently limited, in order to fully exercise the code in
-      --  Expand_N_Extended_Return_Statement, and in order to do
-      --  build-in-place for efficiency when it is 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_Inherently_Limited_Type (Etype (Expression (N)))
-        and then Ada_Version >= Ada_05 --  ???
-        and then not Debug_Flag_Dot_L
-      then
-         declare
-            Return_Object_Entity : constant Entity_Id :=
-                                     Make_Defining_Identifier (Loc,
-                                       New_Internal_Name ('R'));
-
-            Subtype_Ind : constant Node_Id := New_Occurrence_Of (R_Type, Loc);
-
-            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));
-
-         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
+      elsif Present (Isc)
+        and then Present (Iterator_Specification (Isc))
       then
-         Ensure_Valid (Exp);
+         Expand_Iterator_Loop (N);
       end if;
+   end Expand_N_Loop_Statement;
 
-      --  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));
-         Analyze (Exp);
-      end if;
+   ----------------------------
+   -- Expand_Predicated_Loop --
+   ----------------------------
 
-      --  Deal with returning variable length objects and controlled types
+   --  Note: the expander can handle generation of loops over predicated
+   --  subtypes for both the dynamic and static cases. Depending on what
+   --  we decide is allowed in Ada 2012 mode and/or extensions allowed
+   --  mode, the semantic analyzer may disallow one or both forms.
 
-      --  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).
+   procedure Expand_Predicated_Loop (N : Node_Id) is
+      Loc     : constant Source_Ptr := Sloc (N);
+      Isc     : constant Node_Id    := Iteration_Scheme (N);
+      LPS     : constant Node_Id    := Loop_Parameter_Specification (Isc);
+      Loop_Id : constant Entity_Id  := Defining_Identifier (LPS);
+      Ltype   : constant Entity_Id  := Etype (Loop_Id);
+      Stat    : constant List_Id    := Static_Predicate (Ltype);
+      Stmts   : constant List_Id    := Statements (N);
 
-      if Is_Inherently_Limited_Type (Exptyp)
-        or else Is_Limited_Interface (Exptyp)
-      then
-         null;
+   begin
+      --  Case of iteration over non-static predicate, should not be possible
+      --  since this is not allowed by the semantics and should have been
+      --  caught during analysis of the loop statement.
 
-      elsif not Requires_Transient_Scope (R_Type) then
+      if No (Stat) then
+         raise Program_Error;
 
-         --  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.
+      --  If the predicate list is empty, that corresponds to a predicate of
+      --  False, in which case the loop won't run at all, and we rewrite the
+      --  entire loop as a null statement.
 
-         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;
+      elsif Is_Empty_List (Stat) then
+         Rewrite (N, Make_Null_Statement (Loc));
+         Analyze (N);
 
-      --  Here if secondary stack is used
+      --  For expansion over a static predicate we generate the following
+
+      --     declare
+      --        J : Ltype := min-val;
+      --     begin
+      --        loop
+      --           body
+      --           case J is
+      --              when endpoint => J := startpoint;
+      --              when endpoint => J := startpoint;
+      --              ...
+      --              when max-val  => exit;
+      --              when others   => J := Lval'Succ (J);
+      --           end case;
+      --        end loop;
+      --     end;
+
+      --  To make this a little clearer, let's take a specific example:
+
+      --        type Int is range 1 .. 10;
+      --        subtype L is Int with
+      --          predicate => L in 3 | 10 | 5 .. 7;
+      --          ...
+      --        for L in StaticP loop
+      --           Put_Line ("static:" & J'Img);
+      --        end loop;
+
+      --  In this case, the loop is transformed into
+
+      --     begin
+      --        J : L := 3;
+      --        loop
+      --           body
+      --           case J is
+      --              when 3  => J := 5;
+      --              when 7  => J := 10;
+      --              when 10 => exit;
+      --              when others  => J := L'Succ (J);
+      --           end case;
+      --        end loop;
+      --     end;
 
       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_Controlled_Type (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_Controlled_Type (Utyp) then
-            declare
-               Loc        : constant Source_Ptr := Sloc (N);
-               Temp       : constant Entity_Id :=
-                              Make_Defining_Identifier (Loc,
-                                Chars => New_Internal_Name ('R'));
-               Acc_Typ    : constant Entity_Id :=
-                              Make_Defining_Identifier (Loc,
-                                Chars => New_Internal_Name ('A'));
-               Alloc_Node : Node_Id;
-
+         Static_Predicate : declare
+            S    : Node_Id;
+            D    : Node_Id;
+            P    : Node_Id;
+            Alts : List_Id;
+            Cstm : Node_Id;
+
+            function Lo_Val (N : Node_Id) return Node_Id;
+            --  Given static expression or static range, returns an identifier
+            --  whose value is the low bound of the expression value or range.
+
+            function Hi_Val (N : Node_Id) return Node_Id;
+            --  Given static expression or static range, returns an identifier
+            --  whose value is the high bound of the expression value or range.
+
+            ------------
+            -- Hi_Val --
+            ------------
+
+            function Hi_Val (N : Node_Id) return Node_Id is
             begin
-               Set_Ekind (Acc_Typ, E_Access_Type);
-
-               Set_Associated_Storage_Pool (Acc_Typ, RTE (RE_SS_Pool));
-
-               Alloc_Node :=
-                 Make_Allocator (Loc,
-                   Expression =>
-                     Make_Qualified_Expression (Loc,
-                       Subtype_Mark => New_Reference_To (Etype (Exp), Loc),
-                       Expression => Relocate_Node (Exp)));
-
-               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 =>
-                          New_Reference_To (R_Type, Loc))),
-
-                 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)));
-
-               Analyze_And_Resolve (Exp, R_Type);
-            end;
-
-         --  Otherwise use the gigi mechanism to allocate result on the
-         --  secondary stack.
-
-         else
-            Set_Storage_Pool      (N, RTE (RE_SS_Pool));
+               if Is_Static_Expression (N) then
+                  return New_Copy (N);
+               else
+                  pragma Assert (Nkind (N) = N_Range);
+                  return New_Copy (High_Bound (N));
+               end if;
+            end Hi_Val;
 
-            --  If we are generating code for the VM do not use
-            --  SS_Allocate since everything is heap-allocated anyway.
+            ------------
+            -- Lo_Val --
+            ------------
 
-            if VM_Target = No_VM then
-               Set_Procedure_To_Call (N, RTE (RE_SS_Allocate));
-            end if;
-         end if;
-      end if;
+            function Lo_Val (N : Node_Id) return Node_Id is
+            begin
+               if Is_Static_Expression (N) then
+                  return New_Copy (N);
+               else
+                  pragma Assert (Nkind (N) = N_Range);
+                  return New_Copy (Low_Bound (N));
+               end if;
+            end Lo_Val;
 
-      --  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 (Exp) = N_Type_Conversion
-                    or else Nkind (Exp) = 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.
+         --  Start of processing for Static_Predicate
 
-         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 =>
-                          New_Reference_To (First_Tag_Component (Utyp), Loc)),
-                    Right_Opnd =>
-                      Unchecked_Convert_To (RTE (RE_Tag),
-                        New_Reference_To
-                          (Node (First_Elmt
-                                  (Access_Disp_Table (Base_Type (Utyp)))),
-                           Loc))),
-                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.
+         begin
+            --  Convert loop identifier to normal variable and reanalyze it so
+            --  that this conversion works. We have to use the same defining
+            --  identifier, since there may be references in the loop body.
 
-         else
-            declare
-               Result_Id  : constant Entity_Id :=
-                              Make_Defining_Identifier (Loc,
-                                Chars => New_Internal_Name ('R'));
-               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          => Relocate_Node (Exp));
+            Set_Analyzed (Loop_Id, False);
+            Set_Ekind    (Loop_Id, E_Variable);
 
-            begin
-               Set_Assignment_OK (Result_Obj);
-               Insert_Action (Exp, Result_Obj);
+            --  Loop to create branches of case statement
 
-               Rewrite (Exp, Result_Exp);
-               Analyze_And_Resolve (Exp, R_Type);
-            end;
-         end if;
+            Alts := New_List;
+            P := First (Stat);
+            while Present (P) loop
+               if No (Next (P)) then
+                  S := Make_Exit_Statement (Loc);
+               else
+                  S :=
+                    Make_Assignment_Statement (Loc,
+                      Name       => New_Occurrence_Of (Loop_Id, Loc),
+                      Expression => Lo_Val (Next (P)));
+                  Set_Suppress_Assignment_Checks (S);
+               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.
+               Append_To (Alts,
+                 Make_Case_Statement_Alternative (Loc,
+                   Statements       => New_List (S),
+                   Discrete_Choices => New_List (Hi_Val (P))));
 
-      --  Note: accessibility check is skipped in the VM case, since there
-      --  does not seem to be any practical way to implement this check.
+               Next (P);
+            end loop;
 
-      elsif Ada_Version >= Ada_05
-        and then VM_Target = No_VM
-        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 (Exp) = N_Type_Conversion
-            or else Nkind (Exp) = 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;
+            --  Add others choice
+
+            S :=
+               Make_Assignment_Statement (Loc,
+                 Name       => New_Occurrence_Of (Loop_Id, Loc),
+                 Expression =>
+                   Make_Attribute_Reference (Loc,
+                     Prefix => New_Occurrence_Of (Ltype, Loc),
+                     Attribute_Name => Name_Succ,
+                     Expressions    => New_List (
+                       New_Occurrence_Of (Loop_Id, Loc))));
+            Set_Suppress_Assignment_Checks (S);
+
+            Append_To (Alts,
+              Make_Case_Statement_Alternative (Loc,
+                Discrete_Choices => New_List (Make_Others_Choice (Loc)),
+                Statements       => New_List (S)));
+
+            --  Construct case statement and append to body statements
+
+            Cstm :=
+              Make_Case_Statement (Loc,
+                Expression   => New_Occurrence_Of (Loop_Id, Loc),
+                Alternatives => Alts);
+            Append_To (Stmts, Cstm);
+
+            --  Rewrite the loop
+
+            D :=
+               Make_Object_Declaration (Loc,
+                 Defining_Identifier => Loop_Id,
+                 Object_Definition   => New_Occurrence_Of (Ltype, Loc),
+                 Expression          => Lo_Val (First (Stat)));
+            Set_Suppress_Assignment_Checks (D);
 
-         begin
-            --  Ada 2005 (AI-251): In class-wide interface objects we displace
-            --  "this" to reference the base of the object --- 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,
-                   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;
+            Rewrite (N,
+              Make_Block_Statement (Loc,
+                Declarations               => New_List (D),
+                Handled_Statement_Sequence =>
+                  Make_Handled_Sequence_Of_Statements (Loc,
+                    Statements => New_List (
+                      Make_Loop_Statement (Loc,
+                        Statements => Stmts,
+                        End_Label  => Empty)))));
 
-            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;
+            Analyze (N);
+         end Static_Predicate;
       end if;
-   end Expand_Simple_Function_Return;
+   end Expand_Predicated_Loop;
 
    ------------------------------
    -- Make_Tag_Ctrl_Assignment --
@@ -3975,12 +3486,16 @@ package body Exp_Ch5 is
       L   : constant Node_Id    := Name (N);
       T   : constant Entity_Id  := Underlying_Type (Etype (L));
 
-      Ctrl_Act : constant Boolean := Controlled_Type (T)
+      Ctrl_Act : constant Boolean := Needs_Finalization (T)
                                        and then not No_Ctrl_Actions (N);
 
+      Component_Assign : constant Boolean :=
+                           Is_Fully_Repped_Tagged_Type (T);
+
       Save_Tag : constant Boolean := Is_Tagged_Type (T)
+                                       and then not Component_Assign
                                        and then not No_Ctrl_Actions (N)
-                                       and then VM_Target = No_VM;
+                                       and then Tagged_Type_Expansion;
       --  Tags are not saved and restored when VM_Target because VM tags are
       --  represented implicitly in objects.
 
@@ -3994,11 +3509,12 @@ package body Exp_Ch5 is
    begin
       Res := New_List;
 
-      --  Finalize the target of the assignment when controlled.
+      --  Finalize the target of the assignment when controlled
+
       --  We have two exceptions here:
 
-      --   1. If we are in an init proc since it is an initialization
-      --      more than an assignment
+      --   1. If we are in an init proc since it is an initialization more
+      --      than an assignment.
 
       --   2. If the left-hand side is a temporary that was not initialized
       --      (or the parent part of a temporary since it is the case in
@@ -4012,26 +3528,28 @@ package body Exp_Ch5 is
       if not Ctrl_Act then
          null;
 
-      --  The left hand side is an uninitialized temporary
+      --  The left hand side is an uninitialized temporary object
 
       elsif Nkind (L) = N_Type_Conversion
         and then Is_Entity_Name (Expression (L))
+        and then Nkind (Parent (Entity (Expression (L)))) =
+                                              N_Object_Declaration
         and then No_Initialization (Parent (Entity (Expression (L))))
       then
          null;
+
       else
          Append_List_To (Res,
-           Make_Final_Call (
-             Ref         => Duplicate_Subexpr_No_Checks (L),
-             Typ         => Etype (L),
-             With_Detach => New_Reference_To (Standard_False, Loc)));
+           Make_Final_Call
+             (Ref         => Duplicate_Subexpr_No_Checks (L),
+              Typ         => Etype (L),
+              With_Detach => New_Reference_To (Standard_False, Loc)));
       end if;
 
       --  Save the Tag in a local variable Tag_Tmp
 
       if Save_Tag then
-         Tag_Tmp :=
-           Make_Defining_Identifier (Loc, New_Internal_Name ('A'));
+         Tag_Tmp := Make_Temporary (Loc, 'A');
 
          Append_To (Res,
            Make_Object_Declaration (Loc,
@@ -4070,8 +3588,7 @@ package body Exp_Ch5 is
                      New_Reference_To (Controller_Component (T), Loc));
             end if;
 
-            Prev_Tmp :=
-              Make_Defining_Identifier (Loc, New_Internal_Name ('B'));
+            Prev_Tmp := Make_Temporary (Loc, 'B');
 
             Append_To (Res,
               Make_Object_Declaration (Loc,
@@ -4086,9 +3603,7 @@ package body Exp_Ch5 is
                       Unchecked_Convert_To (RTE (RE_Finalizable), Ctrl_Ref),
                     Selector_Name => Make_Identifier (Loc, Name_Prev))));
 
-            Next_Tmp :=
-              Make_Defining_Identifier (Loc,
-                Chars => New_Internal_Name ('C'));
+            Next_Tmp := Make_Temporary (Loc, 'C');
 
             Append_To (Res,
               Make_Object_Declaration (Loc,
@@ -4247,9 +3762,7 @@ package body Exp_Ch5 is
                      Make_Integer_Literal (Loc,
                        Intval => System_Storage_Unit));
 
-               Range_Type :=
-                 Make_Defining_Identifier (Loc,
-                   New_Internal_Name ('G'));
+               Range_Type := Make_Temporary (Loc, 'G');
 
                Append_To (Res,
                  Make_Subtype_Declaration (Loc,
@@ -4268,9 +3781,7 @@ package body Exp_Ch5 is
 
                Append_To (Res,
                  Make_Subtype_Declaration (Loc,
-                   Defining_Identifier =>
-                     Make_Defining_Identifier (Loc,
-                       New_Internal_Name ('S')),
+                   Defining_Identifier => Make_Temporary (Loc, 'S'),
                    Subtype_Indication  =>
                      Make_Subtype_Indication (Loc,
                        Subtype_Mark =>
@@ -4282,9 +3793,7 @@ package body Exp_Ch5 is
 
                --  type A is access S
 
-               Opaque_Type :=
-                 Make_Defining_Identifier (Loc,
-                   Chars => New_Internal_Name ('A'));
+               Opaque_Type := Make_Temporary (Loc, 'A');
 
                Append_To (Res,
                  Make_Full_Type_Declaration (Loc,
@@ -4299,8 +3808,7 @@ package body Exp_Ch5 is
 
                First_After_Root := Make_Integer_Literal (Loc, 1);
 
-               --  For the case of a controlled object, skip the
-               --  Root_Controlled part.
+               --  For controlled object, skip Root_Controlled part
 
                if Is_Controlled (T) then
                   First_After_Root :=
@@ -4315,26 +3823,23 @@ package body Exp_Ch5 is
                end if;
 
                --  For the case of a record with controlled components, skip
-               --  the Prev and Next components of the record controller.
-               --  These components constitute a 'hole' in the middle of the
-               --  data to be copied.
+               --  record controller Prev/Next components. These components
+               --  constitute a 'hole' in the middle of the data to be copied.
 
                if Has_Controlled_Component (T) then
                   Prev_Ref :=
                     Make_Selected_Component (Loc,
-                      Prefix =>
+                      Prefix        =>
                         Make_Selected_Component (Loc,
                           Prefix => Duplicate_Subexpr_No_Checks (L),
                           Selector_Name =>
                             New_Reference_To (Controller_Component (T), Loc)),
                       Selector_Name =>  Make_Identifier (Loc, Name_Prev));
 
-                  --  Last index before hole: determined by position of
-                  --  the _Controller.Prev component.
+                  --  Last index before hole: determined by position of the
+                  --  _Controller.Prev component.
 
-                  Last_Before_Hole :=
-                    Make_Defining_Identifier (Loc,
-                      New_Internal_Name ('L'));
+                  Last_Before_Hole := Make_Temporary (Loc, 'L');
 
                   Append_To (Res,
                     Make_Object_Declaration (Loc,
@@ -4342,7 +3847,8 @@ package body Exp_Ch5 is
                       Object_Definition   => New_Occurrence_Of (
                         RTE (RE_Storage_Offset), Loc),
                       Constant_Present    => True,
-                      Expression          => Make_Op_Add (Loc,
+                      Expression          =>
+                        Make_Op_Add (Loc,
                           Make_Attribute_Reference (Loc,
                             Prefix => Prev_Ref,
                             Attribute_Name => Name_Position),
@@ -4367,9 +3873,7 @@ package body Exp_Ch5 is
 
                   --  First index after hole
 
-                  First_After_Hole :=
-                    Make_Defining_Identifier (Loc,
-                      New_Internal_Name ('F'));
+                  First_After_Hole := Make_Temporary (Loc, 'F');
 
                   Append_To (Res,
                     Make_Object_Declaration (Loc,
@@ -4426,8 +3930,26 @@ package body Exp_Ch5 is
             end Controlled_Actions;
          end if;
 
+      --  Not controlled case
+
       else
-         Append_To (Res, Relocate_Node (N));
+         declare
+            Asn : constant Node_Id := Relocate_Node (N);
+
+         begin
+            --  If this is the case of a tagged type with a full rep clause,
+            --  we must expand it into component assignments, so we mark the
+            --  node as unanalyzed, to get it reanalyzed, but flag it has
+            --  requiring component-wise assignment so we don't get infinite
+            --  recursion.
+
+            if Component_Assign then
+               Set_Analyzed (Asn, False);
+               Set_Componentwise_Assignment (Asn, True);
+            end if;
+
+            Append_To (Res, Asn);
+         end;
       end if;
 
       --  Restore the tag
@@ -4451,7 +3973,7 @@ package body Exp_Ch5 is
               Make_Assignment_Statement (Loc,
                 Name =>
                   Make_Selected_Component (Loc,
-                    Prefix =>
+                    Prefix        =>
                       Unchecked_Convert_To (RTE (RE_Finalizable),
                         New_Copy_Tree (Ctrl_Ref)),
                     Selector_Name => Make_Identifier (Loc, Name_Prev)),
@@ -4461,7 +3983,7 @@ package body Exp_Ch5 is
               Make_Assignment_Statement (Loc,
                 Name =>
                   Make_Selected_Component (Loc,
-                    Prefix =>
+                    Prefix        =>
                       Unchecked_Convert_To (RTE (RE_Finalizable),
                         New_Copy_Tree (Ctrl_Ref)),
                     Selector_Name => Make_Identifier (Loc, Name_Next)),