2013-05-14 Richard Biener <rguenther@suse.de>
[official-gcc.git] / gcc / ada / exp_strm.adb
blob987556a84adbc4607960dc88e5e99255acc7e1ee
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-2011, 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 ------------------------------------------------------------------------------
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;
43 package body Exp_Strm is
45 -----------------------
46 -- Local Subprograms --
47 -----------------------
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.
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.
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.
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).
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.
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).
112 --------------------------------
113 -- Build_Array_Input_Function --
114 --------------------------------
116 -- The function we build looks like
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);
127 -- V : Typ'Base (L1 .. H1, L2 .. H2, ... Ln .. Hn)
129 -- begin
130 -- Typ'Read (S, V);
131 -- return V;
132 -- end typSI[_nnn]
134 -- Note: the suffix [_nnn] is present for non-tagged types, where we
135 -- generate a local subprogram at the point of the occurrence of the
136 -- attribute reference, so the name must be unique.
138 procedure Build_Array_Input_Function
139 (Loc : Source_Ptr;
140 Typ : Entity_Id;
141 Decl : out Node_Id;
142 Fnam : out Entity_Id)
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;
154 begin
155 Decls := New_List;
156 Ranges := New_List;
157 Indx := First_Index (Typ);
159 for J in 1 .. Dim loop
160 Lnam := New_External_Name ('L', J);
161 Hnam := New_External_Name ('H', J);
163 Append_To (Decls,
164 Make_Object_Declaration (Loc,
165 Defining_Identifier => Make_Defining_Identifier (Loc, Lnam),
166 Constant_Present => True,
167 Object_Definition => New_Occurrence_Of (Etype (Indx), Loc),
168 Expression =>
169 Make_Attribute_Reference (Loc,
170 Prefix =>
171 New_Occurrence_Of (Stream_Base_Type (Etype (Indx)), Loc),
172 Attribute_Name => Name_Input,
173 Expressions => New_List (Make_Identifier (Loc, Name_S)))));
175 Append_To (Decls,
176 Make_Object_Declaration (Loc,
177 Defining_Identifier => Make_Defining_Identifier (Loc, Hnam),
178 Constant_Present => True,
179 Object_Definition =>
180 New_Occurrence_Of (Stream_Base_Type (Etype (Indx)), Loc),
181 Expression =>
182 Make_Attribute_Reference (Loc,
183 Prefix =>
184 New_Occurrence_Of (Stream_Base_Type (Etype (Indx)), Loc),
185 Attribute_Name => Name_Input,
186 Expressions => New_List (Make_Identifier (Loc, Name_S)))));
188 Append_To (Ranges,
189 Make_Range (Loc,
190 Low_Bound => Make_Identifier (Loc, Lnam),
191 High_Bound => Make_Identifier (Loc, Hnam)));
193 Next_Index (Indx);
194 end loop;
196 -- If the type is constrained, use it directly. Otherwise build a
197 -- subtype indication with the proper bounds.
199 if Is_Constrained (Typ) then
200 Odecl :=
201 Make_Object_Declaration (Loc,
202 Defining_Identifier => Make_Defining_Identifier (Loc, Name_V),
203 Object_Definition => New_Occurrence_Of (Typ, Loc));
205 else
206 Odecl :=
207 Make_Object_Declaration (Loc,
208 Defining_Identifier => Make_Defining_Identifier (Loc, Name_V),
209 Object_Definition =>
210 Make_Subtype_Indication (Loc,
211 Subtype_Mark =>
212 New_Occurrence_Of (Stream_Base_Type (Typ), Loc),
213 Constraint =>
214 Make_Index_Or_Discriminant_Constraint (Loc, Ranges)));
215 end if;
217 Rstmt :=
218 Make_Attribute_Reference (Loc,
219 Prefix => New_Occurrence_Of (Typ, Loc),
220 Attribute_Name => Name_Read,
221 Expressions => New_List (
222 Make_Identifier (Loc, Name_S),
223 Make_Identifier (Loc, Name_V)));
225 Stms := New_List (
226 Make_Extended_Return_Statement (Loc,
227 Return_Object_Declarations => New_List (Odecl),
228 Handled_Statement_Sequence =>
229 Make_Handled_Sequence_Of_Statements (Loc, New_List (Rstmt))));
231 Fnam :=
232 Make_Defining_Identifier (Loc,
233 Chars => Make_TSS_Name_Local (Typ, TSS_Stream_Input));
235 Build_Stream_Function (Loc, Typ, Decl, Fnam, Decls, Stms);
236 end Build_Array_Input_Function;
238 ----------------------------------
239 -- Build_Array_Output_Procedure --
240 ----------------------------------
242 procedure Build_Array_Output_Procedure
243 (Loc : Source_Ptr;
244 Typ : Entity_Id;
245 Decl : out Node_Id;
246 Pnam : out Entity_Id)
248 Stms : List_Id;
249 Indx : Node_Id;
251 begin
252 -- Build series of statements to output bounds
254 Indx := First_Index (Typ);
255 Stms := New_List;
257 for J in 1 .. Number_Dimensions (Typ) loop
258 Append_To (Stms,
259 Make_Attribute_Reference (Loc,
260 Prefix =>
261 New_Occurrence_Of (Stream_Base_Type (Etype (Indx)), Loc),
262 Attribute_Name => Name_Write,
263 Expressions => New_List (
264 Make_Identifier (Loc, Name_S),
265 Make_Attribute_Reference (Loc,
266 Prefix => Make_Identifier (Loc, Name_V),
267 Attribute_Name => Name_First,
268 Expressions => New_List (
269 Make_Integer_Literal (Loc, J))))));
271 Append_To (Stms,
272 Make_Attribute_Reference (Loc,
273 Prefix =>
274 New_Occurrence_Of (Stream_Base_Type (Etype (Indx)), Loc),
275 Attribute_Name => Name_Write,
276 Expressions => New_List (
277 Make_Identifier (Loc, Name_S),
278 Make_Attribute_Reference (Loc,
279 Prefix => Make_Identifier (Loc, Name_V),
280 Attribute_Name => Name_Last,
281 Expressions => New_List (
282 Make_Integer_Literal (Loc, J))))));
284 Next_Index (Indx);
285 end loop;
287 -- Append Write attribute to write array elements
289 Append_To (Stms,
290 Make_Attribute_Reference (Loc,
291 Prefix => New_Occurrence_Of (Typ, Loc),
292 Attribute_Name => Name_Write,
293 Expressions => New_List (
294 Make_Identifier (Loc, Name_S),
295 Make_Identifier (Loc, Name_V))));
297 Pnam :=
298 Make_Defining_Identifier (Loc,
299 Chars => Make_TSS_Name_Local (Typ, TSS_Stream_Output));
301 Build_Stream_Procedure (Loc, Typ, Decl, Pnam, Stms, False);
302 end Build_Array_Output_Procedure;
304 --------------------------------
305 -- Build_Array_Read_Procedure --
306 --------------------------------
308 procedure Build_Array_Read_Procedure
309 (Nod : Node_Id;
310 Typ : Entity_Id;
311 Decl : out Node_Id;
312 Pnam : out Entity_Id)
314 Loc : constant Source_Ptr := Sloc (Nod);
316 begin
317 Pnam :=
318 Make_Defining_Identifier (Loc,
319 Chars => Make_TSS_Name_Local (Typ, TSS_Stream_Read));
320 Build_Array_Read_Write_Procedure (Nod, Typ, Decl, Pnam, Name_Read);
321 end Build_Array_Read_Procedure;
323 --------------------------------------
324 -- Build_Array_Read_Write_Procedure --
325 --------------------------------------
327 -- The form of the array read/write procedure is as follows:
329 -- procedure pnam (S : access RST, V : [out] Typ) is
330 -- begin
331 -- for L1 in V'Range (1) loop
332 -- for L2 in V'Range (2) loop
333 -- ...
334 -- for Ln in V'Range (n) loop
335 -- Component_Type'Read/Write (S, V (L1, L2, .. Ln));
336 -- end loop;
337 -- ..
338 -- end loop;
339 -- end loop
340 -- end pnam;
342 -- The out keyword for V is supplied in the Read case
344 procedure Build_Array_Read_Write_Procedure
345 (Nod : Node_Id;
346 Typ : Entity_Id;
347 Decl : out Node_Id;
348 Pnam : Entity_Id;
349 Nam : Name_Id)
351 Loc : constant Source_Ptr := Sloc (Nod);
352 Ndim : constant Pos := Number_Dimensions (Typ);
353 Ctyp : constant Entity_Id := Component_Type (Typ);
355 Stm : Node_Id;
356 Exl : List_Id;
357 RW : Entity_Id;
359 begin
360 -- First build the inner attribute call
362 Exl := New_List;
364 for J in 1 .. Ndim loop
365 Append_To (Exl, Make_Identifier (Loc, New_External_Name ('L', J)));
366 end loop;
368 Stm :=
369 Make_Attribute_Reference (Loc,
370 Prefix => New_Occurrence_Of (Stream_Base_Type (Ctyp), Loc),
371 Attribute_Name => Nam,
372 Expressions => New_List (
373 Make_Identifier (Loc, Name_S),
374 Make_Indexed_Component (Loc,
375 Prefix => Make_Identifier (Loc, Name_V),
376 Expressions => Exl)));
378 -- The corresponding stream attribute for the component type of the
379 -- array may be user-defined, and be frozen after the type for which
380 -- we are generating the stream subprogram. In that case, freeze the
381 -- stream attribute of the component type, whose declaration could not
382 -- generate any additional freezing actions in any case.
384 if Nam = Name_Read then
385 RW := TSS (Base_Type (Ctyp), TSS_Stream_Read);
386 else
387 RW := TSS (Base_Type (Ctyp), TSS_Stream_Write);
388 end if;
390 if Present (RW)
391 and then not Is_Frozen (RW)
392 then
393 Set_Is_Frozen (RW);
394 end if;
396 -- Now this is the big loop to wrap that statement up in a sequence
397 -- of loops. The first time around, Stm is the attribute call. The
398 -- second and subsequent times, Stm is an inner loop.
400 for J in 1 .. Ndim loop
401 Stm :=
402 Make_Implicit_Loop_Statement (Nod,
403 Iteration_Scheme =>
404 Make_Iteration_Scheme (Loc,
405 Loop_Parameter_Specification =>
406 Make_Loop_Parameter_Specification (Loc,
407 Defining_Identifier =>
408 Make_Defining_Identifier (Loc,
409 Chars => New_External_Name ('L', Ndim - J + 1)),
411 Discrete_Subtype_Definition =>
412 Make_Attribute_Reference (Loc,
413 Prefix => Make_Identifier (Loc, Name_V),
414 Attribute_Name => Name_Range,
416 Expressions => New_List (
417 Make_Integer_Literal (Loc, Ndim - J + 1))))),
419 Statements => New_List (Stm));
421 end loop;
423 Build_Stream_Procedure
424 (Loc, Typ, Decl, Pnam, New_List (Stm), Nam = Name_Read);
425 end Build_Array_Read_Write_Procedure;
427 ---------------------------------
428 -- Build_Array_Write_Procedure --
429 ---------------------------------
431 procedure Build_Array_Write_Procedure
432 (Nod : Node_Id;
433 Typ : Entity_Id;
434 Decl : out Node_Id;
435 Pnam : out Entity_Id)
437 Loc : constant Source_Ptr := Sloc (Nod);
439 begin
440 Pnam :=
441 Make_Defining_Identifier (Loc,
442 Chars => Make_TSS_Name_Local (Typ, TSS_Stream_Write));
443 Build_Array_Read_Write_Procedure (Nod, Typ, Decl, Pnam, Name_Write);
444 end Build_Array_Write_Procedure;
446 ---------------------------------
447 -- Build_Elementary_Input_Call --
448 ---------------------------------
450 function Build_Elementary_Input_Call (N : Node_Id) return Node_Id is
451 Loc : constant Source_Ptr := Sloc (N);
452 P_Type : constant Entity_Id := Entity (Prefix (N));
453 U_Type : constant Entity_Id := Underlying_Type (P_Type);
454 Rt_Type : constant Entity_Id := Root_Type (U_Type);
455 FST : constant Entity_Id := First_Subtype (U_Type);
456 Strm : constant Node_Id := First (Expressions (N));
457 Targ : constant Node_Id := Next (Strm);
458 P_Size : constant Uint := Get_Stream_Size (FST);
459 Res : Node_Id;
460 Lib_RE : RE_Id;
462 begin
464 -- Check first for Boolean and Character. These are enumeration types,
465 -- but we treat them specially, since they may require special handling
466 -- in the transfer protocol. However, this special handling only applies
467 -- if they have standard representation, otherwise they are treated like
468 -- any other enumeration type.
470 if Rt_Type = Standard_Boolean
471 and then Has_Stream_Standard_Rep (U_Type)
472 then
473 Lib_RE := RE_I_B;
475 elsif Rt_Type = Standard_Character
476 and then Has_Stream_Standard_Rep (U_Type)
477 then
478 Lib_RE := RE_I_C;
480 elsif Rt_Type = Standard_Wide_Character
481 and then Has_Stream_Standard_Rep (U_Type)
482 then
483 Lib_RE := RE_I_WC;
485 elsif Rt_Type = Standard_Wide_Wide_Character
486 and then Has_Stream_Standard_Rep (U_Type)
487 then
488 Lib_RE := RE_I_WWC;
490 -- Floating point types
492 elsif Is_Floating_Point_Type (U_Type) then
494 -- Question: should we use P_Size or Rt_Type to distinguish between
495 -- possible floating point types? If a non-standard size or a stream
496 -- size is specified, then we should certainly use the size. But if
497 -- we have two types the same (notably Short_Float_Size = Float_Size
498 -- which is close to universally true, and Long_Long_Float_Size =
499 -- Long_Float_Size, true on most targets except the x86), then we
500 -- would really rather use the root type, so that if people want to
501 -- fiddle with System.Stream_Attributes to get inter-target portable
502 -- streams, they get the size they expect. Consider in particular the
503 -- case of a stream written on an x86, with 96-bit Long_Long_Float
504 -- being read into a non-x86 target with 64 bit Long_Long_Float. A
505 -- special version of System.Stream_Attributes can deal with this
506 -- provided the proper type is always used.
508 -- To deal with these two requirements we add the special checks
509 -- on equal sizes and use the root type to distinguish.
511 if P_Size <= Standard_Short_Float_Size
512 and then (Standard_Short_Float_Size /= Standard_Float_Size
513 or else Rt_Type = Standard_Short_Float)
514 then
515 Lib_RE := RE_I_SF;
517 elsif P_Size <= Standard_Float_Size then
518 Lib_RE := RE_I_F;
520 elsif P_Size <= Standard_Long_Float_Size
521 and then (Standard_Long_Float_Size /= Standard_Long_Long_Float_Size
522 or else Rt_Type = Standard_Long_Float)
523 then
524 Lib_RE := RE_I_LF;
526 else
527 Lib_RE := RE_I_LLF;
528 end if;
530 -- Signed integer types. Also includes signed fixed-point types and
531 -- enumeration types with a signed representation.
533 -- Note on signed integer types. We do not consider types as signed for
534 -- this purpose if they have no negative numbers, or if they have biased
535 -- representation. The reason is that the value in either case basically
536 -- represents an unsigned value.
538 -- For example, consider:
540 -- type W is range 0 .. 2**32 - 1;
541 -- for W'Size use 32;
543 -- This is a signed type, but the representation is unsigned, and may
544 -- be outside the range of a 32-bit signed integer, so this must be
545 -- treated as 32-bit unsigned.
547 -- Similarly, if we have
549 -- type W is range -1 .. +254;
550 -- for W'Size use 8;
552 -- then the representation is unsigned
554 elsif not Is_Unsigned_Type (FST)
556 -- The following set of tests gets repeated many times, we should
557 -- have an abstraction defined ???
559 and then
560 (Is_Fixed_Point_Type (U_Type)
561 or else
562 Is_Enumeration_Type (U_Type)
563 or else
564 (Is_Signed_Integer_Type (U_Type)
565 and then not Has_Biased_Representation (FST)))
567 then
568 if P_Size <= Standard_Short_Short_Integer_Size then
569 Lib_RE := RE_I_SSI;
571 elsif P_Size <= Standard_Short_Integer_Size then
572 Lib_RE := RE_I_SI;
574 elsif P_Size <= Standard_Integer_Size then
575 Lib_RE := RE_I_I;
577 elsif P_Size <= Standard_Long_Integer_Size then
578 Lib_RE := RE_I_LI;
580 else
581 Lib_RE := RE_I_LLI;
582 end if;
584 -- Unsigned integer types, also includes unsigned fixed-point types
585 -- and enumeration types with an unsigned representation (note that
586 -- we know they are unsigned because we already tested for signed).
588 -- Also includes signed integer types that are unsigned in the sense
589 -- that they do not include negative numbers. See above for details.
591 elsif Is_Modular_Integer_Type (U_Type)
592 or else Is_Fixed_Point_Type (U_Type)
593 or else Is_Enumeration_Type (U_Type)
594 or else Is_Signed_Integer_Type (U_Type)
595 then
596 if P_Size <= Standard_Short_Short_Integer_Size then
597 Lib_RE := RE_I_SSU;
599 elsif P_Size <= Standard_Short_Integer_Size then
600 Lib_RE := RE_I_SU;
602 elsif P_Size <= Standard_Integer_Size then
603 Lib_RE := RE_I_U;
605 elsif P_Size <= Standard_Long_Integer_Size then
606 Lib_RE := RE_I_LU;
608 else
609 Lib_RE := RE_I_LLU;
610 end if;
612 else pragma Assert (Is_Access_Type (U_Type));
613 if P_Size > System_Address_Size then
614 Lib_RE := RE_I_AD;
615 else
616 Lib_RE := RE_I_AS;
617 end if;
618 end if;
620 -- Call the function, and do an unchecked conversion of the result
621 -- to the actual type of the prefix. If the target is a discriminant,
622 -- and we are in the body of the default implementation of a 'Read
623 -- attribute, set target type to force a constraint check (13.13.2(35)).
624 -- If the type of the discriminant is currently private, add another
625 -- unchecked conversion from the full view.
627 if Nkind (Targ) = N_Identifier
628 and then Is_Internal_Name (Chars (Targ))
629 and then Is_TSS (Scope (Entity (Targ)), TSS_Stream_Read)
630 then
631 Res :=
632 Unchecked_Convert_To (Base_Type (U_Type),
633 Make_Function_Call (Loc,
634 Name => New_Occurrence_Of (RTE (Lib_RE), Loc),
635 Parameter_Associations => New_List (
636 Relocate_Node (Strm))));
638 Set_Do_Range_Check (Res);
639 if Base_Type (P_Type) /= Base_Type (U_Type) then
640 Res := Unchecked_Convert_To (Base_Type (P_Type), Res);
641 end if;
643 return Res;
645 else
646 return
647 Unchecked_Convert_To (P_Type,
648 Make_Function_Call (Loc,
649 Name => New_Occurrence_Of (RTE (Lib_RE), Loc),
650 Parameter_Associations => New_List (
651 Relocate_Node (Strm))));
652 end if;
653 end Build_Elementary_Input_Call;
655 ---------------------------------
656 -- Build_Elementary_Write_Call --
657 ---------------------------------
659 function Build_Elementary_Write_Call (N : Node_Id) return Node_Id is
660 Loc : constant Source_Ptr := Sloc (N);
661 P_Type : constant Entity_Id := Entity (Prefix (N));
662 U_Type : constant Entity_Id := Underlying_Type (P_Type);
663 Rt_Type : constant Entity_Id := Root_Type (U_Type);
664 FST : constant Entity_Id := First_Subtype (U_Type);
665 Strm : constant Node_Id := First (Expressions (N));
666 Item : constant Node_Id := Next (Strm);
667 P_Size : Uint;
668 Lib_RE : RE_Id;
669 Libent : Entity_Id;
671 begin
673 -- Compute the size of the stream element. This is either the size of
674 -- the first subtype or if given the size of the Stream_Size attribute.
676 if Has_Stream_Size_Clause (FST) then
677 P_Size := Static_Integer (Expression (Stream_Size_Clause (FST)));
678 else
679 P_Size := Esize (FST);
680 end if;
682 -- Find the routine to be called
684 -- Check for First Boolean and Character. These are enumeration types,
685 -- but we treat them specially, since they may require special handling
686 -- in the transfer protocol. However, this special handling only applies
687 -- if they have standard representation, otherwise they are treated like
688 -- any other enumeration type.
690 if Rt_Type = Standard_Boolean
691 and then Has_Stream_Standard_Rep (U_Type)
692 then
693 Lib_RE := RE_W_B;
695 elsif Rt_Type = Standard_Character
696 and then Has_Stream_Standard_Rep (U_Type)
697 then
698 Lib_RE := RE_W_C;
700 elsif Rt_Type = Standard_Wide_Character
701 and then Has_Stream_Standard_Rep (U_Type)
702 then
703 Lib_RE := RE_W_WC;
705 elsif Rt_Type = Standard_Wide_Wide_Character
706 and then Has_Stream_Standard_Rep (U_Type)
707 then
708 Lib_RE := RE_W_WWC;
710 -- Floating point types
712 elsif Is_Floating_Point_Type (U_Type) then
714 -- Question: should we use P_Size or Rt_Type to distinguish between
715 -- possible floating point types? If a non-standard size or a stream
716 -- size is specified, then we should certainly use the size. But if
717 -- we have two types the same (notably Short_Float_Size = Float_Size
718 -- which is close to universally true, and Long_Long_Float_Size =
719 -- Long_Float_Size, true on most targets except the x86), then we
720 -- would really rather use the root type, so that if people want to
721 -- fiddle with System.Stream_Attributes to get inter-target portable
722 -- streams, they get the size they expect. Consider in particular the
723 -- case of a stream written on an x86, with 96-bit Long_Long_Float
724 -- being read into a non-x86 target with 64 bit Long_Long_Float. A
725 -- special version of System.Stream_Attributes can deal with this
726 -- provided the proper type is always used.
728 -- To deal with these two requirements we add the special checks
729 -- on equal sizes and use the root type to distinguish.
731 if P_Size <= Standard_Short_Float_Size
732 and then (Standard_Short_Float_Size /= Standard_Float_Size
733 or else Rt_Type = Standard_Short_Float)
734 then
735 Lib_RE := RE_W_SF;
737 elsif P_Size <= Standard_Float_Size then
738 Lib_RE := RE_W_F;
740 elsif P_Size <= Standard_Long_Float_Size
741 and then (Standard_Long_Float_Size /= Standard_Long_Long_Float_Size
742 or else Rt_Type = Standard_Long_Float)
743 then
744 Lib_RE := RE_W_LF;
746 else
747 Lib_RE := RE_W_LLF;
748 end if;
750 -- Signed integer types. Also includes signed fixed-point types and
751 -- signed enumeration types share this circuitry.
753 -- Note on signed integer types. We do not consider types as signed for
754 -- this purpose if they have no negative numbers, or if they have biased
755 -- representation. The reason is that the value in either case basically
756 -- represents an unsigned value.
758 -- For example, consider:
760 -- type W is range 0 .. 2**32 - 1;
761 -- for W'Size use 32;
763 -- This is a signed type, but the representation is unsigned, and may
764 -- be outside the range of a 32-bit signed integer, so this must be
765 -- treated as 32-bit unsigned.
767 -- Similarly, the representation is also unsigned if we have:
769 -- type W is range -1 .. +254;
770 -- for W'Size use 8;
772 -- forcing a biased and unsigned representation
774 elsif not Is_Unsigned_Type (FST)
775 and then
776 (Is_Fixed_Point_Type (U_Type)
777 or else
778 Is_Enumeration_Type (U_Type)
779 or else
780 (Is_Signed_Integer_Type (U_Type)
781 and then not Has_Biased_Representation (FST)))
782 then
783 if P_Size <= Standard_Short_Short_Integer_Size then
784 Lib_RE := RE_W_SSI;
785 elsif P_Size <= Standard_Short_Integer_Size then
786 Lib_RE := RE_W_SI;
787 elsif P_Size <= Standard_Integer_Size then
788 Lib_RE := RE_W_I;
789 elsif P_Size <= Standard_Long_Integer_Size then
790 Lib_RE := RE_W_LI;
791 else
792 Lib_RE := RE_W_LLI;
793 end if;
795 -- Unsigned integer types, also includes unsigned fixed-point types
796 -- and unsigned enumeration types (note we know they are unsigned
797 -- because we already tested for signed above).
799 -- Also includes signed integer types that are unsigned in the sense
800 -- that they do not include negative numbers. See above for details.
802 elsif Is_Modular_Integer_Type (U_Type)
803 or else Is_Fixed_Point_Type (U_Type)
804 or else Is_Enumeration_Type (U_Type)
805 or else Is_Signed_Integer_Type (U_Type)
806 then
807 if P_Size <= Standard_Short_Short_Integer_Size then
808 Lib_RE := RE_W_SSU;
809 elsif P_Size <= Standard_Short_Integer_Size then
810 Lib_RE := RE_W_SU;
811 elsif P_Size <= Standard_Integer_Size then
812 Lib_RE := RE_W_U;
813 elsif P_Size <= Standard_Long_Integer_Size then
814 Lib_RE := RE_W_LU;
815 else
816 Lib_RE := RE_W_LLU;
817 end if;
819 else pragma Assert (Is_Access_Type (U_Type));
821 if P_Size > System_Address_Size then
822 Lib_RE := RE_W_AD;
823 else
824 Lib_RE := RE_W_AS;
825 end if;
826 end if;
828 -- Unchecked-convert parameter to the required type (i.e. the type of
829 -- the corresponding parameter, and call the appropriate routine.
831 Libent := RTE (Lib_RE);
833 return
834 Make_Procedure_Call_Statement (Loc,
835 Name => New_Occurrence_Of (Libent, Loc),
836 Parameter_Associations => New_List (
837 Relocate_Node (Strm),
838 Unchecked_Convert_To (Etype (Next_Formal (First_Formal (Libent))),
839 Relocate_Node (Item))));
840 end Build_Elementary_Write_Call;
842 -----------------------------------------
843 -- Build_Mutable_Record_Read_Procedure --
844 -----------------------------------------
846 procedure Build_Mutable_Record_Read_Procedure
847 (Loc : Source_Ptr;
848 Typ : Entity_Id;
849 Decl : out Node_Id;
850 Pnam : out Entity_Id)
852 Out_Formal : Node_Id;
853 -- Expression denoting the out formal parameter
855 Dcls : constant List_Id := New_List;
856 -- Declarations for the 'Read body
858 Stms : constant List_Id := New_List;
859 -- Statements for the 'Read body
861 Disc : Entity_Id;
862 -- Entity of the discriminant being processed
864 Tmp_For_Disc : Entity_Id;
865 -- Temporary object used to read the value of Disc
867 Tmps_For_Discs : constant List_Id := New_List;
868 -- List of object declarations for temporaries holding the read values
869 -- for the discriminants.
871 Cstr : constant List_Id := New_List;
872 -- List of constraints to be applied on temporary record
874 Discriminant_Checks : constant List_Id := New_List;
875 -- List of discriminant checks to be performed if the actual object
876 -- is constrained.
878 Tmp : constant Entity_Id := Make_Defining_Identifier (Loc, Name_V);
879 -- Temporary record must hide formal (assignments to components of the
880 -- record are always generated with V as the identifier for the record).
882 Constrained_Stms : List_Id := New_List;
883 -- Statements within the block where we have the constrained temporary
885 begin
886 -- A mutable type cannot be a tagged type, so we generate a new name
887 -- for the stream procedure.
889 Pnam :=
890 Make_Defining_Identifier (Loc,
891 Chars => Make_TSS_Name_Local (Typ, TSS_Stream_Read));
893 if Is_Unchecked_Union (Typ) then
895 -- If this is an unchecked union, the stream procedure is erroneous,
896 -- because there are no discriminants to read.
898 -- This should generate a warning ???
900 Append_To (Stms,
901 Make_Raise_Program_Error (Loc,
902 Reason => PE_Unchecked_Union_Restriction));
904 Build_Stream_Procedure (Loc, Typ, Decl, Pnam, Stms, Outp => True);
905 return;
906 end if;
908 Disc := First_Discriminant (Typ);
910 Out_Formal :=
911 Make_Selected_Component (Loc,
912 Prefix => New_Occurrence_Of (Pnam, Loc),
913 Selector_Name => Make_Identifier (Loc, Name_V));
915 -- Generate Reads for the discriminants of the type. The discriminants
916 -- need to be read before the rest of the components, so that variants
917 -- are initialized correctly. The discriminants must be read into temp
918 -- variables so an incomplete Read (interrupted by an exception, for
919 -- example) does not alter the passed object.
921 while Present (Disc) loop
922 Tmp_For_Disc := Make_Defining_Identifier (Loc,
923 New_External_Name (Chars (Disc), "D"));
925 Append_To (Tmps_For_Discs,
926 Make_Object_Declaration (Loc,
927 Defining_Identifier => Tmp_For_Disc,
928 Object_Definition => New_Occurrence_Of (Etype (Disc), Loc)));
929 Set_No_Initialization (Last (Tmps_For_Discs));
931 Append_To (Stms,
932 Make_Attribute_Reference (Loc,
933 Prefix => New_Occurrence_Of (Etype (Disc), Loc),
934 Attribute_Name => Name_Read,
935 Expressions => New_List (
936 Make_Identifier (Loc, Name_S),
937 New_Occurrence_Of (Tmp_For_Disc, Loc))));
939 Append_To (Cstr,
940 Make_Discriminant_Association (Loc,
941 Selector_Names => New_List (New_Occurrence_Of (Disc, Loc)),
942 Expression => New_Occurrence_Of (Tmp_For_Disc, Loc)));
944 Append_To (Discriminant_Checks,
945 Make_Raise_Constraint_Error (Loc,
946 Condition =>
947 Make_Op_Ne (Loc,
948 Left_Opnd => New_Occurrence_Of (Tmp_For_Disc, Loc),
949 Right_Opnd =>
950 Make_Selected_Component (Loc,
951 Prefix => New_Copy_Tree (Out_Formal),
952 Selector_Name => New_Occurrence_Of (Disc, Loc))),
953 Reason => CE_Discriminant_Check_Failed));
954 Next_Discriminant (Disc);
955 end loop;
957 -- Generate reads for the components of the record (including those
958 -- that depend on discriminants).
960 Build_Record_Read_Write_Procedure (Loc, Typ, Decl, Pnam, Name_Read);
962 -- Save original statement sequence for component assignments, and
963 -- replace it with Stms.
965 Constrained_Stms := Statements (Handled_Statement_Sequence (Decl));
966 Set_Handled_Statement_Sequence (Decl,
967 Make_Handled_Sequence_Of_Statements (Loc,
968 Statements => Stms));
970 -- If Typ has controlled components (i.e. if it is classwide
971 -- or Has_Controlled), or components constrained using the discriminants
972 -- of Typ, then we need to ensure that all component assignments
973 -- are performed on an object that has been appropriately constrained
974 -- prior to being initialized. To this effect, we wrap the component
975 -- assignments in a block where V is a constrained temporary.
977 Append_To (Dcls,
978 Make_Object_Declaration (Loc,
979 Defining_Identifier => Tmp,
980 Object_Definition =>
981 Make_Subtype_Indication (Loc,
982 Subtype_Mark => New_Occurrence_Of (Typ, Loc),
983 Constraint =>
984 Make_Index_Or_Discriminant_Constraint (Loc,
985 Constraints => Cstr))));
987 -- AI05-023-1: Insert discriminant check prior to initialization of the
988 -- constrained temporary.
990 Append_To (Stms,
991 Make_Implicit_If_Statement (Pnam,
992 Condition =>
993 Make_Attribute_Reference (Loc,
994 Prefix => New_Copy_Tree (Out_Formal),
995 Attribute_Name => Name_Constrained),
996 Then_Statements => Discriminant_Checks));
998 -- Now insert back original component assignments, wrapped in a block
999 -- in which V is the constrained temporary.
1001 Append_To (Stms,
1002 Make_Block_Statement (Loc,
1003 Declarations => Dcls,
1004 Handled_Statement_Sequence => Parent (Constrained_Stms)));
1006 Append_To (Constrained_Stms,
1007 Make_Assignment_Statement (Loc,
1008 Name => Out_Formal,
1009 Expression => Make_Identifier (Loc, Name_V)));
1011 Set_Declarations (Decl, Tmps_For_Discs);
1012 end Build_Mutable_Record_Read_Procedure;
1014 ------------------------------------------
1015 -- Build_Mutable_Record_Write_Procedure --
1016 ------------------------------------------
1018 procedure Build_Mutable_Record_Write_Procedure
1019 (Loc : Source_Ptr;
1020 Typ : Entity_Id;
1021 Decl : out Node_Id;
1022 Pnam : out Entity_Id)
1024 Stms : List_Id;
1025 Disc : Entity_Id;
1026 D_Ref : Node_Id;
1028 begin
1029 Stms := New_List;
1030 Disc := First_Discriminant (Typ);
1032 -- Generate Writes for the discriminants of the type
1033 -- If the type is an unchecked union, use the default values of
1034 -- the discriminants, because they are not stored.
1036 while Present (Disc) loop
1037 if Is_Unchecked_Union (Typ) then
1038 D_Ref :=
1039 New_Copy_Tree (Discriminant_Default_Value (Disc));
1040 else
1041 D_Ref :=
1042 Make_Selected_Component (Loc,
1043 Prefix => Make_Identifier (Loc, Name_V),
1044 Selector_Name => New_Occurrence_Of (Disc, Loc));
1045 end if;
1047 Append_To (Stms,
1048 Make_Attribute_Reference (Loc,
1049 Prefix => New_Occurrence_Of (Etype (Disc), Loc),
1050 Attribute_Name => Name_Write,
1051 Expressions => New_List (
1052 Make_Identifier (Loc, Name_S),
1053 D_Ref)));
1055 Next_Discriminant (Disc);
1056 end loop;
1058 -- A mutable type cannot be a tagged type, so we generate a new name
1059 -- for the stream procedure.
1061 Pnam :=
1062 Make_Defining_Identifier (Loc,
1063 Chars => Make_TSS_Name_Local (Typ, TSS_Stream_Write));
1064 Build_Record_Read_Write_Procedure (Loc, Typ, Decl, Pnam, Name_Write);
1066 -- Write the discriminants before the rest of the components, so
1067 -- that discriminant values are properly set of variants, etc.
1069 if Is_Non_Empty_List (
1070 Statements (Handled_Statement_Sequence (Decl)))
1071 then
1072 Insert_List_Before
1073 (First (Statements (Handled_Statement_Sequence (Decl))), Stms);
1074 else
1075 Set_Statements (Handled_Statement_Sequence (Decl), Stms);
1076 end if;
1077 end Build_Mutable_Record_Write_Procedure;
1079 -----------------------------------------------
1080 -- Build_Record_Or_Elementary_Input_Function --
1081 -----------------------------------------------
1083 -- The function we build looks like
1085 -- function InputN (S : access RST) return Typ is
1086 -- C1 : constant Disc_Type_1;
1087 -- Discr_Type_1'Read (S, C1);
1088 -- C2 : constant Disc_Type_2;
1089 -- Discr_Type_2'Read (S, C2);
1090 -- ...
1091 -- Cn : constant Disc_Type_n;
1092 -- Discr_Type_n'Read (S, Cn);
1093 -- V : Typ (C1, C2, .. Cn)
1095 -- begin
1096 -- Typ'Read (S, V);
1097 -- return V;
1098 -- end InputN
1100 -- The discriminants are of course only present in the case of a record
1101 -- with discriminants. In the case of a record with no discriminants, or
1102 -- an elementary type, then no Cn constants are defined.
1104 procedure Build_Record_Or_Elementary_Input_Function
1105 (Loc : Source_Ptr;
1106 Typ : Entity_Id;
1107 Decl : out Node_Id;
1108 Fnam : out Entity_Id)
1110 B_Typ : constant Entity_Id := Base_Type (Typ);
1111 Cn : Name_Id;
1112 Constr : List_Id;
1113 Decls : List_Id;
1114 Discr : Entity_Id;
1115 Discr_Elmt : Elmt_Id := No_Elmt;
1116 J : Pos;
1117 Obj_Decl : Node_Id;
1118 Odef : Node_Id;
1119 Stms : List_Id;
1121 begin
1122 Decls := New_List;
1123 Constr := New_List;
1125 J := 1;
1127 if Has_Discriminants (B_Typ) then
1128 Discr := First_Discriminant (B_Typ);
1130 -- If the prefix subtype is constrained, then retrieve the first
1131 -- element of its constraint.
1133 if Is_Constrained (Typ) then
1134 Discr_Elmt := First_Elmt (Discriminant_Constraint (Typ));
1135 end if;
1137 while Present (Discr) loop
1138 Cn := New_External_Name ('C', J);
1140 Decl :=
1141 Make_Object_Declaration (Loc,
1142 Defining_Identifier => Make_Defining_Identifier (Loc, Cn),
1143 Object_Definition =>
1144 New_Occurrence_Of (Etype (Discr), Loc));
1146 -- If this is an access discriminant, do not perform default
1147 -- initialization. The discriminant is about to get its value
1148 -- from Read, and if the type is null excluding we do not want
1149 -- spurious warnings on an initial null value.
1151 if Is_Access_Type (Etype (Discr)) then
1152 Set_No_Initialization (Decl);
1153 end if;
1155 Append_To (Decls, Decl);
1156 Append_To (Decls,
1157 Make_Attribute_Reference (Loc,
1158 Prefix => New_Occurrence_Of (Etype (Discr), Loc),
1159 Attribute_Name => Name_Read,
1160 Expressions => New_List (
1161 Make_Identifier (Loc, Name_S),
1162 Make_Identifier (Loc, Cn))));
1164 Append_To (Constr, Make_Identifier (Loc, Cn));
1166 -- If the prefix subtype imposes a discriminant constraint, then
1167 -- check that each discriminant value equals the value read.
1169 if Present (Discr_Elmt) then
1170 Append_To (Decls,
1171 Make_Raise_Constraint_Error (Loc,
1172 Condition => Make_Op_Ne (Loc,
1173 Left_Opnd =>
1174 New_Reference_To
1175 (Defining_Identifier (Decl), Loc),
1176 Right_Opnd =>
1177 New_Copy_Tree (Node (Discr_Elmt))),
1178 Reason => CE_Discriminant_Check_Failed));
1180 Next_Elmt (Discr_Elmt);
1181 end if;
1183 Next_Discriminant (Discr);
1184 J := J + 1;
1185 end loop;
1187 Odef :=
1188 Make_Subtype_Indication (Loc,
1189 Subtype_Mark => New_Occurrence_Of (B_Typ, Loc),
1190 Constraint =>
1191 Make_Index_Or_Discriminant_Constraint (Loc,
1192 Constraints => Constr));
1194 -- If no discriminants, then just use the type with no constraint
1196 else
1197 Odef := New_Occurrence_Of (B_Typ, Loc);
1198 end if;
1200 -- Create an extended return statement encapsulating the result object
1201 -- and 'Read call, which is needed in general for proper handling of
1202 -- build-in-place results (such as when the result type is inherently
1203 -- limited).
1205 Obj_Decl :=
1206 Make_Object_Declaration (Loc,
1207 Defining_Identifier => Make_Defining_Identifier (Loc, Name_V),
1208 Object_Definition => Odef);
1210 -- If the type is an access type, do not perform default initialization.
1211 -- The object is about to get its value from Read, and if the type is
1212 -- null excluding we do not want spurious warnings on an initial null.
1214 if Is_Access_Type (B_Typ) then
1215 Set_No_Initialization (Obj_Decl);
1216 end if;
1218 Stms := New_List (
1219 Make_Extended_Return_Statement (Loc,
1220 Return_Object_Declarations => New_List (Obj_Decl),
1221 Handled_Statement_Sequence =>
1222 Make_Handled_Sequence_Of_Statements (Loc,
1223 Statements => New_List (
1224 Make_Attribute_Reference (Loc,
1225 Prefix => New_Occurrence_Of (B_Typ, Loc),
1226 Attribute_Name => Name_Read,
1227 Expressions => New_List (
1228 Make_Identifier (Loc, Name_S),
1229 Make_Identifier (Loc, Name_V)))))));
1231 Fnam := Make_Stream_Subprogram_Name (Loc, B_Typ, TSS_Stream_Input);
1233 Build_Stream_Function (Loc, B_Typ, Decl, Fnam, Decls, Stms);
1234 end Build_Record_Or_Elementary_Input_Function;
1236 -------------------------------------------------
1237 -- Build_Record_Or_Elementary_Output_Procedure --
1238 -------------------------------------------------
1240 procedure Build_Record_Or_Elementary_Output_Procedure
1241 (Loc : Source_Ptr;
1242 Typ : Entity_Id;
1243 Decl : out Node_Id;
1244 Pnam : out Entity_Id)
1246 Stms : List_Id;
1247 Disc : Entity_Id;
1248 Disc_Ref : Node_Id;
1250 begin
1251 Stms := New_List;
1253 -- Note that of course there will be no discriminants for the
1254 -- elementary type case, so Has_Discriminants will be False.
1256 if Has_Discriminants (Typ) then
1257 Disc := First_Discriminant (Typ);
1259 while Present (Disc) loop
1261 -- If the type is an unchecked union, it must have default
1262 -- discriminants (this is checked earlier), and those defaults
1263 -- are written out to the stream.
1265 if Is_Unchecked_Union (Typ) then
1266 Disc_Ref := New_Copy_Tree (Discriminant_Default_Value (Disc));
1268 else
1269 Disc_Ref :=
1270 Make_Selected_Component (Loc,
1271 Prefix => Make_Identifier (Loc, Name_V),
1272 Selector_Name => New_Occurrence_Of (Disc, Loc));
1273 end if;
1275 Append_To (Stms,
1276 Make_Attribute_Reference (Loc,
1277 Prefix =>
1278 New_Occurrence_Of (Stream_Base_Type (Etype (Disc)), Loc),
1279 Attribute_Name => Name_Write,
1280 Expressions => New_List (
1281 Make_Identifier (Loc, Name_S),
1282 Disc_Ref)));
1284 Next_Discriminant (Disc);
1285 end loop;
1286 end if;
1288 Append_To (Stms,
1289 Make_Attribute_Reference (Loc,
1290 Prefix => New_Occurrence_Of (Typ, Loc),
1291 Attribute_Name => Name_Write,
1292 Expressions => New_List (
1293 Make_Identifier (Loc, Name_S),
1294 Make_Identifier (Loc, Name_V))));
1296 Pnam := Make_Stream_Subprogram_Name (Loc, Typ, TSS_Stream_Output);
1298 Build_Stream_Procedure (Loc, Typ, Decl, Pnam, Stms, False);
1299 end Build_Record_Or_Elementary_Output_Procedure;
1301 ---------------------------------
1302 -- Build_Record_Read_Procedure --
1303 ---------------------------------
1305 procedure Build_Record_Read_Procedure
1306 (Loc : Source_Ptr;
1307 Typ : Entity_Id;
1308 Decl : out Node_Id;
1309 Pnam : out Entity_Id)
1311 begin
1312 Pnam := Make_Stream_Subprogram_Name (Loc, Typ, TSS_Stream_Read);
1313 Build_Record_Read_Write_Procedure (Loc, Typ, Decl, Pnam, Name_Read);
1314 end Build_Record_Read_Procedure;
1316 ---------------------------------------
1317 -- Build_Record_Read_Write_Procedure --
1318 ---------------------------------------
1320 -- The form of the record read/write procedure is as shown by the
1321 -- following example for a case with one discriminant case variant:
1323 -- procedure pnam (S : access RST, V : [out] Typ) is
1324 -- begin
1325 -- Component_Type'Read/Write (S, V.component);
1326 -- Component_Type'Read/Write (S, V.component);
1327 -- ...
1328 -- Component_Type'Read/Write (S, V.component);
1330 -- case V.discriminant is
1331 -- when choices =>
1332 -- Component_Type'Read/Write (S, V.component);
1333 -- Component_Type'Read/Write (S, V.component);
1334 -- ...
1335 -- Component_Type'Read/Write (S, V.component);
1337 -- when choices =>
1338 -- Component_Type'Read/Write (S, V.component);
1339 -- Component_Type'Read/Write (S, V.component);
1340 -- ...
1341 -- Component_Type'Read/Write (S, V.component);
1342 -- ...
1343 -- end case;
1344 -- end pnam;
1346 -- The out keyword for V is supplied in the Read case
1348 procedure Build_Record_Read_Write_Procedure
1349 (Loc : Source_Ptr;
1350 Typ : Entity_Id;
1351 Decl : out Node_Id;
1352 Pnam : Entity_Id;
1353 Nam : Name_Id)
1355 Rdef : Node_Id;
1356 Stms : List_Id;
1357 Typt : Entity_Id;
1359 In_Limited_Extension : Boolean := False;
1360 -- Set to True while processing the record extension definition
1361 -- for an extension of a limited type (for which an ancestor type
1362 -- has an explicit Nam attribute definition).
1364 function Make_Component_List_Attributes (CL : Node_Id) return List_Id;
1365 -- Returns a sequence of attributes to process the components that
1366 -- are referenced in the given component list.
1368 function Make_Field_Attribute (C : Entity_Id) return Node_Id;
1369 -- Given C, the entity for a discriminant or component, build
1370 -- an attribute for the corresponding field values.
1372 function Make_Field_Attributes (Clist : List_Id) return List_Id;
1373 -- Given Clist, a component items list, construct series of attributes
1374 -- for fieldwise processing of the corresponding components.
1376 ------------------------------------
1377 -- Make_Component_List_Attributes --
1378 ------------------------------------
1380 function Make_Component_List_Attributes (CL : Node_Id) return List_Id is
1381 CI : constant List_Id := Component_Items (CL);
1382 VP : constant Node_Id := Variant_Part (CL);
1384 Result : List_Id;
1385 Alts : List_Id;
1386 V : Node_Id;
1387 DC : Node_Id;
1388 DCH : List_Id;
1389 D_Ref : Node_Id;
1391 begin
1392 Result := Make_Field_Attributes (CI);
1394 if Present (VP) then
1395 Alts := New_List;
1397 V := First_Non_Pragma (Variants (VP));
1398 while Present (V) loop
1399 DCH := New_List;
1401 DC := First (Discrete_Choices (V));
1402 while Present (DC) loop
1403 Append_To (DCH, New_Copy_Tree (DC));
1404 Next (DC);
1405 end loop;
1407 Append_To (Alts,
1408 Make_Case_Statement_Alternative (Loc,
1409 Discrete_Choices => DCH,
1410 Statements =>
1411 Make_Component_List_Attributes (Component_List (V))));
1412 Next_Non_Pragma (V);
1413 end loop;
1415 -- Note: in the following, we make sure that we use new occurrence
1416 -- of for the selector, since there are cases in which we make a
1417 -- reference to a hidden discriminant that is not visible.
1419 -- If the enclosing record is an unchecked_union, we use the
1420 -- default expressions for the discriminant (it must exist)
1421 -- because we cannot generate a reference to it, given that
1422 -- it is not stored.
1424 if Is_Unchecked_Union (Scope (Entity (Name (VP)))) then
1425 D_Ref :=
1426 New_Copy_Tree
1427 (Discriminant_Default_Value (Entity (Name (VP))));
1428 else
1429 D_Ref :=
1430 Make_Selected_Component (Loc,
1431 Prefix => Make_Identifier (Loc, Name_V),
1432 Selector_Name =>
1433 New_Occurrence_Of (Entity (Name (VP)), Loc));
1434 end if;
1436 Append_To (Result,
1437 Make_Case_Statement (Loc,
1438 Expression => D_Ref,
1439 Alternatives => Alts));
1440 end if;
1442 return Result;
1443 end Make_Component_List_Attributes;
1445 --------------------------
1446 -- Make_Field_Attribute --
1447 --------------------------
1449 function Make_Field_Attribute (C : Entity_Id) return Node_Id is
1450 Field_Typ : constant Entity_Id := Stream_Base_Type (Etype (C));
1452 TSS_Names : constant array (Name_Input .. Name_Write) of
1453 TSS_Name_Type :=
1454 (Name_Read => TSS_Stream_Read,
1455 Name_Write => TSS_Stream_Write,
1456 Name_Input => TSS_Stream_Input,
1457 Name_Output => TSS_Stream_Output,
1458 others => TSS_Null);
1459 pragma Assert (TSS_Names (Nam) /= TSS_Null);
1461 begin
1462 if In_Limited_Extension
1463 and then Is_Limited_Type (Field_Typ)
1464 and then No (Find_Inherited_TSS (Field_Typ, TSS_Names (Nam)))
1465 then
1466 -- The declaration is illegal per 13.13.2(9/1), and this is
1467 -- enforced in Exp_Ch3.Check_Stream_Attributes. Keep the caller
1468 -- happy by returning a null statement.
1470 return Make_Null_Statement (Loc);
1471 end if;
1473 return
1474 Make_Attribute_Reference (Loc,
1475 Prefix =>
1476 New_Occurrence_Of (Field_Typ, Loc),
1477 Attribute_Name => Nam,
1478 Expressions => New_List (
1479 Make_Identifier (Loc, Name_S),
1480 Make_Selected_Component (Loc,
1481 Prefix => Make_Identifier (Loc, Name_V),
1482 Selector_Name => New_Occurrence_Of (C, Loc))));
1483 end Make_Field_Attribute;
1485 ---------------------------
1486 -- Make_Field_Attributes --
1487 ---------------------------
1489 function Make_Field_Attributes (Clist : List_Id) return List_Id is
1490 Item : Node_Id;
1491 Result : List_Id;
1493 begin
1494 Result := New_List;
1496 if Present (Clist) then
1497 Item := First (Clist);
1499 -- Loop through components, skipping all internal components,
1500 -- which are not part of the value (e.g. _Tag), except that we
1501 -- don't skip the _Parent, since we do want to process that
1502 -- recursively. If _Parent is an interface type, being abstract
1503 -- with no components there is no need to handle it.
1505 while Present (Item) loop
1506 if Nkind (Item) = N_Component_Declaration
1507 and then
1508 ((Chars (Defining_Identifier (Item)) = Name_uParent
1509 and then not Is_Interface
1510 (Etype (Defining_Identifier (Item))))
1511 or else
1512 not Is_Internal_Name (Chars (Defining_Identifier (Item))))
1513 then
1514 Append_To
1515 (Result,
1516 Make_Field_Attribute (Defining_Identifier (Item)));
1517 end if;
1519 Next (Item);
1520 end loop;
1521 end if;
1523 return Result;
1524 end Make_Field_Attributes;
1526 -- Start of processing for Build_Record_Read_Write_Procedure
1528 begin
1529 -- For the protected type case, use corresponding record
1531 if Is_Protected_Type (Typ) then
1532 Typt := Corresponding_Record_Type (Typ);
1533 else
1534 Typt := Typ;
1535 end if;
1537 -- Note that we do nothing with the discriminants, since Read and
1538 -- Write do not read or write the discriminant values. All handling
1539 -- of discriminants occurs in the Input and Output subprograms.
1541 Rdef := Type_Definition
1542 (Declaration_Node (Base_Type (Underlying_Type (Typt))));
1543 Stms := Empty_List;
1545 -- In record extension case, the fields we want, including the _Parent
1546 -- field representing the parent type, are to be found in the extension.
1547 -- Note that we will naturally process the _Parent field using the type
1548 -- of the parent, and hence its stream attributes, which is appropriate.
1550 if Nkind (Rdef) = N_Derived_Type_Definition then
1551 Rdef := Record_Extension_Part (Rdef);
1553 if Is_Limited_Type (Typt) then
1554 In_Limited_Extension := True;
1555 end if;
1556 end if;
1558 if Present (Component_List (Rdef)) then
1559 Append_List_To (Stms,
1560 Make_Component_List_Attributes (Component_List (Rdef)));
1561 end if;
1563 Build_Stream_Procedure
1564 (Loc, Typ, Decl, Pnam, Stms, Nam = Name_Read);
1565 end Build_Record_Read_Write_Procedure;
1567 ----------------------------------
1568 -- Build_Record_Write_Procedure --
1569 ----------------------------------
1571 procedure Build_Record_Write_Procedure
1572 (Loc : Source_Ptr;
1573 Typ : Entity_Id;
1574 Decl : out Node_Id;
1575 Pnam : out Entity_Id)
1577 begin
1578 Pnam := Make_Stream_Subprogram_Name (Loc, Typ, TSS_Stream_Write);
1579 Build_Record_Read_Write_Procedure (Loc, Typ, Decl, Pnam, Name_Write);
1580 end Build_Record_Write_Procedure;
1582 -------------------------------
1583 -- Build_Stream_Attr_Profile --
1584 -------------------------------
1586 function Build_Stream_Attr_Profile
1587 (Loc : Source_Ptr;
1588 Typ : Entity_Id;
1589 Nam : TSS_Name_Type) return List_Id
1591 Profile : List_Id;
1593 begin
1594 -- (Ada 2005: AI-441): Set the null-excluding attribute because it has
1595 -- no semantic meaning in Ada 95 but it is a requirement in Ada 2005.
1597 Profile := New_List (
1598 Make_Parameter_Specification (Loc,
1599 Defining_Identifier => Make_Defining_Identifier (Loc, Name_S),
1600 Parameter_Type =>
1601 Make_Access_Definition (Loc,
1602 Null_Exclusion_Present => True,
1603 Subtype_Mark => New_Reference_To (
1604 Class_Wide_Type (RTE (RE_Root_Stream_Type)), Loc))));
1606 if Nam /= TSS_Stream_Input then
1607 Append_To (Profile,
1608 Make_Parameter_Specification (Loc,
1609 Defining_Identifier => Make_Defining_Identifier (Loc, Name_V),
1610 Out_Present => (Nam = TSS_Stream_Read),
1611 Parameter_Type => New_Reference_To (Typ, Loc)));
1612 end if;
1614 return Profile;
1615 end Build_Stream_Attr_Profile;
1617 ---------------------------
1618 -- Build_Stream_Function --
1619 ---------------------------
1621 procedure Build_Stream_Function
1622 (Loc : Source_Ptr;
1623 Typ : Entity_Id;
1624 Decl : out Node_Id;
1625 Fnam : Entity_Id;
1626 Decls : List_Id;
1627 Stms : List_Id)
1629 Spec : Node_Id;
1631 begin
1632 -- Construct function specification
1634 -- (Ada 2005: AI-441): Set the null-excluding attribute because it has
1635 -- no semantic meaning in Ada 95 but it is a requirement in Ada 2005.
1637 Spec :=
1638 Make_Function_Specification (Loc,
1639 Defining_Unit_Name => Fnam,
1641 Parameter_Specifications => New_List (
1642 Make_Parameter_Specification (Loc,
1643 Defining_Identifier => Make_Defining_Identifier (Loc, Name_S),
1644 Parameter_Type =>
1645 Make_Access_Definition (Loc,
1646 Null_Exclusion_Present => True,
1647 Subtype_Mark => New_Reference_To (
1648 Class_Wide_Type (RTE (RE_Root_Stream_Type)), Loc)))),
1650 Result_Definition => New_Occurrence_Of (Typ, Loc));
1652 Decl :=
1653 Make_Subprogram_Body (Loc,
1654 Specification => Spec,
1655 Declarations => Decls,
1656 Handled_Statement_Sequence =>
1657 Make_Handled_Sequence_Of_Statements (Loc,
1658 Statements => Stms));
1659 end Build_Stream_Function;
1661 ----------------------------
1662 -- Build_Stream_Procedure --
1663 ----------------------------
1665 procedure Build_Stream_Procedure
1666 (Loc : Source_Ptr;
1667 Typ : Entity_Id;
1668 Decl : out Node_Id;
1669 Pnam : Entity_Id;
1670 Stms : List_Id;
1671 Outp : Boolean)
1673 Spec : Node_Id;
1675 begin
1676 -- Construct procedure specification
1678 -- (Ada 2005: AI-441): Set the null-excluding attribute because it has
1679 -- no semantic meaning in Ada 95 but it is a requirement in Ada 2005.
1681 Spec :=
1682 Make_Procedure_Specification (Loc,
1683 Defining_Unit_Name => Pnam,
1685 Parameter_Specifications => New_List (
1686 Make_Parameter_Specification (Loc,
1687 Defining_Identifier => Make_Defining_Identifier (Loc, Name_S),
1688 Parameter_Type =>
1689 Make_Access_Definition (Loc,
1690 Null_Exclusion_Present => True,
1691 Subtype_Mark => New_Reference_To (
1692 Class_Wide_Type (RTE (RE_Root_Stream_Type)), Loc))),
1694 Make_Parameter_Specification (Loc,
1695 Defining_Identifier => Make_Defining_Identifier (Loc, Name_V),
1696 Out_Present => Outp,
1697 Parameter_Type => New_Occurrence_Of (Typ, Loc))));
1699 Decl :=
1700 Make_Subprogram_Body (Loc,
1701 Specification => Spec,
1702 Declarations => Empty_List,
1703 Handled_Statement_Sequence =>
1704 Make_Handled_Sequence_Of_Statements (Loc,
1705 Statements => Stms));
1706 end Build_Stream_Procedure;
1708 -----------------------------
1709 -- Has_Stream_Standard_Rep --
1710 -----------------------------
1712 function Has_Stream_Standard_Rep (U_Type : Entity_Id) return Boolean is
1713 Siz : Uint;
1715 begin
1716 if Has_Non_Standard_Rep (U_Type) then
1717 return False;
1718 end if;
1720 if Has_Stream_Size_Clause (U_Type) then
1721 Siz := Static_Integer (Expression (Stream_Size_Clause (U_Type)));
1722 else
1723 Siz := Esize (First_Subtype (U_Type));
1724 end if;
1726 return Siz = Esize (Root_Type (U_Type));
1727 end Has_Stream_Standard_Rep;
1729 ---------------------------------
1730 -- Make_Stream_Subprogram_Name --
1731 ---------------------------------
1733 function Make_Stream_Subprogram_Name
1734 (Loc : Source_Ptr;
1735 Typ : Entity_Id;
1736 Nam : TSS_Name_Type) return Entity_Id
1738 Sname : Name_Id;
1740 begin
1741 -- For tagged types, we are dealing with a TSS associated with the
1742 -- declaration, so we use the standard primitive function name. For
1743 -- other types, generate a local TSS name since we are generating
1744 -- the subprogram at the point of use.
1746 if Is_Tagged_Type (Typ) then
1747 Sname := Make_TSS_Name (Typ, Nam);
1748 else
1749 Sname := Make_TSS_Name_Local (Typ, Nam);
1750 end if;
1752 return Make_Defining_Identifier (Loc, Sname);
1753 end Make_Stream_Subprogram_Name;
1755 ----------------------
1756 -- Stream_Base_Type --
1757 ----------------------
1759 function Stream_Base_Type (E : Entity_Id) return Entity_Id is
1760 begin
1761 if Is_Array_Type (E)
1762 and then Is_First_Subtype (E)
1763 then
1764 return E;
1765 else
1766 return Base_Type (E);
1767 end if;
1768 end Stream_Base_Type;
1770 end Exp_Strm;