1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 1992-2023, Free Software Foundation, Inc. --
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. --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
24 ------------------------------------------------------------------------------
26 with Atree
; use Atree
;
27 with Einfo
; use Einfo
;
28 with Einfo
.Entities
; use Einfo
.Entities
;
29 with Einfo
.Utils
; use Einfo
.Utils
;
30 with Elists
; use Elists
;
31 with Exp_Util
; use Exp_Util
;
32 with Namet
; use Namet
;
33 with Nlists
; use Nlists
;
34 with Nmake
; use Nmake
;
35 with Rtsfind
; use Rtsfind
;
36 with Sem_Aux
; use Sem_Aux
;
37 with Sem_Util
; use Sem_Util
;
38 with Sinfo
; use Sinfo
;
39 with Sinfo
.Nodes
; use Sinfo
.Nodes
;
40 with Sinfo
.Utils
; use Sinfo
.Utils
;
41 with Snames
; use Snames
;
42 with Stand
; use Stand
;
43 with Tbuild
; use Tbuild
;
44 with Ttypes
; use Ttypes
;
45 with Uintp
; use Uintp
;
47 package body Exp_Strm
is
49 -----------------------
50 -- Local Subprograms --
51 -----------------------
53 procedure Build_Array_Read_Write_Procedure
59 -- Common routine shared to build either an array Read procedure or an
60 -- array Write procedure, Nam is Name_Read or Name_Write to select which.
61 -- Pnam is the defining identifier for the constructed procedure. The
62 -- other parameters are as for Build_Array_Read_Procedure except that
63 -- the first parameter Nod supplies the Sloc to be used to generate code.
65 procedure Build_Record_Read_Write_Procedure
71 -- Common routine shared to build a record Read Write procedure, Nam
72 -- is Name_Read or Name_Write to select which. Pnam is the defining
73 -- identifier for the constructed procedure. The other parameters are
74 -- as for Build_Record_Read_Procedure.
76 procedure Build_Stream_Function
83 -- Called to build an array or record stream function. The first three
84 -- arguments are the same as Build_Record_Or_Elementary_Input_Function.
85 -- Decls and Stms are the declarations and statements for the body and
86 -- The parameter Fnam is the name of the constructed function.
88 function Has_Stream_Standard_Rep
(U_Type
: Entity_Id
) return Boolean;
89 -- This function is used to test the type U_Type, to determine if it has
90 -- a standard representation from a streaming point of view. Standard means
91 -- that it has a standard representation (e.g. no enumeration rep clause),
92 -- and the size of the root type is the same as the streaming size (which
93 -- is defined as value specified by a Stream_Size clause if present, or
94 -- the Esize of U_Type if not).
96 function Make_Stream_Subprogram_Name
99 Nam
: TSS_Name_Type
) return Entity_Id
;
100 -- Return the entity that identifies the stream subprogram for type Typ
101 -- that is identified by the given Nam. This procedure deals with the
102 -- difference between tagged types (where a single subprogram associated
103 -- with the type is generated) and all other cases (where a subprogram
104 -- is generated at the point of the stream attribute reference). The
105 -- Loc parameter is used as the Sloc of the created entity.
107 function Stream_Base_Type
(E
: Entity_Id
) return Entity_Id
;
108 -- Stream attributes work on the basis of the base type except for the
109 -- array case. For the array case, we do not go to the base type, but
110 -- to the first subtype if it is constrained. This avoids problems with
111 -- incorrect conversions in the packed array case. Stream_Base_Type is
112 -- exactly this function (returns the base type, unless we have an array
113 -- type whose first subtype is constrained, in which case it returns the
116 --------------------------------
117 -- Build_Array_Input_Function --
118 --------------------------------
120 -- The function we build looks like
122 -- function typSI[_nnn] (S : access RST) return Typ is
123 -- L1 : constant Index_Type_1 := Index_Type_1'Input (S);
124 -- H1 : constant Index_Type_1 := Index_Type_1'Input (S);
125 -- L2 : constant Index_Type_2 := Index_Type_2'Input (S);
126 -- H2 : constant Index_Type_2 := Index_Type_2'Input (S);
128 -- Ln : constant Index_Type_n := Index_Type_n'Input (S);
129 -- Hn : constant Index_Type_n := Index_Type_n'Input (S);
131 -- V : Typ'Base (L1 .. H1, L2 .. H2, ... Ln .. Hn)
138 -- Note: the suffix [_nnn] is present for untagged types, where we generate
139 -- a local subprogram at the point of the occurrence of the attribute
140 -- reference, so the name must be unique.
142 procedure Build_Array_Input_Function
146 Fnam
: out Entity_Id
)
148 Dim
: constant Pos
:= Number_Dimensions
(Typ
);
161 Indx
:= First_Index
(Typ
);
162 for J
in 1 .. Dim
loop
163 Lnam
:= New_External_Name
('L', J
);
164 Hnam
:= New_External_Name
('H', J
);
167 Make_Object_Declaration
(Loc
,
168 Defining_Identifier
=> Make_Defining_Identifier
(Loc
, Lnam
),
169 Constant_Present
=> True,
170 Object_Definition
=> New_Occurrence_Of
(Etype
(Indx
), Loc
),
172 Make_Attribute_Reference
(Loc
,
174 New_Occurrence_Of
(Stream_Base_Type
(Etype
(Indx
)), Loc
),
175 Attribute_Name
=> Name_Input
,
176 Expressions
=> New_List
(Make_Identifier
(Loc
, Name_S
)))));
179 Make_Object_Declaration
(Loc
,
180 Defining_Identifier
=> Make_Defining_Identifier
(Loc
, Hnam
),
181 Constant_Present
=> True,
183 New_Occurrence_Of
(Stream_Base_Type
(Etype
(Indx
)), Loc
),
185 Make_Attribute_Reference
(Loc
,
187 New_Occurrence_Of
(Stream_Base_Type
(Etype
(Indx
)), Loc
),
188 Attribute_Name
=> Name_Input
,
189 Expressions
=> New_List
(Make_Identifier
(Loc
, Name_S
)))));
193 Low_Bound
=> Make_Identifier
(Loc
, Lnam
),
194 High_Bound
=> Make_Identifier
(Loc
, Hnam
)));
199 -- If the type is constrained, use it directly. Otherwise build a
200 -- subtype indication with the proper bounds.
202 if Is_Constrained
(Typ
) then
204 Make_Object_Declaration
(Loc
,
205 Defining_Identifier
=> Make_Defining_Identifier
(Loc
, Name_V
),
206 Object_Definition
=> New_Occurrence_Of
(Typ
, Loc
));
210 Make_Object_Declaration
(Loc
,
211 Defining_Identifier
=> Make_Defining_Identifier
(Loc
, Name_V
),
213 Make_Subtype_Indication
(Loc
,
215 New_Occurrence_Of
(Stream_Base_Type
(Typ
), Loc
),
217 Make_Index_Or_Discriminant_Constraint
(Loc
, Ranges
)));
221 Make_Attribute_Reference
(Loc
,
222 Prefix
=> New_Occurrence_Of
(Typ
, Loc
),
223 Attribute_Name
=> Name_Read
,
224 Expressions
=> New_List
(
225 Make_Identifier
(Loc
, Name_S
),
226 Make_Identifier
(Loc
, Name_V
)));
229 Make_Extended_Return_Statement
(Loc
,
230 Return_Object_Declarations
=> New_List
(Odecl
),
231 Handled_Statement_Sequence
=>
232 Make_Handled_Sequence_Of_Statements
(Loc
, New_List
(Rstmt
))));
235 Make_Defining_Identifier
(Loc
,
236 Chars
=> Make_TSS_Name_Local
(Typ
, TSS_Stream_Input
));
238 Build_Stream_Function
(Loc
, Typ
, Decl
, Fnam
, Decls
, Stms
);
239 end Build_Array_Input_Function
;
241 ----------------------------------
242 -- Build_Array_Output_Procedure --
243 ----------------------------------
245 procedure Build_Array_Output_Procedure
249 Pnam
: out Entity_Id
)
255 -- Build series of statements to output bounds
257 Indx
:= First_Index
(Typ
);
260 for J
in 1 .. Number_Dimensions
(Typ
) loop
262 Make_Attribute_Reference
(Loc
,
264 New_Occurrence_Of
(Stream_Base_Type
(Etype
(Indx
)), Loc
),
265 Attribute_Name
=> Name_Write
,
266 Expressions
=> New_List
(
267 Make_Identifier
(Loc
, Name_S
),
268 Make_Attribute_Reference
(Loc
,
269 Prefix
=> Make_Identifier
(Loc
, Name_V
),
270 Attribute_Name
=> Name_First
,
271 Expressions
=> New_List
(
272 Make_Integer_Literal
(Loc
, J
))))));
275 Make_Attribute_Reference
(Loc
,
277 New_Occurrence_Of
(Stream_Base_Type
(Etype
(Indx
)), Loc
),
278 Attribute_Name
=> Name_Write
,
279 Expressions
=> New_List
(
280 Make_Identifier
(Loc
, Name_S
),
281 Make_Attribute_Reference
(Loc
,
282 Prefix
=> Make_Identifier
(Loc
, Name_V
),
283 Attribute_Name
=> Name_Last
,
284 Expressions
=> New_List
(
285 Make_Integer_Literal
(Loc
, J
))))));
290 -- Append Write attribute to write array elements
293 Make_Attribute_Reference
(Loc
,
294 Prefix
=> New_Occurrence_Of
(Typ
, Loc
),
295 Attribute_Name
=> Name_Write
,
296 Expressions
=> New_List
(
297 Make_Identifier
(Loc
, Name_S
),
298 Make_Identifier
(Loc
, Name_V
))));
301 Make_Defining_Identifier
(Loc
,
302 Chars
=> Make_TSS_Name_Local
(Typ
, TSS_Stream_Output
));
304 Build_Stream_Procedure
(Loc
, Typ
, Decl
, Pnam
, Stms
, Outp
=> False);
305 end Build_Array_Output_Procedure
;
307 --------------------------------
308 -- Build_Array_Read_Procedure --
309 --------------------------------
311 procedure Build_Array_Read_Procedure
315 Pnam
: out Entity_Id
)
317 Loc
: constant Source_Ptr
:= Sloc
(Nod
);
321 Make_Defining_Identifier
(Loc
,
322 Chars
=> Make_TSS_Name_Local
(Typ
, TSS_Stream_Read
));
323 Build_Array_Read_Write_Procedure
(Nod
, Typ
, Decl
, Pnam
, Name_Read
);
324 end Build_Array_Read_Procedure
;
326 --------------------------------------
327 -- Build_Array_Read_Write_Procedure --
328 --------------------------------------
330 -- The form of the array read/write procedure is as follows:
332 -- procedure pnam (S : access RST, V : [out] Typ) is
334 -- for L1 in V'Range (1) loop
335 -- for L2 in V'Range (2) loop
337 -- for Ln in V'Range (n) loop
338 -- Component_Type'Read/Write (S, V (L1, L2, .. Ln));
345 -- The out keyword for V is supplied in the Read case
347 procedure Build_Array_Read_Write_Procedure
354 Loc
: constant Source_Ptr
:= Sloc
(Nod
);
355 Ndim
: constant Pos
:= Number_Dimensions
(Typ
);
356 Ctyp
: constant Entity_Id
:= Component_Type
(Typ
);
363 -- First build the inner attribute call
367 for J
in 1 .. Ndim
loop
368 Append_To
(Exl
, Make_Identifier
(Loc
, New_External_Name
('L', J
)));
372 Make_Attribute_Reference
(Loc
,
373 Prefix
=> New_Occurrence_Of
(Stream_Base_Type
(Ctyp
), Loc
),
374 Attribute_Name
=> Nam
,
375 Expressions
=> New_List
(
376 Make_Identifier
(Loc
, Name_S
),
377 Make_Indexed_Component
(Loc
,
378 Prefix
=> Make_Identifier
(Loc
, Name_V
),
379 Expressions
=> Exl
)));
381 -- The corresponding stream attribute for the component type of the
382 -- array may be user-defined, and be frozen after the type for which
383 -- we are generating the stream subprogram. In that case, freeze the
384 -- stream attribute of the component type, whose declaration could not
385 -- generate any additional freezing actions in any case.
387 if Nam
= Name_Read
then
388 RW
:= TSS
(Base_Type
(Ctyp
), TSS_Stream_Read
);
390 RW
:= TSS
(Base_Type
(Ctyp
), TSS_Stream_Write
);
394 and then not Is_Frozen
(RW
)
399 -- Now this is the big loop to wrap that statement up in a sequence
400 -- of loops. The first time around, Stm is the attribute call. The
401 -- second and subsequent times, Stm is an inner loop.
403 for J
in 1 .. Ndim
loop
405 Make_Implicit_Loop_Statement
(Nod
,
407 Make_Iteration_Scheme
(Loc
,
408 Loop_Parameter_Specification
=>
409 Make_Loop_Parameter_Specification
(Loc
,
410 Defining_Identifier
=>
411 Make_Defining_Identifier
(Loc
,
412 Chars
=> New_External_Name
('L', Ndim
- J
+ 1)),
414 Discrete_Subtype_Definition
=>
415 Make_Attribute_Reference
(Loc
,
416 Prefix
=> Make_Identifier
(Loc
, Name_V
),
417 Attribute_Name
=> Name_Range
,
419 Expressions
=> New_List
(
420 Make_Integer_Literal
(Loc
, Ndim
- J
+ 1))))),
422 Statements
=> New_List
(Stm
));
426 Build_Stream_Procedure
427 (Loc
, Typ
, Decl
, Pnam
, New_List
(Stm
), Outp
=> Nam
= Name_Read
);
428 end Build_Array_Read_Write_Procedure
;
430 ---------------------------------
431 -- Build_Array_Write_Procedure --
432 ---------------------------------
434 procedure Build_Array_Write_Procedure
438 Pnam
: out Entity_Id
)
440 Loc
: constant Source_Ptr
:= Sloc
(Nod
);
443 Make_Defining_Identifier
(Loc
,
444 Chars
=> Make_TSS_Name_Local
(Typ
, TSS_Stream_Write
));
445 Build_Array_Read_Write_Procedure
(Nod
, Typ
, Decl
, Pnam
, Name_Write
);
446 end Build_Array_Write_Procedure
;
448 ---------------------------------
449 -- Build_Elementary_Input_Call --
450 ---------------------------------
452 function Build_Elementary_Input_Call
(N
: Node_Id
) return Node_Id
is
453 Loc
: constant Source_Ptr
:= Sloc
(N
);
454 P_Type
: constant Entity_Id
:= Entity
(Prefix
(N
));
455 U_Type
: constant Entity_Id
:= Underlying_Type
(P_Type
);
456 Rt_Type
: constant Entity_Id
:= Root_Type
(U_Type
);
457 FST
: constant Entity_Id
:= First_Subtype
(U_Type
);
458 Strm
: constant Node_Id
:= First
(Expressions
(N
));
459 Targ
: constant Node_Id
:= Next
(Strm
);
460 P_Size
: constant Uint
:= Get_Stream_Size
(FST
);
466 -- Check first for Boolean and Character. These are enumeration types,
467 -- but we treat them specially, since they may require special handling
468 -- in the transfer protocol. However, this special handling only applies
469 -- if they have standard representation, otherwise they are treated like
470 -- any other enumeration type.
472 if Rt_Type
= Standard_Boolean
473 and then Has_Stream_Standard_Rep
(U_Type
)
477 elsif Rt_Type
= Standard_Character
478 and then Has_Stream_Standard_Rep
(U_Type
)
482 elsif Rt_Type
= Standard_Wide_Character
483 and then Has_Stream_Standard_Rep
(U_Type
)
487 elsif Rt_Type
= Standard_Wide_Wide_Character
488 and then Has_Stream_Standard_Rep
(U_Type
)
492 -- Floating point types
494 elsif Is_Floating_Point_Type
(U_Type
) then
496 -- Question: should we use P_Size or Rt_Type to distinguish between
497 -- possible floating point types? If a non-standard size or a stream
498 -- size is specified, then we should certainly use the size. But if
499 -- we have two types the same (notably Short_Float_Size = Float_Size
500 -- which is close to universally true, and Long_Long_Float_Size =
501 -- Long_Float_Size, true on most targets except the x86), then we
502 -- would really rather use the root type, so that if people want to
503 -- fiddle with System.Stream_Attributes to get inter-target portable
504 -- streams, they get the size they expect. Consider in particular the
505 -- case of a stream written on an x86, with 96-bit Long_Long_Float
506 -- being read into a non-x86 target with 64 bit Long_Long_Float. A
507 -- special version of System.Stream_Attributes can deal with this
508 -- provided the proper type is always used.
510 -- To deal with these two requirements we add the special checks
511 -- on equal sizes and use the root type to distinguish.
513 if P_Size
<= Standard_Short_Float_Size
514 and then (Standard_Short_Float_Size
/= Standard_Float_Size
515 or else Rt_Type
= Standard_Short_Float
)
519 elsif P_Size
<= Standard_Float_Size
then
522 elsif P_Size
<= Standard_Long_Float_Size
523 and then (Standard_Long_Float_Size
/= Standard_Long_Long_Float_Size
524 or else Rt_Type
= Standard_Long_Float
)
532 -- Signed integer types. Also includes signed fixed-point types and
533 -- enumeration types with a signed representation.
535 -- Note on signed integer types. We do not consider types as signed for
536 -- this purpose if they have no negative numbers, or if they have biased
537 -- representation. The reason is that the value in either case basically
538 -- represents an unsigned value.
540 -- For example, consider:
542 -- type W is range 0 .. 2**32 - 1;
543 -- for W'Size use 32;
545 -- This is a signed type, but the representation is unsigned, and may
546 -- be outside the range of a 32-bit signed integer, so this must be
547 -- treated as 32-bit unsigned.
549 -- Similarly, if we have
551 -- type W is range -1 .. +254;
554 -- then the representation is unsigned
556 elsif not Is_Unsigned_Type
(FST
)
558 -- The following set of tests gets repeated many times, we should
559 -- have an abstraction defined ???
562 (Is_Fixed_Point_Type
(U_Type
)
564 Is_Enumeration_Type
(U_Type
)
566 (Is_Signed_Integer_Type
(U_Type
)
567 and then not Has_Biased_Representation
(FST
)))
570 if P_Size
<= Standard_Short_Short_Integer_Size
then
573 elsif P_Size
<= Standard_Short_Integer_Size
then
576 elsif P_Size
= 24 then
579 elsif P_Size
<= Standard_Integer_Size
then
582 elsif P_Size
<= Standard_Long_Integer_Size
then
585 elsif P_Size
<= Standard_Long_Long_Integer_Size
then
592 -- Unsigned integer types, also includes unsigned fixed-point types
593 -- and enumeration types with an unsigned representation (note that
594 -- we know they are unsigned because we already tested for signed).
596 -- Also includes signed integer types that are unsigned in the sense
597 -- that they do not include negative numbers. See above for details.
599 elsif Is_Modular_Integer_Type
(U_Type
)
600 or else Is_Fixed_Point_Type
(U_Type
)
601 or else Is_Enumeration_Type
(U_Type
)
602 or else Is_Signed_Integer_Type
(U_Type
)
604 if P_Size
<= Standard_Short_Short_Integer_Size
then
607 elsif P_Size
<= Standard_Short_Integer_Size
then
610 elsif P_Size
= 24 then
613 elsif P_Size
<= Standard_Integer_Size
then
616 elsif P_Size
<= Standard_Long_Integer_Size
then
619 elsif P_Size
<= Standard_Long_Long_Integer_Size
then
626 else pragma Assert
(Is_Access_Type
(U_Type
));
627 if Present
(P_Size
) and then P_Size
> System_Address_Size
then
634 -- Call the function, and do an unchecked conversion of the result
635 -- to the actual type of the prefix. If the target is a discriminant,
636 -- and we are in the body of the default implementation of a 'Read
637 -- attribute, set target type to force a constraint check (13.13.2(35)).
638 -- If the type of the discriminant is currently private, add another
639 -- unchecked conversion from the full view.
641 if Nkind
(Targ
) = N_Identifier
642 and then Is_Internal_Name
(Chars
(Targ
))
643 and then Is_TSS
(Scope
(Entity
(Targ
)), TSS_Stream_Read
)
646 Unchecked_Convert_To
(Base_Type
(U_Type
),
647 Make_Function_Call
(Loc
,
648 Name
=> New_Occurrence_Of
(RTE
(Lib_RE
), Loc
),
649 Parameter_Associations
=> New_List
(
650 Relocate_Node
(Strm
))));
652 Set_Do_Range_Check
(Res
);
654 if Base_Type
(P_Type
) /= Base_Type
(U_Type
) then
655 Res
:= Unchecked_Convert_To
(Base_Type
(P_Type
), Res
);
662 Make_Function_Call
(Loc
,
663 Name
=> New_Occurrence_Of
(RTE
(Lib_RE
), Loc
),
664 Parameter_Associations
=> New_List
(
665 Relocate_Node
(Strm
)));
667 -- Now convert to the base type if we do not have a biased type. Note
668 -- that we did not do this in some older versions, and the result was
669 -- losing a required range check in the case where 'Input is being
670 -- called from 'Read.
672 if not Has_Biased_Representation
(P_Type
) then
673 return Unchecked_Convert_To
(Base_Type
(P_Type
), Res
);
675 -- For the biased case, the conversion to the base type loses the
676 -- biasing, so just convert to Ptype. This is not quite right, and
677 -- for example may lose a corner case CE test, but it is such a
678 -- rare case that for now we ignore it ???
681 return Unchecked_Convert_To
(P_Type
, Res
);
684 end Build_Elementary_Input_Call
;
686 ---------------------------------
687 -- Build_Elementary_Write_Call --
688 ---------------------------------
690 function Build_Elementary_Write_Call
(N
: Node_Id
) return Node_Id
is
691 Loc
: constant Source_Ptr
:= Sloc
(N
);
692 P_Type
: constant Entity_Id
:= Entity
(Prefix
(N
));
693 U_Type
: constant Entity_Id
:= Underlying_Type
(P_Type
);
694 Rt_Type
: constant Entity_Id
:= Root_Type
(U_Type
);
695 FST
: constant Entity_Id
:= First_Subtype
(U_Type
);
696 Strm
: constant Node_Id
:= First
(Expressions
(N
));
697 Item
: constant Node_Id
:= Next
(Strm
);
703 -- Compute the size of the stream element. This is either the size of
704 -- the first subtype or if given the size of the Stream_Size attribute.
706 if Has_Stream_Size_Clause
(FST
) then
707 P_Size
:= Static_Integer
(Expression
(Stream_Size_Clause
(FST
)));
709 P_Size
:= Esize
(FST
);
712 -- Find the routine to be called
714 -- Check for First Boolean and Character. These are enumeration types,
715 -- but we treat them specially, since they may require special handling
716 -- in the transfer protocol. However, this special handling only applies
717 -- if they have standard representation, otherwise they are treated like
718 -- any other enumeration type.
720 if Rt_Type
= Standard_Boolean
721 and then Has_Stream_Standard_Rep
(U_Type
)
725 elsif Rt_Type
= Standard_Character
726 and then Has_Stream_Standard_Rep
(U_Type
)
730 elsif Rt_Type
= Standard_Wide_Character
731 and then Has_Stream_Standard_Rep
(U_Type
)
735 elsif Rt_Type
= Standard_Wide_Wide_Character
736 and then Has_Stream_Standard_Rep
(U_Type
)
740 -- Floating point types
742 elsif Is_Floating_Point_Type
(U_Type
) then
744 -- Question: should we use P_Size or Rt_Type to distinguish between
745 -- possible floating point types? If a non-standard size or a stream
746 -- size is specified, then we should certainly use the size. But if
747 -- we have two types the same (notably Short_Float_Size = Float_Size
748 -- which is close to universally true, and Long_Long_Float_Size =
749 -- Long_Float_Size, true on most targets except the x86), then we
750 -- would really rather use the root type, so that if people want to
751 -- fiddle with System.Stream_Attributes to get inter-target portable
752 -- streams, they get the size they expect. Consider in particular the
753 -- case of a stream written on an x86, with 96-bit Long_Long_Float
754 -- being read into a non-x86 target with 64 bit Long_Long_Float. A
755 -- special version of System.Stream_Attributes can deal with this
756 -- provided the proper type is always used.
758 -- To deal with these two requirements we add the special checks
759 -- on equal sizes and use the root type to distinguish.
761 if P_Size
<= Standard_Short_Float_Size
762 and then (Standard_Short_Float_Size
/= Standard_Float_Size
763 or else Rt_Type
= Standard_Short_Float
)
767 elsif P_Size
<= Standard_Float_Size
then
770 elsif P_Size
<= Standard_Long_Float_Size
771 and then (Standard_Long_Float_Size
/= Standard_Long_Long_Float_Size
772 or else Rt_Type
= Standard_Long_Float
)
780 -- Signed integer types. Also includes signed fixed-point types and
781 -- signed enumeration types share this circuitry.
783 -- Note on signed integer types. We do not consider types as signed for
784 -- this purpose if they have no negative numbers, or if they have biased
785 -- representation. The reason is that the value in either case basically
786 -- represents an unsigned value.
788 -- For example, consider:
790 -- type W is range 0 .. 2**32 - 1;
791 -- for W'Size use 32;
793 -- This is a signed type, but the representation is unsigned, and may
794 -- be outside the range of a 32-bit signed integer, so this must be
795 -- treated as 32-bit unsigned.
797 -- Similarly, the representation is also unsigned if we have:
799 -- type W is range -1 .. +254;
802 -- forcing a biased and unsigned representation
804 elsif not Is_Unsigned_Type
(FST
)
806 (Is_Fixed_Point_Type
(U_Type
)
808 Is_Enumeration_Type
(U_Type
)
810 (Is_Signed_Integer_Type
(U_Type
)
811 and then not Has_Biased_Representation
(FST
)))
813 if P_Size
<= Standard_Short_Short_Integer_Size
then
816 elsif P_Size
<= Standard_Short_Integer_Size
then
819 elsif P_Size
= 24 then
822 elsif P_Size
<= Standard_Integer_Size
then
825 elsif P_Size
<= Standard_Long_Integer_Size
then
828 elsif P_Size
<= Standard_Long_Long_Integer_Size
then
835 -- Unsigned integer types, also includes unsigned fixed-point types
836 -- and unsigned enumeration types (note we know they are unsigned
837 -- because we already tested for signed above).
839 -- Also includes signed integer types that are unsigned in the sense
840 -- that they do not include negative numbers. See above for details.
842 elsif Is_Modular_Integer_Type
(U_Type
)
843 or else Is_Fixed_Point_Type
(U_Type
)
844 or else Is_Enumeration_Type
(U_Type
)
845 or else Is_Signed_Integer_Type
(U_Type
)
847 if P_Size
<= Standard_Short_Short_Integer_Size
then
850 elsif P_Size
<= Standard_Short_Integer_Size
then
853 elsif P_Size
= 24 then
856 elsif P_Size
<= Standard_Integer_Size
then
859 elsif P_Size
<= Standard_Long_Integer_Size
then
862 elsif P_Size
<= Standard_Long_Long_Integer_Size
then
869 else pragma Assert
(Is_Access_Type
(U_Type
));
871 if Present
(P_Size
) and then P_Size
> System_Address_Size
then
878 -- Unchecked-convert parameter to the required type (i.e. the type of
879 -- the corresponding parameter, and call the appropriate routine.
881 Libent
:= RTE
(Lib_RE
);
884 Make_Procedure_Call_Statement
(Loc
,
885 Name
=> New_Occurrence_Of
(Libent
, Loc
),
886 Parameter_Associations
=> New_List
(
887 Relocate_Node
(Strm
),
888 Unchecked_Convert_To
(Etype
(Next_Formal
(First_Formal
(Libent
))),
889 Relocate_Node
(Item
))));
890 end Build_Elementary_Write_Call
;
892 -----------------------------------------
893 -- Build_Mutable_Record_Read_Procedure --
894 -----------------------------------------
896 procedure Build_Mutable_Record_Read_Procedure
900 Pnam
: out Entity_Id
)
902 Out_Formal
: Node_Id
;
903 -- Expression denoting the out formal parameter
905 Dcls
: constant List_Id
:= New_List
;
906 -- Declarations for the 'Read body
908 Stms
: constant List_Id
:= New_List
;
909 -- Statements for the 'Read body
912 -- Entity of the discriminant being processed
914 Tmp_For_Disc
: Entity_Id
;
915 -- Temporary object used to read the value of Disc
917 Tmps_For_Discs
: constant List_Id
:= New_List
;
918 -- List of object declarations for temporaries holding the read values
919 -- for the discriminants.
921 Cstr
: constant List_Id
:= New_List
;
922 -- List of constraints to be applied on temporary record
924 Discriminant_Checks
: constant List_Id
:= New_List
;
925 -- List of discriminant checks to be performed if the actual object
928 Tmp
: constant Entity_Id
:= Make_Defining_Identifier
(Loc
, Name_V
);
929 -- Temporary record must hide formal (assignments to components of the
930 -- record are always generated with V as the identifier for the record).
932 Constrained_Stms
: List_Id
:= New_List
;
933 -- Statements within the block where we have the constrained temporary
936 -- A mutable type cannot be a tagged type, so we generate a new name
937 -- for the stream procedure.
940 Make_Defining_Identifier
(Loc
,
941 Chars
=> Make_TSS_Name_Local
(Typ
, TSS_Stream_Read
));
943 if Is_Unchecked_Union
(Typ
) then
945 -- If this is an unchecked union, the stream procedure is erroneous,
946 -- because there are no discriminants to read.
948 -- This should generate a warning ???
951 Make_Raise_Program_Error
(Loc
,
952 Reason
=> PE_Unchecked_Union_Restriction
));
954 Build_Stream_Procedure
(Loc
, Typ
, Decl
, Pnam
, Stms
, Outp
=> True);
958 Disc
:= First_Discriminant
(Typ
);
961 Make_Selected_Component
(Loc
,
962 Prefix
=> New_Occurrence_Of
(Pnam
, Loc
),
963 Selector_Name
=> Make_Identifier
(Loc
, Name_V
));
965 -- Generate Reads for the discriminants of the type. The discriminants
966 -- need to be read before the rest of the components, so that variants
967 -- are initialized correctly. The discriminants must be read into temp
968 -- variables so an incomplete Read (interrupted by an exception, for
969 -- example) does not alter the passed object.
971 while Present
(Disc
) loop
972 Tmp_For_Disc
:= Make_Defining_Identifier
(Loc
,
973 New_External_Name
(Chars
(Disc
), "D"));
975 Append_To
(Tmps_For_Discs
,
976 Make_Object_Declaration
(Loc
,
977 Defining_Identifier
=> Tmp_For_Disc
,
978 Object_Definition
=> New_Occurrence_Of
(Etype
(Disc
), Loc
)));
979 Set_No_Initialization
(Last
(Tmps_For_Discs
));
982 Make_Attribute_Reference
(Loc
,
983 Prefix
=> New_Occurrence_Of
(Etype
(Disc
), Loc
),
984 Attribute_Name
=> Name_Read
,
985 Expressions
=> New_List
(
986 Make_Identifier
(Loc
, Name_S
),
987 New_Occurrence_Of
(Tmp_For_Disc
, Loc
))));
990 Make_Discriminant_Association
(Loc
,
991 Selector_Names
=> New_List
(New_Occurrence_Of
(Disc
, Loc
)),
992 Expression
=> New_Occurrence_Of
(Tmp_For_Disc
, Loc
)));
994 Append_To
(Discriminant_Checks
,
995 Make_Raise_Constraint_Error
(Loc
,
998 Left_Opnd
=> New_Occurrence_Of
(Tmp_For_Disc
, Loc
),
1000 Make_Selected_Component
(Loc
,
1001 Prefix
=> New_Copy_Tree
(Out_Formal
),
1002 Selector_Name
=> New_Occurrence_Of
(Disc
, Loc
))),
1003 Reason
=> CE_Discriminant_Check_Failed
));
1004 Next_Discriminant
(Disc
);
1007 -- Generate reads for the components of the record (including those
1008 -- that depend on discriminants).
1010 Build_Record_Read_Write_Procedure
(Loc
, Typ
, Decl
, Pnam
, Name_Read
);
1012 -- Save original statement sequence for component assignments, and
1013 -- replace it with Stms.
1015 Constrained_Stms
:= Statements
(Handled_Statement_Sequence
(Decl
));
1016 Set_Handled_Statement_Sequence
(Decl
,
1017 Make_Handled_Sequence_Of_Statements
(Loc
,
1018 Statements
=> Stms
));
1020 -- If Typ has controlled components (i.e. if it is classwide or
1021 -- Has_Controlled), or components constrained using the discriminants
1022 -- of Typ, then we need to ensure that all component assignments are
1023 -- performed on an object that has been appropriately constrained
1024 -- prior to being initialized. To this effect, we wrap the component
1025 -- assignments in a block where V is a constrained temporary.
1028 Make_Object_Declaration
(Loc
,
1029 Defining_Identifier
=> Tmp
,
1030 Object_Definition
=>
1031 Make_Subtype_Indication
(Loc
,
1032 Subtype_Mark
=> New_Occurrence_Of
(Base_Type
(Typ
), Loc
),
1034 Make_Index_Or_Discriminant_Constraint
(Loc
,
1035 Constraints
=> Cstr
))));
1037 -- AI05-023-1: Insert discriminant check prior to initialization of the
1038 -- constrained temporary.
1041 Make_Implicit_If_Statement
(Pnam
,
1043 Make_Attribute_Reference
(Loc
,
1044 Prefix
=> New_Copy_Tree
(Out_Formal
),
1045 Attribute_Name
=> Name_Constrained
),
1046 Then_Statements
=> Discriminant_Checks
));
1048 -- Now insert back original component assignments, wrapped in a block
1049 -- in which V is the constrained temporary.
1052 Make_Block_Statement
(Loc
,
1053 Declarations
=> Dcls
,
1054 Handled_Statement_Sequence
=> Parent
(Constrained_Stms
)));
1056 Append_To
(Constrained_Stms
,
1057 Make_Assignment_Statement
(Loc
,
1059 Expression
=> Make_Identifier
(Loc
, Name_V
)));
1061 Set_Declarations
(Decl
, Tmps_For_Discs
);
1062 end Build_Mutable_Record_Read_Procedure
;
1064 ------------------------------------------
1065 -- Build_Mutable_Record_Write_Procedure --
1066 ------------------------------------------
1068 procedure Build_Mutable_Record_Write_Procedure
1072 Pnam
: out Entity_Id
)
1080 Disc
:= First_Discriminant
(Typ
);
1082 -- Generate Writes for the discriminants of the type
1083 -- If the type is an unchecked union, use the default values of
1084 -- the discriminants, because they are not stored.
1086 while Present
(Disc
) loop
1087 if Is_Unchecked_Union
(Typ
) then
1089 New_Copy_Tree
(Discriminant_Default_Value
(Disc
));
1092 Make_Selected_Component
(Loc
,
1093 Prefix
=> Make_Identifier
(Loc
, Name_V
),
1094 Selector_Name
=> New_Occurrence_Of
(Disc
, Loc
));
1098 Make_Attribute_Reference
(Loc
,
1099 Prefix
=> New_Occurrence_Of
(Etype
(Disc
), Loc
),
1100 Attribute_Name
=> Name_Write
,
1101 Expressions
=> New_List
(
1102 Make_Identifier
(Loc
, Name_S
),
1105 Next_Discriminant
(Disc
);
1108 -- A mutable type cannot be a tagged type, so we generate a new name
1109 -- for the stream procedure.
1112 Make_Defining_Identifier
(Loc
,
1113 Chars
=> Make_TSS_Name_Local
(Typ
, TSS_Stream_Write
));
1114 Build_Record_Read_Write_Procedure
(Loc
, Typ
, Decl
, Pnam
, Name_Write
);
1116 -- Write the discriminants before the rest of the components, so
1117 -- that discriminant values are properly set of variants, etc.
1119 if Is_Non_Empty_List
(
1120 Statements
(Handled_Statement_Sequence
(Decl
)))
1123 (First
(Statements
(Handled_Statement_Sequence
(Decl
))), Stms
);
1125 Set_Statements
(Handled_Statement_Sequence
(Decl
), Stms
);
1127 end Build_Mutable_Record_Write_Procedure
;
1129 -----------------------------------------------
1130 -- Build_Record_Or_Elementary_Input_Function --
1131 -----------------------------------------------
1133 -- The function we build looks like
1135 -- function InputN (S : access RST) return Typ is
1136 -- C1 : constant Disc_Type_1;
1137 -- Discr_Type_1'Read (S, C1);
1138 -- C2 : constant Disc_Type_2;
1139 -- Discr_Type_2'Read (S, C2);
1141 -- Cn : constant Disc_Type_n;
1142 -- Discr_Type_n'Read (S, Cn);
1143 -- V : Typ (C1, C2, .. Cn)
1150 -- The discriminants are of course only present in the case of a record
1151 -- with discriminants. In the case of a record with no discriminants, or
1152 -- an elementary type, then no Cn constants are defined.
1154 procedure Build_Record_Or_Elementary_Input_Function
1158 Fnam
: out Entity_Id
)
1160 B_Typ
: constant Entity_Id
:= Underlying_Type
(Base_Type
(Typ
));
1165 Discr_Elmt
: Elmt_Id
:= No_Elmt
;
1177 -- In the presence of multiple instantiations (as in uses of the Booch
1178 -- components) the base type may be private, and the underlying type
1179 -- already constrained, in which case there's no discriminant constraint
1182 if Has_Discriminants
(Typ
)
1183 and then No
(Discriminant_Default_Value
(First_Discriminant
(Typ
)))
1184 and then not Is_Constrained
(Underlying_Type
(B_Typ
))
1186 Discr
:= First_Discriminant
(B_Typ
);
1188 -- If the prefix subtype is constrained, then retrieve the first
1189 -- element of its constraint.
1191 if Is_Constrained
(Typ
) then
1192 Discr_Elmt
:= First_Elmt
(Discriminant_Constraint
(Typ
));
1195 while Present
(Discr
) loop
1196 Cn
:= New_External_Name
('C', J
);
1199 Make_Object_Declaration
(Loc
,
1200 Defining_Identifier
=> Make_Defining_Identifier
(Loc
, Cn
),
1201 Object_Definition
=>
1202 New_Occurrence_Of
(Etype
(Discr
), Loc
));
1204 -- If this is an access discriminant, do not perform default
1205 -- initialization. The discriminant is about to get its value
1206 -- from Read, and if the type is null excluding we do not want
1207 -- spurious warnings on an initial null value.
1209 if Is_Access_Type
(Etype
(Discr
)) then
1210 Set_No_Initialization
(Decl
);
1213 Append_To
(Decls
, Decl
);
1215 Make_Attribute_Reference
(Loc
,
1216 Prefix
=> New_Occurrence_Of
(Etype
(Discr
), Loc
),
1217 Attribute_Name
=> Name_Read
,
1218 Expressions
=> New_List
(
1219 Make_Identifier
(Loc
, Name_S
),
1220 Make_Identifier
(Loc
, Cn
))));
1222 Append_To
(Constr
, Make_Identifier
(Loc
, Cn
));
1224 -- If the prefix subtype imposes a discriminant constraint, then
1225 -- check that each discriminant value equals the value read.
1227 if Present
(Discr_Elmt
) then
1229 Make_Raise_Constraint_Error
(Loc
,
1230 Condition
=> Make_Op_Ne
(Loc
,
1233 (Defining_Identifier
(Decl
), Loc
),
1235 New_Copy_Tree
(Node
(Discr_Elmt
))),
1236 Reason
=> CE_Discriminant_Check_Failed
));
1238 Next_Elmt
(Discr_Elmt
);
1241 Next_Discriminant
(Discr
);
1246 Make_Subtype_Indication
(Loc
,
1247 Subtype_Mark
=> New_Occurrence_Of
(B_Typ
, Loc
),
1249 Make_Index_Or_Discriminant_Constraint
(Loc
,
1250 Constraints
=> Constr
));
1252 -- If no discriminants, then just use the type with no constraint
1255 Odef
:= New_Occurrence_Of
(B_Typ
, Loc
);
1258 -- Create an extended return statement encapsulating the result object
1259 -- and 'Read call, which is needed in general for proper handling of
1260 -- build-in-place results (such as when the result type is inherently
1264 Make_Object_Declaration
(Loc
,
1265 Defining_Identifier
=> Make_Defining_Identifier
(Loc
, Name_V
),
1266 Object_Definition
=> Odef
);
1268 -- If the type is an access type, do not perform default initialization.
1269 -- The object is about to get its value from Read, and if the type is
1270 -- null excluding we do not want spurious warnings on an initial null.
1272 if Is_Access_Type
(B_Typ
) then
1273 Set_No_Initialization
(Obj_Decl
);
1277 Make_Extended_Return_Statement
(Loc
,
1278 Return_Object_Declarations
=> New_List
(Obj_Decl
),
1279 Handled_Statement_Sequence
=>
1280 Make_Handled_Sequence_Of_Statements
(Loc
,
1281 Statements
=> New_List
(
1282 Make_Attribute_Reference
(Loc
,
1283 Prefix
=> New_Occurrence_Of
(B_Typ
, Loc
),
1284 Attribute_Name
=> Name_Read
,
1285 Expressions
=> New_List
(
1286 Make_Identifier
(Loc
, Name_S
),
1287 Make_Identifier
(Loc
, Name_V
)))))));
1289 Fnam
:= Make_Stream_Subprogram_Name
(Loc
, B_Typ
, TSS_Stream_Input
);
1291 Build_Stream_Function
(Loc
, B_Typ
, Decl
, Fnam
, Decls
, Stms
);
1292 end Build_Record_Or_Elementary_Input_Function
;
1294 -------------------------------------------------
1295 -- Build_Record_Or_Elementary_Output_Procedure --
1296 -------------------------------------------------
1298 procedure Build_Record_Or_Elementary_Output_Procedure
1302 Pnam
: out Entity_Id
)
1311 -- Note that of course there will be no discriminants for the elementary
1312 -- type case, so Has_Discriminants will be False. Note that the language
1313 -- rules do not allow writing the discriminants in the defaulted case,
1314 -- because those are written by 'Write.
1316 if Has_Discriminants
(Typ
)
1317 and then No
(Discriminant_Default_Value
(First_Discriminant
(Typ
)))
1319 Disc
:= First_Discriminant
(Typ
);
1320 while Present
(Disc
) loop
1322 -- If the type is an unchecked union, it must have default
1323 -- discriminants (this is checked earlier), and those defaults
1324 -- are written out to the stream.
1326 if Is_Unchecked_Union
(Typ
) then
1327 Disc_Ref
:= New_Copy_Tree
(Discriminant_Default_Value
(Disc
));
1331 Make_Selected_Component
(Loc
,
1332 Prefix
=> Make_Identifier
(Loc
, Name_V
),
1333 Selector_Name
=> New_Occurrence_Of
(Disc
, Loc
));
1337 Make_Attribute_Reference
(Loc
,
1339 New_Occurrence_Of
(Stream_Base_Type
(Etype
(Disc
)), Loc
),
1340 Attribute_Name
=> Name_Write
,
1341 Expressions
=> New_List
(
1342 Make_Identifier
(Loc
, Name_S
),
1345 Next_Discriminant
(Disc
);
1350 Make_Attribute_Reference
(Loc
,
1351 Prefix
=> New_Occurrence_Of
(Typ
, Loc
),
1352 Attribute_Name
=> Name_Write
,
1353 Expressions
=> New_List
(
1354 Make_Identifier
(Loc
, Name_S
),
1355 Make_Identifier
(Loc
, Name_V
))));
1357 Pnam
:= Make_Stream_Subprogram_Name
(Loc
, Typ
, TSS_Stream_Output
);
1359 Build_Stream_Procedure
(Loc
, Typ
, Decl
, Pnam
, Stms
, Outp
=> False);
1360 end Build_Record_Or_Elementary_Output_Procedure
;
1362 ---------------------------------
1363 -- Build_Record_Read_Procedure --
1364 ---------------------------------
1366 procedure Build_Record_Read_Procedure
1370 Pnam
: out Entity_Id
)
1373 Pnam
:= Make_Stream_Subprogram_Name
(Loc
, Typ
, TSS_Stream_Read
);
1374 Build_Record_Read_Write_Procedure
(Loc
, Typ
, Decl
, Pnam
, Name_Read
);
1375 end Build_Record_Read_Procedure
;
1377 ---------------------------------------
1378 -- Build_Record_Read_Write_Procedure --
1379 ---------------------------------------
1381 -- The form of the record read/write procedure is as shown by the
1382 -- following example for a case with one discriminant case variant:
1384 -- procedure pnam (S : access RST, V : [out] Typ) is
1386 -- Component_Type'Read/Write (S, V.component);
1387 -- Component_Type'Read/Write (S, V.component);
1389 -- Component_Type'Read/Write (S, V.component);
1391 -- case V.discriminant is
1393 -- Component_Type'Read/Write (S, V.component);
1394 -- Component_Type'Read/Write (S, V.component);
1396 -- Component_Type'Read/Write (S, V.component);
1399 -- Component_Type'Read/Write (S, V.component);
1400 -- Component_Type'Read/Write (S, V.component);
1402 -- Component_Type'Read/Write (S, V.component);
1407 -- The out keyword for V is supplied in the Read case
1409 procedure Build_Record_Read_Write_Procedure
1420 In_Limited_Extension
: Boolean := False;
1421 -- Set to True while processing the record extension definition
1422 -- for an extension of a limited type (for which an ancestor type
1423 -- has an explicit Nam attribute definition).
1425 function Make_Component_List_Attributes
(CL
: Node_Id
) return List_Id
;
1426 -- Returns a sequence of attributes to process the components that
1427 -- are referenced in the given component list.
1429 function Make_Field_Attribute
(C
: Entity_Id
) return Node_Id
;
1430 -- Given C, the entity for a discriminant or component, build
1431 -- an attribute for the corresponding field values.
1433 function Make_Field_Attributes
(Clist
: List_Id
) return List_Id
;
1434 -- Given Clist, a component items list, construct series of attributes
1435 -- for fieldwise processing of the corresponding components.
1437 ------------------------------------
1438 -- Make_Component_List_Attributes --
1439 ------------------------------------
1441 function Make_Component_List_Attributes
(CL
: Node_Id
) return List_Id
is
1442 CI
: constant List_Id
:= Component_Items
(CL
);
1443 VP
: constant Node_Id
:= Variant_Part
(CL
);
1453 Result
:= Make_Field_Attributes
(CI
);
1455 if Present
(VP
) then
1458 V
:= First_Non_Pragma
(Variants
(VP
));
1459 while Present
(V
) loop
1462 DC
:= First
(Discrete_Choices
(V
));
1463 while Present
(DC
) loop
1464 Append_To
(DCH
, New_Copy_Tree
(DC
));
1469 Make_Case_Statement_Alternative
(Loc
,
1470 Discrete_Choices
=> DCH
,
1472 Make_Component_List_Attributes
(Component_List
(V
))));
1473 Next_Non_Pragma
(V
);
1476 -- Note: in the following, we make sure that we use new occurrence
1477 -- of for the selector, since there are cases in which we make a
1478 -- reference to a hidden discriminant that is not visible.
1480 -- If the enclosing record is an unchecked_union, we use the
1481 -- default expressions for the discriminant (it must exist)
1482 -- because we cannot generate a reference to it, given that
1483 -- it is not stored.
1485 if Is_Unchecked_Union
(Scope
(Entity
(Name
(VP
)))) then
1488 (Discriminant_Default_Value
(Entity
(Name
(VP
))));
1491 Make_Selected_Component
(Loc
,
1492 Prefix
=> Make_Identifier
(Loc
, Name_V
),
1494 New_Occurrence_Of
(Entity
(Name
(VP
)), Loc
));
1498 Make_Case_Statement
(Loc
,
1499 Expression
=> D_Ref
,
1500 Alternatives
=> Alts
));
1504 end Make_Component_List_Attributes
;
1506 --------------------------
1507 -- Make_Field_Attribute --
1508 --------------------------
1510 function Make_Field_Attribute
(C
: Entity_Id
) return Node_Id
is
1511 Field_Typ
: constant Entity_Id
:= Stream_Base_Type
(Etype
(C
));
1513 TSS_Names
: constant array (Name_Input
.. Name_Write
) of
1515 (Name_Read
=> TSS_Stream_Read
,
1516 Name_Write
=> TSS_Stream_Write
,
1517 Name_Input
=> TSS_Stream_Input
,
1518 Name_Output
=> TSS_Stream_Output
,
1519 others => TSS_Null
);
1520 pragma Assert
(TSS_Names
(Nam
) /= TSS_Null
);
1523 if In_Limited_Extension
1524 and then Is_Limited_Type
(Field_Typ
)
1525 and then No
(Find_Inherited_TSS
(Field_Typ
, TSS_Names
(Nam
)))
1527 -- The declaration is illegal per 13.13.2(9/1), and this is
1528 -- enforced in Exp_Ch3.Check_Stream_Attributes. Keep the caller
1529 -- happy by returning a null statement.
1531 return Make_Null_Statement
(Loc
);
1535 Make_Attribute_Reference
(Loc
,
1536 Prefix
=> New_Occurrence_Of
(Field_Typ
, Loc
),
1537 Attribute_Name
=> Nam
,
1538 Expressions
=> New_List
(
1539 Make_Identifier
(Loc
, Name_S
),
1540 Make_Selected_Component
(Loc
,
1541 Prefix
=> Make_Identifier
(Loc
, Name_V
),
1542 Selector_Name
=> New_Occurrence_Of
(C
, Loc
))));
1543 end Make_Field_Attribute
;
1545 ---------------------------
1546 -- Make_Field_Attributes --
1547 ---------------------------
1549 function Make_Field_Attributes
(Clist
: List_Id
) return List_Id
is
1551 Result
: constant List_Id
:= New_List
;
1554 -- Loop through components, skipping all internal components, which
1555 -- are not part of the value (e.g. _Tag), except that we don't skip
1556 -- the _Parent, since we do want to process that recursively. If
1557 -- _Parent is an interface type, being abstract with no components
1558 -- there is no need to handle it.
1560 Item
:= First
(Clist
);
1561 while Present
(Item
) loop
1562 if Nkind
(Item
) = N_Component_Declaration
1564 ((Chars
(Defining_Identifier
(Item
)) = Name_uParent
1565 and then not Is_Interface
1566 (Etype
(Defining_Identifier
(Item
))))
1568 not Is_Internal_Name
(Chars
(Defining_Identifier
(Item
))))
1572 Make_Field_Attribute
(Defining_Identifier
(Item
)));
1579 end Make_Field_Attributes
;
1581 -- Start of processing for Build_Record_Read_Write_Procedure
1584 -- For the protected type case, use corresponding record
1586 if Is_Protected_Type
(Typ
) then
1587 Typt
:= Corresponding_Record_Type
(Typ
);
1592 -- Note that we do nothing with the discriminants, since Read and
1593 -- Write do not read or write the discriminant values. All handling
1594 -- of discriminants occurs in the Input and Output subprograms.
1596 Rdef
:= Type_Definition
1597 (Declaration_Node
(Base_Type
(Underlying_Type
(Typt
))));
1600 -- In record extension case, the fields we want, including the _Parent
1601 -- field representing the parent type, are to be found in the extension.
1602 -- Note that we will naturally process the _Parent field using the type
1603 -- of the parent, and hence its stream attributes, which is appropriate.
1605 if Nkind
(Rdef
) = N_Derived_Type_Definition
then
1606 Rdef
:= Record_Extension_Part
(Rdef
);
1608 if Is_Limited_Type
(Typt
) then
1609 In_Limited_Extension
:= True;
1613 if Present
(Component_List
(Rdef
)) then
1614 Append_List_To
(Stms
,
1615 Make_Component_List_Attributes
(Component_List
(Rdef
)));
1618 Build_Stream_Procedure
1619 (Loc
, Typ
, Decl
, Pnam
, Stms
, Outp
=> Nam
= Name_Read
);
1620 end Build_Record_Read_Write_Procedure
;
1622 ----------------------------------
1623 -- Build_Record_Write_Procedure --
1624 ----------------------------------
1626 procedure Build_Record_Write_Procedure
1630 Pnam
: out Entity_Id
)
1633 Pnam
:= Make_Stream_Subprogram_Name
(Loc
, Typ
, TSS_Stream_Write
);
1634 Build_Record_Read_Write_Procedure
(Loc
, Typ
, Decl
, Pnam
, Name_Write
);
1635 end Build_Record_Write_Procedure
;
1637 -------------------------------
1638 -- Build_Stream_Attr_Profile --
1639 -------------------------------
1641 function Build_Stream_Attr_Profile
1644 Nam
: TSS_Name_Type
) return List_Id
1649 -- (Ada 2005: AI-441): Set the null-excluding attribute because it has
1650 -- no semantic meaning in Ada 95 but it is a requirement in Ada 2005.
1652 Profile
:= New_List
(
1653 Make_Parameter_Specification
(Loc
,
1654 Defining_Identifier
=> Make_Defining_Identifier
(Loc
, Name_S
),
1656 Make_Access_Definition
(Loc
,
1657 Null_Exclusion_Present
=> True,
1658 Subtype_Mark
=> New_Occurrence_Of
(
1659 Class_Wide_Type
(RTE
(RE_Root_Stream_Type
)), Loc
))));
1661 if Nam
/= TSS_Stream_Input
then
1663 Make_Parameter_Specification
(Loc
,
1664 Defining_Identifier
=> Make_Defining_Identifier
(Loc
, Name_V
),
1665 Out_Present
=> (Nam
= TSS_Stream_Read
),
1666 Parameter_Type
=> New_Occurrence_Of
(Typ
, Loc
)));
1670 end Build_Stream_Attr_Profile
;
1672 ---------------------------
1673 -- Build_Stream_Function --
1674 ---------------------------
1676 procedure Build_Stream_Function
1687 -- Construct function specification
1689 -- (Ada 2005: AI-441): Set the null-excluding attribute because it has
1690 -- no semantic meaning in Ada 95 but it is a requirement in Ada 2005.
1693 Make_Function_Specification
(Loc
,
1694 Defining_Unit_Name
=> Fnam
,
1696 Parameter_Specifications
=> New_List
(
1697 Make_Parameter_Specification
(Loc
,
1698 Defining_Identifier
=> Make_Defining_Identifier
(Loc
, Name_S
),
1700 Make_Access_Definition
(Loc
,
1701 Null_Exclusion_Present
=> True,
1704 (Class_Wide_Type
(RTE
(RE_Root_Stream_Type
)), Loc
)))),
1706 Result_Definition
=> New_Occurrence_Of
(Typ
, Loc
));
1709 Make_Subprogram_Body
(Loc
,
1710 Specification
=> Spec
,
1711 Declarations
=> Decls
,
1712 Handled_Statement_Sequence
=>
1713 Make_Handled_Sequence_Of_Statements
(Loc
,
1714 Statements
=> Stms
));
1715 end Build_Stream_Function
;
1717 ----------------------------
1718 -- Build_Stream_Procedure --
1719 ----------------------------
1721 procedure Build_Stream_Procedure
1732 -- Construct procedure specification
1734 -- (Ada 2005: AI-441): Set the null-excluding attribute because it has
1735 -- no semantic meaning in Ada 95 but it is a requirement in Ada 2005.
1738 Make_Procedure_Specification
(Loc
,
1739 Defining_Unit_Name
=> Pnam
,
1741 Parameter_Specifications
=> New_List
(
1742 Make_Parameter_Specification
(Loc
,
1743 Defining_Identifier
=> Make_Defining_Identifier
(Loc
, Name_S
),
1745 Make_Access_Definition
(Loc
,
1746 Null_Exclusion_Present
=> True,
1749 (Class_Wide_Type
(RTE
(RE_Root_Stream_Type
)), Loc
))),
1751 Make_Parameter_Specification
(Loc
,
1752 Defining_Identifier
=> Make_Defining_Identifier
(Loc
, Name_V
),
1753 Out_Present
=> Outp
,
1754 Parameter_Type
=> New_Occurrence_Of
(Typ
, Loc
))));
1757 Make_Subprogram_Body
(Loc
,
1758 Specification
=> Spec
,
1759 Declarations
=> Empty_List
,
1760 Handled_Statement_Sequence
=>
1761 Make_Handled_Sequence_Of_Statements
(Loc
,
1762 Statements
=> Stms
));
1763 end Build_Stream_Procedure
;
1765 -----------------------------
1766 -- Has_Stream_Standard_Rep --
1767 -----------------------------
1769 function Has_Stream_Standard_Rep
(U_Type
: Entity_Id
) return Boolean is
1773 if Has_Non_Standard_Rep
(U_Type
) then
1777 if Has_Stream_Size_Clause
(U_Type
) then
1778 Siz
:= Static_Integer
(Expression
(Stream_Size_Clause
(U_Type
)));
1780 Siz
:= Esize
(First_Subtype
(U_Type
));
1783 return Siz
= Esize
(Root_Type
(U_Type
));
1784 end Has_Stream_Standard_Rep
;
1786 ---------------------------------
1787 -- Make_Stream_Subprogram_Name --
1788 ---------------------------------
1790 function Make_Stream_Subprogram_Name
1793 Nam
: TSS_Name_Type
) return Entity_Id
1798 -- For tagged types, we are dealing with a TSS associated with the
1799 -- declaration, so we use the standard primitive function name. For
1800 -- other types, generate a local TSS name since we are generating
1801 -- the subprogram at the point of use.
1803 if Is_Tagged_Type
(Typ
) then
1804 Sname
:= Make_TSS_Name
(Typ
, Nam
);
1806 Sname
:= Make_TSS_Name_Local
(Typ
, Nam
);
1809 return Make_Defining_Identifier
(Loc
, Sname
);
1810 end Make_Stream_Subprogram_Name
;
1812 ----------------------
1813 -- Stream_Base_Type --
1814 ----------------------
1816 function Stream_Base_Type
(E
: Entity_Id
) return Entity_Id
is
1818 if Is_Array_Type
(E
)
1819 and then Is_First_Subtype
(E
)
1823 return Base_Type
(E
);
1825 end Stream_Base_Type
;