OSDN Git Service

PR target/50678
[pf3gnuchains/gcc-fork.git] / gcc / ada / exp_ch5.adb
index a08cd1f..bdd5d3a 100644 (file)
@@ -6,18 +6,17 @@
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 1992-2004, Free Software Foundation, Inc.         --
+--          Copyright (C) 1992-2010, 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- --
--- ware  Foundation;  either version 2,  or (at your option) any later ver- --
+-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
 -- for  more details.  You should have  received  a copy of the GNU General --
--- Public License  distributed with GNAT;  see file COPYING.  If not, write --
--- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
--- MA 02111-1307, USA.                                                      --
+-- Public License  distributed with GNAT; see file COPYING3.  If not, go to --
+-- http://www.gnu.org/licenses for a complete copy of the license.          --
 --                                                                          --
 -- GNAT was originally developed  by the GNAT team at  New York University. --
 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
 
 with Atree;    use Atree;
 with Checks;   use Checks;
+with Debug;    use Debug;
 with Einfo;    use Einfo;
 with Exp_Aggr; use Exp_Aggr;
+with Exp_Ch6;  use Exp_Ch6;
 with Exp_Ch7;  use Exp_Ch7;
 with Exp_Ch11; use Exp_Ch11;
 with Exp_Dbug; use Exp_Dbug;
 with Exp_Pakd; use Exp_Pakd;
 with Exp_Tss;  use Exp_Tss;
 with Exp_Util; use Exp_Util;
-with Hostparm; use Hostparm;
+with Namet;    use Namet;
 with Nlists;   use Nlists;
 with Nmake;    use Nmake;
 with Opt;      use Opt;
@@ -43,6 +44,8 @@ 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;
 with Sem_Eval; use Sem_Eval;
@@ -51,7 +54,9 @@ with Sem_Util; use Sem_Util;
 with Snames;   use Snames;
 with Stand;    use Stand;
 with Stringt;  use Stringt;
+with Targparm; use Targparm;
 with Tbuild;   use Tbuild;
+with Ttypes;   use Ttypes;
 with Uintp;    use Uintp;
 with Validsw;  use Validsw;
 
@@ -94,22 +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_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_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.
-
-   function Possible_Bit_Aligned_Component (N : Node_Id) return Boolean;
-   --  This function is used in processing the assignment of a record or
-   --  indexed component. The argument N is either the left hand or right
-   --  hand side of an assignment, and this function determines if there
-   --  is a record component reference where the record may be bit aligned
-   --  in a manner that causes trouble for the back end (see description
-   --  of Sem_Util.Component_May_Be_Bit_Aligned for further details).
+   --  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 --
@@ -161,7 +167,7 @@ package body Exp_Ch5 is
       --  This switch is set to True if the array move must be done using
       --  an explicit front end generated loop.
 
-      procedure Apply_Dereference (Arg : in out Node_Id);
+      procedure Apply_Dereference (Arg : Node_Id);
       --  If the argument is an access to an array, and the assignment is
       --  converted into a procedure call, apply explicit dereference.
 
@@ -184,7 +190,7 @@ package body Exp_Ch5 is
       -- Apply_Dereference --
       -----------------------
 
-      procedure Apply_Dereference (Arg : in out Node_Id) is
+      procedure Apply_Dereference (Arg : Node_Id) is
          Typ : constant Entity_Id := Etype (Arg);
       begin
          if Is_Access_Type (Typ) then
@@ -242,38 +248,33 @@ package body Exp_Ch5 is
    --  Start of processing for Expand_Assign_Array
 
    begin
-      --  Deal with length check, note that the length check is done with
+      --  Deal with length check. Note that the length check is done with
       --  respect to the right hand side as given, not a possible underlying
       --  renamed object, since this would generate incorrect extra checks.
 
       Apply_Length_Check (Rhs, L_Type);
 
-      --  We start by assuming that the move can be done in either
-      --  direction, i.e. that the two sides are completely disjoint.
+      --  We start by assuming that the move can be done in either direction,
+      --  i.e. that the two sides are completely disjoint.
 
       Set_Forwards_OK  (N, True);
       Set_Backwards_OK (N, True);
 
-      --  Normally it is only the slice case that can lead to overlap,
-      --  and explicit checks for slices are made below. But there is
-      --  one case where the slice can be implicit and invisible to us
-      --  and that is the case where we have a one dimensional array,
-      --  and either both operands are parameters, or one is a parameter
-      --  and the other is a global variable. In this case the parameter
-      --  could be a slice that overlaps with the other parameter.
-
-      --  Check for the case of slices requiring an explicit loop. Normally
-      --  it is only the explicit slice cases that bother us, but in the
-      --  case of one dimensional arrays, parameters can be slices that
-      --  are passed by reference, so we can have aliasing for assignments
-      --  from one parameter to another, or assignments between parameters
-      --  and nonlocal variables. However, if the array subtype is a
-      --  constrained first subtype in the parameter case, then we don't
-      --  have to worry about overlap, since slice assignments aren't
-      --  possible (other than for a slice denoting the whole array).
-
-      --  Note: overlap is never possible if there is a change of
-      --  representation, so we can exclude this case.
+      --  Normally it is only the slice case that can lead to overlap, and
+      --  explicit checks for slices are made below. But there is one case
+      --  where the slice can be implicit and invisible to us: when we have a
+      --  one dimensional array, and either both operands are parameters, or
+      --  one is a parameter (which can be a slice passed by reference) and the
+      --  other is a non-local variable. In this case the parameter could be a
+      --  slice that overlaps with the other operand.
+
+      --  However, if the array subtype is a constrained first subtype in the
+      --  parameter case, then we don't have to worry about overlap, since
+      --  slice assignments aren't possible (other than for a slice denoting
+      --  the whole array).
+
+      --  Note: No overlap is possible if there is a change of representation,
+      --  so we can exclude this case.
 
       if Ndim = 1
         and then not Crep
@@ -287,27 +288,39 @@ package body Exp_Ch5 is
            (not Is_Constrained (Etype (Lhs))
              or else not Is_First_Subtype (Etype (Lhs)))
 
-         --  In the case of compiling for the Java Virtual Machine,
-         --  slices are always passed by making a copy, so we don't
-         --  have to worry about overlap. We also want to prevent
-         --  generation of "<" comparisons for array addresses,
-         --  since that's a meaningless operation on the JVM.
+         --  In the case of compiling for the Java or .NET Virtual Machine,
+         --  slices are always passed by making a copy, so we don't have to
+         --  worry about overlap. We also want to prevent generation of "<"
+         --  comparisons for array addresses, since that's a meaningless
+         --  operation on the VM.
 
-        and then not Java_VM
+        and then VM_Target = No_VM
       then
          Set_Forwards_OK  (N, False);
          Set_Backwards_OK (N, False);
 
-         --  Note: the bit-packed case is not worrisome here, since if
-         --  we have a slice passed as a parameter, it is always aligned
-         --  on a byte boundary, and if there are no explicit slices, the
-         --  assignment can be performed directly.
+         --  Note: the bit-packed case is not worrisome here, since if we have
+         --  a slice passed as a parameter, it is always aligned on a byte
+         --  boundary, and if there are no explicit slices, the assignment
+         --  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 situation).
+      --  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
+      --  situation).
 
       if Crep then
          Act_Rhs := Get_Referenced_Object (Rhs);
@@ -322,30 +335,46 @@ package body Exp_Ch5 is
       then
          Loop_Required := True;
 
-      --  Arrays with controlled components are expanded into a loop
-      --  to force calls to adjust at the component level.
+      --  Arrays with controlled components are expanded into a loop to force
+      --  calls to Adjust at the component level.
 
       elsif Has_Controlled_Component (L_Type) then
          Loop_Required := True;
 
+         --  If object is atomic, we cannot tolerate a loop
+
+      elsif Is_Atomic_Object (Act_Lhs)
+              or else
+            Is_Atomic_Object (Act_Rhs)
+      then
+         return;
+
+      --  Loop is required if we have atomic components since we have to
+      --  be sure to do any accesses on an element by element basis.
+
+      elsif Has_Atomic_Components (L_Type)
+        or else Has_Atomic_Components (R_Type)
+        or else Is_Atomic (Component_Type (L_Type))
+        or else Is_Atomic (Component_Type (R_Type))
+      then
+         Loop_Required := True;
+
       --  Case where no slice is involved
 
       elsif not L_Slice and not R_Slice then
 
-         --  The following code deals with the case of unconstrained bit
-         --  packed arrays. The problem is that the template for such
-         --  arrays contains the bounds of the actual source level array,
-
-         --  But the copy of an entire array requires the bounds of the
-         --  underlying array. It would be nice if the back end could take
-         --  care of this, but right now it does not know how, so if we
-         --  have such a type, then we expand out into a loop, which is
-         --  inefficient but works correctly. If we don't do this, we
-         --  get the wrong length computed for the array to be moved.
-         --  The two cases we need to worry about are:
+         --  The following code deals with the case of unconstrained bit packed
+         --  arrays. The problem is that the template for such arrays contains
+         --  the bounds of the actual source level array, but the copy of an
+         --  entire array requires the bounds of the underlying array. It would
+         --  be nice if the back end could take care of this, but right now it
+         --  does not know how, so if we have such a type, then we expand out
+         --  into a loop, which is inefficient but works correctly. If we don't
+         --  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;
@@ -358,16 +387,16 @@ package body Exp_Ch5 is
          --       P2.ALL := P1.ALL;
          --    end C52;
 
-         --  A formal parameter reference with an unconstrained bit
-         --  array type is the other case we need to worry about (here
-         --  we assume the same BITS type declared above:
+         --  A formal parameter reference with an unconstrained bit array type
+         --  is the other case we need to worry about (here we assume the same
+         --  BITS type declared above):
 
-         --    procedure Write_All (File : out BITS; Contents : in  BITS);
+         --    procedure Write_All (File : out BITS; Contents : BITS);
          --    begin
          --       File.Storage := Contents;
          --    end Write_All;
 
-         --  We expand to a loop in either of these two cases.
+         --  We expand to a loop in either of these two cases
 
          --  Question for future thought. Another potentially more efficient
          --  approach would be to create the actual subtype, and then do an
@@ -376,8 +405,8 @@ package body Exp_Ch5 is
          Check_Unconstrained_Bit_Packed_Array : declare
 
             function Is_UBPA_Reference (Opnd : Node_Id) return Boolean;
-            --  Function to perform required test for the first case,
-            --  above (dereference of an unconstrained bit packed array)
+            --  Function to perform required test for the first case, above
+            --  (dereference of an unconstrained bit packed array).
 
             -----------------------
             -- Is_UBPA_Reference --
@@ -422,10 +451,9 @@ package body Exp_Ch5 is
             then
                Loop_Required := True;
 
-            --  Here if we do not have the case of a reference to a bit
-            --  packed unconstrained array case. In this case gigi can
-            --  most certainly handle the assignment if a forwards move
-            --  is allowed.
+            --  Here if we do not have the case of a reference to a bit packed
+            --  unconstrained array case. In this case gigi can most certainly
+            --  handle the assignment if a forwards move is allowed.
 
             --  (could it handle the backwards case also???)
 
@@ -434,17 +462,17 @@ package body Exp_Ch5 is
             end if;
          end Check_Unconstrained_Bit_Packed_Array;
 
-      --  Gigi can always handle the assignment if the right side is a string
-      --  literal (note that overlap is definitely impossible in this case).
-      --  If the type is packed, a string literal is always converted into a
-      --  aggregate, except in the case of a null slice, for which no aggregate
-      --  can be written. In that case, rewrite the assignment as a null
-      --  statement, a length check has already been emitted to verify that
-      --  the range of the left-hand side is empty.
+      --  The back end can always handle the assignment if the right side is a
+      --  string literal (note that overlap is definitely impossible in this
+      --  case). If the type is packed, a string literal is always converted
+      --  into an aggregate, except in the case of a null slice, for which no
+      --  aggregate can be written. In that case, rewrite the assignment as a
+      --  null statement, a length check has already been emitted to verify
+      --  that the range of the left-hand side is empty.
 
-      --  Note that this code is not executed if we had an assignment of
-      --  a string literal to a non-bit aligned component of a record, a
-      --  case which cannot be handled by the backend
+      --  Note that this code is not executed if we have an assignment of a
+      --  string literal to a non-bit aligned component of a record, a case
+      --  which cannot be handled by the backend.
 
       elsif Nkind (Rhs) = N_String_Literal then
          if String_Length (Strval (Rhs)) = 0
@@ -456,10 +484,10 @@ package body Exp_Ch5 is
 
          return;
 
-      --  If either operand is bit packed, then we need a loop, since we
-      --  can't be sure that the slice is byte aligned. Similarly, if either
-      --  operand is a possibly unaligned slice, then we need a loop (since
-      --  gigi cannot handle unaligned slices).
+      --  If either operand is bit packed, then we need a loop, since we can't
+      --  be sure that the slice is byte aligned. Similarly, if either operand
+      --  is a possibly unaligned slice, then we need a loop (since the back
+      --  end cannot handle unaligned slices).
 
       elsif Is_Bit_Packed_Array (L_Type)
         or else Is_Bit_Packed_Array (R_Type)
@@ -468,9 +496,9 @@ package body Exp_Ch5 is
       then
          Loop_Required := True;
 
-      --  If we are not bit-packed, and we have only one slice, then no
-      --  overlap is possible except in the parameter case, so we can let
-      --  gigi handle things.
+      --  If we are not bit-packed, and we have only one slice, then no overlap
+      --  is possible except in the parameter case, so we can let the back end
+      --  handle things.
 
       elsif not (L_Slice and R_Slice) then
          if Forwards_OK (N) then
@@ -478,13 +506,12 @@ package body Exp_Ch5 is
          end if;
       end if;
 
-      --  If the right-hand side is a string literal, introduce a temporary
-      --  for it, for use in the generated loop that will follow.
+      --  If the right-hand side is a string literal, introduce a temporary for
+      --  it, for use in the generated loop that will follow.
 
       if Nkind (Rhs) = N_String_Literal then
          declare
-            Temp : constant Entity_Id :=
-                     Make_Defining_Identifier (Loc, Name_T);
+            Temp : constant Entity_Id := Make_Temporary (Loc, 'T', Rhs);
             Decl : Node_Id;
 
          begin
@@ -511,11 +538,11 @@ package body Exp_Ch5 is
       --    Backwards_OK:  Set to False if we already know that a backwards
       --                   move is not safe, else set to True
 
-      --  Our task at this stage is to complete the overlap analysis, which
-      --  can result in possibly setting Forwards_OK or Backwards_OK to
-      --  False, and then generating the final code, either by deciding
-      --  that it is OK after all to let Gigi handle it, or by generating
-      --  appropriate code in the front end.
+      --  Our task at this stage is to complete the overlap analysis, which can
+      --  result in possibly setting Forwards_OK or Backwards_OK to False, and
+      --  then generating the final code, either by deciding that it is OK
+      --  after all to let Gigi handle it, or by generating appropriate code
+      --  in the front end.
 
       declare
          L_Index_Typ : constant Node_Id := Etype (First_Index (L_Type));
@@ -538,19 +565,27 @@ package body Exp_Ch5 is
       begin
          --  Get the expressions for the arrays. If we are dealing with a
          --  private type, then convert to the underlying type. We can do
-         --  direct assignments to an array that is a private type, but
-         --  we cannot assign to elements of the array without this extra
+         --  direct assignments to an array that is a private type, but we
+         --  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;
 
@@ -560,25 +595,29 @@ 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;
 
-         --  If both sides are slices, we must figure out whether
-         --  it is safe to do the move in one direction or the other
-         --  It is always safe if there is a change of representation
-         --  since obviously two arrays with different representations
-         --  cannot possibly overlap.
+         --  If both sides are slices, we must figure out whether it is safe
+         --  to do the move in one direction or the other. It is always safe
+         --  if there is a change of representation since obviously two arrays
+         --  with different representations cannot possibly overlap.
 
          if (not Crep) and L_Slice and R_Slice then
             Act_L_Array := Get_Referenced_Object (Prefix (Act_Lhs));
             Act_R_Array := Get_Referenced_Object (Prefix (Act_Rhs));
 
-            --  If both left and right hand arrays are entity names, and
-            --  refer to different entities, then we know that the move
-            --  is safe (the two storage areas are completely disjoint).
+            --  If both left and right hand arrays are entity names, and refer
+            --  to different entities, then we know that the move is safe (the
+            --  two storage areas are completely disjoint).
 
             if Is_Entity_Name (Act_L_Array)
               and then Is_Entity_Name (Act_R_Array)
@@ -586,22 +625,25 @@ package body Exp_Ch5 is
             then
                null;
 
-            --  Otherwise, we assume the worst, which is that the two
-            --  arrays are the same array. There is no need to check if
-            --  we know that is the case, because if we don't know it,
-            --  we still have to assume it!
+            --  Otherwise, we assume the worst, which is that the two arrays
+            --  are the same array. There is no need to check if we know that
+            --  is the case, because if we don't know it, we still have to
+            --  assume it!
 
-            --  Generally if the same array is involved, then we have
-            --  an overlapping case. We will have to really assume the
-            --  worst (i.e. set neither of the OK flags) unless we can
-            --  determine the lower or upper bounds at compile time and
-            --  compare them.
+            --  Generally if the same array is involved, then we have an
+            --  overlapping case. We will have to really assume the worst (i.e.
+            --  set neither of the OK flags) unless we can determine the lower
+            --  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
@@ -613,23 +655,34 @@ 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
-            if Forwards_OK (N) then
+
+            --  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;
 
-            else
-               null;
-               --  Here is where a memmove would be appropriate ???
+            --  Assume other back ends can handle it if Forwards_OK is set
+
+            elsif Forwards_OK (N) then
+               return;
+
+            --  If Forwards_OK is not set, the back end will need something
+            --  like memmove to handle the move. For now, this processing is
+            --  activated using the .s debug flag (-gnatd.s).
+
+            elsif Debug_Flag_Dot_S then
+               return;
             end if;
          end if;
 
-         --  At this stage we have to generate an explicit loop, and
-         --  we have the following cases:
+         --  At this stage we have to generate an explicit loop, and we have
+         --  the following cases:
 
          --  Forwards_OK = True
 
@@ -639,9 +692,9 @@ package body Exp_Ch5 is
          --       Rnn := right_index'Succ (Rnn);
          --    end loop;
 
-         --    Note: the above code MUST be analyzed with checks off,
-         --    because otherwise the Succ could overflow. But in any
-         --    case this is more efficient!
+         --    Note: the above code MUST be analyzed with checks off, because
+         --    otherwise the Succ could overflow. But in any case this is more
+         --    efficient!
 
          --  Forwards_OK = False, Backwards_OK = True
 
@@ -651,9 +704,9 @@ package body Exp_Ch5 is
          --       Rnn := right_index'Pred (Rnn);
          --    end loop;
 
-         --    Note: the above code MUST be analyzed with checks off,
-         --    because otherwise the Pred could overflow. But in any
-         --    case this is more efficient!
+         --    Note: the above code MUST be analyzed with checks off, because
+         --    otherwise the Pred could overflow. But in any case this is more
+         --    efficient!
 
          --  Forwards_OK = Backwards_OK = False
 
@@ -678,17 +731,42 @@ package body Exp_Ch5 is
          --         <code for Backwards_OK = True above>
          --      end if;
 
+         --  In order to detect possible aliasing, we examine the renamed
+         --  expression when the source or target is a renaming. However,
+         --  the renaming may be intended to capture an address that may be
+         --  affected by subsequent code, and therefore we must recover
+         --  the actual entity for the expansion that follows, not the
+         --  object it renames. In particular, if source or target designate
+         --  a portion of a dynamically allocated object, the pointer to it
+         --  may be reassigned but the renaming preserves the proper location.
+
+         if Is_Entity_Name (Rhs)
+           and then
+             Nkind (Parent (Entity (Rhs))) = N_Object_Renaming_Declaration
+           and then Nkind (Act_Rhs) = N_Slice
+         then
+            Rarray := Rhs;
+         end if;
+
+         if Is_Entity_Name (Lhs)
+           and then
+             Nkind (Parent (Entity (Lhs))) = N_Object_Renaming_Declaration
+           and then Nkind (Act_Lhs) = N_Slice
+         then
+            Larray := Lhs;
+         end if;
+
          --  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
@@ -702,13 +780,9 @@ package body Exp_Ch5 is
                     Duplicate_Subexpr (Right_Lo, Name_Req => True),
                     Duplicate_Subexpr (Right_Hi, Name_Req => True));
 
-                  if Forwards_OK (N) then
-                     Append_To (Actuals,
-                       New_Occurrence_Of (Standard_False, Loc));
-                  else
-                     Append_To (Actuals,
-                       New_Occurrence_Of (Standard_True, Loc));
-                  end if;
+                  Append_To (Actuals,
+                    New_Occurrence_Of (
+                      Boolean_Literals (not Forwards_OK (N)), Loc));
 
                   Rewrite (N,
                     Make_Procedure_Call_Statement (Loc,
@@ -752,21 +826,20 @@ package body Exp_Ch5 is
          --  Case of both are false with implicit conditionals allowed
 
          else
-            --  Before we generate this code, we must ensure that the
-            --  left and right side array types are defined. They may
-            --  be itypes, and we cannot let them be defined inside the
-            --  if, since the first use in the then may not be executed.
+            --  Before we generate this code, we must ensure that the left and
+            --  right side array types are defined. They may be itypes, and we
+            --  cannot let them be defined inside the if, since the first use
+            --  in the then may not be executed.
 
             Ensure_Defined (L_Type, N);
             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 parameters, conversions etc. But we can't do that
-            --  in the bit packed case or the Java VM case, because addresses
-            --  don't work there.
+            --  We normally compare addresses to find out which way round to
+            --  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.
 
-            if not Is_Bit_Packed_Array (L_Type) and then not Java_VM then
+            if not Is_Bit_Packed_Array (L_Type) and then VM_Target = No_VM then
                Condition :=
                  Make_Op_Le (Loc,
                    Left_Opnd =>
@@ -799,18 +872,29 @@ package body Exp_Ch5 is
                                  Attribute_Name => Name_First))),
                          Attribute_Name => Name_Address)));
 
-            --  For the bit packed and Java VM cases we use the bounds.
-            --  That's OK, because we don't have to worry about parameters,
-            --  since they cannot cause overlap. Perhaps we should worry
-            --  about weird slice conversions ???
+            --  For the bit packed and VM cases we use the bounds. That's OK,
+            --  because we don't have to worry about parameters, since they
+            --  cannot cause overlap. Perhaps we should worry about weird slice
+            --  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);
 
@@ -820,18 +904,18 @@ 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 explicit bounds of right- and left-hand side.
+               --  explicit bounds of right and left hand sides.
 
                declare
-                  Proc     : constant Node_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
@@ -844,7 +928,10 @@ package body Exp_Ch5 is
                     Duplicate_Subexpr (Left_Hi,  Name_Req => True),
                     Duplicate_Subexpr (Right_Lo, Name_Req => True),
                     Duplicate_Subexpr (Right_Hi, Name_Req => True));
-                  Append_To (Actuals, Condition);
+
+                  Append_To (Actuals,
+                     Make_Op_Not (Loc,
+                       Right_Opnd => Condition));
 
                   Rewrite (N,
                     Make_Procedure_Call_Statement (Loc,
@@ -881,8 +968,8 @@ package body Exp_Ch5 is
    -- Expand_Assign_Array_Loop --
    ------------------------------
 
-   --  The following is an example of the loop generated for the case of
-   --  two-dimensional array:
+   --  The following is an example of the loop generated for the case of a
+   --  two-dimensional array:
 
    --    declare
    --       R2b : Tm1X1 := 1;
@@ -900,9 +987,9 @@ package body Exp_Ch5 is
    --       end loop;
    --    end;
 
-   --  Here Rev is False, and Tm1Xn are the subscript types for the right
-   --  hand side. The declarations of R2b and R4b are inserted before the
-   --  original assignment statement.
+   --  Here Rev is False, and Tm1Xn are the subscript types for the right hand
+   --  side. The declarations of R2b and R4b are inserted before the original
+   --  assignment statement.
 
    function Expand_Assign_Array_Loop
      (N      : Node_Id;
@@ -928,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;
@@ -948,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);
@@ -980,13 +1118,20 @@ package body Exp_Ch5 is
            Make_Assignment_Statement (Loc,
              Name =>
                Make_Indexed_Component (Loc,
-                 Prefix => Duplicate_Subexpr (Larray, Name_Req => True),
+                 Prefix      => Duplicate_Subexpr (Larray, Name_Req => True),
                  Expressions => ExprL),
              Expression =>
                Make_Indexed_Component (Loc,
-                 Prefix => Duplicate_Subexpr (Rarray, Name_Req => True),
+                 Prefix      => Duplicate_Subexpr (Rarray, Name_Req => True),
                  Expressions => ExprR));
 
+         --  We set assignment OK, since there are some cases, e.g. in object
+         --  declarations, where we are actually assigning into a constant.
+         --  If there really is an illegality, it was caught long before now,
+         --  and was flagged when the original assignment was analyzed.
+
+         Set_Assignment_OK (Name (Assign));
+
          --  Propagate the No_Ctrl_Actions flag to individual assignments
 
          Set_No_Ctrl_Actions (Assign, No_Ctrl_Actions (N));
@@ -1022,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;
@@ -1043,27 +1177,24 @@ 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 from the type conversion, and proceed with component-wise
-      --  assignment, since the two types are not the same as far as the
-      --  back end is concerned.
+      --  If change of representation, then extract the real right hand side
+      --  from the type conversion, and proceed with component-wise assignment,
+      --  since the two types are not the same as far as the back end is
+      --  concerned.
 
       if Change_Of_Representation (N) then
          Rhs := Expression (Rhs);
 
-      --  If this may be a case of a large bit aligned component, then
-      --  proceed with component-wise assignment, to avoid possible
-      --  clobbering of other components sharing bits in the first or
-      --  last byte of the component to be assigned.
+      --  If this may be a case of a large bit aligned component, then proceed
+      --  with component-wise assignment, to avoid possible clobbering of other
+      --  components sharing bits in the first or last byte of the component to
+      --  be assigned.
 
       elsif Possible_Bit_Aligned_Component (Lhs)
               or
@@ -1071,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.
 
@@ -1083,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;
@@ -1092,17 +1230,25 @@ package body Exp_Ch5 is
            (Typ  : Entity_Id;
             Comp : Entity_Id) return Entity_Id;
          --  Find the component with the given name in the underlying record
-         --  declaration for Typ. We need to use the actual entity because
-         --  the type may be private and resolution by identifier alone would
-         --  fail.
+         --  declaration for Typ. We need to use the actual entity because the
+         --  type may be private and resolution by identifier alone would fail.
 
-         function Make_Component_List_Assign (CL : Node_Id) return List_Id;
+         function Make_Component_List_Assign
+           (CL  : Node_Id;
+            U_U : Boolean := False) return List_Id;
          --  Returns a sequence of statements to assign the components that
-         --  are referenced in the given component list.
-
-         function Make_Field_Assign (C : Entity_Id) return Node_Id;
-         --  Given C, the entity for a discriminant or component, build
-         --  an assignment for the corresponding field values.
+         --  are referenced in the given component list. The flag U_U is
+         --  used to force the usage of the inferred value of the variant
+         --  part expression as the switch for the generated case statement.
+
+         function Make_Field_Assign
+           (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
+         --  signals the presence of an Unchecked_Union and forces the usage
+         --  of the inferred discriminant value of C as the right hand side
+         --  of the assignment.
 
          function Make_Field_Assigns (CI : List_Id) return List_Id;
          --  Given CI, a component items list, construct series of statements
@@ -1121,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;
 
@@ -1136,25 +1282,27 @@ package body Exp_Ch5 is
          -- Make_Component_List_Assign --
          --------------------------------
 
-         function Make_Component_List_Assign (CL : Node_Id) return List_Id is
+         function Make_Component_List_Assign
+           (CL  : Node_Id;
+            U_U : Boolean := False) return List_Id
+         is
             CI : constant List_Id := Component_Items (CL);
             VP : constant Node_Id := Variant_Part (CL);
 
-            Result : List_Id;
             Alts   : List_Id;
-            V      : Node_Id;
             DC     : Node_Id;
             DCH    : List_Id;
+            Expr   : Node_Id;
+            Result : List_Id;
+            V      : Node_Id;
 
          begin
             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
@@ -1170,15 +1318,29 @@ package body Exp_Ch5 is
                   Next_Non_Pragma (V);
                end loop;
 
+               --  If we have an Unchecked_Union, use the value of the inferred
+               --  discriminant of the variant part expression as the switch
+               --  for the case statement. The case statement may later be
+               --  folded.
+
+               if U_U then
+                  Expr :=
+                    New_Copy (Get_Discriminant_Value (
+                      Entity (Name (VP)),
+                      Etype (Rhs),
+                      Discriminant_Constraint (Etype (Rhs))));
+               else
+                  Expr :=
+                    Make_Selected_Component (Loc,
+                      Prefix        => Duplicate_Subexpr (Rhs),
+                      Selector_Name =>
+                        Make_Identifier (Loc, Chars (Name (VP))));
+               end if;
+
                Append_To (Result,
                  Make_Case_Statement (Loc,
-                   Expression =>
-                     Make_Selected_Component (Loc,
-                       Prefix => Duplicate_Subexpr (Rhs),
-                       Selector_Name =>
-                         Make_Identifier (Loc, Chars (Name (VP)))),
+                   Expression => Expr,
                    Alternatives => Alts));
-
             end if;
 
             return Result;
@@ -1188,25 +1350,49 @@ package body Exp_Ch5 is
          -- Make_Field_Assign --
          -----------------------
 
-         function Make_Field_Assign (C : Entity_Id) return Node_Id is
-            A : Node_Id;
+         function Make_Field_Assign
+           (C   : Entity_Id;
+            U_U : Boolean := False) return Node_Id
+         is
+            A    : Node_Id;
+            Expr : Node_Id;
 
          begin
+            --  In the case of an Unchecked_Union, use the discriminant
+            --  constraint value as on the right hand side of the assignment.
+
+            if U_U then
+               Expr :=
+                 New_Copy (Get_Discriminant_Value (C,
+                   Etype (Rhs),
+                   Discriminant_Constraint (Etype (Rhs))));
+            else
+               Expr :=
+                 Make_Selected_Component (Loc,
+                   Prefix        => Duplicate_Subexpr (Rhs),
+                   Selector_Name => New_Occurrence_Of (C, Loc));
+            end if;
+
             A :=
               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 =>
-                  Make_Selected_Component (Loc,
-                    Prefix => Duplicate_Subexpr (Rhs),
-                    Selector_Name => New_Occurrence_Of (C, Loc)));
+                Expression => Expr);
 
             --  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;
 
@@ -1223,7 +1409,14 @@ package body Exp_Ch5 is
             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;
@@ -1251,15 +1444,39 @@ package body Exp_Ch5 is
          if Has_Discriminants (L_Typ) then
             F := First_Discriminant (R_Typ);
             while Present (F) loop
-               Insert_Action (N, Make_Field_Assign (F));
-               Next_Discriminant (F);
+
+               --  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);
+               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)));
@@ -1267,15 +1484,23 @@ 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
-            Insert_Actions
-              (N, Make_Component_List_Assign (Component_List (RDef)));
+            if Is_Unchecked_Union (R_Typ) then
+               Insert_Actions (N,
+                 Make_Component_List_Assign (Component_List (RDef), True));
+            else
+               Insert_Actions
+                 (N, Make_Component_List_Assign (Component_List (RDef)));
+            end if;
 
             Rewrite (N, Make_Null_Statement (Loc));
          end if;
-
       end;
    end Expand_Assign_Record;
 
@@ -1283,9 +1508,8 @@ package body Exp_Ch5 is
    -- Expand_N_Assignment_Statement --
    -----------------------------------
 
-   --  For array types, deal with slice assignments and setting the flags
-   --  to indicate if it can be statically determined which direction the
-   --  move should go in. Also deal with generating range/length checks.
+   --  This procedure implements various cases where an assignment statement
+   --  cannot just be passed on to the back end in untransformed state.
 
    procedure Expand_N_Assignment_Statement (N : Node_Id) is
       Loc  : constant Source_Ptr := Sloc (N);
@@ -1295,14 +1519,127 @@ package body Exp_Ch5 is
       Exp  : Node_Id;
 
    begin
-      --  First deal with generation of range check if required. For now
-      --  we do this only for discrete types.
+      --  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.
 
-      if Do_Range_Check (Rhs)
-        and then Is_Discrete_Type (Typ)
+      --  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
-         Set_Do_Range_Check (Rhs, False);
-         Generate_Range_Check (Rhs, Typ, CE_Range_Check_Failed);
+         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
+
+      --   For example:         X'Priority := New_Prio_Expr;
+      --   ...is expanded into  Set_Ceiling (X._Object, New_Prio_Expr);
+
+      --  Note that although X'Priority is notionally an object, it is quite
+      --  deliberately not defined as an aliased object in the RM. This means
+      --  that it works fine to rewrite it as a call, without having to worry
+      --  about complications that would other arise from X'Priority'Access,
+      --  which is illegal, because of the lack of aliasing.
+
+      if Ada_Version >= Ada_2005 then
+         declare
+            Call           : Node_Id;
+            Conctyp        : Entity_Id;
+            Ent            : Entity_Id;
+            Subprg         : Entity_Id;
+            RT_Subprg_Name : Node_Id;
+
+         begin
+            --  Handle chains of renamings
+
+            Ent := Name (N);
+            while Nkind (Ent) in N_Has_Entity
+              and then Present (Entity (Ent))
+              and then Present (Renamed_Object (Entity (Ent)))
+            loop
+               Ent := Renamed_Object (Entity (Ent));
+            end loop;
+
+            --  The attribute Priority applied to protected objects has been
+            --  previously expanded into a call to the Get_Ceiling run-time
+            --  subprogram.
+
+            if Nkind (Ent) = N_Function_Call
+              and then (Entity (Name (Ent)) = RTE (RE_Get_Ceiling)
+                          or else
+                        Entity (Name (Ent)) = RTE (RO_PE_Get_Ceiling))
+            then
+               --  Look for the enclosing concurrent type
+
+               Conctyp := Current_Scope;
+               while not Is_Concurrent_Type (Conctyp) loop
+                  Conctyp := Scope (Conctyp);
+               end loop;
+
+               pragma Assert (Is_Protected_Type (Conctyp));
+
+               --  Generate the first actual of the call
+
+               Subprg := Current_Scope;
+               while not Present (Protected_Body_Subprogram (Subprg)) loop
+                  Subprg := Scope (Subprg);
+               end loop;
+
+               --  Select the appropriate run-time call
+
+               if Number_Entries (Conctyp) = 0 then
+                  RT_Subprg_Name :=
+                    New_Reference_To (RTE (RE_Set_Ceiling), Loc);
+               else
+                  RT_Subprg_Name :=
+                    New_Reference_To (RTE (RO_PE_Set_Ceiling), Loc);
+               end if;
+
+               Call :=
+                 Make_Procedure_Call_Statement (Loc,
+                   Name => RT_Subprg_Name,
+                   Parameter_Associations => New_List (
+                     New_Copy_Tree (First (Parameter_Associations (Ent))),
+                     Relocate_Node (Expression (N))));
+
+               Rewrite (N, Call);
+               Analyze (N);
+               return;
+            end if;
+         end;
+      end if;
+
+      --  Deal with assignment checks unless suppressed
+
+      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
@@ -1316,11 +1653,11 @@ package body Exp_Ch5 is
       --  packed array is as follows:
 
       --    An indexed component whose prefix is a bit packed array is a
-      --     reference to a bit packed array.
+      --    reference to a bit packed array.
 
       --    An indexed component or selected component whose prefix is a
-      --     reference to a bit packed array is itself a reference ot a
-      --     bit packed array.
+      --    reference to a bit packed array is itself a reference ot a
+      --    bit packed array.
 
       --  The required transformation is
 
@@ -1337,48 +1674,44 @@ 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 BPAR_Expr tree before it gets analyzed in the context
-            --  of the pre assignment. Note that we do not analyze the
-            --  post assignment yet (we cannot till we have completed the
-            --  analysis of the pre assignment). As usual, the analysis
-            --  of this post assignment will happen on its own when we
-            --  "run into" it after finishing the current assignment.
+            --  Insert the post assignment first, because we want to copy the
+            --  BPAR_Expr tree before it gets analyzed in the context of the
+            --  pre assignment. Note that we do not analyze the post assignment
+            --  yet (we cannot till we have completed the analysis of the pre
+            --  assignment). As usual, the analysis of this post assignment
+            --  will happen on its own when we "run into" it after finishing
+            --  the current assignment.
 
             Insert_After (N,
               Make_Assignment_Statement (Loc,
                 Name       => New_Copy_Tree (BPAR_Expr),
                 Expression => New_Occurrence_Of (Tnn, Loc)));
 
-            --  At this stage BPAR_Expr is a reference to a bit packed
-            --  array where the reference was not expanded in the original
-            --  tree, since it was on the left side of an assignment. But
-            --  in the pre-assignment statement (the object definition),
-            --  BPAR_Expr will end up on the right hand side, and must be
-            --  reexpanded. To achieve this, we reset the analyzed flag
-            --  of all selected and indexed components down to the actual
-            --  indexed component for the packed array.
+            --  At this stage BPAR_Expr is a reference to a bit packed array
+            --  where the reference was not expanded in the original tree,
+            --  since it was on the left side of an assignment. But in the
+            --  pre-assignment statement (the object definition), BPAR_Expr
+            --  will end up on the right hand side, and must be reexpanded. To
+            --  achieve this, we reset the analyzed flag of all selected and
+            --  indexed components down to the actual indexed component for
+            --  the packed array.
 
             Exp := BPAR_Expr;
             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
@@ -1386,7 +1719,7 @@ package body Exp_Ch5 is
                end if;
             end loop;
 
-            --  Now we can insert and analyze the pre-assignment.
+            --  Now we can insert and analyze the pre-assignment
 
             --  If the right-hand side requires a transient scope, it has
             --  already been placed on the stack. However, the declaration is
@@ -1396,11 +1729,12 @@ package body Exp_Ch5 is
 
             declare
                Uses_Transient_Scope : constant Boolean :=
-                  Scope_Is_Transient and then N = Node_To_Be_Wrapped;
+                                        Scope_Is_Transient
+                                          and then N = Node_To_Be_Wrapped;
 
             begin
                if Uses_Transient_Scope then
-                  New_Scope (Scope (Current_Scope));
+                  Push_Scope (Scope (Current_Scope));
                end if;
 
                Insert_Before_And_Analyze (N,
@@ -1422,16 +1756,16 @@ package body Exp_Ch5 is
             --  We do not need to reanalyze that assignment, and we do not need
             --  to worry about references to the temporary, but we do need to
             --  make sure that the temporary is not marked as a true constant
-            --  since we now have a generate assignment to it!
+            --  since we now have a generated assignment to it!
 
             Set_Is_True_Constant (Tnn, False);
          end;
       end if;
 
-      --  When we have the appropriate type of aggregate in the
-      --  expression (it has been determined during analysis of the
-      --  aggregate by setting the delay flag), let's perform in place
-      --  assignment and thus avoid creating a temporay.
+      --  When we have the appropriate type of aggregate in the expression (it
+      --  has been determined during analysis of the aggregate by setting the
+      --  delay flag), let's perform in place assignment and thus avoid
+      --  creating a temporary.
 
       if Is_Delayed_Aggregate (Rhs) then
          Convert_Aggr_In_Assignment (N);
@@ -1440,8 +1774,8 @@ package body Exp_Ch5 is
          return;
       end if;
 
-      --  Apply discriminant check if required. If Lhs is an access type
-      --  to a designated type with discriminants, we must always check.
+      --  Apply discriminant check if required. If Lhs is an access type to a
+      --  designated type with discriminants, we must always check.
 
       if Has_Discriminants (Etype (Lhs)) then
 
@@ -1456,13 +1790,14 @@ 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
       --  create dereferences but are not semantic aliasings.
 
       elsif Is_Private_Type (Etype (Lhs))
-        and then  Has_Discriminants (Typ)
+        and then Has_Discriminants (Typ)
         and then Nkind (Lhs) = N_Explicit_Dereference
         and then Comes_From_Source (Lhs)
       then
@@ -1486,8 +1821,8 @@ package body Exp_Ch5 is
          Rewrite (Rhs, OK_Convert_To (Base_Type (Typ), Rhs));
          Apply_Discriminant_Check (Rhs, Typ, Lhs);
 
-      --  In the access type case, we need the same discriminant check,
-      --  and also range checks if we have an access to constrained array.
+      --  In the access type case, we need the same discriminant check, and
+      --  also range checks if we have an access to constrained array.
 
       elsif Is_Access_Type (Etype (Lhs))
         and then Is_Constrained (Designated_Type (Etype (Lhs)))
@@ -1515,7 +1850,7 @@ package body Exp_Ch5 is
 
                begin
                   C_Es :=
-                    Range_Check
+                    Get_Range_Checks
                       (Lhs,
                        Target_Typ,
                        Etype (Designated_Type (Etype (Lhs))));
@@ -1541,16 +1876,13 @@ package body Exp_Ch5 is
            (Expression (Rhs), Designated_Type (Etype (Lhs)));
       end if;
 
-      --  If we are assigning an access type and the left side is an
-      --  entity, then make sure that Is_Known_Non_Null properly
-      --  reflects the state of the entity after the assignment
+      --  Ada 2005 (AI-231): Generate the run-time check
 
       if Is_Access_Type (Typ)
-        and then Is_Entity_Name (Lhs)
-        and then Known_Non_Null (Rhs)
-        and then Safe_To_Capture_Value (N, Entity (Lhs))
+        and then Can_Never_Be_Null (Etype (Lhs))
+        and then not Can_Never_Be_Null (Etype (Rhs))
       then
-         Set_Is_Known_Non_Null (Entity (Lhs), Known_Non_Null (Rhs));
+         Apply_Constraint_Check (Rhs, Etype (Lhs));
       end if;
 
       --  Case of assignment to a bit packed array element
@@ -1561,20 +1893,33 @@ package body Exp_Ch5 is
          Expand_Bit_Packed_Element_Set (N);
          return;
 
-      --  Case of tagged type assignment
+      --  Build-in-place function call case. Note that we're not yet doing
+      --  build-in-place for user-written assignment statements (the assignment
+      --  here came from an aggregate.)
+
+      elsif Ada_Version >= Ada_2005
+        and then Is_Build_In_Place_Function_Call (Rhs)
+      then
+         Make_Build_In_Place_Call_In_Assignment (N, Rhs);
+
+      elsif Is_Tagged_Type (Typ) and then Is_Value_Type (Etype (Lhs)) then
+
+         --  Nothing to do for valuetypes
+         --  ??? Set_Scope_Is_Transient (False);
+
+         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);
@@ -1587,24 +1932,28 @@ package body Exp_Ch5 is
 
             if Is_Class_Wide_Type (Typ)
 
-            --  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
-            --  a 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.
-
-            or else (Is_Tagged_Type (Typ)
-              and then Chars (Current_Scope) /= Name_uAssign
-              and then Expand_Ctrl_Actions
-              and then not Discriminant_Checks_Suppressed (Empty))
+               --  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 assignments 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).
+
+               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))
             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.
+               --  Fetch the primitive op _assign and proper type to call it.
+               --  Because of possible conflicts between private and full view,
+               --  fetch the proper type directly from the operation profile.
 
                declare
                   Op    : constant Entity_Id :=
@@ -1613,35 +1962,81 @@ package body Exp_Ch5 is
 
                begin
                   --  If the assignment is dispatching, make sure to use the
-                  --  ??? where is rest of this comment ???
+                  --  proper type.
 
                   if Is_Class_Wide_Type (Typ) then
                      F_Typ := Class_Wide_Type (F_Typ);
                   end if;
 
-                  L := New_List (
-                    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)))));
+                  L := New_List;
+
+                  --  In case of assignment to a class-wide tagged type, before
+                  --  the assignment we generate run-time check to ensure that
+                  --  the tags of source and target match.
+
+                  if Is_Class_Wide_Type (Typ)
+                    and then Is_Tagged_Type (Typ)
+                    and then Is_Tagged_Type (Underlying_Type (Etype (Rhs)))
+                  then
+                     Append_To (L,
+                       Make_Raise_Constraint_Error (Loc,
+                         Condition =>
+                             Make_Op_Ne (Loc,
+                               Left_Opnd =>
+                                 Make_Selected_Component (Loc,
+                                   Prefix        => Duplicate_Subexpr (Lhs),
+                                   Selector_Name =>
+                                     Make_Identifier (Loc, Name_uTag)),
+                               Right_Opnd =>
+                                 Make_Selected_Component (Loc,
+                                   Prefix        => Duplicate_Subexpr (Rhs),
+                                   Selector_Name =>
+                                     Make_Identifier (Loc, Name_uTag))),
+                         Reason => CE_Tag_Check_Failed));
+                  end if;
+
+                  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
                L := Make_Tag_Ctrl_Assignment (N);
 
-               --  We can't afford to have destructive Finalization Actions
-               --  in the Self assignment case, so if the target and the
-               --  source are not obviously different, code is generated to
-               --  avoid the self assignment case
-               --
+               --  We can't afford to have destructive Finalization Actions in
+               --  the Self assignment case, so if the target and the source
+               --  are not obviously different, code is generated to avoid the
+               --  self assignment case:
+
                --    if lhs'address /= rhs'address then
                --       <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,
@@ -1661,9 +2056,9 @@ package body Exp_Ch5 is
                end if;
 
                --  We need to set up an exception handler for implementing
-               --  7.6.1 (18). The remaining adjustments are tackled by the
+               --  7.6.1(18). The remaining adjustments are tackled by the
                --  implementation of adjust for record_controllers (see
-               --  s-finimp.adb)
+               --  s-finimp.adb).
 
                --  This is skipped if we have no finalization
 
@@ -1676,14 +2071,7 @@ package body Exp_Ch5 is
                         Make_Handled_Sequence_Of_Statements (Loc,
                           Statements => L,
                           Exception_Handlers => New_List (
-                            Make_Exception_Handler (Loc,
-                              Exception_Choices =>
-                                New_List (Make_Others_Choice (Loc)),
-                              Statements        => New_List (
-                                Make_Raise_Program_Error (Loc,
-                                  Reason =>
-                                    PE_Finalize_Raised_Exception)
-                              ))))));
+                            Make_Handler_For_Ctrl_Operation (Loc)))));
                end if;
             end if;
 
@@ -1692,17 +2080,17 @@ 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
-            --  for controlled objects as per 9.8(11)
+            --  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
                declare
                   Blk : constant Entity_Id :=
-                    New_Internal_Entity (
-                      E_Block, Current_Scope, Sloc (N), 'B');
+                          New_Internal_Entity
+                            (E_Block, Current_Scope, Sloc (N), 'B');
 
                begin
                   Set_Scope (Blk, Current_Scope);
@@ -1717,7 +2105,11 @@ package body Exp_Ch5 is
                end;
             end if;
 
-            Analyze (N);
+            --  N has been rewritten to a block statement for which it is
+            --  known by construction that no checks are necessary: analyze
+            --  it with all checks suppressed.
+
+            Analyze (N, Suppress => All_Checks);
             return;
          end Tagged_Case;
 
@@ -1728,9 +2120,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;
@@ -1745,9 +2136,9 @@ package body Exp_Ch5 is
          Expand_Assign_Record (N);
          return;
 
-      --  Scalar types. This is where we perform the processing related
-      --  to the requirements of (RM 13.9.1(9-11)) concerning the handling
-      --  of invalid scalar values.
+      --  Scalar types. This is where we perform the processing related to the
+      --  requirements of (RM 13.9.1(9-11)) concerning the handling of invalid
+      --  scalar values.
 
       elsif Is_Scalar_Type (Typ) then
 
@@ -1755,23 +2146,40 @@ package body Exp_Ch5 is
 
          if Expr_Known_Valid (Rhs) then
 
-            --  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.
+            --  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 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
-         --  reference above. The RM does not require that we check for
-         --  the validity on an assignment, but it does require that the
-         --  assignment of an invalid value not cause erroneous behavior.
+         --  reference above. The RM does not require that we check for the
+         --  validity on an assignment, but it does require that the assignment
+         --  of an invalid value not cause erroneous behavior.
 
          --  The general approach in GNAT is to use the Is_Known_Valid flag
          --  to avoid the need for validity checking on assignments. However
@@ -1782,9 +2190,18 @@ package body Exp_Ch5 is
             --  Validate right side if we are validating copies
 
             if Validity_Checks_On
-               and then Validity_Check_Copies
+              and then Validity_Check_Copies
             then
-               Ensure_Valid (Rhs);
+               --  Skip this if left hand side is an array or record component
+               --  and elementary component validity checks are suppressed.
+
+               if Nkind_In (Lhs, N_Selected_Component, N_Indexed_Component)
+                 and then not Validity_Check_Components
+               then
+                  null;
+               else
+                  Ensure_Valid (Rhs);
+               end if;
 
                --  We can propagate this to the left side where appropriate
 
@@ -1797,32 +2214,30 @@ package body Exp_Ch5 is
 
             --  Otherwise check to see what should be done
 
-            --  If left side is a local variable, then we just set its
-            --  flag to indicate that its value may no longer be valid,
-            --  since we are copying a potentially invalid value.
+            --  If left side is a local variable, then we just set its flag to
+            --  indicate that its value may no longer be valid, since we are
+            --  copying a potentially invalid value.
 
             elsif Is_Local_Variable_Reference (Lhs) then
                Set_Is_Known_Valid (Entity (Lhs), False);
 
-            --  Check for case of a nonlocal variable on the left side
-            --  which is currently known to be valid. In this case, we
-            --  simply ensure that the right side is valid. We only play
-            --  the game of copying validity status for local variables,
-            --  since we are doing this statically, not by tracing the
-            --  full flow graph.
+            --  Check for case of a nonlocal variable on the left side which
+            --  is currently known to be valid. In this case, we simply ensure
+            --  that the right side is valid. We only play the game of copying
+            --  validity status for local variables, since we are doing this
+            --  statically, not by tracing the full flow graph.
 
             elsif Is_Entity_Name (Lhs)
               and then Is_Known_Valid (Entity (Lhs))
             then
-               --  Note that the Ensure_Valid call is ignored if the
-               --  Validity_Checking mode is set to none so we do not
-               --  need to worry about that case here.
+               --  Note: If Validity_Checking mode is set to none, we ignore
+               --  the Ensure_Valid call so don't worry about that case here.
 
                Ensure_Valid (Rhs);
 
-            --  In all other cases, we can safely copy an invalid value
-            --  without worrying about the status of the left side. Since
-            --  it is not a variable reference it will not be considered
+            --  In all other cases, we can safely copy an invalid value without
+            --  worrying about the status of the left side. Since it is not a
+            --  variable reference it will not be considered
             --  as being known to be valid in any case.
 
             else
@@ -1831,17 +2246,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;
@@ -1872,24 +2276,41 @@ package body Exp_Ch5 is
       Chlist : List_Id;
 
    begin
-      --  Check for the situation where we know at compile time which
-      --  branch will be taken
+      --  Check for the situation where we know at compile time which branch
+      --  will be taken
 
       if Compile_Time_Known_Value (Expr) then
          Alt := Find_Static_Alternative (N);
 
-         --  Move the statements from this alternative after the case
-         --  statement. They are already analyzed, so will be skipped
-         --  by the analyzer.
+         --  Move statements from this alternative after the case statement.
+         --  They are already analyzed, so will be skipped by the analyzer.
 
          Insert_List_After (N, Statements (Alt));
 
-         --  That leaves the case statement as a shell. The alternative
-         --  that will be executed is reset to a null list. So now we can
-         --  kill the entire case statement.
+         --  That leaves the case statement as a shell. So now we can kill all
+         --  other alternatives in the case statement.
 
          Kill_Dead_Code (Expression (N));
-         Kill_Dead_Code (Alternatives (N));
+
+         declare
+            A : Node_Id;
+
+         begin
+            --  Loop through case alternatives, skipping pragmas, and skipping
+            --  the one alternative that we select (and therefore retain).
+
+            A := First (Alternatives (N));
+            while Present (A) loop
+               if A /= Alt
+                 and then Nkind (A) = N_Case_Statement_Alternative
+               then
+                  Kill_Dead_Code (Statements (A), Warn_On_Deleted_Code);
+               end if;
+
+               Next (A);
+            end loop;
+         end;
+
          Rewrite (N, Make_Null_Statement (Loc));
          return;
       end if;
@@ -1926,9 +2347,9 @@ package body Exp_Ch5 is
             Ensure_Valid (Expr);
          end if;
 
-         --  If there is only a single alternative, just replace it with
-         --  the sequence of statements since obviously that is what is
-         --  going to be executed in all cases.
+         --  If there is only a single alternative, just replace it with the
+         --  sequence of statements since obviously that is what is going to
+         --  be executed in all cases.
 
          Len := List_Length (Alternatives (N));
 
@@ -1940,9 +2361,9 @@ package body Exp_Ch5 is
 
             Insert_List_After (N, Statements (First (Alternatives (N))));
 
-            --  That leaves the case statement as a shell. The alternative
-            --  that will be executed is reset to a null list. So now we can
-            --  kill the entire case statement.
+            --  That leaves the case statement as a shell. The alternative that
+            --  will be executed is reset to a null list. So now we can kill
+            --  the entire case statement.
 
             Kill_Dead_Code (Expression (N));
             Rewrite (N, Make_Null_Statement (Loc));
@@ -1951,7 +2372,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)
@@ -2016,16 +2437,16 @@ package body Exp_Ch5 is
             end if;
          end if;
 
-         --  If the last alternative is not an Others choice, replace it
-         --  with an N_Others_Choice. Note that we do not bother to call
-         --  Analyze on the modified case statement, since it's only effect
-         --  would be to compute the contents of the Others_Discrete_Choices
-         --  which is not needed by the back end anyway.
+         --  If the last alternative is not an Others choice, replace it with
+         --  an N_Others_Choice. Note that we do not bother to call Analyze on
+         --  the modified case statement, since it's only effect would be to
+         --  compute the contents of the Others_Discrete_Choices which is not
+         --  needed by the back end anyway.
 
          --  The reason we do this is that the back end always needs some
          --  default for a switch, so if we have not supplied one in the
-         --  processing above for validity checking, then we need to
-         --  supply one here.
+         --  processing above for validity checking, then we need to supply
+         --  one here.
 
          if not Others_Present then
             Others_Node := Make_Others_Choice (Sloc (Last_Alt));
@@ -2063,14 +2484,14 @@ package body Exp_Ch5 is
    -- Expand_N_If_Statement --
    ---------------------------
 
-   --  First we deal with the case of C and Fortran convention boolean
-   --  values, with zero/non-zero semantics.
+   --  First we deal with the case of C and Fortran convention boolean values,
+   --  with zero/non-zero semantics.
 
    --  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
@@ -2088,8 +2509,8 @@ package body Exp_Ch5 is
    --     end if;
 
    --  This rewriting is needed if at least one elsif part has a non-empty
-   --  Condition_Actions list. We also do the same processing if there is
-   --  constant condition in an elsif part (in conjunction with the first
+   --  Condition_Actions list. We also do the same processing if there is a
+   --  constant condition in an elsif part (in conjunction with the first
    --  processing step mentioned above, for the recursive call made to deal
    --  with the created inner if, this deals with properly optimizing the
    --  cases of constant elsif conditions).
@@ -2100,6 +2521,12 @@ package body Exp_Ch5 is
       E      : Node_Id;
       New_If : Node_Id;
 
+      Warn_If_Deleted : constant Boolean :=
+                          Warn_On_Deleted_Code and then Comes_From_Source (N);
+      --  Indicates whether we want warnings when we delete branches of the
+      --  if statement based on constant condition analysis. We never want
+      --  these warnings for expander generated code.
+
    begin
       Adjust_Condition (Condition (N));
 
@@ -2109,15 +2536,15 @@ package body Exp_Ch5 is
 
       while Compile_Time_Known_Value (Condition (N)) loop
 
-         --  If condition is True, we can simply rewrite the if statement
-         --  now by replacing it by the series of then statements.
+         --  If condition is True, we can simply rewrite the if statement now
+         --  by replacing it by the series of then statements.
 
          if Is_True (Expr_Value (Condition (N))) then
 
             --  All the else parts can be killed
 
-            Kill_Dead_Code (Elsif_Parts (N));
-            Kill_Dead_Code (Else_Statements (N));
+            Kill_Dead_Code (Elsif_Parts (N), Warn_If_Deleted);
+            Kill_Dead_Code (Else_Statements (N), Warn_If_Deleted);
 
             Hed := Remove_Head (Then_Statements (N));
             Insert_List_After (N, Then_Statements (N));
@@ -2128,28 +2555,26 @@ package body Exp_Ch5 is
          --  the Then statements
 
          else
-            --  We do not delete the condition if constant condition
-            --  warnings are enabled, since otherwise we end up deleting
-            --  the desired warning. Of course the backend will get rid
-            --  of this True/False test anyway, so nothing is lost here.
+            --  We do not delete the condition if constant condition warnings
+            --  are enabled, since otherwise we end up deleting the desired
+            --  warning. Of course the backend will get rid of this True/False
+            --  test anyway, so nothing is lost here.
 
             if not Constant_Condition_Warnings then
                Kill_Dead_Code (Condition (N));
             end if;
 
-            Kill_Dead_Code (Then_Statements (N));
+            Kill_Dead_Code (Then_Statements (N), Warn_If_Deleted);
 
-            --  If there are no elsif statements, then we simply replace
-            --  the entire if statement by the sequence of else statements.
+            --  If there are no elsif statements, then we simply replace the
+            --  entire if statement by the sequence of else statements.
 
             if No (Elsif_Parts (N)) then
-
                if No (Else_Statements (N))
                  or else Is_Empty_List (Else_Statements (N))
                then
                   Rewrite (N,
                     Make_Null_Statement (Sloc (N)));
-
                else
                   Hed := Remove_Head (Else_Statements (N));
                   Insert_List_After (N, Else_Statements (N));
@@ -2158,9 +2583,9 @@ package body Exp_Ch5 is
 
                return;
 
-            --  If there are elsif statements, the first of them becomes
-            --  the if/then section of the rebuilt if statement This is
-            --  the case where we loop to reprocess this copied condition.
+            --  If there are elsif statements, the first of them becomes the
+            --  if/then section of the rebuilt if statement This is the case
+            --  where we loop to reprocess this copied condition.
 
             else
                Hed := Remove_Head (Elsif_Parts (N));
@@ -2168,6 +2593,13 @@ package body Exp_Ch5 is
                Set_Condition       (N, Condition (Hed));
                Set_Then_Statements (N, Then_Statements (Hed));
 
+               --  Hed might have been captured as the condition determining
+               --  the current value for an entity. Now it is detached from
+               --  the tree, so a Current_Value pointer in the condition might
+               --  need to be updated.
+
+               Set_Current_Value_Condition (N);
+
                if Is_Empty_List (Elsif_Parts (N)) then
                   Set_Elsif_Parts (N, No_List);
                end if;
@@ -2183,18 +2615,18 @@ package body Exp_Ch5 is
          while Present (E) loop
             Adjust_Condition (Condition (E));
 
-            --  If there are condition actions, then we rewrite the if
-            --  statement as indicated above. We also do the same rewrite
-            --  if the condition is True or False. The further processing
-            --  of this constant condition is then done by the recursive
-            --  call to expand the newly created if statement
+            --  If there are condition actions, then rewrite the if statement
+            --  as indicated above. We also do the same rewrite for a True or
+            --  False condition. The further processing of this constant
+            --  condition is then done by the recursive call to expand the
+            --  newly created if statement
 
             if Present (Condition_Actions (E))
               or else Compile_Time_Known_Value (Condition (E))
             then
-               --  Note this is not an implicit if statement, since it is
-               --  part of an explicit if statement in the source (or of an
-               --  implicit if statement that has already been tested).
+               --  Note this is not an implicit if statement, since it is part
+               --  of an explicit if statement in the source (or of an implicit
+               --  if statement that has already been tested).
 
                New_If :=
                  Make_If_Statement (Sloc (E),
@@ -2266,103 +2698,314 @@ 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
-      then
-         declare
-            Then_Stm : constant Node_Id := First (Then_Statements (N));
-            Else_Stm : constant Node_Id := First (Else_Statements (N));
+      --  Only do these optimizations if we are at least at -O1 level and
+      --  do not do them if control flow optimizations are suppressed.
 
-         begin
-            if Nkind (Then_Stm) = N_Return_Statement
-                 and then
-               Nkind (Else_Stm) = N_Return_Statement
-            then
-               declare
-                  Then_Expr : constant Node_Id := Expression (Then_Stm);
-                  Else_Expr : constant Node_Id := Expression (Else_Stm);
+      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_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_Return_Statement (Loc,
-                            Expression => Relocate_Node (Condition (N))));
-                        Analyze (N);
-                        return;
-
-                     elsif Entity (Then_Expr) = Standard_False
-                       and then Entity (Else_Expr) = Standard_True
+            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
-                        Rewrite (N,
-                          Make_Return_Statement (Loc,
-                            Expression =>
-                              Make_Op_Not (Loc,
-                                Right_Opnd => Relocate_Node (Condition (N)))));
-                        Analyze (N);
-                        return;
+                        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 if;
-               end;
-            end if;
-         end;
+                  end;
+               end if;
+            end;
+         end if;
       end if;
    end Expand_N_If_Statement;
 
-   -----------------------------
-   -- Expand_N_Loop_Statement --
+   --------------------------
+   -- Expand_Iterator_Loop --
+   --------------------------
+
+   procedure Expand_Iterator_Loop (N : Node_Id) is
+      Loc        : constant Source_Ptr := Sloc (N);
+      Isc        : constant Node_Id    := Iteration_Scheme (N);
+      I_Spec     : constant Node_Id    := Iterator_Specification (Isc);
+      Id         : constant Entity_Id  := Defining_Identifier (I_Spec);
+      Container  : constant Entity_Id  :=  Entity (Name (I_Spec));
+      Typ        : constant Entity_Id  := Etype (Container);
+
+      Cursor   : Entity_Id;
+      New_Loop : Node_Id;
+      Stats    : List_Id;
+
+   begin
+      if Is_Array_Type (Typ) then
+         if Of_Present (I_Spec) then
+            Cursor := Make_Temporary (Loc, 'C');
+
+            --  for Elem of Arr loop ...
+
+            declare
+               Decl : constant Node_Id :=
+                        Make_Object_Renaming_Declaration (Loc,
+                          Defining_Identifier => Id,
+                          Subtype_Mark        =>
+                            New_Occurrence_Of (Component_Type (Typ), Loc),
+                          Name                =>
+                            Make_Indexed_Component (Loc,
+                              Prefix      =>
+                                New_Occurrence_Of (Container, Loc),
+                              Expressions =>
+                                New_List (New_Occurrence_Of (Cursor, Loc))));
+            begin
+               Stats := Statements (N);
+               Prepend (Decl, Stats);
+
+               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         =>
+                                  New_Occurrence_Of (Container, Loc),
+                                Attribute_Name => Name_Range),
+                           Reverse_Present => Reverse_Present (I_Spec))),
+                   Statements       => Stats,
+                   End_Label        => Empty);
+            end;
+
+         else
+            --  for Index in Array loop ...
+
+            --  The cursor (index into the array) is the source Id
+
+            Cursor := Id;
+            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         =>
+                               New_Occurrence_Of (Container, Loc),
+                             Attribute_Name => Name_Range),
+                        Reverse_Present => Reverse_Present (I_Spec))),
+                Statements       => Statements (N),
+                End_Label        => Empty);
+         end if;
+
+      --  Iterators over containers
+
+      else
+         --  In both cases these require a cursor of the proper type
+
+         --    Cursor : P.Cursor_Type := Container.First;
+         --    while Cursor /= P.No_Element loop
+
+         --       Obj : P.Element_Type renames Element (Cursor);
+         --       --  For the "of" form, the element name renames the element
+         --       --  designated by the cursor.
+
+         --       Statements;
+         --       P.Next (Cursor);
+         --    end loop;
+
+         --  with the obvious replacements if "reverse" is specified.
+
+         declare
+            Element_Type  : constant Entity_Id := Etype (Id);
+            Pack          : constant Entity_Id := Scope (Etype (Container));
+            Name_Init     : Name_Id;
+            Name_Step     : Name_Id;
+            Cond          : Node_Id;
+            Cursor_Decl   : Node_Id;
+            Renaming_Decl : Node_Id;
+
+         begin
+            Stats := Statements (N);
+
+            if Of_Present (I_Spec) then
+               Cursor := Make_Temporary (Loc, 'C');
+            else
+               Cursor := Id;
+            end if;
+
+            if Reverse_Present (I_Spec) then
+
+               --  Must verify that the container has a reverse iterator ???
+
+               Name_Init := Name_Last;
+               Name_Step := Name_Previous;
+
+            else
+               Name_Init := Name_First;
+               Name_Step := Name_Next;
+            end if;
+
+            --  C : Cursor_Type := Container.First;
+
+            Cursor_Decl :=
+              Make_Object_Declaration (Loc,
+                Defining_Identifier => Cursor,
+                Object_Definition   =>
+                  Make_Selected_Component (Loc,
+                    Prefix        => New_Occurrence_Of (Pack, Loc),
+                    Selector_Name => Make_Identifier (Loc, Name_Cursor)),
+                Expression =>
+                  Make_Selected_Component (Loc,
+                    Prefix        => New_Occurrence_Of (Container, Loc),
+                    Selector_Name => Make_Identifier (Loc, Name_Init)));
+
+            Insert_Action (N, Cursor_Decl);
+
+            --  while C /= No_Element loop
+
+            Cond := Make_Op_Ne (Loc,
+                      Left_Opnd  => New_Occurrence_Of (Cursor, Loc),
+                      Right_Opnd => Make_Selected_Component (Loc,
+                         Prefix        => New_Occurrence_Of (Pack, Loc),
+                         Selector_Name =>
+                           Make_Identifier (Loc, Name_No_Element)));
+
+            if Of_Present (I_Spec) then
+
+               --  Id : Element_Type renames Pack.Element (Cursor);
+
+               Renaming_Decl :=
+                 Make_Object_Renaming_Declaration (Loc,
+                   Defining_Identifier => Id,
+                   Subtype_Mark        =>
+                     New_Occurrence_Of (Element_Type, Loc),
+                   Name                =>
+                     Make_Indexed_Component (Loc,
+                       Prefix =>
+                         Make_Selected_Component (Loc,
+                           Prefix        =>  New_Occurrence_Of (Pack, Loc),
+                           Selector_Name =>
+                             Make_Identifier (Loc, Chars => Name_Element)),
+                       Expressions =>
+                         New_List (New_Occurrence_Of (Cursor, Loc))));
+
+               Prepend (Renaming_Decl, Stats);
+            end if;
+
+            --  For both iterator forms, add call to step operation (Next or
+            --  Previous) to advance cursor.
+
+            Append_To (Stats,
+              Make_Procedure_Call_Statement (Loc,
+                Name =>
+                  Make_Selected_Component (Loc,
+                    Prefix        => New_Occurrence_Of (Pack, Loc),
+                    Selector_Name => Make_Identifier (Loc, Name_Step)),
+                Parameter_Associations =>
+                  New_List (New_Occurrence_Of (Cursor, Loc))));
+
+            New_Loop := Make_Loop_Statement (Loc,
+              Iteration_Scheme =>
+                Make_Iteration_Scheme (Loc, Condition => Cond),
+              Statements       => Stats,
+              End_Label        => Empty);
+         end;
+      end if;
+
+      --  Set_Analyzed (I_Spec);
+      --  Why is this commented out???
+
+      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;
 
-      if No (Isc) then
-         return;
-      end if;
-
-      --  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:
+      --  Nothing more to do for plain loop with no iteration scheme
 
-      --    for x in [reverse] a .. b loop
-      --       ...
-      --    end loop;
+      if No (Isc) then
+         null;
 
-      --  to
+      --  Case of for loop (Loop_Parameter_Specification present)
 
-      --    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;
+      --  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.
 
-      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);
@@ -2372,99 +3015,133 @@ package body Exp_Ch5 is
             New_Id  : Entity_Id;
 
          begin
-            if not Is_Enumeration_Type (Btype)
-              or else No (Enum_Pos_To_Rep (Btype))
-            then
-               return;
-            end if;
-
-            New_Id :=
-              Make_Defining_Identifier (Loc,
-                Chars => New_External_Name (Chars (Loop_Id), 'P'));
+            --  Deal with loop over predicates
 
-            --  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.
-
-               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;
+            if Is_Discrete_Type (Ltype)
+              and then Present (Predicate_Function (Ltype))
+            then
+               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'));
+
+               --  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
+
+                  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)))),
+
+                   End_Label => End_Label (N)));
+               Analyze (N);
 
-                    Handled_Statement_Sequence =>
-                      Make_Handled_Sequence_Of_Statements (Loc,
-                        Statements => Statements (N)))),
+            --  Nothing to do with other cases of for loops
 
-                End_Label => End_Label (N)));
-            Analyze (N);
+            else
+               null;
+            end if;
          end;
 
-      --  Second case, if we have a while loop with Condition_Actions set,
-      --  then we change it into a plain loop:
+      --  Second case, if we have a while loop with Condition_Actions set, then
+      --  we change it into a plain loop:
 
       --    while C loop
       --       ...
@@ -2494,10 +3171,10 @@ package body Exp_Ch5 is
             Prepend (ES, Statements (N));
             Insert_List_Before (ES, Condition_Actions (Isc));
 
-            --  This is not an implicit loop, since it is generated in
-            --  response to the loop statement being processed. If this
-            --  is itself implicit, the restriction has already been
-            --  checked. If not, it is an explicit loop.
+            --  This is not an implicit loop, since it is generated in response
+            --  to the loop statement being processed. If this is itself
+            --  implicit, the restriction has already been checked. If not,
+            --  it is an explicit loop.
 
             Rewrite (N,
               Make_Loop_Statement (Sloc (N),
@@ -2507,497 +3184,218 @@ package body Exp_Ch5 is
 
             Analyze (N);
          end;
-      end if;
-   end Expand_N_Loop_Statement;
-
-   -------------------------------
-   -- Expand_N_Return_Statement --
-   -------------------------------
-
-   procedure Expand_N_Return_Statement (N : Node_Id) is
-      Loc         : constant Source_Ptr := Sloc (N);
-      Exp         : constant Node_Id    := Expression (N);
-      Exptyp      : Entity_Id;
-      T           : Entity_Id;
-      Utyp        : Entity_Id;
-      Scope_Id    : Entity_Id;
-      Kind        : Entity_Kind;
-      Call        : Node_Id;
-      Acc_Stat    : Node_Id;
-      Goto_Stat   : Node_Id;
-      Lab_Node    : Node_Id;
-      Cur_Idx     : Nat;
-      Return_Type : Entity_Id;
-      Result_Exp  : Node_Id;
-      Result_Id   : Entity_Id;
-      Result_Obj  : Node_Id;
-
-   begin
-      --  Case where returned expression is present
-
-      if Present (Exp) then
-
-         --  Always normalize C/Fortran boolean result. This is not always
-         --  necessary, 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.
-
-         Exptyp := Etype (Exp);
-
-         if Is_Boolean_Type (Exptyp)
-           and then Nonzero_Is_True (Exptyp)
-         then
-            Adjust_Condition (Exp);
-            Adjust_Result_Type (Exp, Exptyp);
-         end if;
-
-         --  Do validity check if enabled for returns
-
-         if Validity_Checks_On
-           and then Validity_Check_Returns
-         then
-            Ensure_Valid (Exp);
-         end if;
-      end if;
-
-      --  Find relevant enclosing scope from which return is returning
-
-      Cur_Idx := Scope_Stack.Last;
-      loop
-         Scope_Id := Scope_Stack.Table (Cur_Idx).Entity;
-
-         if Ekind (Scope_Id) /= E_Block
-           and then Ekind (Scope_Id) /= E_Loop
-         then
-            exit;
-
-         else
-            Cur_Idx := Cur_Idx - 1;
-            pragma Assert (Cur_Idx >= 0);
-         end if;
-      end loop;
-
-      if No (Exp) then
-         Kind := Ekind (Scope_Id);
-
-         --  If it is a return from procedures do no extra steps.
-
-         if Kind = E_Procedure or else Kind = E_Generic_Procedure then
-            return;
-         end if;
 
-         pragma Assert (Is_Entry (Scope_Id));
+      --  Here to deal with iterator case
 
-         --  Look at the enclosing block to see whether the return is from
-         --  an accept statement or an entry body.
-
-         for J in reverse 0 .. Cur_Idx 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 should be expanded
-         --  as a 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;
-
-         return;
-      end if;
-
-      T := Etype (Exp);
-      Return_Type := Etype (Scope_Id);
-      Utyp := Underlying_Type (Return_Type);
-
-      --  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 (T) then
-         Rewrite (Exp, Convert_To (Return_Type, Exp));
-         Analyze (Exp);
-      end if;
-
-      --  Implement the rules of 6.5(8-10), which require a tag check in
-      --  the case of a limited tagged return type, and tag reassignment
-      --  for nonlimited tagged results. These actions are needed when
-      --  the return type is a specific tagged type and the result
-      --  expression is a conversion or a formal parameter, because in
-      --  that case the tag of the expression might differ from the tag
-      --  of the specific result type.
-
-      if Is_Tagged_Type (Utyp)
-        and then not Is_Class_Wide_Type (Utyp)
-        and then (Nkind (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))
+      elsif Present (Isc)
+        and then Present (Iterator_Specification (Isc))
       then
-         --  When the return type is limited, perform a check that the
-         --  tag of the result is the same as the tag of the return type.
-
-         if Is_Limited_Type (Return_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 (Tag_Component (Utyp), Loc)),
-                    Right_Opnd =>
-                      Unchecked_Convert_To (RTE (RE_Tag),
-                        New_Reference_To
-                          (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.
-
-         else
-            Result_Id :=
-              Make_Defining_Identifier (Loc, New_Internal_Name ('R'));
-            Result_Exp := New_Reference_To (Result_Id, Loc);
-
-            Result_Obj :=
-              Make_Object_Declaration (Loc,
-                Defining_Identifier => Result_Id,
-                Object_Definition   => New_Reference_To (Return_Type, Loc),
-                Constant_Present    => True,
-                Expression          => Relocate_Node (Exp));
-
-            Set_Assignment_OK (Result_Obj);
-            Insert_Action (Exp, Result_Obj);
-
-            Rewrite (Exp, Result_Exp);
-            Analyze_And_Resolve (Exp, Return_Type);
-         end if;
+         Expand_Iterator_Loop (N);
       end if;
+   end Expand_N_Loop_Statement;
 
-      --  Deal with returning variable length objects and controlled types
-
-      --  Nothing to do if we are returning by reference, or this is not
-      --  a type that requires special processing (indicated by the fact
-      --  that it requires a cleanup scope for the secondary stack case)
-
-      if Is_Return_By_Reference_Type (T)
-        or else not Requires_Transient_Scope (Return_Type)
-      then
-         null;
-
-      --  Case of secondary stack not used
-
-      elsif Function_Returns_With_DSP (Scope_Id) then
+   ----------------------------
+   -- Expand_Predicated_Loop --
+   ----------------------------
 
-         --  Here what we need to do is to always return by reference, since
-         --  we will return with the stack pointer depressed. We may need to
-         --  do a copy to a local temporary before doing this return.
+   --  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.
 
-         No_Secondary_Stack_Case : declare
-            Local_Copy_Required : Boolean := False;
-            --  Set to True if a local copy is required
+   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);
 
-            Copy_Ent : Entity_Id;
-            --  Used for the target entity if a copy is required
+   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.
 
-            Decl : Node_Id;
-            --  Declaration used to create copy if needed
+      if No (Stat) then
+         raise Program_Error;
 
-            procedure Test_Copy_Required (Expr : Node_Id);
-            --  Determines if Expr represents a return value for which a
-            --  copy is required. More specifically, a copy is not required
-            --  if Expr represents an object or component of an object that
-            --  is either in the local subprogram frame, or is constant.
-            --  If a copy is required, then Local_Copy_Required is set True.
+      --  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.
 
-            ------------------------
-            -- Test_Copy_Required --
-            ------------------------
+      elsif Is_Empty_List (Stat) then
+         Rewrite (N, Make_Null_Statement (Loc));
+         Analyze (N);
 
-            procedure Test_Copy_Required (Expr : Node_Id) is
-               Ent : Entity_Id;
+      --  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
+         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
-               --  If component, test prefix (object containing component)
-
-               if Nkind (Expr) = N_Indexed_Component
-                    or else
-                  Nkind (Expr) = N_Selected_Component
-               then
-                  Test_Copy_Required (Prefix (Expr));
-                  return;
-
-               --  See if we have an entity name
-
-               elsif Is_Entity_Name (Expr) then
-                  Ent := Entity (Expr);
-
-                  --  Constant entity is always OK, no copy required
-
-                  if Ekind (Ent) = E_Constant then
-                     return;
-
-                  --  No copy required for local variable
-
-                  elsif Ekind (Ent) = E_Variable
-                    and then Scope (Ent) = Current_Subprogram
-                  then
-                     return;
-                  end if;
+               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;
 
-               --  All other cases require a copy
+            ------------
+            -- Lo_Val --
+            ------------
 
-               Local_Copy_Required := True;
-            end Test_Copy_Required;
+            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;
 
-         --  Start of processing for No_Secondary_Stack_Case
+         --  Start of processing for Static_Predicate
 
          begin
-            --  No copy needed if result is from a function call.
-            --  In this case the result is already being returned by
-            --  reference with the stack pointer depressed.
-
-            --  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 (T)
-              and then
-                (not Is_Array_Type (T)
-                   or else Is_Constrained (T) = Is_Constrained (Return_Type)
-                   or else Controlled_Type (T))
-              and then Nkind (Exp) = N_Function_Call
-            then
-               Set_By_Ref (N);
-
-            --  We always need a local copy for a controlled type, since
-            --  we are required to finalize the local value before return.
-            --  The copy will automatically include the required finalize.
-            --  Moreover, gigi cannot make this copy, since we need special
-            --  processing to ensure proper behavior for finalization.
-
-            --  Note: the reason we are returning with a depressed stack
-            --  pointer in the controlled case (even if the type involved
-            --  is constrained) is that we must make a local copy to deal
-            --  properly with the requirement that the local result be
-            --  finalized.
-
-            elsif Controlled_Type (Utyp) then
-               Copy_Ent :=
-                 Make_Defining_Identifier (Loc,
-                   Chars => New_Internal_Name ('R'));
-
-               --  Build declaration to do the copy, and insert it, setting
-               --  Assignment_OK, because we may be copying a limited type.
-               --  In addition we set the special flag to inhibit finalize
-               --  attachment if this is a controlled type (since this attach
-               --  must be done by the caller, otherwise if we attach it here
-               --  we will finalize the returned result prematurely).
+            --  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.
 
-               Decl :=
-                 Make_Object_Declaration (Loc,
-                   Defining_Identifier => Copy_Ent,
-                   Object_Definition   => New_Occurrence_Of (Return_Type, Loc),
-                   Expression          => Relocate_Node (Exp));
+            Set_Analyzed (Loop_Id, False);
+            Set_Ekind    (Loop_Id, E_Variable);
 
-               Set_Assignment_OK (Decl);
-               Set_Delay_Finalize_Attach (Decl);
-               Insert_Action (N, Decl);
+            --  Loop to create branches of case statement
 
-               --  Now the actual return uses the copied value
-
-               Rewrite (Exp, New_Occurrence_Of (Copy_Ent, Loc));
-               Analyze_And_Resolve (Exp, Return_Type);
-
-               --  Since we have made the copy, gigi does not have to, so
-               --  we set the By_Ref flag to prevent another copy being made.
-
-               Set_By_Ref (N);
-
-            --  Non-controlled cases
-
-            else
-               Test_Copy_Required (Exp);
-
-               --  If a local copy is required, then gigi will make the
-               --  copy, otherwise, we can return the result directly,
-               --  so set By_Ref to suppress the gigi copy.
-
-               if not Local_Copy_Required then
-                  Set_By_Ref (N);
+            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;
-            end if;
-         end No_Secondary_Stack_Case;
 
-      --  Here if secondary stack is used
+               Append_To (Alts,
+                 Make_Case_Statement_Alternative (Loc,
+                   Statements       => New_List (S),
+                   Discrete_Choices => New_List (Hi_Val (P))));
 
-      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. See example in 7417-003.
-
-         declare
-            S : Entity_Id := Current_Scope;
-
-         begin
-            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);
+               Next (P);
             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 (T)
-           and then
-              (not Is_Array_Type (T)
-                or else Is_Constrained (T) = Is_Constrained (Return_Type)
-                or else Controlled_Type (T))
-           and then Nkind (Exp) = N_Function_Call
-         then
-            Set_By_Ref (N);
 
-         --  For controlled types, do the allocation on the sec-stack
-         --  manually in order to call adjust at the right time
-         --    type Anon1 is access Return_Type;
-         --    for Anon1'Storage_pool use ss_pool;
-         --    Anon2 : anon1 := new Return_Type'(expr);
-         --    return Anon2.all;
+            --  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);
 
-         elsif 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;
-
-            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 (Return_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, Return_Type);
-            end;
-
-         --  Otherwise use the gigi mechanism to allocate result on the
-         --  secondary stack.
-
-         else
-            Set_Storage_Pool      (N, RTE (RE_SS_Pool));
-
-            --  If we are generating code for the Java VM do not use
-            --  SS_Allocate since everything is heap-allocated anyway.
+            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)))));
 
-            if not Java_VM then
-               Set_Procedure_To_Call (N, RTE (RE_SS_Allocate));
-            end if;
-         end if;
+            Analyze (N);
+         end Static_Predicate;
       end if;
-
-   exception
-      when RE_Not_Available =>
-         return;
-   end Expand_N_Return_Statement;
+   end Expand_Predicated_Loop;
 
    ------------------------------
    -- Make_Tag_Ctrl_Assignment --
@@ -3008,32 +3406,35 @@ 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 not Java_VM;
-      --  Tags are not saved and restored when Java_VM because JVM tags
-      --  are represented implicitly in objects.
-
-      Res       : List_Id;
-      Tag_Tmp   : Entity_Id;
-      Prev_Tmp  : Entity_Id;
-      Next_Tmp  : Entity_Id;
-      Ctrl_Ref  : Node_Id;
-      Ctrl_Ref2 : Node_Id   := Empty;
-      Prev_Tmp2 : Entity_Id := Empty;  -- prevent warning
-      Next_Tmp2 : Entity_Id := Empty;  -- prevent warning
+                                       and then Tagged_Type_Expansion;
+      --  Tags are not saved and restored when VM_Target because VM tags are
+      --  represented implicitly in objects.
+
+      Res      : List_Id;
+      Tag_Tmp  : Entity_Id;
+
+      Prev_Tmp : Entity_Id;
+      Next_Tmp : Entity_Id;
+      Ctrl_Ref : Node_Id;
 
    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
@@ -3047,28 +3448,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;
 
-      Next_Tmp := Make_Defining_Identifier (Loc, New_Internal_Name ('C'));
-
       --  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,
@@ -3077,7 +3478,8 @@ package body Exp_Ch5 is
              Expression =>
                Make_Selected_Component (Loc,
                  Prefix        => Duplicate_Subexpr_No_Checks (L),
-                 Selector_Name => New_Reference_To (Tag_Component (T), Loc))));
+                 Selector_Name => New_Reference_To (First_Tag_Component (T),
+                                                    Loc))));
 
       --  Otherwise Tag_Tmp not used
 
@@ -3085,64 +3487,32 @@ package body Exp_Ch5 is
          Tag_Tmp := Empty;
       end if;
 
-      --  Save the Finalization Pointers in local variables Prev_Tmp and
-      --  Next_Tmp. For objects with Has_Controlled_Component set, these
-      --  pointers are in the Record_Controller and if it is also
-      --  Is_Controlled, we need to save the object pointers as well.
-
       if Ctrl_Act then
-         Ctrl_Ref := Duplicate_Subexpr_No_Checks (L);
+         if VM_Target /= No_VM then
 
-         if Has_Controlled_Component (T) then
-            Ctrl_Ref :=
-              Make_Selected_Component (Loc,
-                Prefix => Ctrl_Ref,
-                Selector_Name =>
-                  New_Reference_To (Controller_Component (T), Loc));
+            --  Cannot assign part of the object in a VM context, so instead
+            --  fallback to the previous mechanism, even though it is not
+            --  completely correct ???
 
-            if Is_Controlled (T) then
-               Ctrl_Ref2 := Duplicate_Subexpr_No_Checks (L);
-            end if;
-         end if;
-
-         Prev_Tmp := Make_Defining_Identifier (Loc, New_Internal_Name ('B'));
-
-         Append_To (Res,
-           Make_Object_Declaration (Loc,
-             Defining_Identifier => Prev_Tmp,
-
-             Object_Definition =>
-               New_Reference_To (RTE (RE_Finalizable_Ptr), Loc),
+            --  Save the Finalization Pointers in local variables Prev_Tmp and
+            --  Next_Tmp. For objects with Has_Controlled_Component set, these
+            --  pointers are in the Record_Controller
 
-             Expression =>
-               Make_Selected_Component (Loc,
-                 Prefix =>
-                   Unchecked_Convert_To (RTE (RE_Finalizable), Ctrl_Ref),
-                 Selector_Name => Make_Identifier (Loc, Name_Prev))));
-
-         Next_Tmp := Make_Defining_Identifier (Loc, New_Internal_Name ('C'));
-
-         Append_To (Res,
-           Make_Object_Declaration (Loc,
-             Defining_Identifier => Next_Tmp,
+            Ctrl_Ref := Duplicate_Subexpr (L);
 
-             Object_Definition =>
-               New_Reference_To (RTE (RE_Finalizable_Ptr), Loc),
-
-             Expression =>
-               Make_Selected_Component (Loc,
-                 Prefix =>
-                   Unchecked_Convert_To (RTE (RE_Finalizable),
-                     New_Copy_Tree (Ctrl_Ref)),
-                 Selector_Name => Make_Identifier (Loc, Name_Next))));
+            if Has_Controlled_Component (T) then
+               Ctrl_Ref :=
+                 Make_Selected_Component (Loc,
+                   Prefix => Ctrl_Ref,
+                   Selector_Name =>
+                     New_Reference_To (Controller_Component (T), Loc));
+            end if;
 
-         if Present (Ctrl_Ref2) then
-            Prev_Tmp2 :=
-              Make_Defining_Identifier (Loc, New_Internal_Name ('B'));
+            Prev_Tmp := Make_Temporary (Loc, 'B');
 
             Append_To (Res,
               Make_Object_Declaration (Loc,
-                Defining_Identifier => Prev_Tmp2,
+                Defining_Identifier => Prev_Tmp,
 
                 Object_Definition =>
                   New_Reference_To (RTE (RE_Finalizable_Ptr), Loc),
@@ -3150,39 +3520,359 @@ package body Exp_Ch5 is
                 Expression =>
                   Make_Selected_Component (Loc,
                     Prefix =>
-                      Unchecked_Convert_To (RTE (RE_Finalizable), Ctrl_Ref2),
+                      Unchecked_Convert_To (RTE (RE_Finalizable), Ctrl_Ref),
                     Selector_Name => Make_Identifier (Loc, Name_Prev))));
 
-            Next_Tmp2 :=
-              Make_Defining_Identifier (Loc, New_Internal_Name ('C'));
+            Next_Tmp := Make_Temporary (Loc, 'C');
 
             Append_To (Res,
               Make_Object_Declaration (Loc,
-                Defining_Identifier => Next_Tmp2,
+                Defining_Identifier => Next_Tmp,
 
-                Object_Definition =>
+                Object_Definition   =>
                   New_Reference_To (RTE (RE_Finalizable_Ptr), Loc),
 
-                Expression =>
+                Expression          =>
                   Make_Selected_Component (Loc,
                     Prefix =>
                       Unchecked_Convert_To (RTE (RE_Finalizable),
-                        New_Copy_Tree (Ctrl_Ref2)),
+                        New_Copy_Tree (Ctrl_Ref)),
                     Selector_Name => Make_Identifier (Loc, Name_Next))));
+
+            --  Do the Assignment
+
+            Append_To (Res, Relocate_Node (N));
+
+         else
+            --  Regular (non VM) processing for controlled types and types with
+            --  controlled components
+
+            --  Variables of such types contain pointers used to chain them in
+            --  finalization lists, in addition to user data. These pointers
+            --  are specific to each object of the type, not to the value being
+            --  assigned.
+
+            --  Thus they need to be left intact during the assignment. We
+            --  achieve this by constructing a Storage_Array subtype, and by
+            --  overlaying objects of this type on the source and target of the
+            --  assignment. The assignment is then rewritten to assignments of
+            --  slices of these arrays, copying the user data, and leaving the
+            --  pointers untouched.
+
+            Controlled_Actions : declare
+               Prev_Ref : Node_Id;
+               --  A reference to the Prev component of the record controller
+
+               First_After_Root : Node_Id := Empty;
+               --  Index of first byte to be copied (used to skip
+               --  Root_Controlled in controlled objects).
+
+               Last_Before_Hole : Node_Id := Empty;
+               --  Index of last byte to be copied before outermost record
+               --  controller data.
+
+               Hole_Length : Node_Id := Empty;
+               --  Length of record controller data (Prev and Next pointers)
+
+               First_After_Hole : Node_Id := Empty;
+               --  Index of first byte to be copied after outermost record
+               --  controller data.
+
+               Expr, Source_Size     : Node_Id;
+               Source_Actual_Subtype : Entity_Id;
+               --  Used for computation of the size of the data to be copied
+
+               Range_Type  : Entity_Id;
+               Opaque_Type : Entity_Id;
+
+               function Build_Slice
+                 (Rec : Entity_Id;
+                  Lo  : Node_Id;
+                  Hi  : Node_Id) return Node_Id;
+               --  Build and return a slice of an array of type S overlaid on
+               --  object Rec, with bounds specified by Lo and Hi. If either
+               --  bound is empty, a default of S'First (respectively S'Last)
+               --  is used.
+
+               -----------------
+               -- Build_Slice --
+               -----------------
+
+               function Build_Slice
+                 (Rec : Node_Id;
+                  Lo  : Node_Id;
+                  Hi  : Node_Id) return Node_Id
+               is
+                  Lo_Bound : Node_Id;
+                  Hi_Bound : Node_Id;
+
+                  Opaque : constant Node_Id :=
+                             Unchecked_Convert_To (Opaque_Type,
+                               Make_Attribute_Reference (Loc,
+                                 Prefix         => Rec,
+                                 Attribute_Name => Name_Address));
+                  --  Access value designating an opaque storage array of type
+                  --  S overlaid on record Rec.
+
+               begin
+                  --  Compute slice bounds using S'First (1) and S'Last as
+                  --  default values when not specified by the caller.
+
+                  if No (Lo) then
+                     Lo_Bound := Make_Integer_Literal (Loc, 1);
+                  else
+                     Lo_Bound := Lo;
+                  end if;
+
+                  if No (Hi) then
+                     Hi_Bound := Make_Attribute_Reference (Loc,
+                       Prefix => New_Occurrence_Of (Range_Type, Loc),
+                       Attribute_Name => Name_Last);
+                  else
+                     Hi_Bound := Hi;
+                  end if;
+
+                  return Make_Slice (Loc,
+                    Prefix =>
+                      Opaque,
+                    Discrete_Range => Make_Range (Loc,
+                      Lo_Bound, Hi_Bound));
+               end Build_Slice;
+
+            --  Start of processing for Controlled_Actions
+
+            begin
+               --  Create a constrained subtype of Storage_Array whose size
+               --  corresponds to the value being assigned.
+
+               --  subtype G is Storage_Offset range
+               --    1 .. (Expr'Size + Storage_Unit - 1) / Storage_Unit
+
+               Expr := Duplicate_Subexpr_No_Checks (Expression (N));
+
+               if Nkind (Expr) = N_Qualified_Expression then
+                  Expr := Expression (Expr);
+               end if;
+
+               Source_Actual_Subtype := Etype (Expr);
+
+               if Has_Discriminants (Source_Actual_Subtype)
+                 and then not Is_Constrained (Source_Actual_Subtype)
+               then
+                  Append_To (Res,
+                    Build_Actual_Subtype (Source_Actual_Subtype, Expr));
+                  Source_Actual_Subtype := Defining_Identifier (Last (Res));
+               end if;
+
+               Source_Size :=
+                 Make_Op_Add (Loc,
+                   Left_Opnd =>
+                     Make_Attribute_Reference (Loc,
+                       Prefix =>
+                         New_Occurrence_Of (Source_Actual_Subtype, Loc),
+                     Attribute_Name => Name_Size),
+                   Right_Opnd =>
+                     Make_Integer_Literal (Loc,
+                       Intval => System_Storage_Unit - 1));
+
+               Source_Size :=
+                 Make_Op_Divide (Loc,
+                   Left_Opnd => Source_Size,
+                   Right_Opnd =>
+                     Make_Integer_Literal (Loc,
+                       Intval => System_Storage_Unit));
+
+               Range_Type := Make_Temporary (Loc, 'G');
+
+               Append_To (Res,
+                 Make_Subtype_Declaration (Loc,
+                   Defining_Identifier => Range_Type,
+                   Subtype_Indication =>
+                     Make_Subtype_Indication (Loc,
+                       Subtype_Mark =>
+                         New_Reference_To (RTE (RE_Storage_Offset), Loc),
+                       Constraint   => Make_Range_Constraint (Loc,
+                         Range_Expression =>
+                           Make_Range (Loc,
+                             Low_Bound  => Make_Integer_Literal (Loc, 1),
+                             High_Bound => Source_Size)))));
+
+               --  subtype S is Storage_Array (G)
+
+               Append_To (Res,
+                 Make_Subtype_Declaration (Loc,
+                   Defining_Identifier => Make_Temporary (Loc, 'S'),
+                   Subtype_Indication  =>
+                     Make_Subtype_Indication (Loc,
+                       Subtype_Mark =>
+                         New_Reference_To (RTE (RE_Storage_Array), Loc),
+                       Constraint =>
+                         Make_Index_Or_Discriminant_Constraint (Loc,
+                           Constraints =>
+                             New_List (New_Reference_To (Range_Type, Loc))))));
+
+               --  type A is access S
+
+               Opaque_Type := Make_Temporary (Loc, 'A');
+
+               Append_To (Res,
+                 Make_Full_Type_Declaration (Loc,
+                   Defining_Identifier => Opaque_Type,
+                   Type_Definition     =>
+                     Make_Access_To_Object_Definition (Loc,
+                       Subtype_Indication =>
+                         New_Occurrence_Of (
+                           Defining_Identifier (Last (Res)), Loc))));
+
+               --  Generate appropriate slice assignments
+
+               First_After_Root := Make_Integer_Literal (Loc, 1);
+
+               --  For controlled object, skip Root_Controlled part
+
+               if Is_Controlled (T) then
+                  First_After_Root :=
+                    Make_Op_Add (Loc,
+                      First_After_Root,
+                      Make_Op_Divide (Loc,
+                        Make_Attribute_Reference (Loc,
+                          Prefix =>
+                            New_Occurrence_Of (RTE (RE_Root_Controlled), Loc),
+                          Attribute_Name => Name_Size),
+                        Make_Integer_Literal (Loc, System_Storage_Unit)));
+               end if;
+
+               --  For the case of a record with controlled components, skip
+               --  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        =>
+                        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_Before_Hole := Make_Temporary (Loc, 'L');
+
+                  Append_To (Res,
+                    Make_Object_Declaration (Loc,
+                      Defining_Identifier => Last_Before_Hole,
+                      Object_Definition   => New_Occurrence_Of (
+                        RTE (RE_Storage_Offset), Loc),
+                      Constant_Present    => True,
+                      Expression          =>
+                        Make_Op_Add (Loc,
+                          Make_Attribute_Reference (Loc,
+                            Prefix => Prev_Ref,
+                            Attribute_Name => Name_Position),
+                          Make_Attribute_Reference (Loc,
+                            Prefix => New_Copy_Tree (Prefix (Prev_Ref)),
+                            Attribute_Name => Name_Position))));
+
+                  --  Hole length: size of the Prev and Next components
+
+                  Hole_Length :=
+                    Make_Op_Multiply (Loc,
+                      Left_Opnd  => Make_Integer_Literal (Loc, Uint_2),
+                      Right_Opnd =>
+                        Make_Op_Divide (Loc,
+                          Left_Opnd =>
+                            Make_Attribute_Reference (Loc,
+                              Prefix         => New_Copy_Tree (Prev_Ref),
+                              Attribute_Name => Name_Size),
+                          Right_Opnd =>
+                            Make_Integer_Literal (Loc,
+                              Intval => System_Storage_Unit)));
+
+                  --  First index after hole
+
+                  First_After_Hole := Make_Temporary (Loc, 'F');
+
+                  Append_To (Res,
+                    Make_Object_Declaration (Loc,
+                      Defining_Identifier => First_After_Hole,
+                      Object_Definition   => New_Occurrence_Of (
+                        RTE (RE_Storage_Offset), Loc),
+                      Constant_Present    => True,
+                      Expression          =>
+                        Make_Op_Add (Loc,
+                          Left_Opnd  =>
+                            Make_Op_Add (Loc,
+                              Left_Opnd  =>
+                                New_Occurrence_Of (Last_Before_Hole, Loc),
+                              Right_Opnd => Hole_Length),
+                          Right_Opnd => Make_Integer_Literal (Loc, 1))));
+
+                  Last_Before_Hole :=
+                    New_Occurrence_Of (Last_Before_Hole, Loc);
+                  First_After_Hole :=
+                    New_Occurrence_Of (First_After_Hole, Loc);
+               end if;
+
+               --  Assign the first slice (possibly skipping Root_Controlled,
+               --  up to the beginning of the record controller if present,
+               --  up to the end of the object if not).
+
+               Append_To (Res, Make_Assignment_Statement (Loc,
+                 Name       => Build_Slice (
+                   Rec => Duplicate_Subexpr_No_Checks (L),
+                   Lo  => First_After_Root,
+                   Hi  => Last_Before_Hole),
+
+                 Expression => Build_Slice (
+                   Rec => Expression (N),
+                   Lo  => First_After_Root,
+                   Hi  => New_Copy_Tree (Last_Before_Hole))));
+
+               if Present (First_After_Hole) then
+
+                  --  If a record controller is present, copy the second slice,
+                  --  from right after the _Controller.Next component up to the
+                  --  end of the object.
+
+                  Append_To (Res, Make_Assignment_Statement (Loc,
+                    Name       => Build_Slice (
+                      Rec => Duplicate_Subexpr_No_Checks (L),
+                      Lo  => First_After_Hole,
+                      Hi  => Empty),
+                    Expression => Build_Slice (
+                      Rec => Duplicate_Subexpr_No_Checks (Expression (N)),
+                      Lo  => New_Copy_Tree (First_After_Hole),
+                      Hi  => Empty)));
+               end if;
+            end Controlled_Actions;
          end if;
 
-      --  If not controlled type, then Prev_Tmp and Ctrl_Ref unused
+      --  Not controlled case
 
       else
-         Prev_Tmp := Empty;
-         Ctrl_Ref := Empty;
-      end if;
+         declare
+            Asn : constant Node_Id := Relocate_Node (N);
 
-      --  Do the Assignment
+         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, Relocate_Node (N));
+            Append_To (Res, Asn);
+         end;
+      end if;
 
-      --  Restore the Tag
+      --  Restore the tag
 
       if Save_Tag then
          Append_To (Res,
@@ -3190,61 +3880,39 @@ package body Exp_Ch5 is
              Name =>
                Make_Selected_Component (Loc,
                  Prefix        => Duplicate_Subexpr_No_Checks (L),
-                 Selector_Name => New_Reference_To (Tag_Component (T), Loc)),
+                 Selector_Name => New_Reference_To (First_Tag_Component (T),
+                                                    Loc)),
              Expression => New_Reference_To (Tag_Tmp, Loc)));
       end if;
 
-      --  Restore the finalization pointers
-
       if Ctrl_Act then
-         Append_To (Res,
-           Make_Assignment_Statement (Loc,
-             Name =>
-               Make_Selected_Component (Loc,
-                 Prefix =>
-                   Unchecked_Convert_To (RTE (RE_Finalizable),
-                     New_Copy_Tree (Ctrl_Ref)),
-                 Selector_Name => Make_Identifier (Loc, Name_Prev)),
-             Expression => New_Reference_To (Prev_Tmp, Loc)));
+         if VM_Target /= No_VM then
+            --  Restore the finalization pointers
 
-         Append_To (Res,
-           Make_Assignment_Statement (Loc,
-             Name =>
-               Make_Selected_Component (Loc,
-                 Prefix =>
-                   Unchecked_Convert_To (RTE (RE_Finalizable),
-                     New_Copy_Tree (Ctrl_Ref)),
-                 Selector_Name => Make_Identifier (Loc, Name_Next)),
-             Expression => New_Reference_To (Next_Tmp, Loc)));
-
-         if Present (Ctrl_Ref2) then
             Append_To (Res,
               Make_Assignment_Statement (Loc,
                 Name =>
                   Make_Selected_Component (Loc,
-                    Prefix =>
+                    Prefix        =>
                       Unchecked_Convert_To (RTE (RE_Finalizable),
-                        New_Copy_Tree (Ctrl_Ref2)),
+                        New_Copy_Tree (Ctrl_Ref)),
                     Selector_Name => Make_Identifier (Loc, Name_Prev)),
-                Expression => New_Reference_To (Prev_Tmp2, Loc)));
+                Expression => New_Reference_To (Prev_Tmp, Loc)));
 
             Append_To (Res,
               Make_Assignment_Statement (Loc,
                 Name =>
                   Make_Selected_Component (Loc,
-                    Prefix =>
+                    Prefix        =>
                       Unchecked_Convert_To (RTE (RE_Finalizable),
-                        New_Copy_Tree (Ctrl_Ref2)),
+                        New_Copy_Tree (Ctrl_Ref)),
                     Selector_Name => Make_Identifier (Loc, Name_Next)),
-                Expression => New_Reference_To (Next_Tmp2, Loc)));
+                Expression => New_Reference_To (Next_Tmp, Loc)));
          end if;
-      end if;
 
-      --  Adjust the target after the assignment when controlled. (not in
-      --  the init proc since it is an initialization more than an
-      --  assignment)
+         --  Adjust the target after the assignment when controlled (not in the
+         --  init proc since it is an initialization more than an assignment).
 
-      if Ctrl_Act then
          Append_List_To (Res,
            Make_Adjust_Call (
              Ref         => Duplicate_Subexpr_Move_Checks (L),
@@ -3256,71 +3924,10 @@ package body Exp_Ch5 is
       return Res;
 
    exception
+      --  Could use comment here ???
+
       when RE_Not_Available =>
          return Empty_List;
    end Make_Tag_Ctrl_Assignment;
 
-   ------------------------------------
-   -- Possible_Bit_Aligned_Component --
-   ------------------------------------
-
-   function Possible_Bit_Aligned_Component (N : Node_Id) return Boolean is
-   begin
-      case Nkind (N) is
-
-         --  Case of indexed component
-
-         when N_Indexed_Component =>
-            declare
-               P    : constant Node_Id   := Prefix (N);
-               Ptyp : constant Entity_Id := Etype (P);
-
-            begin
-               --  If we know the component size and it is less than 64, then
-               --  we are definitely OK. The back end always does assignment
-               --  of misaligned small objects correctly.
-
-               if Known_Static_Component_Size (Ptyp)
-                 and then Component_Size (Ptyp) <= 64
-               then
-                  return False;
-
-               --  Otherwise, we need to test the prefix, to see if we are
-               --  indexing from a possibly unaligned component.
-
-               else
-                  return Possible_Bit_Aligned_Component (P);
-               end if;
-            end;
-
-         --  Case of selected component
-
-         when N_Selected_Component =>
-            declare
-               P    : constant Node_Id   := Prefix (N);
-               Comp : constant Entity_Id := Entity (Selector_Name (N));
-
-            begin
-               --  If there is no component clause, then we are in the clear
-               --  since the back end will never misalign a large component
-               --  unless it is forced to do so. In the clear means we need
-               --  only the recursive test on the prefix.
-
-               if Component_May_Be_Bit_Aligned (Comp) then
-                  return True;
-               else
-                  return Possible_Bit_Aligned_Component (P);
-               end if;
-            end;
-
-         --  If we have neither a record nor array component, it means that
-         --  we have fallen off the top testing prefixes recursively, and
-         --  we now have a stand alone object, where we don't have a problem
-
-         when others =>
-            return False;
-
-      end case;
-   end Possible_Bit_Aligned_Component;
-
 end Exp_Ch5;