File : exp_strm.adb


   1 ------------------------------------------------------------------------------
   2 --                                                                          --
   3 --                         GNAT COMPILER COMPONENTS                         --
   4 --                                                                          --
   5 --                             E X P _ S T R M                              --
   6 --                                                                          --
   7 --                                 B o d y                                  --
   8 --                                                                          --
   9 --          Copyright (C) 1992-2015, Free Software Foundation, Inc.         --
  10 --                                                                          --
  11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  12 -- terms of the  GNU General Public License as published  by the Free Soft- --
  13 -- ware  Foundation;  either version 3,  or (at your option) any later ver- --
  14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  16 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
  17 -- for  more details.  You should have  received  a copy of the GNU General --
  18 -- Public License  distributed with GNAT; see file COPYING3.  If not, go to --
  19 -- http://www.gnu.org/licenses for a complete copy of the license.          --
  20 --                                                                          --
  21 -- GNAT was originally developed  by the GNAT team at  New York University. --
  22 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
  23 --                                                                          --
  24 ------------------------------------------------------------------------------
  25 
  26 with Atree;    use Atree;
  27 with Einfo;    use Einfo;
  28 with Elists;   use Elists;
  29 with Exp_Util; use Exp_Util;
  30 with Namet;    use Namet;
  31 with Nlists;   use Nlists;
  32 with Nmake;    use Nmake;
  33 with Rtsfind;  use Rtsfind;
  34 with Sem_Aux;  use Sem_Aux;
  35 with Sem_Util; use Sem_Util;
  36 with Sinfo;    use Sinfo;
  37 with Snames;   use Snames;
  38 with Stand;    use Stand;
  39 with Tbuild;   use Tbuild;
  40 with Ttypes;   use Ttypes;
  41 with Uintp;    use Uintp;
  42 
  43 package body Exp_Strm is
  44 
  45    -----------------------
  46    -- Local Subprograms --
  47    -----------------------
  48 
  49    procedure Build_Array_Read_Write_Procedure
  50      (Nod  : Node_Id;
  51       Typ  : Entity_Id;
  52       Decl : out Node_Id;
  53       Pnam : Entity_Id;
  54       Nam  : Name_Id);
  55    --  Common routine shared to build either an array Read procedure or an
  56    --  array Write procedure, Nam is Name_Read or Name_Write to select which.
  57    --  Pnam is the defining identifier for the constructed procedure. The
  58    --  other parameters are as for Build_Array_Read_Procedure except that
  59    --  the first parameter Nod supplies the Sloc to be used to generate code.
  60 
  61    procedure Build_Record_Read_Write_Procedure
  62      (Loc  : Source_Ptr;
  63       Typ  : Entity_Id;
  64       Decl : out Node_Id;
  65       Pnam : Entity_Id;
  66       Nam  : Name_Id);
  67    --  Common routine shared to build a record Read Write procedure, Nam
  68    --  is Name_Read or Name_Write to select which. Pnam is the defining
  69    --  identifier for the constructed procedure. The other parameters are
  70    --  as for Build_Record_Read_Procedure.
  71 
  72    procedure Build_Stream_Function
  73      (Loc   : Source_Ptr;
  74       Typ   : Entity_Id;
  75       Decl  : out Node_Id;
  76       Fnam  : Entity_Id;
  77       Decls : List_Id;
  78       Stms  : List_Id);
  79    --  Called to build an array or record stream function. The first three
  80    --  arguments are the same as Build_Record_Or_Elementary_Input_Function.
  81    --  Decls and Stms are the declarations and statements for the body and
  82    --  The parameter Fnam is the name of the constructed function.
  83 
  84    function Has_Stream_Standard_Rep (U_Type : Entity_Id) return Boolean;
  85    --  This function is used to test the type U_Type, to determine if it has
  86    --  a standard representation from a streaming point of view. Standard means
  87    --  that it has a standard representation (e.g. no enumeration rep clause),
  88    --  and the size of the root type is the same as the streaming size (which
  89    --  is defined as value specified by a Stream_Size clause if present, or
  90    --  the Esize of U_Type if not).
  91 
  92    function Make_Stream_Subprogram_Name
  93      (Loc : Source_Ptr;
  94       Typ : Entity_Id;
  95       Nam : TSS_Name_Type) return Entity_Id;
  96    --  Return the entity that identifies the stream subprogram for type Typ
  97    --  that is identified by the given Nam. This procedure deals with the
  98    --  difference between tagged types (where a single subprogram associated
  99    --  with the type is generated) and all other cases (where a subprogram
 100    --  is generated at the point of the stream attribute reference). The
 101    --  Loc parameter is used as the Sloc of the created entity.
 102 
 103    function Stream_Base_Type (E : Entity_Id) return Entity_Id;
 104    --  Stream attributes work on the basis of the base type except for the
 105    --  array case. For the array case, we do not go to the base type, but
 106    --  to the first subtype if it is constrained. This avoids problems with
 107    --  incorrect conversions in the packed array case. Stream_Base_Type is
 108    --  exactly this function (returns the base type, unless we have an array
 109    --  type whose first subtype is constrained, in which case it returns the
 110    --  first subtype).
 111 
 112    --------------------------------
 113    -- Build_Array_Input_Function --
 114    --------------------------------
 115 
 116    --  The function we build looks like
 117 
 118    --    function typSI[_nnn] (S : access RST) return Typ is
 119    --      L1 : constant Index_Type_1 := Index_Type_1'Input (S);
 120    --      H1 : constant Index_Type_1 := Index_Type_1'Input (S);
 121    --      L2 : constant Index_Type_2 := Index_Type_2'Input (S);
 122    --      H2 : constant Index_Type_2 := Index_Type_2'Input (S);
 123    --      ..
 124    --      Ln : constant Index_Type_n := Index_Type_n'Input (S);
 125    --      Hn : constant Index_Type_n := Index_Type_n'Input (S);
 126    --
 127    --      V : Typ'Base (L1 .. H1, L2 .. H2, ... Ln .. Hn)
 128 
 129    --    begin
 130    --      Typ'Read (S, V);
 131    --      return V;
 132    --    end typSI[_nnn]
 133 
 134    --  Note: the suffix [_nnn] is present for untagged types, where we generate
 135    --  a local subprogram at the point of the occurrence of the attribute
 136    --  reference, so the name must be unique.
 137 
 138    procedure Build_Array_Input_Function
 139      (Loc  : Source_Ptr;
 140       Typ  : Entity_Id;
 141       Decl : out Node_Id;
 142       Fnam : out Entity_Id)
 143    is
 144       Dim    : constant Pos := Number_Dimensions (Typ);
 145       Lnam   : Name_Id;
 146       Hnam   : Name_Id;
 147       Decls  : List_Id;
 148       Ranges : List_Id;
 149       Stms   : List_Id;
 150       Rstmt  : Node_Id;
 151       Indx   : Node_Id;
 152       Odecl  : Node_Id;
 153 
 154    begin
 155       Decls := New_List;
 156       Ranges := New_List;
 157       Indx  := First_Index (Typ);
 158       for J in 1 .. Dim loop
 159          Lnam := New_External_Name ('L', J);
 160          Hnam := New_External_Name ('H', J);
 161 
 162          Append_To (Decls,
 163            Make_Object_Declaration (Loc,
 164              Defining_Identifier => Make_Defining_Identifier (Loc, Lnam),
 165              Constant_Present    => True,
 166              Object_Definition   => New_Occurrence_Of (Etype (Indx), Loc),
 167              Expression =>
 168                Make_Attribute_Reference (Loc,
 169                  Prefix         =>
 170                    New_Occurrence_Of (Stream_Base_Type (Etype (Indx)), Loc),
 171                  Attribute_Name => Name_Input,
 172                  Expressions    => New_List (Make_Identifier (Loc, Name_S)))));
 173 
 174          Append_To (Decls,
 175            Make_Object_Declaration (Loc,
 176              Defining_Identifier => Make_Defining_Identifier (Loc, Hnam),
 177              Constant_Present    => True,
 178              Object_Definition   =>
 179                    New_Occurrence_Of (Stream_Base_Type (Etype (Indx)), Loc),
 180              Expression =>
 181                Make_Attribute_Reference (Loc,
 182                  Prefix         =>
 183                    New_Occurrence_Of (Stream_Base_Type (Etype (Indx)), Loc),
 184                  Attribute_Name => Name_Input,
 185                  Expressions    => New_List (Make_Identifier (Loc, Name_S)))));
 186 
 187          Append_To (Ranges,
 188            Make_Range (Loc,
 189              Low_Bound  => Make_Identifier (Loc, Lnam),
 190              High_Bound => Make_Identifier (Loc, Hnam)));
 191 
 192          Next_Index (Indx);
 193       end loop;
 194 
 195       --  If the type is constrained, use it directly. Otherwise build a
 196       --  subtype indication with the proper bounds.
 197 
 198       if Is_Constrained (Typ) then
 199          Odecl :=
 200            Make_Object_Declaration (Loc,
 201              Defining_Identifier => Make_Defining_Identifier (Loc, Name_V),
 202              Object_Definition   => New_Occurrence_Of (Typ, Loc));
 203 
 204       else
 205          Odecl :=
 206            Make_Object_Declaration (Loc,
 207              Defining_Identifier => Make_Defining_Identifier (Loc, Name_V),
 208              Object_Definition   =>
 209                Make_Subtype_Indication (Loc,
 210                  Subtype_Mark =>
 211                    New_Occurrence_Of (Stream_Base_Type (Typ), Loc),
 212                  Constraint   =>
 213                    Make_Index_Or_Discriminant_Constraint (Loc, Ranges)));
 214       end if;
 215 
 216       Rstmt :=
 217         Make_Attribute_Reference (Loc,
 218           Prefix         => New_Occurrence_Of (Typ, Loc),
 219           Attribute_Name => Name_Read,
 220           Expressions    => New_List (
 221             Make_Identifier (Loc, Name_S),
 222             Make_Identifier (Loc, Name_V)));
 223 
 224       Stms := New_List (
 225          Make_Extended_Return_Statement (Loc,
 226            Return_Object_Declarations => New_List (Odecl),
 227            Handled_Statement_Sequence =>
 228              Make_Handled_Sequence_Of_Statements (Loc, New_List (Rstmt))));
 229 
 230       Fnam :=
 231         Make_Defining_Identifier (Loc,
 232           Chars => Make_TSS_Name_Local (Typ, TSS_Stream_Input));
 233 
 234       Build_Stream_Function (Loc, Typ, Decl, Fnam, Decls, Stms);
 235    end Build_Array_Input_Function;
 236 
 237    ----------------------------------
 238    -- Build_Array_Output_Procedure --
 239    ----------------------------------
 240 
 241    procedure Build_Array_Output_Procedure
 242      (Loc  : Source_Ptr;
 243       Typ  : Entity_Id;
 244       Decl : out Node_Id;
 245       Pnam : out Entity_Id)
 246    is
 247       Stms : List_Id;
 248       Indx : Node_Id;
 249 
 250    begin
 251       --  Build series of statements to output bounds
 252 
 253       Indx := First_Index (Typ);
 254       Stms := New_List;
 255 
 256       for J in 1 .. Number_Dimensions (Typ) loop
 257          Append_To (Stms,
 258            Make_Attribute_Reference (Loc,
 259              Prefix         =>
 260                New_Occurrence_Of (Stream_Base_Type (Etype (Indx)), Loc),
 261              Attribute_Name => Name_Write,
 262              Expressions    => New_List (
 263                Make_Identifier (Loc, Name_S),
 264                Make_Attribute_Reference (Loc,
 265                  Prefix         => Make_Identifier (Loc, Name_V),
 266                  Attribute_Name => Name_First,
 267                  Expressions    => New_List (
 268                    Make_Integer_Literal (Loc, J))))));
 269 
 270          Append_To (Stms,
 271            Make_Attribute_Reference (Loc,
 272              Prefix         =>
 273                New_Occurrence_Of (Stream_Base_Type (Etype (Indx)), Loc),
 274              Attribute_Name => Name_Write,
 275              Expressions    => New_List (
 276                Make_Identifier (Loc, Name_S),
 277                Make_Attribute_Reference (Loc,
 278                  Prefix         => Make_Identifier (Loc, Name_V),
 279                  Attribute_Name => Name_Last,
 280                  Expressions    => New_List (
 281                    Make_Integer_Literal (Loc, J))))));
 282 
 283          Next_Index (Indx);
 284       end loop;
 285 
 286       --  Append Write attribute to write array elements
 287 
 288       Append_To (Stms,
 289         Make_Attribute_Reference (Loc,
 290           Prefix         => New_Occurrence_Of (Typ, Loc),
 291           Attribute_Name => Name_Write,
 292           Expressions => New_List (
 293             Make_Identifier (Loc, Name_S),
 294             Make_Identifier (Loc, Name_V))));
 295 
 296       Pnam :=
 297         Make_Defining_Identifier (Loc,
 298           Chars => Make_TSS_Name_Local (Typ, TSS_Stream_Output));
 299 
 300       Build_Stream_Procedure (Loc, Typ, Decl, Pnam, Stms, False);
 301    end Build_Array_Output_Procedure;
 302 
 303    --------------------------------
 304    -- Build_Array_Read_Procedure --
 305    --------------------------------
 306 
 307    procedure Build_Array_Read_Procedure
 308      (Nod  : Node_Id;
 309       Typ  : Entity_Id;
 310       Decl : out Node_Id;
 311       Pnam : out Entity_Id)
 312    is
 313       Loc : constant Source_Ptr := Sloc (Nod);
 314 
 315    begin
 316       Pnam :=
 317         Make_Defining_Identifier (Loc,
 318           Chars => Make_TSS_Name_Local (Typ, TSS_Stream_Read));
 319       Build_Array_Read_Write_Procedure (Nod, Typ, Decl, Pnam, Name_Read);
 320    end Build_Array_Read_Procedure;
 321 
 322    --------------------------------------
 323    -- Build_Array_Read_Write_Procedure --
 324    --------------------------------------
 325 
 326    --  The form of the array read/write procedure is as follows:
 327 
 328    --    procedure pnam (S : access RST, V : [out] Typ) is
 329    --    begin
 330    --       for L1 in V'Range (1) loop
 331    --          for L2 in V'Range (2) loop
 332    --             ...
 333    --                for Ln in V'Range (n) loop
 334    --                   Component_Type'Read/Write (S, V (L1, L2, .. Ln));
 335    --                end loop;
 336    --             ..
 337    --          end loop;
 338    --       end loop
 339    --    end pnam;
 340 
 341    --  The out keyword for V is supplied in the Read case
 342 
 343    procedure Build_Array_Read_Write_Procedure
 344      (Nod  : Node_Id;
 345       Typ  : Entity_Id;
 346       Decl : out Node_Id;
 347       Pnam : Entity_Id;
 348       Nam  : Name_Id)
 349    is
 350       Loc  : constant Source_Ptr := Sloc (Nod);
 351       Ndim : constant Pos        := Number_Dimensions (Typ);
 352       Ctyp : constant Entity_Id  := Component_Type (Typ);
 353 
 354       Stm  : Node_Id;
 355       Exl  : List_Id;
 356       RW   : Entity_Id;
 357 
 358    begin
 359       --  First build the inner attribute call
 360 
 361       Exl := New_List;
 362 
 363       for J in 1 .. Ndim loop
 364          Append_To (Exl, Make_Identifier (Loc, New_External_Name ('L', J)));
 365       end loop;
 366 
 367       Stm :=
 368         Make_Attribute_Reference (Loc,
 369           Prefix => New_Occurrence_Of (Stream_Base_Type (Ctyp), Loc),
 370           Attribute_Name => Nam,
 371           Expressions => New_List (
 372             Make_Identifier (Loc, Name_S),
 373             Make_Indexed_Component (Loc,
 374               Prefix      => Make_Identifier (Loc, Name_V),
 375               Expressions => Exl)));
 376 
 377       --  The corresponding stream attribute for the component type of the
 378       --  array may be user-defined, and be frozen after the type for which
 379       --  we are generating the stream subprogram. In that case, freeze the
 380       --  stream attribute of the component type, whose declaration could not
 381       --  generate any additional freezing actions in any case.
 382 
 383       if Nam = Name_Read then
 384          RW := TSS (Base_Type (Ctyp), TSS_Stream_Read);
 385       else
 386          RW := TSS (Base_Type (Ctyp), TSS_Stream_Write);
 387       end if;
 388 
 389       if Present (RW)
 390         and then not Is_Frozen (RW)
 391       then
 392          Set_Is_Frozen (RW);
 393       end if;
 394 
 395       --  Now this is the big loop to wrap that statement up in a sequence
 396       --  of loops. The first time around, Stm is the attribute call. The
 397       --  second and subsequent times, Stm is an inner loop.
 398 
 399       for J in 1 .. Ndim loop
 400          Stm :=
 401            Make_Implicit_Loop_Statement (Nod,
 402              Iteration_Scheme =>
 403                Make_Iteration_Scheme (Loc,
 404                  Loop_Parameter_Specification =>
 405                    Make_Loop_Parameter_Specification (Loc,
 406                      Defining_Identifier =>
 407                        Make_Defining_Identifier (Loc,
 408                          Chars => New_External_Name ('L', Ndim - J + 1)),
 409 
 410                      Discrete_Subtype_Definition =>
 411                        Make_Attribute_Reference (Loc,
 412                          Prefix         => Make_Identifier (Loc, Name_V),
 413                          Attribute_Name => Name_Range,
 414 
 415                          Expressions => New_List (
 416                            Make_Integer_Literal (Loc, Ndim - J + 1))))),
 417 
 418              Statements => New_List (Stm));
 419 
 420       end loop;
 421 
 422       Build_Stream_Procedure
 423         (Loc, Typ, Decl, Pnam, New_List (Stm), Nam = Name_Read);
 424    end Build_Array_Read_Write_Procedure;
 425 
 426    ---------------------------------
 427    -- Build_Array_Write_Procedure --
 428    ---------------------------------
 429 
 430    procedure Build_Array_Write_Procedure
 431      (Nod  : Node_Id;
 432       Typ  : Entity_Id;
 433       Decl : out Node_Id;
 434       Pnam : out Entity_Id)
 435    is
 436       Loc : constant Source_Ptr := Sloc (Nod);
 437    begin
 438       Pnam :=
 439         Make_Defining_Identifier (Loc,
 440           Chars => Make_TSS_Name_Local (Typ, TSS_Stream_Write));
 441       Build_Array_Read_Write_Procedure (Nod, Typ, Decl, Pnam, Name_Write);
 442    end Build_Array_Write_Procedure;
 443 
 444    ---------------------------------
 445    -- Build_Elementary_Input_Call --
 446    ---------------------------------
 447 
 448    function Build_Elementary_Input_Call (N : Node_Id) return Node_Id is
 449       Loc     : constant Source_Ptr := Sloc (N);
 450       P_Type  : constant Entity_Id  := Entity (Prefix (N));
 451       U_Type  : constant Entity_Id  := Underlying_Type (P_Type);
 452       Rt_Type : constant Entity_Id  := Root_Type (U_Type);
 453       FST     : constant Entity_Id  := First_Subtype (U_Type);
 454       Strm    : constant Node_Id    := First (Expressions (N));
 455       Targ    : constant Node_Id    := Next (Strm);
 456       P_Size  : constant Uint       := Get_Stream_Size (FST);
 457       Res     : Node_Id;
 458       Lib_RE  : RE_Id;
 459 
 460    begin
 461 
 462       --  Check first for Boolean and Character. These are enumeration types,
 463       --  but we treat them specially, since they may require special handling
 464       --  in the transfer protocol. However, this special handling only applies
 465       --  if they have standard representation, otherwise they are treated like
 466       --  any other enumeration type.
 467 
 468       if Rt_Type = Standard_Boolean
 469         and then Has_Stream_Standard_Rep (U_Type)
 470       then
 471          Lib_RE := RE_I_B;
 472 
 473       elsif Rt_Type = Standard_Character
 474         and then Has_Stream_Standard_Rep (U_Type)
 475       then
 476          Lib_RE := RE_I_C;
 477 
 478       elsif Rt_Type = Standard_Wide_Character
 479         and then Has_Stream_Standard_Rep (U_Type)
 480       then
 481          Lib_RE := RE_I_WC;
 482 
 483       elsif Rt_Type = Standard_Wide_Wide_Character
 484         and then Has_Stream_Standard_Rep (U_Type)
 485       then
 486          Lib_RE := RE_I_WWC;
 487 
 488       --  Floating point types
 489 
 490       elsif Is_Floating_Point_Type (U_Type) then
 491 
 492          --  Question: should we use P_Size or Rt_Type to distinguish between
 493          --  possible floating point types? If a non-standard size or a stream
 494          --  size is specified, then we should certainly use the size. But if
 495          --  we have two types the same (notably Short_Float_Size = Float_Size
 496          --  which is close to universally true, and Long_Long_Float_Size =
 497          --  Long_Float_Size, true on most targets except the x86), then we
 498          --  would really rather use the root type, so that if people want to
 499          --  fiddle with System.Stream_Attributes to get inter-target portable
 500          --  streams, they get the size they expect. Consider in particular the
 501          --  case of a stream written on an x86, with 96-bit Long_Long_Float
 502          --  being read into a non-x86 target with 64 bit Long_Long_Float. A
 503          --  special version of System.Stream_Attributes can deal with this
 504          --  provided the proper type is always used.
 505 
 506          --  To deal with these two requirements we add the special checks
 507          --  on equal sizes and use the root type to distinguish.
 508 
 509          if P_Size <= Standard_Short_Float_Size
 510            and then (Standard_Short_Float_Size /= Standard_Float_Size
 511                      or else Rt_Type = Standard_Short_Float)
 512          then
 513             Lib_RE := RE_I_SF;
 514 
 515          elsif P_Size <= Standard_Float_Size then
 516             Lib_RE := RE_I_F;
 517 
 518          elsif P_Size <= Standard_Long_Float_Size
 519            and then (Standard_Long_Float_Size /= Standard_Long_Long_Float_Size
 520                        or else Rt_Type = Standard_Long_Float)
 521          then
 522             Lib_RE := RE_I_LF;
 523 
 524          else
 525             Lib_RE := RE_I_LLF;
 526          end if;
 527 
 528       --  Signed integer types. Also includes signed fixed-point types and
 529       --  enumeration types with a signed representation.
 530 
 531       --  Note on signed integer types. We do not consider types as signed for
 532       --  this purpose if they have no negative numbers, or if they have biased
 533       --  representation. The reason is that the value in either case basically
 534       --  represents an unsigned value.
 535 
 536       --  For example, consider:
 537 
 538       --     type W is range 0 .. 2**32 - 1;
 539       --     for W'Size use 32;
 540 
 541       --  This is a signed type, but the representation is unsigned, and may
 542       --  be outside the range of a 32-bit signed integer, so this must be
 543       --  treated as 32-bit unsigned.
 544 
 545       --  Similarly, if we have
 546 
 547       --     type W is range -1 .. +254;
 548       --     for W'Size use 8;
 549 
 550       --  then the representation is unsigned
 551 
 552       elsif not Is_Unsigned_Type (FST)
 553 
 554         --  The following set of tests gets repeated many times, we should
 555         --  have an abstraction defined ???
 556 
 557         and then
 558           (Is_Fixed_Point_Type (U_Type)
 559              or else
 560            Is_Enumeration_Type (U_Type)
 561              or else
 562            (Is_Signed_Integer_Type (U_Type)
 563               and then not Has_Biased_Representation (FST)))
 564 
 565       then
 566          if P_Size <= Standard_Short_Short_Integer_Size then
 567             Lib_RE := RE_I_SSI;
 568 
 569          elsif P_Size <= Standard_Short_Integer_Size then
 570             Lib_RE := RE_I_SI;
 571 
 572          elsif P_Size <= Standard_Integer_Size then
 573             Lib_RE := RE_I_I;
 574 
 575          elsif P_Size <= Standard_Long_Integer_Size then
 576             Lib_RE := RE_I_LI;
 577 
 578          else
 579             Lib_RE := RE_I_LLI;
 580          end if;
 581 
 582       --  Unsigned integer types, also includes unsigned fixed-point types
 583       --  and enumeration types with an unsigned representation (note that
 584       --  we know they are unsigned because we already tested for signed).
 585 
 586       --  Also includes signed integer types that are unsigned in the sense
 587       --  that they do not include negative numbers. See above for details.
 588 
 589       elsif Is_Modular_Integer_Type    (U_Type)
 590         or else Is_Fixed_Point_Type    (U_Type)
 591         or else Is_Enumeration_Type    (U_Type)
 592         or else Is_Signed_Integer_Type (U_Type)
 593       then
 594          if P_Size <= Standard_Short_Short_Integer_Size then
 595             Lib_RE := RE_I_SSU;
 596 
 597          elsif P_Size <= Standard_Short_Integer_Size then
 598             Lib_RE := RE_I_SU;
 599 
 600          elsif P_Size <= Standard_Integer_Size then
 601             Lib_RE := RE_I_U;
 602 
 603          elsif P_Size <= Standard_Long_Integer_Size then
 604             Lib_RE := RE_I_LU;
 605 
 606          else
 607             Lib_RE := RE_I_LLU;
 608          end if;
 609 
 610       else pragma Assert (Is_Access_Type (U_Type));
 611          if P_Size > System_Address_Size then
 612             Lib_RE := RE_I_AD;
 613          else
 614             Lib_RE := RE_I_AS;
 615          end if;
 616       end if;
 617 
 618       --  Call the function, and do an unchecked conversion of the result
 619       --  to the actual type of the prefix. If the target is a discriminant,
 620       --  and we are in the body of the default implementation of a 'Read
 621       --  attribute, set target type to force a constraint check (13.13.2(35)).
 622       --  If the type of the discriminant is currently private, add another
 623       --  unchecked conversion from the full view.
 624 
 625       if Nkind (Targ) = N_Identifier
 626         and then Is_Internal_Name (Chars (Targ))
 627         and then Is_TSS (Scope (Entity (Targ)), TSS_Stream_Read)
 628       then
 629          Res :=
 630            Unchecked_Convert_To (Base_Type (U_Type),
 631              Make_Function_Call (Loc,
 632                Name => New_Occurrence_Of (RTE (Lib_RE), Loc),
 633                Parameter_Associations => New_List (
 634                  Relocate_Node (Strm))));
 635 
 636          Set_Do_Range_Check (Res);
 637 
 638          if Base_Type (P_Type) /= Base_Type (U_Type) then
 639             Res := Unchecked_Convert_To (Base_Type (P_Type), Res);
 640          end if;
 641 
 642          return Res;
 643 
 644       else
 645          Res :=
 646            Make_Function_Call (Loc,
 647              Name => New_Occurrence_Of (RTE (Lib_RE), Loc),
 648              Parameter_Associations => New_List (
 649                Relocate_Node (Strm)));
 650 
 651          --  Now convert to the base type if we do not have a biased type. Note
 652          --  that we did not do this in some older versions, and the result was
 653          --  losing a required range check in the case where 'Input is being
 654          --  called from 'Read.
 655 
 656          if not Has_Biased_Representation (P_Type) then
 657             return Unchecked_Convert_To (Base_Type (P_Type), Res);
 658 
 659          --  For the biased case, the conversion to the base type loses the
 660          --  biasing, so just convert to Ptype. This is not quite right, and
 661          --  for example may lose a corner case CE test, but it is such a
 662          --  rare case that for now we ignore it ???
 663 
 664          else
 665             return Unchecked_Convert_To (P_Type, Res);
 666          end if;
 667       end if;
 668    end Build_Elementary_Input_Call;
 669 
 670    ---------------------------------
 671    -- Build_Elementary_Write_Call --
 672    ---------------------------------
 673 
 674    function Build_Elementary_Write_Call (N : Node_Id) return Node_Id is
 675       Loc     : constant Source_Ptr := Sloc (N);
 676       P_Type  : constant Entity_Id  := Entity (Prefix (N));
 677       U_Type  : constant Entity_Id  := Underlying_Type (P_Type);
 678       Rt_Type : constant Entity_Id  := Root_Type (U_Type);
 679       FST     : constant Entity_Id  := First_Subtype (U_Type);
 680       Strm    : constant Node_Id    := First (Expressions (N));
 681       Item    : constant Node_Id    := Next (Strm);
 682       P_Size  : Uint;
 683       Lib_RE  : RE_Id;
 684       Libent  : Entity_Id;
 685 
 686    begin
 687       --  Compute the size of the stream element. This is either the size of
 688       --  the first subtype or if given the size of the Stream_Size attribute.
 689 
 690       if Has_Stream_Size_Clause (FST) then
 691          P_Size := Static_Integer (Expression (Stream_Size_Clause (FST)));
 692       else
 693          P_Size := Esize (FST);
 694       end if;
 695 
 696       --  Find the routine to be called
 697 
 698       --  Check for First Boolean and Character. These are enumeration types,
 699       --  but we treat them specially, since they may require special handling
 700       --  in the transfer protocol. However, this special handling only applies
 701       --  if they have standard representation, otherwise they are treated like
 702       --  any other enumeration type.
 703 
 704       if Rt_Type = Standard_Boolean
 705         and then Has_Stream_Standard_Rep (U_Type)
 706       then
 707          Lib_RE := RE_W_B;
 708 
 709       elsif Rt_Type = Standard_Character
 710         and then Has_Stream_Standard_Rep (U_Type)
 711       then
 712          Lib_RE := RE_W_C;
 713 
 714       elsif Rt_Type = Standard_Wide_Character
 715         and then Has_Stream_Standard_Rep (U_Type)
 716       then
 717          Lib_RE := RE_W_WC;
 718 
 719       elsif Rt_Type = Standard_Wide_Wide_Character
 720         and then Has_Stream_Standard_Rep (U_Type)
 721       then
 722          Lib_RE := RE_W_WWC;
 723 
 724       --  Floating point types
 725 
 726       elsif Is_Floating_Point_Type (U_Type) then
 727 
 728          --  Question: should we use P_Size or Rt_Type to distinguish between
 729          --  possible floating point types? If a non-standard size or a stream
 730          --  size is specified, then we should certainly use the size. But if
 731          --  we have two types the same (notably Short_Float_Size = Float_Size
 732          --  which is close to universally true, and Long_Long_Float_Size =
 733          --  Long_Float_Size, true on most targets except the x86), then we
 734          --  would really rather use the root type, so that if people want to
 735          --  fiddle with System.Stream_Attributes to get inter-target portable
 736          --  streams, they get the size they expect. Consider in particular the
 737          --  case of a stream written on an x86, with 96-bit Long_Long_Float
 738          --  being read into a non-x86 target with 64 bit Long_Long_Float. A
 739          --  special version of System.Stream_Attributes can deal with this
 740          --  provided the proper type is always used.
 741 
 742          --  To deal with these two requirements we add the special checks
 743          --  on equal sizes and use the root type to distinguish.
 744 
 745          if P_Size <= Standard_Short_Float_Size
 746            and then (Standard_Short_Float_Size /= Standard_Float_Size
 747                       or else Rt_Type = Standard_Short_Float)
 748          then
 749             Lib_RE := RE_W_SF;
 750 
 751          elsif P_Size <= Standard_Float_Size then
 752             Lib_RE := RE_W_F;
 753 
 754          elsif P_Size <= Standard_Long_Float_Size
 755            and then (Standard_Long_Float_Size /= Standard_Long_Long_Float_Size
 756                       or else Rt_Type = Standard_Long_Float)
 757          then
 758             Lib_RE := RE_W_LF;
 759 
 760          else
 761             Lib_RE := RE_W_LLF;
 762          end if;
 763 
 764       --  Signed integer types. Also includes signed fixed-point types and
 765       --  signed enumeration types share this circuitry.
 766 
 767       --  Note on signed integer types. We do not consider types as signed for
 768       --  this purpose if they have no negative numbers, or if they have biased
 769       --  representation. The reason is that the value in either case basically
 770       --  represents an unsigned value.
 771 
 772       --  For example, consider:
 773 
 774       --     type W is range 0 .. 2**32 - 1;
 775       --     for W'Size use 32;
 776 
 777       --  This is a signed type, but the representation is unsigned, and may
 778       --  be outside the range of a 32-bit signed integer, so this must be
 779       --  treated as 32-bit unsigned.
 780 
 781       --  Similarly, the representation is also unsigned if we have:
 782 
 783       --     type W is range -1 .. +254;
 784       --     for W'Size use 8;
 785 
 786       --  forcing a biased and unsigned representation
 787 
 788       elsif not Is_Unsigned_Type (FST)
 789         and then
 790           (Is_Fixed_Point_Type (U_Type)
 791              or else
 792            Is_Enumeration_Type (U_Type)
 793              or else
 794            (Is_Signed_Integer_Type (U_Type)
 795               and then not Has_Biased_Representation (FST)))
 796       then
 797          if P_Size <= Standard_Short_Short_Integer_Size then
 798             Lib_RE := RE_W_SSI;
 799          elsif P_Size <= Standard_Short_Integer_Size then
 800             Lib_RE := RE_W_SI;
 801          elsif P_Size <= Standard_Integer_Size then
 802             Lib_RE := RE_W_I;
 803          elsif P_Size <= Standard_Long_Integer_Size then
 804             Lib_RE := RE_W_LI;
 805          else
 806             Lib_RE := RE_W_LLI;
 807          end if;
 808 
 809       --  Unsigned integer types, also includes unsigned fixed-point types
 810       --  and unsigned enumeration types (note we know they are unsigned
 811       --  because we already tested for signed above).
 812 
 813       --  Also includes signed integer types that are unsigned in the sense
 814       --  that they do not include negative numbers. See above for details.
 815 
 816       elsif Is_Modular_Integer_Type    (U_Type)
 817         or else Is_Fixed_Point_Type    (U_Type)
 818         or else Is_Enumeration_Type    (U_Type)
 819         or else Is_Signed_Integer_Type (U_Type)
 820       then
 821          if P_Size <= Standard_Short_Short_Integer_Size then
 822             Lib_RE := RE_W_SSU;
 823          elsif P_Size <= Standard_Short_Integer_Size then
 824             Lib_RE := RE_W_SU;
 825          elsif P_Size <= Standard_Integer_Size then
 826             Lib_RE := RE_W_U;
 827          elsif P_Size <= Standard_Long_Integer_Size then
 828             Lib_RE := RE_W_LU;
 829          else
 830             Lib_RE := RE_W_LLU;
 831          end if;
 832 
 833       else pragma Assert (Is_Access_Type (U_Type));
 834 
 835          if P_Size > System_Address_Size then
 836             Lib_RE := RE_W_AD;
 837          else
 838             Lib_RE := RE_W_AS;
 839          end if;
 840       end if;
 841 
 842       --  Unchecked-convert parameter to the required type (i.e. the type of
 843       --  the corresponding parameter, and call the appropriate routine.
 844 
 845       Libent := RTE (Lib_RE);
 846 
 847       return
 848         Make_Procedure_Call_Statement (Loc,
 849           Name => New_Occurrence_Of (Libent, Loc),
 850           Parameter_Associations => New_List (
 851             Relocate_Node (Strm),
 852             Unchecked_Convert_To (Etype (Next_Formal (First_Formal (Libent))),
 853               Relocate_Node (Item))));
 854    end Build_Elementary_Write_Call;
 855 
 856    -----------------------------------------
 857    -- Build_Mutable_Record_Read_Procedure --
 858    -----------------------------------------
 859 
 860    procedure Build_Mutable_Record_Read_Procedure
 861      (Loc  : Source_Ptr;
 862       Typ  : Entity_Id;
 863       Decl : out Node_Id;
 864       Pnam : out Entity_Id)
 865    is
 866       Out_Formal : Node_Id;
 867       --  Expression denoting the out formal parameter
 868 
 869       Dcls : constant List_Id := New_List;
 870       --  Declarations for the 'Read body
 871 
 872       Stms : constant List_Id := New_List;
 873       --  Statements for the 'Read body
 874 
 875       Disc : Entity_Id;
 876       --  Entity of the discriminant being processed
 877 
 878       Tmp_For_Disc : Entity_Id;
 879       --  Temporary object used to read the value of Disc
 880 
 881       Tmps_For_Discs : constant List_Id := New_List;
 882       --  List of object declarations for temporaries holding the read values
 883       --  for the discriminants.
 884 
 885       Cstr : constant List_Id := New_List;
 886       --  List of constraints to be applied on temporary record
 887 
 888       Discriminant_Checks : constant List_Id := New_List;
 889       --  List of discriminant checks to be performed if the actual object
 890       --  is constrained.
 891 
 892       Tmp : constant Entity_Id := Make_Defining_Identifier (Loc, Name_V);
 893       --  Temporary record must hide formal (assignments to components of the
 894       --  record are always generated with V as the identifier for the record).
 895 
 896       Constrained_Stms : List_Id := New_List;
 897       --  Statements within the block where we have the constrained temporary
 898 
 899    begin
 900       --  A mutable type cannot be a tagged type, so we generate a new name
 901       --  for the stream procedure.
 902 
 903       Pnam :=
 904         Make_Defining_Identifier (Loc,
 905           Chars => Make_TSS_Name_Local (Typ, TSS_Stream_Read));
 906 
 907       if Is_Unchecked_Union (Typ) then
 908 
 909          --  If this is an unchecked union, the stream procedure is erroneous,
 910          --  because there are no discriminants to read.
 911 
 912          --  This should generate a warning ???
 913 
 914          Append_To (Stms,
 915            Make_Raise_Program_Error (Loc,
 916              Reason => PE_Unchecked_Union_Restriction));
 917 
 918          Build_Stream_Procedure (Loc, Typ, Decl, Pnam, Stms, Outp => True);
 919          return;
 920       end if;
 921 
 922       Disc := First_Discriminant (Typ);
 923 
 924       Out_Formal :=
 925         Make_Selected_Component (Loc,
 926           Prefix        => New_Occurrence_Of (Pnam, Loc),
 927           Selector_Name => Make_Identifier (Loc, Name_V));
 928 
 929       --  Generate Reads for the discriminants of the type. The discriminants
 930       --  need to be read before the rest of the components, so that variants
 931       --  are initialized correctly. The discriminants must be read into temp
 932       --  variables so an incomplete Read (interrupted by an exception, for
 933       --  example) does not alter the passed object.
 934 
 935       while Present (Disc) loop
 936          Tmp_For_Disc := Make_Defining_Identifier (Loc,
 937                            New_External_Name (Chars (Disc), "D"));
 938 
 939          Append_To (Tmps_For_Discs,
 940            Make_Object_Declaration (Loc,
 941              Defining_Identifier => Tmp_For_Disc,
 942              Object_Definition   => New_Occurrence_Of (Etype (Disc), Loc)));
 943          Set_No_Initialization (Last (Tmps_For_Discs));
 944 
 945          Append_To (Stms,
 946            Make_Attribute_Reference (Loc,
 947              Prefix         => New_Occurrence_Of (Etype (Disc), Loc),
 948              Attribute_Name => Name_Read,
 949              Expressions    => New_List (
 950                Make_Identifier (Loc, Name_S),
 951                New_Occurrence_Of (Tmp_For_Disc, Loc))));
 952 
 953          Append_To (Cstr,
 954            Make_Discriminant_Association (Loc,
 955              Selector_Names => New_List (New_Occurrence_Of (Disc, Loc)),
 956              Expression     => New_Occurrence_Of (Tmp_For_Disc, Loc)));
 957 
 958          Append_To (Discriminant_Checks,
 959            Make_Raise_Constraint_Error (Loc,
 960              Condition =>
 961                Make_Op_Ne (Loc,
 962                  Left_Opnd  => New_Occurrence_Of (Tmp_For_Disc, Loc),
 963                  Right_Opnd =>
 964                    Make_Selected_Component (Loc,
 965                      Prefix        => New_Copy_Tree (Out_Formal),
 966                      Selector_Name => New_Occurrence_Of (Disc, Loc))),
 967              Reason => CE_Discriminant_Check_Failed));
 968          Next_Discriminant (Disc);
 969       end loop;
 970 
 971       --  Generate reads for the components of the record (including those
 972       --  that depend on discriminants).
 973 
 974       Build_Record_Read_Write_Procedure (Loc, Typ, Decl, Pnam, Name_Read);
 975 
 976       --  Save original statement sequence for component assignments, and
 977       --  replace it with Stms.
 978 
 979       Constrained_Stms := Statements (Handled_Statement_Sequence (Decl));
 980       Set_Handled_Statement_Sequence (Decl,
 981         Make_Handled_Sequence_Of_Statements (Loc,
 982           Statements => Stms));
 983 
 984       --  If Typ has controlled components (i.e. if it is classwide or
 985       --  Has_Controlled), or components constrained using the discriminants
 986       --  of Typ, then we need to ensure that all component assignments are
 987       --  performed on an object that has been appropriately constrained
 988       --  prior to being initialized. To this effect, we wrap the component
 989       --  assignments in a block where V is a constrained temporary.
 990 
 991       Append_To (Dcls,
 992         Make_Object_Declaration (Loc,
 993           Defining_Identifier => Tmp,
 994           Object_Definition   =>
 995             Make_Subtype_Indication (Loc,
 996               Subtype_Mark => New_Occurrence_Of (Base_Type (Typ), Loc),
 997               Constraint   =>
 998                 Make_Index_Or_Discriminant_Constraint (Loc,
 999                   Constraints => Cstr))));
1000 
1001       --  AI05-023-1: Insert discriminant check prior to initialization of the
1002       --  constrained temporary.
1003 
1004       Append_To (Stms,
1005         Make_Implicit_If_Statement (Pnam,
1006           Condition =>
1007             Make_Attribute_Reference (Loc,
1008               Prefix         => New_Copy_Tree (Out_Formal),
1009               Attribute_Name => Name_Constrained),
1010           Then_Statements => Discriminant_Checks));
1011 
1012       --  Now insert back original component assignments, wrapped in a block
1013       --  in which V is the constrained temporary.
1014 
1015       Append_To (Stms,
1016         Make_Block_Statement (Loc,
1017           Declarations               => Dcls,
1018           Handled_Statement_Sequence => Parent (Constrained_Stms)));
1019 
1020       Append_To (Constrained_Stms,
1021         Make_Assignment_Statement (Loc,
1022           Name       => Out_Formal,
1023           Expression => Make_Identifier (Loc, Name_V)));
1024 
1025       Set_Declarations (Decl, Tmps_For_Discs);
1026    end Build_Mutable_Record_Read_Procedure;
1027 
1028    ------------------------------------------
1029    -- Build_Mutable_Record_Write_Procedure --
1030    ------------------------------------------
1031 
1032    procedure Build_Mutable_Record_Write_Procedure
1033      (Loc  : Source_Ptr;
1034       Typ  : Entity_Id;
1035       Decl : out Node_Id;
1036       Pnam : out Entity_Id)
1037    is
1038       Stms  : List_Id;
1039       Disc  : Entity_Id;
1040       D_Ref : Node_Id;
1041 
1042    begin
1043       Stms := New_List;
1044       Disc := First_Discriminant (Typ);
1045 
1046       --  Generate Writes for the discriminants of the type
1047       --  If the type is an unchecked union, use the default values of
1048       --  the discriminants, because they are not stored.
1049 
1050       while Present (Disc) loop
1051          if Is_Unchecked_Union (Typ) then
1052             D_Ref :=
1053                New_Copy_Tree (Discriminant_Default_Value (Disc));
1054          else
1055             D_Ref :=
1056               Make_Selected_Component (Loc,
1057                 Prefix        => Make_Identifier (Loc, Name_V),
1058                 Selector_Name => New_Occurrence_Of (Disc, Loc));
1059          end if;
1060 
1061          Append_To (Stms,
1062            Make_Attribute_Reference (Loc,
1063              Prefix => New_Occurrence_Of (Etype (Disc), Loc),
1064                Attribute_Name => Name_Write,
1065                Expressions    => New_List (
1066                  Make_Identifier (Loc, Name_S),
1067                  D_Ref)));
1068 
1069          Next_Discriminant (Disc);
1070       end loop;
1071 
1072       --  A mutable type cannot be a tagged type, so we generate a new name
1073       --  for the stream procedure.
1074 
1075       Pnam :=
1076         Make_Defining_Identifier (Loc,
1077           Chars => Make_TSS_Name_Local (Typ, TSS_Stream_Write));
1078       Build_Record_Read_Write_Procedure (Loc, Typ, Decl, Pnam, Name_Write);
1079 
1080       --  Write the discriminants before the rest of the components, so
1081       --  that discriminant values are properly set of variants, etc.
1082 
1083       if Is_Non_Empty_List (
1084         Statements (Handled_Statement_Sequence (Decl)))
1085       then
1086          Insert_List_Before
1087             (First (Statements (Handled_Statement_Sequence (Decl))), Stms);
1088       else
1089          Set_Statements (Handled_Statement_Sequence (Decl), Stms);
1090       end if;
1091    end Build_Mutable_Record_Write_Procedure;
1092 
1093    -----------------------------------------------
1094    -- Build_Record_Or_Elementary_Input_Function --
1095    -----------------------------------------------
1096 
1097    --  The function we build looks like
1098 
1099    --    function InputN (S : access RST) return Typ is
1100    --      C1 : constant Disc_Type_1;
1101    --      Discr_Type_1'Read (S, C1);
1102    --      C2 : constant Disc_Type_2;
1103    --      Discr_Type_2'Read (S, C2);
1104    --      ...
1105    --      Cn : constant Disc_Type_n;
1106    --      Discr_Type_n'Read (S, Cn);
1107    --      V : Typ (C1, C2, .. Cn)
1108 
1109    --    begin
1110    --      Typ'Read (S, V);
1111    --      return V;
1112    --    end InputN
1113 
1114    --  The discriminants are of course only present in the case of a record
1115    --  with discriminants. In the case of a record with no discriminants, or
1116    --  an elementary type, then no Cn constants are defined.
1117 
1118    procedure Build_Record_Or_Elementary_Input_Function
1119      (Loc  : Source_Ptr;
1120       Typ  : Entity_Id;
1121       Decl : out Node_Id;
1122       Fnam : out Entity_Id)
1123    is
1124       B_Typ      : constant Entity_Id := Underlying_Type (Base_Type (Typ));
1125       Cn         : Name_Id;
1126       Constr     : List_Id;
1127       Decls      : List_Id;
1128       Discr      : Entity_Id;
1129       Discr_Elmt : Elmt_Id            := No_Elmt;
1130       J          : Pos;
1131       Obj_Decl   : Node_Id;
1132       Odef       : Node_Id;
1133       Stms       : List_Id;
1134 
1135    begin
1136       Decls  := New_List;
1137       Constr := New_List;
1138 
1139       J := 1;
1140 
1141       --  In the presence of multiple instantiations (as in uses of the Booch
1142       --  components) the base type may be private, and the underlying type
1143       --  already constrained, in which case there's no discriminant constraint
1144       --  to construct.
1145 
1146       if Has_Discriminants (Typ)
1147         and then No (Discriminant_Default_Value (First_Discriminant (Typ)))
1148         and then not Is_Constrained (Underlying_Type (B_Typ))
1149       then
1150          Discr := First_Discriminant (B_Typ);
1151 
1152          --  If the prefix subtype is constrained, then retrieve the first
1153          --  element of its constraint.
1154 
1155          if Is_Constrained (Typ) then
1156             Discr_Elmt := First_Elmt (Discriminant_Constraint (Typ));
1157          end if;
1158 
1159          while Present (Discr) loop
1160             Cn := New_External_Name ('C', J);
1161 
1162             Decl :=
1163               Make_Object_Declaration (Loc,
1164                 Defining_Identifier => Make_Defining_Identifier (Loc, Cn),
1165                 Object_Definition   =>
1166                   New_Occurrence_Of (Etype (Discr), Loc));
1167 
1168             --  If this is an access discriminant, do not perform default
1169             --  initialization. The discriminant is about to get its value
1170             --  from Read, and if the type is null excluding we do not want
1171             --  spurious warnings on an initial null value.
1172 
1173             if Is_Access_Type (Etype (Discr)) then
1174                Set_No_Initialization (Decl);
1175             end if;
1176 
1177             Append_To (Decls, Decl);
1178             Append_To (Decls,
1179               Make_Attribute_Reference (Loc,
1180                 Prefix         => New_Occurrence_Of (Etype (Discr), Loc),
1181                 Attribute_Name => Name_Read,
1182                 Expressions    => New_List (
1183                   Make_Identifier (Loc, Name_S),
1184                   Make_Identifier (Loc, Cn))));
1185 
1186             Append_To (Constr, Make_Identifier (Loc, Cn));
1187 
1188             --  If the prefix subtype imposes a discriminant constraint, then
1189             --  check that each discriminant value equals the value read.
1190 
1191             if Present (Discr_Elmt) then
1192                Append_To (Decls,
1193                  Make_Raise_Constraint_Error (Loc,
1194                    Condition => Make_Op_Ne (Loc,
1195                                   Left_Opnd  =>
1196                                     New_Occurrence_Of
1197                                       (Defining_Identifier (Decl), Loc),
1198                                   Right_Opnd =>
1199                                     New_Copy_Tree (Node (Discr_Elmt))),
1200                    Reason    => CE_Discriminant_Check_Failed));
1201 
1202                Next_Elmt (Discr_Elmt);
1203             end if;
1204 
1205             Next_Discriminant (Discr);
1206             J := J + 1;
1207          end loop;
1208 
1209          Odef :=
1210            Make_Subtype_Indication (Loc,
1211              Subtype_Mark => New_Occurrence_Of (B_Typ, Loc),
1212              Constraint   =>
1213                Make_Index_Or_Discriminant_Constraint (Loc,
1214                  Constraints => Constr));
1215 
1216       --  If no discriminants, then just use the type with no constraint
1217 
1218       else
1219          Odef := New_Occurrence_Of (B_Typ, Loc);
1220       end if;
1221 
1222       --  Create an extended return statement encapsulating the result object
1223       --  and 'Read call, which is needed in general for proper handling of
1224       --  build-in-place results (such as when the result type is inherently
1225       --  limited).
1226 
1227       Obj_Decl :=
1228         Make_Object_Declaration (Loc,
1229           Defining_Identifier => Make_Defining_Identifier (Loc, Name_V),
1230           Object_Definition => Odef);
1231 
1232       --  If the type is an access type, do not perform default initialization.
1233       --  The object is about to get its value from Read, and if the type is
1234       --  null excluding we do not want spurious warnings on an initial null.
1235 
1236       if Is_Access_Type (B_Typ) then
1237          Set_No_Initialization (Obj_Decl);
1238       end if;
1239 
1240       Stms := New_List (
1241         Make_Extended_Return_Statement (Loc,
1242           Return_Object_Declarations => New_List (Obj_Decl),
1243           Handled_Statement_Sequence =>
1244             Make_Handled_Sequence_Of_Statements (Loc,
1245               Statements => New_List (
1246                 Make_Attribute_Reference (Loc,
1247                   Prefix         => New_Occurrence_Of (B_Typ, Loc),
1248                   Attribute_Name => Name_Read,
1249                   Expressions    => New_List (
1250                     Make_Identifier (Loc, Name_S),
1251                     Make_Identifier (Loc, Name_V)))))));
1252 
1253       Fnam := Make_Stream_Subprogram_Name (Loc, B_Typ, TSS_Stream_Input);
1254 
1255       Build_Stream_Function (Loc, B_Typ, Decl, Fnam, Decls, Stms);
1256    end Build_Record_Or_Elementary_Input_Function;
1257 
1258    -------------------------------------------------
1259    -- Build_Record_Or_Elementary_Output_Procedure --
1260    -------------------------------------------------
1261 
1262    procedure Build_Record_Or_Elementary_Output_Procedure
1263      (Loc  : Source_Ptr;
1264       Typ  : Entity_Id;
1265       Decl : out Node_Id;
1266       Pnam : out Entity_Id)
1267    is
1268       Stms     : List_Id;
1269       Disc     : Entity_Id;
1270       Disc_Ref : Node_Id;
1271 
1272    begin
1273       Stms := New_List;
1274 
1275       --  Note that of course there will be no discriminants for the elementary
1276       --  type case, so Has_Discriminants will be False. Note that the language
1277       --  rules do not allow writing the discriminants in the defaulted case,
1278       --  because those are written by 'Write.
1279 
1280       if Has_Discriminants (Typ)
1281         and then No (Discriminant_Default_Value (First_Discriminant (Typ)))
1282       then
1283          Disc := First_Discriminant (Typ);
1284          while Present (Disc) loop
1285 
1286             --  If the type is an unchecked union, it must have default
1287             --  discriminants (this is checked earlier), and those defaults
1288             --  are written out to the stream.
1289 
1290             if Is_Unchecked_Union (Typ) then
1291                Disc_Ref := New_Copy_Tree (Discriminant_Default_Value (Disc));
1292 
1293             else
1294                Disc_Ref :=
1295                  Make_Selected_Component (Loc,
1296                    Prefix        => Make_Identifier (Loc, Name_V),
1297                    Selector_Name => New_Occurrence_Of (Disc, Loc));
1298             end if;
1299 
1300             Append_To (Stms,
1301               Make_Attribute_Reference (Loc,
1302                 Prefix         =>
1303                   New_Occurrence_Of (Stream_Base_Type (Etype (Disc)), Loc),
1304                 Attribute_Name => Name_Write,
1305                 Expressions    => New_List (
1306                   Make_Identifier (Loc, Name_S),
1307                   Disc_Ref)));
1308 
1309             Next_Discriminant (Disc);
1310          end loop;
1311       end if;
1312 
1313       Append_To (Stms,
1314         Make_Attribute_Reference (Loc,
1315           Prefix         => New_Occurrence_Of (Typ, Loc),
1316           Attribute_Name => Name_Write,
1317           Expressions    => New_List (
1318             Make_Identifier (Loc, Name_S),
1319             Make_Identifier (Loc, Name_V))));
1320 
1321       Pnam := Make_Stream_Subprogram_Name (Loc, Typ, TSS_Stream_Output);
1322 
1323       Build_Stream_Procedure (Loc, Typ, Decl, Pnam, Stms, False);
1324    end Build_Record_Or_Elementary_Output_Procedure;
1325 
1326    ---------------------------------
1327    -- Build_Record_Read_Procedure --
1328    ---------------------------------
1329 
1330    procedure Build_Record_Read_Procedure
1331      (Loc  : Source_Ptr;
1332       Typ  : Entity_Id;
1333       Decl : out Node_Id;
1334       Pnam : out Entity_Id)
1335    is
1336    begin
1337       Pnam := Make_Stream_Subprogram_Name (Loc, Typ, TSS_Stream_Read);
1338       Build_Record_Read_Write_Procedure (Loc, Typ, Decl, Pnam, Name_Read);
1339    end Build_Record_Read_Procedure;
1340 
1341    ---------------------------------------
1342    -- Build_Record_Read_Write_Procedure --
1343    ---------------------------------------
1344 
1345    --  The form of the record read/write procedure is as shown by the
1346    --  following example for a case with one discriminant case variant:
1347 
1348    --    procedure pnam (S : access RST, V : [out] Typ) is
1349    --    begin
1350    --       Component_Type'Read/Write (S, V.component);
1351    --       Component_Type'Read/Write (S, V.component);
1352    --       ...
1353    --       Component_Type'Read/Write (S, V.component);
1354    --
1355    --       case V.discriminant is
1356    --          when choices =>
1357    --             Component_Type'Read/Write (S, V.component);
1358    --             Component_Type'Read/Write (S, V.component);
1359    --             ...
1360    --             Component_Type'Read/Write (S, V.component);
1361    --
1362    --          when choices =>
1363    --             Component_Type'Read/Write (S, V.component);
1364    --             Component_Type'Read/Write (S, V.component);
1365    --             ...
1366    --             Component_Type'Read/Write (S, V.component);
1367    --          ...
1368    --       end case;
1369    --    end pnam;
1370 
1371    --  The out keyword for V is supplied in the Read case
1372 
1373    procedure Build_Record_Read_Write_Procedure
1374      (Loc  : Source_Ptr;
1375       Typ  : Entity_Id;
1376       Decl : out Node_Id;
1377       Pnam : Entity_Id;
1378       Nam  : Name_Id)
1379    is
1380       Rdef : Node_Id;
1381       Stms : List_Id;
1382       Typt : Entity_Id;
1383 
1384       In_Limited_Extension : Boolean := False;
1385       --  Set to True while processing the record extension definition
1386       --  for an extension of a limited type (for which an ancestor type
1387       --  has an explicit Nam attribute definition).
1388 
1389       function Make_Component_List_Attributes (CL : Node_Id) return List_Id;
1390       --  Returns a sequence of attributes to process the components that
1391       --  are referenced in the given component list.
1392 
1393       function Make_Field_Attribute (C : Entity_Id) return Node_Id;
1394       --  Given C, the entity for a discriminant or component, build
1395       --  an attribute for the corresponding field values.
1396 
1397       function Make_Field_Attributes (Clist : List_Id) return List_Id;
1398       --  Given Clist, a component items list, construct series of attributes
1399       --  for fieldwise processing of the corresponding components.
1400 
1401       ------------------------------------
1402       -- Make_Component_List_Attributes --
1403       ------------------------------------
1404 
1405       function Make_Component_List_Attributes (CL : Node_Id) return List_Id is
1406          CI : constant List_Id := Component_Items (CL);
1407          VP : constant Node_Id := Variant_Part (CL);
1408 
1409          Result : List_Id;
1410          Alts   : List_Id;
1411          V      : Node_Id;
1412          DC     : Node_Id;
1413          DCH    : List_Id;
1414          D_Ref  : Node_Id;
1415 
1416       begin
1417          Result := Make_Field_Attributes (CI);
1418 
1419          if Present (VP) then
1420             Alts := New_List;
1421 
1422             V := First_Non_Pragma (Variants (VP));
1423             while Present (V) loop
1424                DCH := New_List;
1425 
1426                DC := First (Discrete_Choices (V));
1427                while Present (DC) loop
1428                   Append_To (DCH, New_Copy_Tree (DC));
1429                   Next (DC);
1430                end loop;
1431 
1432                Append_To (Alts,
1433                  Make_Case_Statement_Alternative (Loc,
1434                    Discrete_Choices => DCH,
1435                    Statements =>
1436                      Make_Component_List_Attributes (Component_List (V))));
1437                Next_Non_Pragma (V);
1438             end loop;
1439 
1440             --  Note: in the following, we make sure that we use new occurrence
1441             --  of for the selector, since there are cases in which we make a
1442             --  reference to a hidden discriminant that is not visible.
1443 
1444             --  If the enclosing record is an unchecked_union, we use the
1445             --  default expressions for the discriminant (it must exist)
1446             --  because we cannot generate a reference to it, given that
1447             --  it is not stored.
1448 
1449             if Is_Unchecked_Union (Scope (Entity (Name (VP)))) then
1450                D_Ref :=
1451                  New_Copy_Tree
1452                    (Discriminant_Default_Value (Entity (Name (VP))));
1453             else
1454                D_Ref :=
1455                   Make_Selected_Component (Loc,
1456                     Prefix        => Make_Identifier (Loc, Name_V),
1457                     Selector_Name =>
1458                       New_Occurrence_Of (Entity (Name (VP)), Loc));
1459             end if;
1460 
1461             Append_To (Result,
1462               Make_Case_Statement (Loc,
1463                 Expression   => D_Ref,
1464                 Alternatives => Alts));
1465          end if;
1466 
1467          return Result;
1468       end Make_Component_List_Attributes;
1469 
1470       --------------------------
1471       -- Make_Field_Attribute --
1472       --------------------------
1473 
1474       function Make_Field_Attribute (C : Entity_Id) return Node_Id is
1475          Field_Typ : constant Entity_Id := Stream_Base_Type (Etype (C));
1476 
1477          TSS_Names : constant array (Name_Input .. Name_Write) of
1478                        TSS_Name_Type :=
1479                         (Name_Read   => TSS_Stream_Read,
1480                          Name_Write  => TSS_Stream_Write,
1481                          Name_Input  => TSS_Stream_Input,
1482                          Name_Output => TSS_Stream_Output,
1483                          others      => TSS_Null);
1484          pragma Assert (TSS_Names (Nam) /= TSS_Null);
1485 
1486       begin
1487          if In_Limited_Extension
1488            and then Is_Limited_Type (Field_Typ)
1489            and then No (Find_Inherited_TSS (Field_Typ, TSS_Names (Nam)))
1490          then
1491             --  The declaration is illegal per 13.13.2(9/1), and this is
1492             --  enforced in Exp_Ch3.Check_Stream_Attributes. Keep the caller
1493             --  happy by returning a null statement.
1494 
1495             return Make_Null_Statement (Loc);
1496          end if;
1497 
1498          return
1499            Make_Attribute_Reference (Loc,
1500              Prefix         => New_Occurrence_Of (Field_Typ, Loc),
1501              Attribute_Name => Nam,
1502              Expressions    => New_List (
1503                Make_Identifier (Loc, Name_S),
1504                Make_Selected_Component (Loc,
1505                  Prefix        => Make_Identifier (Loc, Name_V),
1506                  Selector_Name => New_Occurrence_Of (C, Loc))));
1507       end Make_Field_Attribute;
1508 
1509       ---------------------------
1510       -- Make_Field_Attributes --
1511       ---------------------------
1512 
1513       function Make_Field_Attributes (Clist : List_Id) return List_Id is
1514          Item   : Node_Id;
1515          Result : List_Id;
1516 
1517       begin
1518          Result := New_List;
1519 
1520          if Present (Clist) then
1521             Item := First (Clist);
1522 
1523             --  Loop through components, skipping all internal components,
1524             --  which are not part of the value (e.g. _Tag), except that we
1525             --  don't skip the _Parent, since we do want to process that
1526             --  recursively. If _Parent is an interface type, being abstract
1527             --  with no components there is no need to handle it.
1528 
1529             while Present (Item) loop
1530                if Nkind (Item) = N_Component_Declaration
1531                  and then
1532                    ((Chars (Defining_Identifier (Item)) = Name_uParent
1533                        and then not Is_Interface
1534                                       (Etype (Defining_Identifier (Item))))
1535                      or else
1536                     not Is_Internal_Name (Chars (Defining_Identifier (Item))))
1537                then
1538                   Append_To
1539                     (Result,
1540                      Make_Field_Attribute (Defining_Identifier (Item)));
1541                end if;
1542 
1543                Next (Item);
1544             end loop;
1545          end if;
1546 
1547          return Result;
1548       end Make_Field_Attributes;
1549 
1550    --  Start of processing for Build_Record_Read_Write_Procedure
1551 
1552    begin
1553       --  For the protected type case, use corresponding record
1554 
1555       if Is_Protected_Type (Typ) then
1556          Typt := Corresponding_Record_Type (Typ);
1557       else
1558          Typt := Typ;
1559       end if;
1560 
1561       --  Note that we do nothing with the discriminants, since Read and
1562       --  Write do not read or write the discriminant values. All handling
1563       --  of discriminants occurs in the Input and Output subprograms.
1564 
1565       Rdef := Type_Definition
1566                 (Declaration_Node (Base_Type (Underlying_Type (Typt))));
1567       Stms := Empty_List;
1568 
1569       --  In record extension case, the fields we want, including the _Parent
1570       --  field representing the parent type, are to be found in the extension.
1571       --  Note that we will naturally process the _Parent field using the type
1572       --  of the parent, and hence its stream attributes, which is appropriate.
1573 
1574       if Nkind (Rdef) = N_Derived_Type_Definition then
1575          Rdef := Record_Extension_Part (Rdef);
1576 
1577          if Is_Limited_Type (Typt) then
1578             In_Limited_Extension := True;
1579          end if;
1580       end if;
1581 
1582       if Present (Component_List (Rdef)) then
1583          Append_List_To (Stms,
1584            Make_Component_List_Attributes (Component_List (Rdef)));
1585       end if;
1586 
1587       Build_Stream_Procedure
1588         (Loc, Typ, Decl, Pnam, Stms, Nam = Name_Read);
1589    end Build_Record_Read_Write_Procedure;
1590 
1591    ----------------------------------
1592    -- Build_Record_Write_Procedure --
1593    ----------------------------------
1594 
1595    procedure Build_Record_Write_Procedure
1596      (Loc  : Source_Ptr;
1597       Typ  : Entity_Id;
1598       Decl : out Node_Id;
1599       Pnam : out Entity_Id)
1600    is
1601    begin
1602       Pnam := Make_Stream_Subprogram_Name (Loc, Typ, TSS_Stream_Write);
1603       Build_Record_Read_Write_Procedure (Loc, Typ, Decl, Pnam, Name_Write);
1604    end Build_Record_Write_Procedure;
1605 
1606    -------------------------------
1607    -- Build_Stream_Attr_Profile --
1608    -------------------------------
1609 
1610    function Build_Stream_Attr_Profile
1611      (Loc : Source_Ptr;
1612       Typ : Entity_Id;
1613       Nam : TSS_Name_Type) return List_Id
1614    is
1615       Profile : List_Id;
1616 
1617    begin
1618       --  (Ada 2005: AI-441): Set the null-excluding attribute because it has
1619       --  no semantic meaning in Ada 95 but it is a requirement in Ada 2005.
1620 
1621       Profile := New_List (
1622         Make_Parameter_Specification (Loc,
1623           Defining_Identifier => Make_Defining_Identifier (Loc, Name_S),
1624           Parameter_Type      =>
1625           Make_Access_Definition (Loc,
1626              Null_Exclusion_Present => True,
1627              Subtype_Mark => New_Occurrence_Of (
1628                Class_Wide_Type (RTE (RE_Root_Stream_Type)), Loc))));
1629 
1630       if Nam /= TSS_Stream_Input then
1631          Append_To (Profile,
1632            Make_Parameter_Specification (Loc,
1633              Defining_Identifier => Make_Defining_Identifier (Loc, Name_V),
1634              Out_Present         => (Nam = TSS_Stream_Read),
1635              Parameter_Type      => New_Occurrence_Of (Typ, Loc)));
1636       end if;
1637 
1638       return Profile;
1639    end Build_Stream_Attr_Profile;
1640 
1641    ---------------------------
1642    -- Build_Stream_Function --
1643    ---------------------------
1644 
1645    procedure Build_Stream_Function
1646      (Loc   : Source_Ptr;
1647       Typ   : Entity_Id;
1648       Decl  : out Node_Id;
1649       Fnam  : Entity_Id;
1650       Decls : List_Id;
1651       Stms  : List_Id)
1652    is
1653       Spec : Node_Id;
1654 
1655    begin
1656       --  Construct function specification
1657 
1658       --  (Ada 2005: AI-441): Set the null-excluding attribute because it has
1659       --  no semantic meaning in Ada 95 but it is a requirement in Ada 2005.
1660 
1661       Spec :=
1662         Make_Function_Specification (Loc,
1663           Defining_Unit_Name => Fnam,
1664 
1665           Parameter_Specifications => New_List (
1666             Make_Parameter_Specification (Loc,
1667               Defining_Identifier => Make_Defining_Identifier (Loc, Name_S),
1668               Parameter_Type      =>
1669                 Make_Access_Definition (Loc,
1670                   Null_Exclusion_Present => True,
1671                   Subtype_Mark           =>
1672                     New_Occurrence_Of
1673                       (Class_Wide_Type (RTE (RE_Root_Stream_Type)), Loc)))),
1674 
1675           Result_Definition => New_Occurrence_Of (Typ, Loc));
1676 
1677       Decl :=
1678         Make_Subprogram_Body (Loc,
1679           Specification              => Spec,
1680           Declarations               => Decls,
1681           Handled_Statement_Sequence =>
1682             Make_Handled_Sequence_Of_Statements (Loc,
1683               Statements => Stms));
1684    end Build_Stream_Function;
1685 
1686    ----------------------------
1687    -- Build_Stream_Procedure --
1688    ----------------------------
1689 
1690    procedure Build_Stream_Procedure
1691      (Loc  : Source_Ptr;
1692       Typ  : Entity_Id;
1693       Decl : out Node_Id;
1694       Pnam : Entity_Id;
1695       Stms : List_Id;
1696       Outp : Boolean)
1697    is
1698       Spec : Node_Id;
1699 
1700    begin
1701       --  Construct procedure specification
1702 
1703       --  (Ada 2005: AI-441): Set the null-excluding attribute because it has
1704       --  no semantic meaning in Ada 95 but it is a requirement in Ada 2005.
1705 
1706       Spec :=
1707         Make_Procedure_Specification (Loc,
1708           Defining_Unit_Name => Pnam,
1709 
1710           Parameter_Specifications => New_List (
1711             Make_Parameter_Specification (Loc,
1712               Defining_Identifier => Make_Defining_Identifier (Loc, Name_S),
1713               Parameter_Type      =>
1714                 Make_Access_Definition (Loc,
1715                   Null_Exclusion_Present => True,
1716                   Subtype_Mark           =>
1717                     New_Occurrence_Of
1718                       (Class_Wide_Type (RTE (RE_Root_Stream_Type)), Loc))),
1719 
1720             Make_Parameter_Specification (Loc,
1721               Defining_Identifier => Make_Defining_Identifier (Loc, Name_V),
1722               Out_Present         => Outp,
1723               Parameter_Type      => New_Occurrence_Of (Typ, Loc))));
1724 
1725       Decl :=
1726         Make_Subprogram_Body (Loc,
1727           Specification              => Spec,
1728           Declarations               => Empty_List,
1729           Handled_Statement_Sequence =>
1730             Make_Handled_Sequence_Of_Statements (Loc,
1731               Statements => Stms));
1732    end Build_Stream_Procedure;
1733 
1734    -----------------------------
1735    -- Has_Stream_Standard_Rep --
1736    -----------------------------
1737 
1738    function Has_Stream_Standard_Rep (U_Type : Entity_Id) return Boolean is
1739       Siz : Uint;
1740 
1741    begin
1742       if Has_Non_Standard_Rep (U_Type) then
1743          return False;
1744       end if;
1745 
1746       if Has_Stream_Size_Clause (U_Type) then
1747          Siz := Static_Integer (Expression (Stream_Size_Clause (U_Type)));
1748       else
1749          Siz := Esize (First_Subtype (U_Type));
1750       end if;
1751 
1752       return Siz = Esize (Root_Type (U_Type));
1753    end Has_Stream_Standard_Rep;
1754 
1755    ---------------------------------
1756    -- Make_Stream_Subprogram_Name --
1757    ---------------------------------
1758 
1759    function Make_Stream_Subprogram_Name
1760      (Loc : Source_Ptr;
1761       Typ : Entity_Id;
1762       Nam : TSS_Name_Type) return Entity_Id
1763    is
1764       Sname : Name_Id;
1765 
1766    begin
1767       --  For tagged types, we are dealing with a TSS associated with the
1768       --  declaration, so we use the standard primitive function name. For
1769       --  other types, generate a local TSS name since we are generating
1770       --  the subprogram at the point of use.
1771 
1772       if Is_Tagged_Type (Typ) then
1773          Sname := Make_TSS_Name (Typ, Nam);
1774       else
1775          Sname := Make_TSS_Name_Local (Typ, Nam);
1776       end if;
1777 
1778       return Make_Defining_Identifier (Loc, Sname);
1779    end Make_Stream_Subprogram_Name;
1780 
1781    ----------------------
1782    -- Stream_Base_Type --
1783    ----------------------
1784 
1785    function Stream_Base_Type (E : Entity_Id) return Entity_Id is
1786    begin
1787       if Is_Array_Type (E)
1788         and then Is_First_Subtype (E)
1789       then
1790          return E;
1791       else
1792          return Base_Type (E);
1793       end if;
1794    end Stream_Base_Type;
1795 
1796 end Exp_Strm;