OSDN Git Service

2007-04-20 Ed Schonberg <schonberg@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / sem_ch13.adb
index e620044..e6925f3 100644 (file)
@@ -1,12 +1,12 @@
 ------------------------------------------------------------------------------
---                   c                                                       --
+--                                                                          --
 --                         GNAT COMPILER COMPONENTS                         --
 --                                                                          --
 --                             S E M _ C H 1 3                              --
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 1992-2004, Free Software Foundation, Inc.         --
+--          Copyright (C) 1992-2006, 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- --
@@ -16,8 +16,8 @@
 -- 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.                                                      --
+-- to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, --
+-- Boston, MA 02110-1301, USA.                                              --
 --                                                                          --
 -- GNAT was originally developed  by the GNAT team at  New York University. --
 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
@@ -43,6 +43,7 @@ with Sem_Eval; use Sem_Eval;
 with Sem_Res;  use Sem_Res;
 with Sem_Type; use Sem_Type;
 with Sem_Util; use Sem_Util;
+with Sem_Warn; use Sem_Warn;
 with Snames;   use Snames;
 with Stand;    use Stand;
 with Sinfo;    use Sinfo;
@@ -92,19 +93,19 @@ package body Sem_Ch13 is
    --  the expression N is of the form of K'Address, then the entity that
    --  is associated with K is marked as volatile.
 
-   procedure New_Stream_Function
+   procedure New_Stream_Subprogram
      (N    : Node_Id;
       Ent  : Entity_Id;
       Subp : Entity_Id;
       Nam  : TSS_Name_Type);
-   --  Create a function renaming of a given stream attribute to the
-   --  designated subprogram and then in the tagged case, provide this as
-   --  a primitive operation, or in the non-tagged case make an appropriate
-   --  TSS entry. Used for Input. This is more properly an expansion activity
-   --  than just semantics, but the presence of user-defined stream functions
-   --  for limited types is a legality check, which is why this takes place
-   --  here rather than in exp_ch13, where it was previously. Nam indicates
-   --  the name of the TSS function to be generated.
+   --  Create a subprogram renaming of a given stream attribute to the
+   --  designated subprogram and then in the tagged case, provide this as a
+   --  primitive operation, or in the non-tagged case make an appropriate TSS
+   --  entry. This is more properly an expansion activity than just semantics,
+   --  but the presence of user-defined stream functions for limited types is a
+   --  legality check, which is why this takes place here rather than in
+   --  exp_ch13, where it was previously. Nam indicates the name of the TSS
+   --  function to be generated.
    --
    --  To avoid elaboration anomalies with freeze nodes, for untagged types
    --  we generate both a subprogram declaration and a subprogram renaming
@@ -112,18 +113,6 @@ package body Sem_Ch13 is
    --  renaming_as_body. For tagged types, the specification is one of the
    --  primitive specs.
 
-   procedure New_Stream_Procedure
-     (N     : Node_Id;
-      Ent   : Entity_Id;
-      Subp  : Entity_Id;
-      Nam   : TSS_Name_Type;
-      Out_P : Boolean := False);
-   --  Create a procedure renaming of a given stream attribute to the
-   --  designated subprogram and then in the tagged case, provide this as
-   --  a primitive operation, or in the non-tagged case make an appropriate
-   --  TSS entry. Used for Read, Output, Write. Nam indicates the name of
-   --  the TSS procedure to be generated.
-
    ----------------------------------------------
    -- Table for Validate_Unchecked_Conversions --
    ----------------------------------------------
@@ -177,6 +166,265 @@ package body Sem_Ch13 is
       return Empty;
    end Address_Aliased_Entity;
 
+   -----------------------------------------
+   -- Adjust_Record_For_Reverse_Bit_Order --
+   -----------------------------------------
+
+   procedure Adjust_Record_For_Reverse_Bit_Order (R : Entity_Id) is
+      Max_Machine_Scalar_Size : constant Uint :=
+                                  UI_From_Int
+                                    (Standard_Long_Long_Integer_Size);
+      --  We use this as the maximum machine scalar size in the sense of AI-133
+
+      Num_CC : Natural;
+      Comp   : Entity_Id;
+      SSU    : constant Uint := UI_From_Int (System_Storage_Unit);
+
+   begin
+      --  This first loop through components does two things. First it deals
+      --  with the case of components with component clauses whose length is
+      --  greater than the maximum machine scalar size (either accepting them
+      --  or rejecting as needed). Second, it counts the number of components
+      --  with component clauses whose length does not exceed this maximum for
+      --  later processing.
+
+      Num_CC := 0;
+      Comp   := First_Component_Or_Discriminant (R);
+      while Present (Comp) loop
+         declare
+            CC    : constant Node_Id := Component_Clause (Comp);
+            Fbit  : constant Uint    := Static_Integer (First_Bit (CC));
+
+         begin
+            if Present (CC) then
+
+               --  Case of component with size > max machine scalar
+
+               if Esize (Comp) > Max_Machine_Scalar_Size then
+
+                  --  Must begin on byte boundary
+
+                  if Fbit mod SSU /= 0 then
+                     Error_Msg_N
+                       ("illegal first bit value for reverse bit order",
+                        First_Bit (CC));
+                     Error_Msg_Uint_1 := SSU;
+                     Error_Msg_Uint_2 := Max_Machine_Scalar_Size;
+
+                     Error_Msg_N
+                       ("\must be a multiple of ^ if size greater than ^",
+                        First_Bit (CC));
+
+                  --  Must end on byte boundary
+
+                  elsif Esize (Comp) mod SSU /= 0 then
+                     Error_Msg_N
+                       ("illegal last bit value for reverse bit order",
+                        Last_Bit (CC));
+                     Error_Msg_Uint_1 := SSU;
+                     Error_Msg_Uint_2 := Max_Machine_Scalar_Size;
+
+                     Error_Msg_N
+                       ("\must be a multiple of ^ if size greater than ^",
+                        Last_Bit (CC));
+
+                  --  OK, give warning if enabled
+
+                  elsif Warn_On_Reverse_Bit_Order then
+                     Error_Msg_N
+                       ("multi-byte field specified with non-standard"
+                        & " Bit_Order?", CC);
+
+                     if Bytes_Big_Endian then
+                        Error_Msg_N
+                          ("\bytes are not reversed "
+                           & "(component is big-endian)?", CC);
+                     else
+                        Error_Msg_N
+                          ("\bytes are not reversed "
+                           & "(component is little-endian)?", CC);
+                     end if;
+                  end if;
+
+               --  Case where size is not greater than max machine scalar.
+               --  For now, we just count these.
+
+               else
+                  Num_CC := Num_CC + 1;
+               end if;
+            end if;
+         end;
+
+         Next_Component_Or_Discriminant (Comp);
+      end loop;
+
+      --  We need to sort the component clauses on the basis of the Position
+      --  values in the clause, so we can group clauses with the same Position
+      --  together to determine the relevant machine scalar size.
+
+      declare
+         Comps : array (0 .. Num_CC) of Entity_Id;
+         --  Array to collect component and discrimninant entities. The data
+         --  starts at index 1, the 0'th entry is for GNAT.Heap_Sort_A.
+
+         function CP_Lt (Op1, Op2 : Natural) return Boolean;
+         --  Compare routine for Sort (See GNAT.Heap_Sort_A)
+
+         procedure CP_Move (From : Natural; To : Natural);
+         --  Move routine for Sort (see GNAT.Heap_Sort_A)
+
+         Start : Natural;
+         Stop  : Natural;
+         --  Start and stop positions in component list of set of components
+         --  with the same starting position (that constitute components in
+         --  a single machine scalar).
+
+         MaxL : Uint;
+         --  Maximum last bit value of any component in this set
+
+         MSS : Uint;
+         --  Corresponding machine scalar size
+
+         -----------
+         -- CP_Lt --
+         -----------
+
+         function CP_Lt (Op1, Op2 : Natural) return Boolean is
+         begin
+            return Position (Component_Clause (Comps (Op1))) <
+                   Position (Component_Clause (Comps (Op2)));
+         end CP_Lt;
+
+         -------------
+         -- CP_Move --
+         -------------
+
+         procedure CP_Move (From : Natural; To : Natural) is
+         begin
+            Comps (To) := Comps (From);
+         end CP_Move;
+
+      begin
+         --  Collect the component clauses
+
+         Num_CC := 0;
+         Comp   := First_Component_Or_Discriminant (R);
+         while Present (Comp) loop
+            if Present (Component_Clause (Comp))
+              and then Esize (Comp) <= Max_Machine_Scalar_Size
+            then
+               Num_CC := Num_CC + 1;
+               Comps (Num_CC) := Comp;
+            end if;
+
+            Next_Component_Or_Discriminant (Comp);
+         end loop;
+
+         --  Sort by ascending position number
+
+         Sort (Num_CC, CP_Move'Unrestricted_Access, CP_Lt'Unrestricted_Access);
+
+         --  We now have all the components whose size does not exceed the max
+         --  machine scalar value, sorted by starting position. In this loop
+         --  we gather groups of clauses starting at the same position, to
+         --  process them in accordance with Ada 2005 AI-133.
+
+         Stop := 0;
+         while Stop < Num_CC loop
+            Start := Stop + 1;
+            Stop  := Start;
+            MaxL  :=
+              Static_Integer (Last_Bit (Component_Clause (Comps (Start))));
+            while Stop < Num_CC loop
+               if Static_Integer
+                    (Position (Component_Clause (Comps (Stop + 1)))) =
+                  Static_Integer
+                    (Position (Component_Clause (Comps (Stop))))
+               then
+                  Stop := Stop + 1;
+                  MaxL :=
+                    UI_Max
+                      (MaxL,
+                       Static_Integer
+                         (Last_Bit (Component_Clause (Comps (Stop)))));
+               else
+                  exit;
+               end if;
+            end loop;
+
+            --  Now we have a group of component clauses from Start to Stop
+            --  whose positions are identical, and MaxL is the maximum last bit
+            --  value of any of these components.
+
+            --  We need to determine the corresponding machine scalar size.
+            --  This loop assumes that machine scalar sizes are even, and that
+            --  each possible machine scalar has twice as many bits as the
+            --  next smaller one.
+
+            MSS := Max_Machine_Scalar_Size;
+            while MSS mod 2 = 0
+              and then (MSS / 2) >= SSU
+              and then (MSS / 2) > MaxL
+            loop
+               MSS := MSS / 2;
+            end loop;
+
+            --  Here is where we fix up the Component_Bit_Offset value to
+            --  account for the reverse bit order. Some examples of what needs
+            --  to be done for the case of a machine scalar size of 8 are:
+
+            --    First_Bit .. Last_Bit     Component_Bit_Offset
+            --      old          new          old       new
+
+            --     0 .. 0       7 .. 7         0         7
+            --     0 .. 1       6 .. 7         0         6
+            --     0 .. 2       5 .. 7         0         5
+            --     0 .. 7       0 .. 7         0         4
+
+            --     1 .. 1       6 .. 6         1         6
+            --     1 .. 4       3 .. 6         1         3
+            --     4 .. 7       0 .. 3         4         0
+
+            --  The general rule is that the first bit is is obtained by
+            --  subtracting the old ending bit from machine scalar size - 1.
+
+            for C in Start .. Stop loop
+               declare
+                  Comp : constant Entity_Id := Comps (C);
+                  CC   : constant Node_Id   := Component_Clause (Comp);
+                  LB   : constant Uint := Static_Integer (Last_Bit (CC));
+                  NFB  : constant Uint := MSS - Uint_1 - LB;
+                  NLB  : constant Uint := NFB + Esize (Comp) - 1;
+                  Pos  : constant Uint := Static_Integer (Position (CC));
+
+               begin
+                  if Warn_On_Reverse_Bit_Order then
+                     Error_Msg_Uint_1 := MSS;
+                     Error_Msg_N
+                       ("?reverse bit order in machine " &
+                       "scalar of length^", First_Bit (CC));
+                     Error_Msg_Uint_1 := NFB;
+                     Error_Msg_Uint_2 := NLB;
+
+                     if Bytes_Big_Endian then
+                        Error_Msg_NE
+                          ("?\big-endian range for component & is ^ .. ^",
+                           First_Bit (CC), Comp);
+                     else
+                        Error_Msg_NE
+                          ("?\little-endian range for component & is ^ .. ^",
+                           First_Bit (CC), Comp);
+                     end if;
+                  end if;
+
+                  Set_Component_Bit_Offset (Comp, Pos * SSU + NFB);
+                  Set_Normalized_First_Bit (Comp, NFB mod SSU);
+               end;
+            end loop;
+         end loop;
+      end;
+   end Adjust_Record_For_Reverse_Bit_Order;
+
    --------------------------------------
    -- Alignment_Check_For_Esize_Change --
    --------------------------------------
@@ -244,6 +492,146 @@ package body Sem_Ch13 is
       --  disallow Storage_Size for derived task types, but that is also
       --  clearly unintentional.
 
+      procedure Analyze_Stream_TSS_Definition (TSS_Nam : TSS_Name_Type);
+      --  Common processing for 'Read, 'Write, 'Input and 'Output attribute
+      --  definition clauses.
+
+      procedure Analyze_Stream_TSS_Definition (TSS_Nam : TSS_Name_Type) is
+         Subp : Entity_Id := Empty;
+         I    : Interp_Index;
+         It   : Interp;
+         Pnam : Entity_Id;
+
+         Is_Read : constant Boolean := (TSS_Nam = TSS_Stream_Read);
+
+         function Has_Good_Profile (Subp : Entity_Id) return Boolean;
+         --  Return true if the entity is a subprogram with an appropriate
+         --  profile for the attribute being defined.
+
+         ----------------------
+         -- Has_Good_Profile --
+         ----------------------
+
+         function Has_Good_Profile (Subp : Entity_Id) return Boolean is
+            F              : Entity_Id;
+            Is_Function    : constant Boolean := (TSS_Nam = TSS_Stream_Input);
+            Expected_Ekind : constant array (Boolean) of Entity_Kind :=
+                               (False => E_Procedure, True => E_Function);
+            Typ            : Entity_Id;
+
+         begin
+            if Ekind (Subp) /= Expected_Ekind (Is_Function) then
+               return False;
+            end if;
+
+            F := First_Formal (Subp);
+
+            if No (F)
+              or else Ekind (Etype (F)) /= E_Anonymous_Access_Type
+              or else Designated_Type (Etype (F)) /=
+                               Class_Wide_Type (RTE (RE_Root_Stream_Type))
+            then
+               return False;
+            end if;
+
+            if not Is_Function then
+               Next_Formal (F);
+
+               declare
+                  Expected_Mode : constant array (Boolean) of Entity_Kind :=
+                                    (False => E_In_Parameter,
+                                     True  => E_Out_Parameter);
+               begin
+                  if Parameter_Mode (F) /= Expected_Mode (Is_Read) then
+                     return False;
+                  end if;
+               end;
+
+               Typ := Etype (F);
+
+            else
+               Typ := Etype (Subp);
+            end if;
+
+            return Base_Type (Typ) = Base_Type (Ent)
+              and then No (Next_Formal (F));
+
+         end Has_Good_Profile;
+
+      --  Start of processing for Analyze_Stream_TSS_Definition
+
+      begin
+         FOnly := True;
+
+         if not Is_Type (U_Ent) then
+            Error_Msg_N ("local name must be a subtype", Nam);
+            return;
+         end if;
+
+         Pnam := TSS (Base_Type (U_Ent), TSS_Nam);
+
+         --  If Pnam is present, it can be either inherited from an ancestor
+         --  type (in which case it is legal to redefine it for this type), or
+         --  be a previous definition of the attribute for the same type (in
+         --  which case it is illegal).
+
+         --  In the first case, it will have been analyzed already, and we
+         --  can check that its profile does not match the expected profile
+         --  for a stream attribute of U_Ent. In the second case, either Pnam
+         --  has been analyzed (and has the expected profile), or it has not
+         --  been analyzed yet (case of a type that has not been frozen yet
+         --  and for which the stream attribute has been set using Set_TSS).
+
+         if Present (Pnam)
+           and then (No (First_Entity (Pnam)) or else Has_Good_Profile (Pnam))
+         then
+            Error_Msg_Sloc := Sloc (Pnam);
+            Error_Msg_Name_1 := Attr;
+            Error_Msg_N ("% attribute already defined #", Nam);
+            return;
+         end if;
+
+         Analyze (Expr);
+
+         if Is_Entity_Name (Expr) then
+            if not Is_Overloaded (Expr) then
+               if Has_Good_Profile (Entity (Expr)) then
+                  Subp := Entity (Expr);
+               end if;
+
+            else
+               Get_First_Interp (Expr, I, It);
+
+               while Present (It.Nam) loop
+                  if Has_Good_Profile (It.Nam) then
+                     Subp := It.Nam;
+                     exit;
+                  end if;
+
+                  Get_Next_Interp (I, It);
+               end loop;
+            end if;
+         end if;
+
+         if Present (Subp) then
+            if Is_Abstract_Subprogram (Subp) then
+               Error_Msg_N ("stream subprogram must not be abstract", Expr);
+               return;
+            end if;
+
+            Set_Entity (Expr, Subp);
+            Set_Etype (Expr, Etype (Subp));
+
+            New_Stream_Subprogram (N, U_Ent, Subp, TSS_Nam);
+
+         else
+            Error_Msg_Name_1 := Attr;
+            Error_Msg_N ("incorrect expression for% attribute", Expr);
+         end if;
+      end Analyze_Stream_TSS_Definition;
+
+   --  Start of processing for Analyze_Attribute_Definition_Clause
+
    begin
       Analyze (Nam);
       Ent := Entity (Nam);
@@ -252,26 +640,26 @@ package body Sem_Ch13 is
          return;
       end if;
 
-      --  Rep clause applies to full view of incomplete type or private type
-      --  if we have one (if not, this is a premature use of the type).
-      --  However, certain semantic checks need to be done on the specified
-      --  entity (i.e. the private view), so we save it in Ent.
+      --  Rep clause applies to full view of incomplete type or private type if
+      --  we have one (if not, this is a premature use of the type). However,
+      --  certain semantic checks need to be done on the specified entity (i.e.
+      --  the private view), so we save it in Ent.
 
       if Is_Private_Type (Ent)
         and then Is_Derived_Type (Ent)
         and then not Is_Tagged_Type (Ent)
         and then No (Full_View (Ent))
       then
-         --  If this is a private type whose completion is a derivation
-         --  from another private type, there is no full view, and the
-         --  attribute belongs to the type itself, not its underlying parent.
+         --  If this is a private type whose completion is a derivation from
+         --  another private type, there is no full view, and the attribute
+         --  belongs to the type itself, not its underlying parent.
 
          U_Ent := Ent;
 
       elsif Ekind (Ent) = E_Incomplete_Type then
 
-         --  The attribute applies to the full view, set the entity
-         --  of the attribute definition accordingly.
+         --  The attribute applies to the full view, set the entity of the
+         --  attribute definition accordingly.
 
          Ent := Underlying_Type (Ent);
          U_Ent := Ent;
@@ -301,7 +689,6 @@ package body Sem_Ch13 is
       then
          Error_Msg_N ("cannot specify attribute for subtype", Nam);
          return;
-
       end if;
 
       --  Switch on particular attribute
@@ -452,7 +839,7 @@ package body Sem_Ch13 is
                   Mark_Aliased_Address_As_Volatile (Expr);
 
                   --  Second case is where we have a constant whose
-                  --  definition is of the form of an adress as in:
+                  --  definition is of the form of an address as in:
 
                   --     A : constant Address := K'Address;
                   --     ...
@@ -493,11 +880,14 @@ package body Sem_Ch13 is
                         Nam);
                   end if;
 
-                  --  Entity has delayed freeze, so we will generate
-                  --  an alignment check at the freeze point.
+                  --  Entity has delayed freeze, so we will generate an
+                  --  alignment check at the freeze point unless suppressed.
 
-                  Set_Check_Address_Alignment
-                    (N, not Range_Checks_Suppressed (U_Ent));
+                  if not Range_Checks_Suppressed (U_Ent)
+                    and then not Alignment_Checks_Suppressed (U_Ent)
+                  then
+                     Set_Check_Address_Alignment (N);
+                  end if;
 
                   --  Kill the size check code, since we are not allocating
                   --  the variable, it is somewhere else.
@@ -669,94 +1059,9 @@ package body Sem_Ch13 is
          -- Input --
          -----------
 
-         when Attribute_Input => Input : declare
-            Subp : Entity_Id := Empty;
-            I    : Interp_Index;
-            It   : Interp;
-            Pnam : Entity_Id;
-
-            function Has_Good_Profile (Subp : Entity_Id) return Boolean;
-            --  Return true if the entity is a function with an appropriate
-            --  profile for the Input attribute.
-
-            ----------------------
-            -- Has_Good_Profile --
-            ----------------------
-
-            function Has_Good_Profile (Subp : Entity_Id) return Boolean is
-               F  : Entity_Id;
-               Ok : Boolean := False;
-
-            begin
-               if Ekind (Subp) = E_Function then
-                  F := First_Formal (Subp);
-
-                  if Present (F) and then No (Next_Formal (F)) then
-                     if Ekind (Etype (F)) = E_Anonymous_Access_Type
-                       and then
-                         Designated_Type (Etype (F)) =
-                           Class_Wide_Type (RTE (RE_Root_Stream_Type))
-                     then
-                        Ok := Base_Type (Etype (Subp)) = Base_Type (Ent);
-                     end if;
-                  end if;
-               end if;
-
-               return Ok;
-            end Has_Good_Profile;
-
-         --  Start of processing for Input attribute definition
-
-         begin
-            FOnly := True;
-
-            if not Is_Type (U_Ent) then
-               Error_Msg_N ("local name must be a subtype", Nam);
-               return;
-
-            else
-               Pnam := TSS (Base_Type (U_Ent), TSS_Stream_Input);
-
-               if Present (Pnam)
-                 and then Base_Type (Etype (Pnam)) = Base_Type (U_Ent)
-               then
-                  Error_Msg_Sloc := Sloc (Pnam);
-                  Error_Msg_N ("input attribute already defined #", Nam);
-                  return;
-               end if;
-            end if;
-
-            Analyze (Expr);
-
-            if Is_Entity_Name (Expr) then
-               if not Is_Overloaded (Expr) then
-                  if Has_Good_Profile (Entity (Expr)) then
-                     Subp := Entity (Expr);
-                  end if;
-
-               else
-                  Get_First_Interp (Expr, I, It);
-
-                  while Present (It.Nam) loop
-                     if Has_Good_Profile (It.Nam) then
-                        Subp := It.Nam;
-                        exit;
-                     end if;
-
-                     Get_Next_Interp (I, It);
-                  end loop;
-               end if;
-            end if;
-
-            if Present (Subp) then
-               Set_Entity (Expr, Subp);
-               Set_Etype (Expr, Etype (Subp));
-               New_Stream_Function (N, U_Ent, Subp,  TSS_Stream_Input);
-            else
-               Error_Msg_N ("incorrect expression for input attribute", Expr);
-               return;
-            end if;
-         end Input;
+         when Attribute_Input =>
+            Analyze_Stream_TSS_Definition (TSS_Stream_Input);
+            Set_Has_Specified_Stream_Input (Ent);
 
          -------------------
          -- Machine_Radix --
@@ -832,198 +1137,17 @@ package body Sem_Ch13 is
          -- Output --
          ------------
 
-         when Attribute_Output => Output : declare
-            Subp : Entity_Id := Empty;
-            I    : Interp_Index;
-            It   : Interp;
-            Pnam : Entity_Id;
-
-            function Has_Good_Profile (Subp : Entity_Id) return Boolean;
-            --  Return true if the entity is a procedure with an
-            --  appropriate profile for the output attribute.
-
-            ----------------------
-            -- Has_Good_Profile --
-            ----------------------
-
-            function Has_Good_Profile (Subp : Entity_Id) return Boolean is
-               F  : Entity_Id;
-               Ok : Boolean := False;
-
-            begin
-               if Ekind (Subp) = E_Procedure then
-                  F := First_Formal (Subp);
-
-                  if Present (F) then
-                     if Ekind (Etype (F)) = E_Anonymous_Access_Type
-                       and then
-                         Designated_Type (Etype (F)) =
-                           Class_Wide_Type (RTE (RE_Root_Stream_Type))
-                     then
-                        Next_Formal (F);
-                        Ok :=  Present (F)
-                          and then Parameter_Mode (F) = E_In_Parameter
-                          and then Base_Type (Etype (F)) = Base_Type (Ent)
-                          and then No (Next_Formal (F));
-                     end if;
-                  end if;
-               end if;
-
-               return Ok;
-            end Has_Good_Profile;
-
-         --  Start of processing for Output attribute definition
-
-         begin
-            FOnly := True;
-
-            if not Is_Type (U_Ent) then
-               Error_Msg_N ("local name must be a subtype", Nam);
-               return;
-
-            else
-               Pnam := TSS (Base_Type (U_Ent), TSS_Stream_Output);
-
-               if Present (Pnam)
-                 and then
-                   Base_Type (Etype (Next_Formal (First_Formal (Pnam))))
-                                                        = Base_Type (U_Ent)
-               then
-                  Error_Msg_Sloc := Sloc (Pnam);
-                  Error_Msg_N ("output attribute already defined #", Nam);
-                  return;
-               end if;
-            end if;
-
-            Analyze (Expr);
-
-            if Is_Entity_Name (Expr) then
-               if not Is_Overloaded (Expr) then
-                  if Has_Good_Profile (Entity (Expr)) then
-                     Subp := Entity (Expr);
-                  end if;
-
-               else
-                  Get_First_Interp (Expr, I, It);
-
-                  while Present (It.Nam) loop
-                     if Has_Good_Profile (It.Nam) then
-                        Subp := It.Nam;
-                        exit;
-                     end if;
-
-                     Get_Next_Interp (I, It);
-                  end loop;
-               end if;
-            end if;
-
-            if Present (Subp) then
-               Set_Entity (Expr, Subp);
-               Set_Etype (Expr, Etype (Subp));
-               New_Stream_Procedure (N, U_Ent, Subp, TSS_Stream_Output);
-            else
-               Error_Msg_N ("incorrect expression for output attribute", Expr);
-               return;
-            end if;
-         end Output;
+         when Attribute_Output =>
+            Analyze_Stream_TSS_Definition (TSS_Stream_Output);
+            Set_Has_Specified_Stream_Output (Ent);
 
          ----------
          -- Read --
          ----------
 
-         when Attribute_Read => Read : declare
-            Subp : Entity_Id := Empty;
-            I    : Interp_Index;
-            It   : Interp;
-            Pnam : Entity_Id;
-
-            function Has_Good_Profile (Subp : Entity_Id) return Boolean;
-            --  Return true if the entity is a procedure with an appropriate
-            --  profile for the Read attribute.
-
-            ----------------------
-            -- Has_Good_Profile --
-            ----------------------
-
-            function Has_Good_Profile (Subp : Entity_Id) return Boolean is
-               F     : Entity_Id;
-               Ok    : Boolean := False;
-
-            begin
-               if Ekind (Subp) = E_Procedure then
-                  F := First_Formal (Subp);
-
-                  if Present (F) then
-                     if Ekind (Etype (F)) = E_Anonymous_Access_Type
-                       and then
-                         Designated_Type (Etype (F)) =
-                           Class_Wide_Type (RTE (RE_Root_Stream_Type))
-                     then
-                        Next_Formal (F);
-                        Ok :=  Present (F)
-                          and then Parameter_Mode (F) = E_Out_Parameter
-                          and then Base_Type (Etype (F)) = Base_Type (Ent)
-                          and then No (Next_Formal (F));
-                     end if;
-                  end if;
-               end if;
-
-               return Ok;
-            end Has_Good_Profile;
-
-         --  Start of processing for Read attribute definition
-
-         begin
-            FOnly := True;
-
-            if not Is_Type (U_Ent) then
-               Error_Msg_N ("local name must be a subtype", Nam);
-               return;
-
-            else
-               Pnam := TSS (Base_Type (U_Ent), TSS_Stream_Read);
-
-               if Present (Pnam)
-                 and then Base_Type (Etype (Next_Formal (First_Formal (Pnam))))
-                   = Base_Type (U_Ent)
-               then
-                  Error_Msg_Sloc := Sloc (Pnam);
-                  Error_Msg_N ("read attribute already defined #", Nam);
-                  return;
-               end if;
-            end if;
-
-            Analyze (Expr);
-
-            if Is_Entity_Name (Expr) then
-               if not Is_Overloaded (Expr) then
-                  if Has_Good_Profile (Entity (Expr)) then
-                     Subp := Entity (Expr);
-                  end if;
-
-               else
-                  Get_First_Interp (Expr, I, It);
-
-                  while Present (It.Nam) loop
-                     if Has_Good_Profile (It.Nam) then
-                        Subp := It.Nam;
-                        exit;
-                     end if;
-
-                     Get_Next_Interp (I, It);
-                  end loop;
-               end if;
-            end if;
-
-            if Present (Subp) then
-               Set_Entity (Expr, Subp);
-               Set_Etype (Expr, Etype (Subp));
-               New_Stream_Procedure (N, U_Ent, Subp, TSS_Stream_Read, True);
-            else
-               Error_Msg_N ("incorrect expression for read attribute", Expr);
-               return;
-            end if;
-         end Read;
+         when Attribute_Read =>
+            Analyze_Stream_TSS_Definition (TSS_Stream_Read);
+            Set_Has_Specified_Stream_Read (Ent);
 
          ----------
          -- Size --
@@ -1061,12 +1185,12 @@ package body Sem_Ch13 is
                   Etyp := Etype (U_Ent);
                end if;
 
-               --  Check size, note that Gigi is in charge of checking
-               --  that the size of an array or record type is OK. Also
-               --  we do not check the size in the ordinary fixed-point
-               --  case, since it is too early to do so (there may be a
-               --  subsequent small clause that affects the size). We can
-               --  check the size if a small clause has already been given.
+               --  Check size, note that Gigi is in charge of checking that the
+               --  size of an array or record type is OK. Also we do not check
+               --  the size in the ordinary fixed-point case, since it is too
+               --  early to do so (there may be subsequent small clause that
+               --  affects the size). We can check the size if a small clause
+               --  has already been given.
 
                if not Is_Ordinary_Fixed_Point_Type (U_Ent)
                  or else Has_Small_Clause (U_Ent)
@@ -1080,9 +1204,9 @@ package body Sem_Ch13 is
                if Is_Type (U_Ent) then
                   Set_RM_Size (U_Ent, Size);
 
-                  --  For scalar types, increase Object_Size to power of 2,
-                  --  but not less than a storage unit in any case (i.e.,
-                  --  normally this means it will be byte addressable).
+                  --  For scalar types, increase Object_Size to power of 2, but
+                  --  not less than a storage unit in any case (i.e., normally
+                  --  this means it will be byte addressable).
 
                   if Is_Scalar_Type (U_Ent) then
                      if Size <= System_Storage_Unit then
@@ -1117,9 +1241,10 @@ package body Sem_Ch13 is
                         Size /= System_Storage_Unit * 8
                      then
                         Error_Msg_Uint_1 := UI_From_Int (System_Storage_Unit);
+                        Error_Msg_Uint_2 := Error_Msg_Uint_1 * 8;
                         Error_Msg_N
                           ("size for primitive object must be a power of 2"
-                            & " and at least ^", N);
+                            & " in the range ^-^", N);
                      end if;
                   end if;
 
@@ -1163,92 +1288,23 @@ package body Sem_Ch13 is
 
             if not Is_Ordinary_Fixed_Point_Type (U_Ent) then
                Error_Msg_N
-                 ("small requires an ordinary fixed point type", Nam);
-
-            elsif Has_Small_Clause (U_Ent) then
-               Error_Msg_N ("small already given for &", Nam);
-
-            elsif Small > Delta_Value (U_Ent) then
-               Error_Msg_N
-                 ("small value must not be greater then delta value", Nam);
-
-            else
-               Set_Small_Value (U_Ent, Small);
-               Set_Small_Value (Implicit_Base, Small);
-               Set_Has_Small_Clause (U_Ent);
-               Set_Has_Small_Clause (Implicit_Base);
-               Set_Has_Non_Standard_Rep (Implicit_Base);
-            end if;
-         end Small;
-
-         ------------------
-         -- Storage_Size --
-         ------------------
-
-         --  Storage_Size attribute definition clause
-
-         when Attribute_Storage_Size => Storage_Size : declare
-            Btype : constant Entity_Id := Base_Type (U_Ent);
-            Sprag : Node_Id;
-
-         begin
-            if Is_Task_Type (U_Ent) then
-               Check_Restriction (No_Obsolescent_Features, N);
-
-               if Warn_On_Obsolescent_Feature then
-                  Error_Msg_N
-                    ("storage size clause for task is an " &
-                     "obsolescent feature ('R'M 'J.9)?", N);
-                  Error_Msg_N
-                    ("\use Storage_Size pragma instead?", N);
-               end if;
-
-               FOnly := True;
-            end if;
-
-            if not Is_Access_Type (U_Ent)
-              and then Ekind (U_Ent) /= E_Task_Type
-            then
-               Error_Msg_N ("storage size cannot be given for &", Nam);
-
-            elsif Is_Access_Type (U_Ent) and Is_Derived_Type (U_Ent) then
-               Error_Msg_N
-                 ("storage size cannot be given for a derived access type",
-                  Nam);
-
-            elsif Has_Storage_Size_Clause (Btype) then
-               Error_Msg_N ("storage size already given for &", Nam);
-
-            else
-               Analyze_And_Resolve (Expr, Any_Integer);
-
-               if Is_Access_Type (U_Ent) then
-
-                  if Present (Associated_Storage_Pool (U_Ent)) then
-                     Error_Msg_N ("storage pool already given for &", Nam);
-                     return;
-                  end if;
-
-                  if Compile_Time_Known_Value (Expr)
-                    and then Expr_Value (Expr) = 0
-                  then
-                     Set_No_Pool_Assigned (Btype);
-                  end if;
+                 ("small requires an ordinary fixed point type", Nam);
 
-               else -- Is_Task_Type (U_Ent)
-                  Sprag := Get_Rep_Pragma (Btype, Name_Storage_Size);
+            elsif Has_Small_Clause (U_Ent) then
+               Error_Msg_N ("small already given for &", Nam);
 
-                  if Present (Sprag) then
-                     Error_Msg_Sloc := Sloc (Sprag);
-                     Error_Msg_N
-                       ("Storage_Size already specified#", Nam);
-                     return;
-                  end if;
-               end if;
+            elsif Small > Delta_Value (U_Ent) then
+               Error_Msg_N
+                 ("small value must not be greater then delta value", Nam);
 
-               Set_Has_Storage_Size_Clause (Btype);
+            else
+               Set_Small_Value (U_Ent, Small);
+               Set_Small_Value (Implicit_Base, Small);
+               Set_Has_Small_Clause (U_Ent);
+               Set_Has_Small_Clause (Implicit_Base);
+               Set_Has_Non_Standard_Rep (Implicit_Base);
             end if;
-         end Storage_Size;
+         end Small;
 
          ------------------
          -- Storage_Pool --
@@ -1261,11 +1317,17 @@ package body Sem_Ch13 is
             T    : Entity_Id;
 
          begin
-            if Ekind (U_Ent) /= E_Access_Type
+            if Ekind (U_Ent) = E_Access_Subprogram_Type then
+               Error_Msg_N
+                 ("storage pool cannot be given for access-to-subprogram type",
+                  Nam);
+               return;
+
+            elsif Ekind (U_Ent) /= E_Access_Type
               and then Ekind (U_Ent) /= E_General_Access_Type
             then
-               Error_Msg_N (
-                 "storage pool can only be given for access types", Nam);
+               Error_Msg_N
+                 ("storage pool can only be given for access types", Nam);
                return;
 
             elsif Is_Derived_Type (U_Ent) then
@@ -1364,6 +1426,113 @@ package body Sem_Ch13 is
             end if;
          end Storage_Pool;
 
+         ------------------
+         -- Storage_Size --
+         ------------------
+
+         --  Storage_Size attribute definition clause
+
+         when Attribute_Storage_Size => Storage_Size : declare
+            Btype : constant Entity_Id := Base_Type (U_Ent);
+            Sprag : Node_Id;
+
+         begin
+            if Is_Task_Type (U_Ent) then
+               Check_Restriction (No_Obsolescent_Features, N);
+
+               if Warn_On_Obsolescent_Feature then
+                  Error_Msg_N
+                    ("storage size clause for task is an " &
+                     "obsolescent feature ('R'M 'J.9)?", N);
+                  Error_Msg_N
+                    ("\use Storage_Size pragma instead?", N);
+               end if;
+
+               FOnly := True;
+            end if;
+
+            if not Is_Access_Type (U_Ent)
+              and then Ekind (U_Ent) /= E_Task_Type
+            then
+               Error_Msg_N ("storage size cannot be given for &", Nam);
+
+            elsif Is_Access_Type (U_Ent) and Is_Derived_Type (U_Ent) then
+               Error_Msg_N
+                 ("storage size cannot be given for a derived access type",
+                  Nam);
+
+            elsif Has_Storage_Size_Clause (Btype) then
+               Error_Msg_N ("storage size already given for &", Nam);
+
+            else
+               Analyze_And_Resolve (Expr, Any_Integer);
+
+               if Is_Access_Type (U_Ent) then
+                  if Present (Associated_Storage_Pool (U_Ent)) then
+                     Error_Msg_N ("storage pool already given for &", Nam);
+                     return;
+                  end if;
+
+                  if Compile_Time_Known_Value (Expr)
+                    and then Expr_Value (Expr) = 0
+                  then
+                     Set_No_Pool_Assigned (Btype);
+                  end if;
+
+               else -- Is_Task_Type (U_Ent)
+                  Sprag := Get_Rep_Pragma (Btype, Name_Storage_Size);
+
+                  if Present (Sprag) then
+                     Error_Msg_Sloc := Sloc (Sprag);
+                     Error_Msg_N
+                       ("Storage_Size already specified#", Nam);
+                     return;
+                  end if;
+               end if;
+
+               Set_Has_Storage_Size_Clause (Btype);
+            end if;
+         end Storage_Size;
+
+         -----------------
+         -- Stream_Size --
+         -----------------
+
+         when Attribute_Stream_Size => Stream_Size : declare
+            Size : constant Uint := Static_Integer (Expr);
+
+         begin
+            if Has_Stream_Size_Clause (U_Ent) then
+               Error_Msg_N ("Stream_Size already given for &", Nam);
+
+            elsif Is_Elementary_Type (U_Ent) then
+               if Size /= System_Storage_Unit
+                    and then
+                  Size /= System_Storage_Unit * 2
+                    and then
+                  Size /= System_Storage_Unit * 4
+                     and then
+                  Size /= System_Storage_Unit * 8
+               then
+                  Error_Msg_Uint_1 := UI_From_Int (System_Storage_Unit);
+                  Error_Msg_N
+                    ("stream size for elementary type must be a"
+                       & " power of 2 and at least ^", N);
+
+               elsif RM_Size (U_Ent) > Size then
+                  Error_Msg_Uint_1 := RM_Size (U_Ent);
+                  Error_Msg_N
+                    ("stream size for elementary type must be a"
+                       & " power of 2 and at least ^", N);
+               end if;
+
+               Set_Has_Stream_Size_Clause (U_Ent);
+
+            else
+               Error_Msg_N ("Stream_Size cannot be given for &", Nam);
+            end if;
+         end Stream_Size;
+
          ----------------
          -- Value_Size --
          ----------------
@@ -1384,6 +1553,12 @@ package body Sem_Ch13 is
             then
                Error_Msg_N ("Value_Size already given for &", Nam);
 
+            elsif Is_Array_Type (U_Ent)
+              and then not Is_Constrained (U_Ent)
+            then
+               Error_Msg_N
+                 ("Value_Size cannot be given for unconstrained array", Nam);
+
             else
                if Is_Elementary_Type (U_Ent) then
                   Check_Size (Expr, U_Ent, Size, Biased);
@@ -1398,108 +1573,15 @@ package body Sem_Ch13 is
          -- Write --
          -----------
 
-         --  Write attribute definition clause
-         --  check for class-wide case will be performed later
-
-         when Attribute_Write => Write : declare
-            Subp : Entity_Id := Empty;
-            I    : Interp_Index;
-            It   : Interp;
-            Pnam : Entity_Id;
-
-            function Has_Good_Profile (Subp : Entity_Id) return Boolean;
-            --  Return true if the entity is a procedure with an
-            --  appropriate profile for the write attribute.
-
-            ----------------------
-            -- Has_Good_Profile --
-            ----------------------
-
-            function Has_Good_Profile (Subp : Entity_Id) return Boolean is
-               F     : Entity_Id;
-               Ok    : Boolean := False;
-
-            begin
-               if Ekind (Subp) = E_Procedure then
-                  F := First_Formal (Subp);
-
-                  if Present (F) then
-                     if Ekind (Etype (F)) = E_Anonymous_Access_Type
-                       and then
-                         Designated_Type (Etype (F)) =
-                           Class_Wide_Type (RTE (RE_Root_Stream_Type))
-                     then
-                        Next_Formal (F);
-                        Ok :=  Present (F)
-                          and then Parameter_Mode (F) = E_In_Parameter
-                          and then Base_Type (Etype (F)) = Base_Type (Ent)
-                          and then No (Next_Formal (F));
-                     end if;
-                  end if;
-               end if;
-
-               return Ok;
-            end Has_Good_Profile;
-
-         --  Start of processing for Write attribute definition
-
-         begin
-            FOnly := True;
-
-            if not Is_Type (U_Ent) then
-               Error_Msg_N ("local name must be a subtype", Nam);
-               return;
-            end if;
-
-            Pnam := TSS (Base_Type (U_Ent), TSS_Stream_Write);
-
-            if Present (Pnam)
-              and then Base_Type (Etype (Next_Formal (First_Formal (Pnam))))
-                = Base_Type (U_Ent)
-            then
-               Error_Msg_Sloc := Sloc (Pnam);
-               Error_Msg_N ("write attribute already defined #", Nam);
-               return;
-            end if;
-
-            Analyze (Expr);
-
-            if Is_Entity_Name (Expr) then
-               if not Is_Overloaded (Expr) then
-                  if Has_Good_Profile (Entity (Expr)) then
-                     Subp := Entity (Expr);
-                  end if;
-
-               else
-                  Get_First_Interp (Expr, I, It);
-
-                  while Present (It.Nam) loop
-                     if Has_Good_Profile (It.Nam) then
-                        Subp := It.Nam;
-                        exit;
-                     end if;
-
-                     Get_Next_Interp (I, It);
-                  end loop;
-               end if;
-            end if;
-
-            if Present (Subp) then
-               Set_Entity (Expr, Subp);
-               Set_Etype (Expr, Etype (Subp));
-               New_Stream_Procedure (N, U_Ent, Subp, TSS_Stream_Write);
-            else
-               Error_Msg_N ("incorrect expression for write attribute", Expr);
-               return;
-            end if;
-         end Write;
+         when Attribute_Write =>
+            Analyze_Stream_TSS_Definition (TSS_Stream_Write);
+            Set_Has_Specified_Stream_Write (Ent);
 
          --  All other attributes cannot be set
 
          when others =>
             Error_Msg_N
               ("attribute& cannot be set with definition clause", N);
-
       end case;
 
       --  The test for the type being frozen must be performed after
@@ -1538,6 +1620,8 @@ package body Sem_Ch13 is
          return;
       end if;
 
+      Check_Code_Statement (N);
+
       --  Make sure we appear in the handled statement sequence of a
       --  subprogram (RM 13.8(3)).
 
@@ -1669,14 +1753,23 @@ package body Sem_Ch13 is
          Error_Msg_N ("duplicate enumeration rep clause ignored", N);
          return;
 
-      --  Don't allow rep clause if root type is standard [wide_]character
+      --  Don't allow rep clause for standard [wide_[wide_]]character
 
       elsif Root_Type (Enumtype) = Standard_Character
         or else Root_Type (Enumtype) = Standard_Wide_Character
+        or else Root_Type (Enumtype) = Standard_Wide_Wide_Character
       then
          Error_Msg_N ("enumeration rep clause not allowed for this type", N);
          return;
 
+      --  Check that the expression is a proper aggregate (no parentheses)
+
+      elsif Paren_Count (Aggr) /= 0 then
+         Error_Msg
+           ("extra parentheses surrounding aggregate not allowed",
+            First_Sloc (Aggr));
+         return;
+
       --  All tests passed, so set rep clause in place
 
       else
@@ -1689,10 +1782,6 @@ package body Sem_Ch13 is
       --  normal expansion activities, and a number of special semantic
       --  rules apply (including the component type being any integer type)
 
-      --  Badent signals that we found some incorrect entries processing
-      --  the list. The final checks for completeness and ordering are
-      --  skipped in this case.
-
       Elit := First_Literal (Enumtype);
 
       --  First the positional entries if any
@@ -1707,9 +1796,12 @@ package body Sem_Ch13 is
 
             Val := Static_Integer (Expr);
 
+            --  Err signals that we found some incorrect entries processing
+            --  the list. The final checks for completeness and ordering are
+            --  skipped in this case.
+
             if Val = No_Uint then
                Err := True;
-
             elsif Val < Lo or else Hi < Val then
                Error_Msg_N ("value outside permitted range", Expr);
                Err := True;
@@ -1913,6 +2005,9 @@ package body Sem_Ch13 is
       Ccount : Natural := 0;
       --  Number of component clauses in record rep clause
 
+      CR_Pragma : Node_Id := Empty;
+      --  Points to N_Pragma node if Complete_Representation pragma present
+
    begin
       Find_Type (Ident);
       Rectype := Entity (Ident);
@@ -2007,17 +2102,10 @@ package body Sem_Ch13 is
       --  Clear any existing component clauses for the type (this happens
       --  with derived types, where we are now overriding the original)
 
-      Fent := First_Entity (Rectype);
-
-      Comp := Fent;
+      Comp := First_Component_Or_Discriminant (Rectype);
       while Present (Comp) loop
-         if Ekind (Comp) = E_Component
-           or else Ekind (Comp) = E_Discriminant
-         then
-            Set_Component_Clause (Comp, Empty);
-         end if;
-
-         Next_Entity (Comp);
+         Set_Component_Clause (Comp, Empty);
+         Next_Component_Or_Discriminant (Comp);
       end loop;
 
       --  All done if no component clauses
@@ -2032,6 +2120,8 @@ package body Sem_Ch13 is
       --  it at the start of the record (otherwise gigi may place it after
       --  other fields that have rep clauses).
 
+      Fent := First_Entity (Rectype);
+
       if Nkind (Fent) = N_Defining_Identifier
         and then Chars (Fent) = Name_uTag
       then
@@ -2075,11 +2165,17 @@ package body Sem_Ch13 is
 
       while Present (CC) loop
 
-         --  If pragma, just analyze it
+         --  Pragma
 
          if Nkind (CC) = N_Pragma then
             Analyze (CC);
 
+            --  The only pragma of interest is Complete_Representation
+
+            if Chars (CC) = Name_Complete_Representation then
+               CR_Pragma := CC;
+            end if;
+
          --  Processing for real component clause
 
          else
@@ -2448,23 +2544,32 @@ package body Sem_Ch13 is
       then
          --  Nothing to do if at least one component with no component clause
 
-         Comp := First_Entity (Rectype);
+         Comp := First_Component_Or_Discriminant (Rectype);
          while Present (Comp) loop
-            if Ekind (Comp) = E_Component
-              or else Ekind (Comp) = E_Discriminant
-            then
-               if No (Component_Clause (Comp)) then
-                  return;
-               end if;
-            end if;
-
-            Next_Entity (Comp);
+            exit when No (Component_Clause (Comp));
+            Next_Component_Or_Discriminant (Comp);
          end loop;
 
          --  If we fall out of loop, all components have component clauses
          --  and so we can set the size to the maximum value.
 
-         Set_RM_Size (Rectype, Hbit + 1);
+         if No (Comp) then
+            Set_RM_Size (Rectype, Hbit + 1);
+         end if;
+      end if;
+
+      --  Check missing components if Complete_Representation pragma appeared
+
+      if Present (CR_Pragma) then
+         Comp := First_Component_Or_Discriminant (Rectype);
+         while Present (Comp) loop
+            if No (Component_Clause (Comp)) then
+               Error_Msg_NE
+                 ("missing component clause for &", CR_Pragma, Comp);
+            end if;
+
+            Next_Component_Or_Discriminant (Comp);
+         end loop;
       end if;
    end Analyze_Record_Representation_Clause;
 
@@ -2753,7 +2858,6 @@ package body Sem_Ch13 is
                Check_Expr_Constants (Prefix (Nod));
 
             when N_Attribute_Reference =>
-
                if Attribute_Name (Nod) = Name_Address
                    or else
                   Attribute_Name (Nod) = Name_Access
@@ -2784,7 +2888,7 @@ package body Sem_Ch13 is
             when N_Null =>
                return;
 
-            when N_Binary_Op | N_And_Then | N_Or_Else | N_In | N_Not_In =>
+            when N_Binary_Op | N_And_Then | N_Or_Else | N_Membership_Test =>
                Check_Expr_Constants (Left_Opnd (Nod));
                Check_Expr_Constants (Right_Opnd (Nod));
 
@@ -3270,15 +3374,15 @@ package body Sem_Ch13 is
       return S;
    end Minimum_Size;
 
-   -------------------------
-   -- New_Stream_Function --
-   -------------------------
+   ---------------------------
+   -- New_Stream_Subprogram --
+   ---------------------------
 
-   procedure New_Stream_Function
-     (N    : Node_Id;
-      Ent  : Entity_Id;
-      Subp : Entity_Id;
-      Nam  : TSS_Name_Type)
+   procedure New_Stream_Subprogram
+     (N     : Node_Id;
+      Ent   : Entity_Id;
+      Subp  : Entity_Id;
+      Nam   : TSS_Name_Type)
    is
       Loc       : constant Source_Ptr := Sloc (N);
       Sname     : constant Name_Id    := Make_TSS_Name (Base_Type (Ent), Nam);
@@ -3287,6 +3391,14 @@ package body Sem_Ch13 is
       F         : Entity_Id;
       Etyp      : Entity_Id;
 
+      Defer_Declaration : constant Boolean :=
+                            Is_Tagged_Type (Ent) or else Is_Private_Type (Ent);
+      --  For a tagged type, there is a declaration for each stream attribute
+      --  at the freeze point, and we must generate only a completion of this
+      --  declaration. We do the same for private types, because the full view
+      --  might be tagged. Otherwise we generate a declaration at the point of
+      --  the attribute definition clause.
+
       function Build_Spec return Node_Id;
       --  Used for declaration and renaming declaration, so that this is
       --  treated as a renaming_as_body.
@@ -3296,130 +3408,101 @@ package body Sem_Ch13 is
       ----------------
 
       function Build_Spec return Node_Id is
+         Out_P   : constant Boolean := (Nam = TSS_Stream_Read);
+         Formals : List_Id;
+         Spec    : Node_Id;
+         T_Ref   : constant Node_Id := New_Reference_To (Etyp, Loc);
+
       begin
          Subp_Id := Make_Defining_Identifier (Loc, Sname);
 
-         return
-           Make_Function_Specification (Loc,
-             Defining_Unit_Name => Subp_Id,
-             Parameter_Specifications =>
-               New_List (
-                 Make_Parameter_Specification (Loc,
-                   Defining_Identifier =>
-                     Make_Defining_Identifier (Loc, Name_S),
-                   Parameter_Type =>
-                     Make_Access_Definition (Loc,
-                       Subtype_Mark =>
-                         New_Reference_To (
-                           Designated_Type (Etype (F)), Loc)))),
-
-             Subtype_Mark =>
-               New_Reference_To (Etyp, Loc));
-      end Build_Spec;
+         --  S : access Root_Stream_Type'Class
+
+         Formals := New_List (
+                      Make_Parameter_Specification (Loc,
+                        Defining_Identifier =>
+                          Make_Defining_Identifier (Loc, Name_S),
+                        Parameter_Type =>
+                          Make_Access_Definition (Loc,
+                            Subtype_Mark =>
+                              New_Reference_To (
+                                Designated_Type (Etype (F)), Loc))));
+
+         if Nam = TSS_Stream_Input then
+            Spec := Make_Function_Specification (Loc,
+                      Defining_Unit_Name       => Subp_Id,
+                      Parameter_Specifications => Formals,
+                      Result_Definition        => T_Ref);
+         else
+            --  V : [out] T
 
-   --  Start of processing for New_Stream_Function
+            Append_To (Formals,
+              Make_Parameter_Specification (Loc,
+                Defining_Identifier => Make_Defining_Identifier (Loc, Name_V),
+                Out_Present         => Out_P,
+                Parameter_Type      => T_Ref));
 
-   begin
-      F    := First_Formal (Subp);
-      Etyp := Etype (Subp);
+            Spec := Make_Procedure_Specification (Loc,
+                      Defining_Unit_Name       => Subp_Id,
+                      Parameter_Specifications => Formals);
+         end if;
 
-      if not Is_Tagged_Type (Ent) then
-         Subp_Decl :=
-           Make_Subprogram_Declaration (Loc,
-             Specification => Build_Spec);
-         Insert_Action (N, Subp_Decl);
-      end if;
+         return Spec;
+      end Build_Spec;
 
-      Subp_Decl :=
-        Make_Subprogram_Renaming_Declaration (Loc,
-          Specification => Build_Spec,
-          Name => New_Reference_To (Subp, Loc));
+   --  Start of processing for New_Stream_Subprogram
 
-      if Is_Tagged_Type (Ent) and then not Is_Limited_Type (Ent) then
-         Set_TSS (Base_Type (Ent), Subp_Id);
+   begin
+      F := First_Formal (Subp);
+
+      if Ekind (Subp) = E_Procedure then
+         Etyp := Etype (Next_Formal (F));
       else
-         Insert_Action (N, Subp_Decl);
-         Copy_TSS (Subp_Id, Base_Type (Ent));
+         Etyp := Etype (Subp);
       end if;
-   end New_Stream_Function;
-
-   --------------------------
-   -- New_Stream_Procedure --
-   --------------------------
-
-   procedure New_Stream_Procedure
-     (N     : Node_Id;
-      Ent   : Entity_Id;
-      Subp  : Entity_Id;
-      Nam   : TSS_Name_Type;
-      Out_P : Boolean := False)
-   is
-      Loc       : constant Source_Ptr := Sloc (N);
-      Sname     : constant Name_Id    := Make_TSS_Name (Base_Type (Ent), Nam);
-      Subp_Id   : Entity_Id;
-      Subp_Decl : Node_Id;
-      F         : Entity_Id;
-      Etyp      : Entity_Id;
-
-      function Build_Spec return Node_Id;
-      --  Used for declaration and renaming declaration, so that this is
-      --  treated as a renaming_as_body.
-
-      ----------------
-      -- Build_Spec --
-      ----------------
-
-      function Build_Spec return Node_Id is
-      begin
-         Subp_Id := Make_Defining_Identifier (Loc, Sname);
-
-         return
-           Make_Procedure_Specification (Loc,
-             Defining_Unit_Name => Subp_Id,
-             Parameter_Specifications =>
-               New_List (
-                 Make_Parameter_Specification (Loc,
-                   Defining_Identifier =>
-                     Make_Defining_Identifier (Loc, Name_S),
-                   Parameter_Type =>
-                     Make_Access_Definition (Loc,
-                       Subtype_Mark =>
-                         New_Reference_To (
-                           Designated_Type (Etype (F)), Loc))),
-
-                 Make_Parameter_Specification (Loc,
-                   Defining_Identifier =>
-                     Make_Defining_Identifier (Loc, Name_V),
-                   Out_Present => Out_P,
-                   Parameter_Type =>
-                     New_Reference_To (Etyp, Loc))));
-      end Build_Spec;
 
-      --  Start of processing for New_Stream_Procedure
+      --  Prepare subprogram declaration and insert it as an action on the
+      --  clause node. The visibility for this entity is used to test for
+      --  visibility of the attribute definition clause (in the sense of
+      --  8.3(23) as amended by AI-195).
 
-   begin
-      F        := First_Formal (Subp);
-      Etyp     := Etype (Next_Formal (F));
-
-      if not Is_Tagged_Type (Ent) then
+      if not Defer_Declaration then
          Subp_Decl :=
            Make_Subprogram_Declaration (Loc,
              Specification => Build_Spec);
-         Insert_Action (N, Subp_Decl);
+
+      --  For a tagged type, there is always a visible declaration for each
+      --  stream TSS (it is a predefined primitive operation), and the for the
+      --  completion of this declaration occurs at the freeze point, which is
+      --  not always visible at places where the attribute definition clause is
+      --  visible. So, we create a dummy entity here for the purpose of
+      --  tracking the visibility of the attribute definition clause itself.
+
+      else
+         Subp_Id :=
+           Make_Defining_Identifier (Loc,
+             Chars => New_External_Name (Sname, 'V'));
+         Subp_Decl :=
+           Make_Object_Declaration (Loc,
+             Defining_Identifier => Subp_Id,
+             Object_Definition   => New_Occurrence_Of (Standard_Boolean, Loc));
       end if;
 
+      Insert_Action (N, Subp_Decl);
+      Set_Entity (N, Subp_Id);
+
       Subp_Decl :=
         Make_Subprogram_Renaming_Declaration (Loc,
           Specification => Build_Spec,
           Name => New_Reference_To (Subp, Loc));
 
-      if Is_Tagged_Type (Ent) and then not Is_Limited_Type (Ent) then
+      if Defer_Declaration then
          Set_TSS (Base_Type (Ent), Subp_Id);
       else
          Insert_Action (N, Subp_Decl);
          Copy_TSS (Subp_Id, Base_Type (Ent));
       end if;
-   end New_Stream_Procedure;
+   end New_Stream_Subprogram;
 
    ------------------------
    -- Rep_Item_Too_Early --
@@ -3427,8 +3510,7 @@ package body Sem_Ch13 is
 
    function Rep_Item_Too_Early (T : Entity_Id; N : Node_Id) return Boolean is
    begin
-      --  Cannot apply rep items that are not operational items
-      --  to generic types
+      --  Cannot apply non-operational rep items to generic types
 
       if Is_Operational_Item (N) then
          return False;
@@ -3508,7 +3590,7 @@ package body Sem_Ch13 is
 
          if Present (Freeze_Node (S)) then
             Error_Msg_NE
-              ("?no more representation items for }!", Freeze_Node (S), S);
+              ("?no more representation items for }", Freeze_Node (S), S);
          end if;
 
          return True;