]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/ada/exp_strm.adb
[Ada] Variable-sized node types
[thirdparty/gcc.git] / gcc / ada / exp_strm.adb
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- E X P _ S T R M --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1992-2021, Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING3. If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license. --
20 -- --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
23 -- --
24 ------------------------------------------------------------------------------
25
26 with Atree; use Atree;
27 with Einfo; use Einfo;
28 with 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;
46
47 package body Exp_Strm is
48
49 -----------------------
50 -- Local Subprograms --
51 -----------------------
52
53 procedure Build_Array_Read_Write_Procedure
54 (Nod : Node_Id;
55 Typ : Entity_Id;
56 Decl : out Node_Id;
57 Pnam : Entity_Id;
58 Nam : Name_Id);
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.
64
65 procedure Build_Record_Read_Write_Procedure
66 (Loc : Source_Ptr;
67 Typ : Entity_Id;
68 Decl : out Node_Id;
69 Pnam : Entity_Id;
70 Nam : Name_Id);
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.
75
76 procedure Build_Stream_Function
77 (Loc : Source_Ptr;
78 Typ : Entity_Id;
79 Decl : out Node_Id;
80 Fnam : Entity_Id;
81 Decls : List_Id;
82 Stms : List_Id);
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.
87
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).
95
96 function Make_Stream_Subprogram_Name
97 (Loc : Source_Ptr;
98 Typ : Entity_Id;
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.
106
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
114 -- first subtype).
115
116 --------------------------------
117 -- Build_Array_Input_Function --
118 --------------------------------
119
120 -- The function we build looks like
121
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);
127 -- ..
128 -- Ln : constant Index_Type_n := Index_Type_n'Input (S);
129 -- Hn : constant Index_Type_n := Index_Type_n'Input (S);
130 --
131 -- V : Typ'Base (L1 .. H1, L2 .. H2, ... Ln .. Hn)
132
133 -- begin
134 -- Typ'Read (S, V);
135 -- return V;
136 -- end typSI[_nnn]
137
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.
141
142 procedure Build_Array_Input_Function
143 (Loc : Source_Ptr;
144 Typ : Entity_Id;
145 Decl : out Node_Id;
146 Fnam : out Entity_Id)
147 is
148 Dim : constant Pos := Number_Dimensions (Typ);
149 Lnam : Name_Id;
150 Hnam : Name_Id;
151 Decls : List_Id;
152 Ranges : List_Id;
153 Stms : List_Id;
154 Rstmt : Node_Id;
155 Indx : Node_Id;
156 Odecl : Node_Id;
157
158 begin
159 Decls := New_List;
160 Ranges := New_List;
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);
165
166 Append_To (Decls,
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),
171 Expression =>
172 Make_Attribute_Reference (Loc,
173 Prefix =>
174 New_Occurrence_Of (Stream_Base_Type (Etype (Indx)), Loc),
175 Attribute_Name => Name_Input,
176 Expressions => New_List (Make_Identifier (Loc, Name_S)))));
177
178 Append_To (Decls,
179 Make_Object_Declaration (Loc,
180 Defining_Identifier => Make_Defining_Identifier (Loc, Hnam),
181 Constant_Present => True,
182 Object_Definition =>
183 New_Occurrence_Of (Stream_Base_Type (Etype (Indx)), Loc),
184 Expression =>
185 Make_Attribute_Reference (Loc,
186 Prefix =>
187 New_Occurrence_Of (Stream_Base_Type (Etype (Indx)), Loc),
188 Attribute_Name => Name_Input,
189 Expressions => New_List (Make_Identifier (Loc, Name_S)))));
190
191 Append_To (Ranges,
192 Make_Range (Loc,
193 Low_Bound => Make_Identifier (Loc, Lnam),
194 High_Bound => Make_Identifier (Loc, Hnam)));
195
196 Next_Index (Indx);
197 end loop;
198
199 -- If the type is constrained, use it directly. Otherwise build a
200 -- subtype indication with the proper bounds.
201
202 if Is_Constrained (Typ) then
203 Odecl :=
204 Make_Object_Declaration (Loc,
205 Defining_Identifier => Make_Defining_Identifier (Loc, Name_V),
206 Object_Definition => New_Occurrence_Of (Typ, Loc));
207
208 else
209 Odecl :=
210 Make_Object_Declaration (Loc,
211 Defining_Identifier => Make_Defining_Identifier (Loc, Name_V),
212 Object_Definition =>
213 Make_Subtype_Indication (Loc,
214 Subtype_Mark =>
215 New_Occurrence_Of (Stream_Base_Type (Typ), Loc),
216 Constraint =>
217 Make_Index_Or_Discriminant_Constraint (Loc, Ranges)));
218 end if;
219
220 Rstmt :=
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)));
227
228 Stms := New_List (
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))));
233
234 Fnam :=
235 Make_Defining_Identifier (Loc,
236 Chars => Make_TSS_Name_Local (Typ, TSS_Stream_Input));
237
238 Build_Stream_Function (Loc, Typ, Decl, Fnam, Decls, Stms);
239 end Build_Array_Input_Function;
240
241 ----------------------------------
242 -- Build_Array_Output_Procedure --
243 ----------------------------------
244
245 procedure Build_Array_Output_Procedure
246 (Loc : Source_Ptr;
247 Typ : Entity_Id;
248 Decl : out Node_Id;
249 Pnam : out Entity_Id)
250 is
251 Stms : List_Id;
252 Indx : Node_Id;
253
254 begin
255 -- Build series of statements to output bounds
256
257 Indx := First_Index (Typ);
258 Stms := New_List;
259
260 for J in 1 .. Number_Dimensions (Typ) loop
261 Append_To (Stms,
262 Make_Attribute_Reference (Loc,
263 Prefix =>
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))))));
273
274 Append_To (Stms,
275 Make_Attribute_Reference (Loc,
276 Prefix =>
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))))));
286
287 Next_Index (Indx);
288 end loop;
289
290 -- Append Write attribute to write array elements
291
292 Append_To (Stms,
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))));
299
300 Pnam :=
301 Make_Defining_Identifier (Loc,
302 Chars => Make_TSS_Name_Local (Typ, TSS_Stream_Output));
303
304 Build_Stream_Procedure (Loc, Typ, Decl, Pnam, Stms, Outp => False);
305 end Build_Array_Output_Procedure;
306
307 --------------------------------
308 -- Build_Array_Read_Procedure --
309 --------------------------------
310
311 procedure Build_Array_Read_Procedure
312 (Nod : Node_Id;
313 Typ : Entity_Id;
314 Decl : out Node_Id;
315 Pnam : out Entity_Id)
316 is
317 Loc : constant Source_Ptr := Sloc (Nod);
318
319 begin
320 Pnam :=
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;
325
326 --------------------------------------
327 -- Build_Array_Read_Write_Procedure --
328 --------------------------------------
329
330 -- The form of the array read/write procedure is as follows:
331
332 -- procedure pnam (S : access RST, V : [out] Typ) is
333 -- begin
334 -- for L1 in V'Range (1) loop
335 -- for L2 in V'Range (2) loop
336 -- ...
337 -- for Ln in V'Range (n) loop
338 -- Component_Type'Read/Write (S, V (L1, L2, .. Ln));
339 -- end loop;
340 -- ..
341 -- end loop;
342 -- end loop
343 -- end pnam;
344
345 -- The out keyword for V is supplied in the Read case
346
347 procedure Build_Array_Read_Write_Procedure
348 (Nod : Node_Id;
349 Typ : Entity_Id;
350 Decl : out Node_Id;
351 Pnam : Entity_Id;
352 Nam : Name_Id)
353 is
354 Loc : constant Source_Ptr := Sloc (Nod);
355 Ndim : constant Pos := Number_Dimensions (Typ);
356 Ctyp : constant Entity_Id := Component_Type (Typ);
357
358 Stm : Node_Id;
359 Exl : List_Id;
360 RW : Entity_Id;
361
362 begin
363 -- First build the inner attribute call
364
365 Exl := New_List;
366
367 for J in 1 .. Ndim loop
368 Append_To (Exl, Make_Identifier (Loc, New_External_Name ('L', J)));
369 end loop;
370
371 Stm :=
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)));
380
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.
386
387 if Nam = Name_Read then
388 RW := TSS (Base_Type (Ctyp), TSS_Stream_Read);
389 else
390 RW := TSS (Base_Type (Ctyp), TSS_Stream_Write);
391 end if;
392
393 if Present (RW)
394 and then not Is_Frozen (RW)
395 then
396 Set_Is_Frozen (RW);
397 end if;
398
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.
402
403 for J in 1 .. Ndim loop
404 Stm :=
405 Make_Implicit_Loop_Statement (Nod,
406 Iteration_Scheme =>
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)),
413
414 Discrete_Subtype_Definition =>
415 Make_Attribute_Reference (Loc,
416 Prefix => Make_Identifier (Loc, Name_V),
417 Attribute_Name => Name_Range,
418
419 Expressions => New_List (
420 Make_Integer_Literal (Loc, Ndim - J + 1))))),
421
422 Statements => New_List (Stm));
423
424 end loop;
425
426 Build_Stream_Procedure
427 (Loc, Typ, Decl, Pnam, New_List (Stm), Outp => Nam = Name_Read);
428 end Build_Array_Read_Write_Procedure;
429
430 ---------------------------------
431 -- Build_Array_Write_Procedure --
432 ---------------------------------
433
434 procedure Build_Array_Write_Procedure
435 (Nod : Node_Id;
436 Typ : Entity_Id;
437 Decl : out Node_Id;
438 Pnam : out Entity_Id)
439 is
440 Loc : constant Source_Ptr := Sloc (Nod);
441 begin
442 Pnam :=
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;
447
448 ---------------------------------
449 -- Build_Elementary_Input_Call --
450 ---------------------------------
451
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);
461 Res : Node_Id;
462 Lib_RE : RE_Id;
463
464 begin
465
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.
471
472 if Rt_Type = Standard_Boolean
473 and then Has_Stream_Standard_Rep (U_Type)
474 then
475 Lib_RE := RE_I_B;
476
477 elsif Rt_Type = Standard_Character
478 and then Has_Stream_Standard_Rep (U_Type)
479 then
480 Lib_RE := RE_I_C;
481
482 elsif Rt_Type = Standard_Wide_Character
483 and then Has_Stream_Standard_Rep (U_Type)
484 then
485 Lib_RE := RE_I_WC;
486
487 elsif Rt_Type = Standard_Wide_Wide_Character
488 and then Has_Stream_Standard_Rep (U_Type)
489 then
490 Lib_RE := RE_I_WWC;
491
492 -- Floating point types
493
494 elsif Is_Floating_Point_Type (U_Type) then
495
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.
509
510 -- To deal with these two requirements we add the special checks
511 -- on equal sizes and use the root type to distinguish.
512
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)
516 then
517 Lib_RE := RE_I_SF;
518
519 elsif P_Size <= Standard_Float_Size then
520 Lib_RE := RE_I_F;
521
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)
525 then
526 Lib_RE := RE_I_LF;
527
528 else
529 Lib_RE := RE_I_LLF;
530 end if;
531
532 -- Signed integer types. Also includes signed fixed-point types and
533 -- enumeration types with a signed representation.
534
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.
539
540 -- For example, consider:
541
542 -- type W is range 0 .. 2**32 - 1;
543 -- for W'Size use 32;
544
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.
548
549 -- Similarly, if we have
550
551 -- type W is range -1 .. +254;
552 -- for W'Size use 8;
553
554 -- then the representation is unsigned
555
556 elsif not Is_Unsigned_Type (FST)
557
558 -- The following set of tests gets repeated many times, we should
559 -- have an abstraction defined ???
560
561 and then
562 (Is_Fixed_Point_Type (U_Type)
563 or else
564 Is_Enumeration_Type (U_Type)
565 or else
566 (Is_Signed_Integer_Type (U_Type)
567 and then not Has_Biased_Representation (FST)))
568
569 then
570 if P_Size <= Standard_Short_Short_Integer_Size then
571 Lib_RE := RE_I_SSI;
572
573 elsif P_Size <= Standard_Short_Integer_Size then
574 Lib_RE := RE_I_SI;
575
576 elsif P_Size = 24 then
577 Lib_RE := RE_I_I24;
578
579 elsif P_Size <= Standard_Integer_Size then
580 Lib_RE := RE_I_I;
581
582 elsif P_Size <= Standard_Long_Integer_Size then
583 Lib_RE := RE_I_LI;
584
585 elsif P_Size <= Standard_Long_Long_Integer_Size then
586 Lib_RE := RE_I_LLI;
587
588 else
589 Lib_RE := RE_I_LLLI;
590 end if;
591
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).
595
596 -- Also includes signed integer types that are unsigned in the sense
597 -- that they do not include negative numbers. See above for details.
598
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)
603 then
604 if P_Size <= Standard_Short_Short_Integer_Size then
605 Lib_RE := RE_I_SSU;
606
607 elsif P_Size <= Standard_Short_Integer_Size then
608 Lib_RE := RE_I_SU;
609
610 elsif P_Size = 24 then
611 Lib_RE := RE_I_U24;
612
613 elsif P_Size <= Standard_Integer_Size then
614 Lib_RE := RE_I_U;
615
616 elsif P_Size <= Standard_Long_Integer_Size then
617 Lib_RE := RE_I_LU;
618
619 elsif P_Size <= Standard_Long_Long_Integer_Size then
620 Lib_RE := RE_I_LLU;
621
622 else
623 Lib_RE := RE_I_LLLU;
624 end if;
625
626 else pragma Assert (Is_Access_Type (U_Type));
627 if P_Size > System_Address_Size then
628 Lib_RE := RE_I_AD;
629 else
630 Lib_RE := RE_I_AS;
631 end if;
632 end if;
633
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.
640
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)
644 then
645 Res :=
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))));
651
652 Set_Do_Range_Check (Res);
653
654 if Base_Type (P_Type) /= Base_Type (U_Type) then
655 Res := Unchecked_Convert_To (Base_Type (P_Type), Res);
656 end if;
657
658 return Res;
659
660 else
661 Res :=
662 Make_Function_Call (Loc,
663 Name => New_Occurrence_Of (RTE (Lib_RE), Loc),
664 Parameter_Associations => New_List (
665 Relocate_Node (Strm)));
666
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.
671
672 if not Has_Biased_Representation (P_Type) then
673 return Unchecked_Convert_To (Base_Type (P_Type), Res);
674
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 ???
679
680 else
681 return Unchecked_Convert_To (P_Type, Res);
682 end if;
683 end if;
684 end Build_Elementary_Input_Call;
685
686 ---------------------------------
687 -- Build_Elementary_Write_Call --
688 ---------------------------------
689
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);
698 P_Size : Uint;
699 Lib_RE : RE_Id;
700 Libent : Entity_Id;
701
702 begin
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.
705
706 if Has_Stream_Size_Clause (FST) then
707 P_Size := Static_Integer (Expression (Stream_Size_Clause (FST)));
708 else
709 P_Size := Esize (FST);
710 end if;
711
712 -- Find the routine to be called
713
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.
719
720 if Rt_Type = Standard_Boolean
721 and then Has_Stream_Standard_Rep (U_Type)
722 then
723 Lib_RE := RE_W_B;
724
725 elsif Rt_Type = Standard_Character
726 and then Has_Stream_Standard_Rep (U_Type)
727 then
728 Lib_RE := RE_W_C;
729
730 elsif Rt_Type = Standard_Wide_Character
731 and then Has_Stream_Standard_Rep (U_Type)
732 then
733 Lib_RE := RE_W_WC;
734
735 elsif Rt_Type = Standard_Wide_Wide_Character
736 and then Has_Stream_Standard_Rep (U_Type)
737 then
738 Lib_RE := RE_W_WWC;
739
740 -- Floating point types
741
742 elsif Is_Floating_Point_Type (U_Type) then
743
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.
757
758 -- To deal with these two requirements we add the special checks
759 -- on equal sizes and use the root type to distinguish.
760
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)
764 then
765 Lib_RE := RE_W_SF;
766
767 elsif P_Size <= Standard_Float_Size then
768 Lib_RE := RE_W_F;
769
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)
773 then
774 Lib_RE := RE_W_LF;
775
776 else
777 Lib_RE := RE_W_LLF;
778 end if;
779
780 -- Signed integer types. Also includes signed fixed-point types and
781 -- signed enumeration types share this circuitry.
782
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.
787
788 -- For example, consider:
789
790 -- type W is range 0 .. 2**32 - 1;
791 -- for W'Size use 32;
792
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.
796
797 -- Similarly, the representation is also unsigned if we have:
798
799 -- type W is range -1 .. +254;
800 -- for W'Size use 8;
801
802 -- forcing a biased and unsigned representation
803
804 elsif not Is_Unsigned_Type (FST)
805 and then
806 (Is_Fixed_Point_Type (U_Type)
807 or else
808 Is_Enumeration_Type (U_Type)
809 or else
810 (Is_Signed_Integer_Type (U_Type)
811 and then not Has_Biased_Representation (FST)))
812 then
813 if P_Size <= Standard_Short_Short_Integer_Size then
814 Lib_RE := RE_W_SSI;
815
816 elsif P_Size <= Standard_Short_Integer_Size then
817 Lib_RE := RE_W_SI;
818
819 elsif P_Size = 24 then
820 Lib_RE := RE_W_I24;
821
822 elsif P_Size <= Standard_Integer_Size then
823 Lib_RE := RE_W_I;
824
825 elsif P_Size <= Standard_Long_Integer_Size then
826 Lib_RE := RE_W_LI;
827
828 elsif P_Size <= Standard_Long_Long_Integer_Size then
829 Lib_RE := RE_W_LLI;
830
831 else
832 Lib_RE := RE_W_LLLI;
833 end if;
834
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).
838
839 -- Also includes signed integer types that are unsigned in the sense
840 -- that they do not include negative numbers. See above for details.
841
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)
846 then
847 if P_Size <= Standard_Short_Short_Integer_Size then
848 Lib_RE := RE_W_SSU;
849
850 elsif P_Size <= Standard_Short_Integer_Size then
851 Lib_RE := RE_W_SU;
852
853 elsif P_Size = 24 then
854 Lib_RE := RE_W_U24;
855
856 elsif P_Size <= Standard_Integer_Size then
857 Lib_RE := RE_W_U;
858
859 elsif P_Size <= Standard_Long_Integer_Size then
860 Lib_RE := RE_W_LU;
861
862 elsif P_Size <= Standard_Long_Long_Integer_Size then
863 Lib_RE := RE_W_LLU;
864
865 else
866 Lib_RE := RE_W_LLLU;
867 end if;
868
869 else pragma Assert (Is_Access_Type (U_Type));
870
871 if P_Size > System_Address_Size then
872 Lib_RE := RE_W_AD;
873 else
874 Lib_RE := RE_W_AS;
875 end if;
876 end if;
877
878 -- Unchecked-convert parameter to the required type (i.e. the type of
879 -- the corresponding parameter, and call the appropriate routine.
880
881 Libent := RTE (Lib_RE);
882
883 return
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;
891
892 -----------------------------------------
893 -- Build_Mutable_Record_Read_Procedure --
894 -----------------------------------------
895
896 procedure Build_Mutable_Record_Read_Procedure
897 (Loc : Source_Ptr;
898 Typ : Entity_Id;
899 Decl : out Node_Id;
900 Pnam : out Entity_Id)
901 is
902 Out_Formal : Node_Id;
903 -- Expression denoting the out formal parameter
904
905 Dcls : constant List_Id := New_List;
906 -- Declarations for the 'Read body
907
908 Stms : constant List_Id := New_List;
909 -- Statements for the 'Read body
910
911 Disc : Entity_Id;
912 -- Entity of the discriminant being processed
913
914 Tmp_For_Disc : Entity_Id;
915 -- Temporary object used to read the value of Disc
916
917 Tmps_For_Discs : constant List_Id := New_List;
918 -- List of object declarations for temporaries holding the read values
919 -- for the discriminants.
920
921 Cstr : constant List_Id := New_List;
922 -- List of constraints to be applied on temporary record
923
924 Discriminant_Checks : constant List_Id := New_List;
925 -- List of discriminant checks to be performed if the actual object
926 -- is constrained.
927
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).
931
932 Constrained_Stms : List_Id := New_List;
933 -- Statements within the block where we have the constrained temporary
934
935 begin
936 -- A mutable type cannot be a tagged type, so we generate a new name
937 -- for the stream procedure.
938
939 Pnam :=
940 Make_Defining_Identifier (Loc,
941 Chars => Make_TSS_Name_Local (Typ, TSS_Stream_Read));
942
943 if Is_Unchecked_Union (Typ) then
944
945 -- If this is an unchecked union, the stream procedure is erroneous,
946 -- because there are no discriminants to read.
947
948 -- This should generate a warning ???
949
950 Append_To (Stms,
951 Make_Raise_Program_Error (Loc,
952 Reason => PE_Unchecked_Union_Restriction));
953
954 Build_Stream_Procedure (Loc, Typ, Decl, Pnam, Stms, Outp => True);
955 return;
956 end if;
957
958 Disc := First_Discriminant (Typ);
959
960 Out_Formal :=
961 Make_Selected_Component (Loc,
962 Prefix => New_Occurrence_Of (Pnam, Loc),
963 Selector_Name => Make_Identifier (Loc, Name_V));
964
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.
970
971 while Present (Disc) loop
972 Tmp_For_Disc := Make_Defining_Identifier (Loc,
973 New_External_Name (Chars (Disc), "D"));
974
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));
980
981 Append_To (Stms,
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))));
988
989 Append_To (Cstr,
990 Make_Discriminant_Association (Loc,
991 Selector_Names => New_List (New_Occurrence_Of (Disc, Loc)),
992 Expression => New_Occurrence_Of (Tmp_For_Disc, Loc)));
993
994 Append_To (Discriminant_Checks,
995 Make_Raise_Constraint_Error (Loc,
996 Condition =>
997 Make_Op_Ne (Loc,
998 Left_Opnd => New_Occurrence_Of (Tmp_For_Disc, Loc),
999 Right_Opnd =>
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);
1005 end loop;
1006
1007 -- Generate reads for the components of the record (including those
1008 -- that depend on discriminants).
1009
1010 Build_Record_Read_Write_Procedure (Loc, Typ, Decl, Pnam, Name_Read);
1011
1012 -- Save original statement sequence for component assignments, and
1013 -- replace it with Stms.
1014
1015 Constrained_Stms := Statements (Handled_Statement_Sequence (Decl));
1016 Set_Handled_Statement_Sequence (Decl,
1017 Make_Handled_Sequence_Of_Statements (Loc,
1018 Statements => Stms));
1019
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.
1026
1027 Append_To (Dcls,
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),
1033 Constraint =>
1034 Make_Index_Or_Discriminant_Constraint (Loc,
1035 Constraints => Cstr))));
1036
1037 -- AI05-023-1: Insert discriminant check prior to initialization of the
1038 -- constrained temporary.
1039
1040 Append_To (Stms,
1041 Make_Implicit_If_Statement (Pnam,
1042 Condition =>
1043 Make_Attribute_Reference (Loc,
1044 Prefix => New_Copy_Tree (Out_Formal),
1045 Attribute_Name => Name_Constrained),
1046 Then_Statements => Discriminant_Checks));
1047
1048 -- Now insert back original component assignments, wrapped in a block
1049 -- in which V is the constrained temporary.
1050
1051 Append_To (Stms,
1052 Make_Block_Statement (Loc,
1053 Declarations => Dcls,
1054 Handled_Statement_Sequence => Parent (Constrained_Stms)));
1055
1056 Append_To (Constrained_Stms,
1057 Make_Assignment_Statement (Loc,
1058 Name => Out_Formal,
1059 Expression => Make_Identifier (Loc, Name_V)));
1060
1061 Set_Declarations (Decl, Tmps_For_Discs);
1062 end Build_Mutable_Record_Read_Procedure;
1063
1064 ------------------------------------------
1065 -- Build_Mutable_Record_Write_Procedure --
1066 ------------------------------------------
1067
1068 procedure Build_Mutable_Record_Write_Procedure
1069 (Loc : Source_Ptr;
1070 Typ : Entity_Id;
1071 Decl : out Node_Id;
1072 Pnam : out Entity_Id)
1073 is
1074 Stms : List_Id;
1075 Disc : Entity_Id;
1076 D_Ref : Node_Id;
1077
1078 begin
1079 Stms := New_List;
1080 Disc := First_Discriminant (Typ);
1081
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.
1085
1086 while Present (Disc) loop
1087 if Is_Unchecked_Union (Typ) then
1088 D_Ref :=
1089 New_Copy_Tree (Discriminant_Default_Value (Disc));
1090 else
1091 D_Ref :=
1092 Make_Selected_Component (Loc,
1093 Prefix => Make_Identifier (Loc, Name_V),
1094 Selector_Name => New_Occurrence_Of (Disc, Loc));
1095 end if;
1096
1097 Append_To (Stms,
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),
1103 D_Ref)));
1104
1105 Next_Discriminant (Disc);
1106 end loop;
1107
1108 -- A mutable type cannot be a tagged type, so we generate a new name
1109 -- for the stream procedure.
1110
1111 Pnam :=
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);
1115
1116 -- Write the discriminants before the rest of the components, so
1117 -- that discriminant values are properly set of variants, etc.
1118
1119 if Is_Non_Empty_List (
1120 Statements (Handled_Statement_Sequence (Decl)))
1121 then
1122 Insert_List_Before
1123 (First (Statements (Handled_Statement_Sequence (Decl))), Stms);
1124 else
1125 Set_Statements (Handled_Statement_Sequence (Decl), Stms);
1126 end if;
1127 end Build_Mutable_Record_Write_Procedure;
1128
1129 -----------------------------------------------
1130 -- Build_Record_Or_Elementary_Input_Function --
1131 -----------------------------------------------
1132
1133 -- The function we build looks like
1134
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);
1140 -- ...
1141 -- Cn : constant Disc_Type_n;
1142 -- Discr_Type_n'Read (S, Cn);
1143 -- V : Typ (C1, C2, .. Cn)
1144
1145 -- begin
1146 -- Typ'Read (S, V);
1147 -- return V;
1148 -- end InputN
1149
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.
1153
1154 procedure Build_Record_Or_Elementary_Input_Function
1155 (Loc : Source_Ptr;
1156 Typ : Entity_Id;
1157 Decl : out Node_Id;
1158 Fnam : out Entity_Id)
1159 is
1160 B_Typ : constant Entity_Id := Underlying_Type (Base_Type (Typ));
1161 Cn : Name_Id;
1162 Constr : List_Id;
1163 Decls : List_Id;
1164 Discr : Entity_Id;
1165 Discr_Elmt : Elmt_Id := No_Elmt;
1166 J : Pos;
1167 Obj_Decl : Node_Id;
1168 Odef : Node_Id;
1169 Stms : List_Id;
1170
1171 begin
1172 Decls := New_List;
1173 Constr := New_List;
1174
1175 J := 1;
1176
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
1180 -- to construct.
1181
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))
1185 then
1186 Discr := First_Discriminant (B_Typ);
1187
1188 -- If the prefix subtype is constrained, then retrieve the first
1189 -- element of its constraint.
1190
1191 if Is_Constrained (Typ) then
1192 Discr_Elmt := First_Elmt (Discriminant_Constraint (Typ));
1193 end if;
1194
1195 while Present (Discr) loop
1196 Cn := New_External_Name ('C', J);
1197
1198 Decl :=
1199 Make_Object_Declaration (Loc,
1200 Defining_Identifier => Make_Defining_Identifier (Loc, Cn),
1201 Object_Definition =>
1202 New_Occurrence_Of (Etype (Discr), Loc));
1203
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.
1208
1209 if Is_Access_Type (Etype (Discr)) then
1210 Set_No_Initialization (Decl);
1211 end if;
1212
1213 Append_To (Decls, Decl);
1214 Append_To (Decls,
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))));
1221
1222 Append_To (Constr, Make_Identifier (Loc, Cn));
1223
1224 -- If the prefix subtype imposes a discriminant constraint, then
1225 -- check that each discriminant value equals the value read.
1226
1227 if Present (Discr_Elmt) then
1228 Append_To (Decls,
1229 Make_Raise_Constraint_Error (Loc,
1230 Condition => Make_Op_Ne (Loc,
1231 Left_Opnd =>
1232 New_Occurrence_Of
1233 (Defining_Identifier (Decl), Loc),
1234 Right_Opnd =>
1235 New_Copy_Tree (Node (Discr_Elmt))),
1236 Reason => CE_Discriminant_Check_Failed));
1237
1238 Next_Elmt (Discr_Elmt);
1239 end if;
1240
1241 Next_Discriminant (Discr);
1242 J := J + 1;
1243 end loop;
1244
1245 Odef :=
1246 Make_Subtype_Indication (Loc,
1247 Subtype_Mark => New_Occurrence_Of (B_Typ, Loc),
1248 Constraint =>
1249 Make_Index_Or_Discriminant_Constraint (Loc,
1250 Constraints => Constr));
1251
1252 -- If no discriminants, then just use the type with no constraint
1253
1254 else
1255 Odef := New_Occurrence_Of (B_Typ, Loc);
1256 end if;
1257
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
1261 -- limited).
1262
1263 Obj_Decl :=
1264 Make_Object_Declaration (Loc,
1265 Defining_Identifier => Make_Defining_Identifier (Loc, Name_V),
1266 Object_Definition => Odef);
1267
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.
1271
1272 if Is_Access_Type (B_Typ) then
1273 Set_No_Initialization (Obj_Decl);
1274 end if;
1275
1276 Stms := New_List (
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)))))));
1288
1289 Fnam := Make_Stream_Subprogram_Name (Loc, B_Typ, TSS_Stream_Input);
1290
1291 Build_Stream_Function (Loc, B_Typ, Decl, Fnam, Decls, Stms);
1292 end Build_Record_Or_Elementary_Input_Function;
1293
1294 -------------------------------------------------
1295 -- Build_Record_Or_Elementary_Output_Procedure --
1296 -------------------------------------------------
1297
1298 procedure Build_Record_Or_Elementary_Output_Procedure
1299 (Loc : Source_Ptr;
1300 Typ : Entity_Id;
1301 Decl : out Node_Id;
1302 Pnam : out Entity_Id)
1303 is
1304 Stms : List_Id;
1305 Disc : Entity_Id;
1306 Disc_Ref : Node_Id;
1307
1308 begin
1309 Stms := New_List;
1310
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.
1315
1316 if Has_Discriminants (Typ)
1317 and then No (Discriminant_Default_Value (First_Discriminant (Typ)))
1318 then
1319 Disc := First_Discriminant (Typ);
1320 while Present (Disc) loop
1321
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.
1325
1326 if Is_Unchecked_Union (Typ) then
1327 Disc_Ref := New_Copy_Tree (Discriminant_Default_Value (Disc));
1328
1329 else
1330 Disc_Ref :=
1331 Make_Selected_Component (Loc,
1332 Prefix => Make_Identifier (Loc, Name_V),
1333 Selector_Name => New_Occurrence_Of (Disc, Loc));
1334 end if;
1335
1336 Append_To (Stms,
1337 Make_Attribute_Reference (Loc,
1338 Prefix =>
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),
1343 Disc_Ref)));
1344
1345 Next_Discriminant (Disc);
1346 end loop;
1347 end if;
1348
1349 Append_To (Stms,
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))));
1356
1357 Pnam := Make_Stream_Subprogram_Name (Loc, Typ, TSS_Stream_Output);
1358
1359 Build_Stream_Procedure (Loc, Typ, Decl, Pnam, Stms, Outp => False);
1360 end Build_Record_Or_Elementary_Output_Procedure;
1361
1362 ---------------------------------
1363 -- Build_Record_Read_Procedure --
1364 ---------------------------------
1365
1366 procedure Build_Record_Read_Procedure
1367 (Loc : Source_Ptr;
1368 Typ : Entity_Id;
1369 Decl : out Node_Id;
1370 Pnam : out Entity_Id)
1371 is
1372 begin
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;
1376
1377 ---------------------------------------
1378 -- Build_Record_Read_Write_Procedure --
1379 ---------------------------------------
1380
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:
1383
1384 -- procedure pnam (S : access RST, V : [out] Typ) is
1385 -- begin
1386 -- Component_Type'Read/Write (S, V.component);
1387 -- Component_Type'Read/Write (S, V.component);
1388 -- ...
1389 -- Component_Type'Read/Write (S, V.component);
1390 --
1391 -- case V.discriminant is
1392 -- when choices =>
1393 -- Component_Type'Read/Write (S, V.component);
1394 -- Component_Type'Read/Write (S, V.component);
1395 -- ...
1396 -- Component_Type'Read/Write (S, V.component);
1397 --
1398 -- when choices =>
1399 -- Component_Type'Read/Write (S, V.component);
1400 -- Component_Type'Read/Write (S, V.component);
1401 -- ...
1402 -- Component_Type'Read/Write (S, V.component);
1403 -- ...
1404 -- end case;
1405 -- end pnam;
1406
1407 -- The out keyword for V is supplied in the Read case
1408
1409 procedure Build_Record_Read_Write_Procedure
1410 (Loc : Source_Ptr;
1411 Typ : Entity_Id;
1412 Decl : out Node_Id;
1413 Pnam : Entity_Id;
1414 Nam : Name_Id)
1415 is
1416 Rdef : Node_Id;
1417 Stms : List_Id;
1418 Typt : Entity_Id;
1419
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).
1424
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.
1428
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.
1432
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.
1436
1437 ------------------------------------
1438 -- Make_Component_List_Attributes --
1439 ------------------------------------
1440
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);
1444
1445 Result : List_Id;
1446 Alts : List_Id;
1447 V : Node_Id;
1448 DC : Node_Id;
1449 DCH : List_Id;
1450 D_Ref : Node_Id;
1451
1452 begin
1453 Result := Make_Field_Attributes (CI);
1454
1455 if Present (VP) then
1456 Alts := New_List;
1457
1458 V := First_Non_Pragma (Variants (VP));
1459 while Present (V) loop
1460 DCH := New_List;
1461
1462 DC := First (Discrete_Choices (V));
1463 while Present (DC) loop
1464 Append_To (DCH, New_Copy_Tree (DC));
1465 Next (DC);
1466 end loop;
1467
1468 Append_To (Alts,
1469 Make_Case_Statement_Alternative (Loc,
1470 Discrete_Choices => DCH,
1471 Statements =>
1472 Make_Component_List_Attributes (Component_List (V))));
1473 Next_Non_Pragma (V);
1474 end loop;
1475
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.
1479
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.
1484
1485 if Is_Unchecked_Union (Scope (Entity (Name (VP)))) then
1486 D_Ref :=
1487 New_Copy_Tree
1488 (Discriminant_Default_Value (Entity (Name (VP))));
1489 else
1490 D_Ref :=
1491 Make_Selected_Component (Loc,
1492 Prefix => Make_Identifier (Loc, Name_V),
1493 Selector_Name =>
1494 New_Occurrence_Of (Entity (Name (VP)), Loc));
1495 end if;
1496
1497 Append_To (Result,
1498 Make_Case_Statement (Loc,
1499 Expression => D_Ref,
1500 Alternatives => Alts));
1501 end if;
1502
1503 return Result;
1504 end Make_Component_List_Attributes;
1505
1506 --------------------------
1507 -- Make_Field_Attribute --
1508 --------------------------
1509
1510 function Make_Field_Attribute (C : Entity_Id) return Node_Id is
1511 Field_Typ : constant Entity_Id := Stream_Base_Type (Etype (C));
1512
1513 TSS_Names : constant array (Name_Input .. Name_Write) of
1514 TSS_Name_Type :=
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);
1521
1522 begin
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)))
1526 then
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.
1530
1531 return Make_Null_Statement (Loc);
1532 end if;
1533
1534 return
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;
1544
1545 ---------------------------
1546 -- Make_Field_Attributes --
1547 ---------------------------
1548
1549 function Make_Field_Attributes (Clist : List_Id) return List_Id is
1550 Item : Node_Id;
1551 Result : List_Id;
1552
1553 begin
1554 Result := New_List;
1555
1556 if Present (Clist) then
1557 Item := First (Clist);
1558
1559 -- Loop through components, skipping all internal components,
1560 -- which are not part of the value (e.g. _Tag), except that we
1561 -- don't skip the _Parent, since we do want to process that
1562 -- recursively. If _Parent is an interface type, being abstract
1563 -- with no components there is no need to handle it.
1564
1565 while Present (Item) loop
1566 if Nkind (Item) = N_Component_Declaration
1567 and then
1568 ((Chars (Defining_Identifier (Item)) = Name_uParent
1569 and then not Is_Interface
1570 (Etype (Defining_Identifier (Item))))
1571 or else
1572 not Is_Internal_Name (Chars (Defining_Identifier (Item))))
1573 then
1574 Append_To
1575 (Result,
1576 Make_Field_Attribute (Defining_Identifier (Item)));
1577 end if;
1578
1579 Next (Item);
1580 end loop;
1581 end if;
1582
1583 return Result;
1584 end Make_Field_Attributes;
1585
1586 -- Start of processing for Build_Record_Read_Write_Procedure
1587
1588 begin
1589 -- For the protected type case, use corresponding record
1590
1591 if Is_Protected_Type (Typ) then
1592 Typt := Corresponding_Record_Type (Typ);
1593 else
1594 Typt := Typ;
1595 end if;
1596
1597 -- Note that we do nothing with the discriminants, since Read and
1598 -- Write do not read or write the discriminant values. All handling
1599 -- of discriminants occurs in the Input and Output subprograms.
1600
1601 Rdef := Type_Definition
1602 (Declaration_Node (Base_Type (Underlying_Type (Typt))));
1603 Stms := Empty_List;
1604
1605 -- In record extension case, the fields we want, including the _Parent
1606 -- field representing the parent type, are to be found in the extension.
1607 -- Note that we will naturally process the _Parent field using the type
1608 -- of the parent, and hence its stream attributes, which is appropriate.
1609
1610 if Nkind (Rdef) = N_Derived_Type_Definition then
1611 Rdef := Record_Extension_Part (Rdef);
1612
1613 if Is_Limited_Type (Typt) then
1614 In_Limited_Extension := True;
1615 end if;
1616 end if;
1617
1618 if Present (Component_List (Rdef)) then
1619 Append_List_To (Stms,
1620 Make_Component_List_Attributes (Component_List (Rdef)));
1621 end if;
1622
1623 Build_Stream_Procedure
1624 (Loc, Typ, Decl, Pnam, Stms, Outp => Nam = Name_Read);
1625 end Build_Record_Read_Write_Procedure;
1626
1627 ----------------------------------
1628 -- Build_Record_Write_Procedure --
1629 ----------------------------------
1630
1631 procedure Build_Record_Write_Procedure
1632 (Loc : Source_Ptr;
1633 Typ : Entity_Id;
1634 Decl : out Node_Id;
1635 Pnam : out Entity_Id)
1636 is
1637 begin
1638 Pnam := Make_Stream_Subprogram_Name (Loc, Typ, TSS_Stream_Write);
1639 Build_Record_Read_Write_Procedure (Loc, Typ, Decl, Pnam, Name_Write);
1640 end Build_Record_Write_Procedure;
1641
1642 -------------------------------
1643 -- Build_Stream_Attr_Profile --
1644 -------------------------------
1645
1646 function Build_Stream_Attr_Profile
1647 (Loc : Source_Ptr;
1648 Typ : Entity_Id;
1649 Nam : TSS_Name_Type) return List_Id
1650 is
1651 Profile : List_Id;
1652
1653 begin
1654 -- (Ada 2005: AI-441): Set the null-excluding attribute because it has
1655 -- no semantic meaning in Ada 95 but it is a requirement in Ada 2005.
1656
1657 Profile := New_List (
1658 Make_Parameter_Specification (Loc,
1659 Defining_Identifier => Make_Defining_Identifier (Loc, Name_S),
1660 Parameter_Type =>
1661 Make_Access_Definition (Loc,
1662 Null_Exclusion_Present => True,
1663 Subtype_Mark => New_Occurrence_Of (
1664 Class_Wide_Type (RTE (RE_Root_Stream_Type)), Loc))));
1665
1666 if Nam /= TSS_Stream_Input then
1667 Append_To (Profile,
1668 Make_Parameter_Specification (Loc,
1669 Defining_Identifier => Make_Defining_Identifier (Loc, Name_V),
1670 Out_Present => (Nam = TSS_Stream_Read),
1671 Parameter_Type => New_Occurrence_Of (Typ, Loc)));
1672 end if;
1673
1674 return Profile;
1675 end Build_Stream_Attr_Profile;
1676
1677 ---------------------------
1678 -- Build_Stream_Function --
1679 ---------------------------
1680
1681 procedure Build_Stream_Function
1682 (Loc : Source_Ptr;
1683 Typ : Entity_Id;
1684 Decl : out Node_Id;
1685 Fnam : Entity_Id;
1686 Decls : List_Id;
1687 Stms : List_Id)
1688 is
1689 Spec : Node_Id;
1690
1691 begin
1692 -- Construct function specification
1693
1694 -- (Ada 2005: AI-441): Set the null-excluding attribute because it has
1695 -- no semantic meaning in Ada 95 but it is a requirement in Ada 2005.
1696
1697 Spec :=
1698 Make_Function_Specification (Loc,
1699 Defining_Unit_Name => Fnam,
1700
1701 Parameter_Specifications => New_List (
1702 Make_Parameter_Specification (Loc,
1703 Defining_Identifier => Make_Defining_Identifier (Loc, Name_S),
1704 Parameter_Type =>
1705 Make_Access_Definition (Loc,
1706 Null_Exclusion_Present => True,
1707 Subtype_Mark =>
1708 New_Occurrence_Of
1709 (Class_Wide_Type (RTE (RE_Root_Stream_Type)), Loc)))),
1710
1711 Result_Definition => New_Occurrence_Of (Typ, Loc));
1712
1713 Decl :=
1714 Make_Subprogram_Body (Loc,
1715 Specification => Spec,
1716 Declarations => Decls,
1717 Handled_Statement_Sequence =>
1718 Make_Handled_Sequence_Of_Statements (Loc,
1719 Statements => Stms));
1720 end Build_Stream_Function;
1721
1722 ----------------------------
1723 -- Build_Stream_Procedure --
1724 ----------------------------
1725
1726 procedure Build_Stream_Procedure
1727 (Loc : Source_Ptr;
1728 Typ : Entity_Id;
1729 Decl : out Node_Id;
1730 Pnam : Entity_Id;
1731 Stms : List_Id;
1732 Outp : Boolean)
1733 is
1734 Spec : Node_Id;
1735
1736 begin
1737 -- Construct procedure specification
1738
1739 -- (Ada 2005: AI-441): Set the null-excluding attribute because it has
1740 -- no semantic meaning in Ada 95 but it is a requirement in Ada 2005.
1741
1742 Spec :=
1743 Make_Procedure_Specification (Loc,
1744 Defining_Unit_Name => Pnam,
1745
1746 Parameter_Specifications => New_List (
1747 Make_Parameter_Specification (Loc,
1748 Defining_Identifier => Make_Defining_Identifier (Loc, Name_S),
1749 Parameter_Type =>
1750 Make_Access_Definition (Loc,
1751 Null_Exclusion_Present => True,
1752 Subtype_Mark =>
1753 New_Occurrence_Of
1754 (Class_Wide_Type (RTE (RE_Root_Stream_Type)), Loc))),
1755
1756 Make_Parameter_Specification (Loc,
1757 Defining_Identifier => Make_Defining_Identifier (Loc, Name_V),
1758 Out_Present => Outp,
1759 Parameter_Type => New_Occurrence_Of (Typ, Loc))));
1760
1761 Decl :=
1762 Make_Subprogram_Body (Loc,
1763 Specification => Spec,
1764 Declarations => Empty_List,
1765 Handled_Statement_Sequence =>
1766 Make_Handled_Sequence_Of_Statements (Loc,
1767 Statements => Stms));
1768 end Build_Stream_Procedure;
1769
1770 -----------------------------
1771 -- Has_Stream_Standard_Rep --
1772 -----------------------------
1773
1774 function Has_Stream_Standard_Rep (U_Type : Entity_Id) return Boolean is
1775 Siz : Uint;
1776
1777 begin
1778 if Has_Non_Standard_Rep (U_Type) then
1779 return False;
1780 end if;
1781
1782 if Has_Stream_Size_Clause (U_Type) then
1783 Siz := Static_Integer (Expression (Stream_Size_Clause (U_Type)));
1784 else
1785 Siz := Esize (First_Subtype (U_Type));
1786 end if;
1787
1788 return Siz = Esize (Root_Type (U_Type));
1789 end Has_Stream_Standard_Rep;
1790
1791 ---------------------------------
1792 -- Make_Stream_Subprogram_Name --
1793 ---------------------------------
1794
1795 function Make_Stream_Subprogram_Name
1796 (Loc : Source_Ptr;
1797 Typ : Entity_Id;
1798 Nam : TSS_Name_Type) return Entity_Id
1799 is
1800 Sname : Name_Id;
1801
1802 begin
1803 -- For tagged types, we are dealing with a TSS associated with the
1804 -- declaration, so we use the standard primitive function name. For
1805 -- other types, generate a local TSS name since we are generating
1806 -- the subprogram at the point of use.
1807
1808 if Is_Tagged_Type (Typ) then
1809 Sname := Make_TSS_Name (Typ, Nam);
1810 else
1811 Sname := Make_TSS_Name_Local (Typ, Nam);
1812 end if;
1813
1814 return Make_Defining_Identifier (Loc, Sname);
1815 end Make_Stream_Subprogram_Name;
1816
1817 ----------------------
1818 -- Stream_Base_Type --
1819 ----------------------
1820
1821 function Stream_Base_Type (E : Entity_Id) return Entity_Id is
1822 begin
1823 if Is_Array_Type (E)
1824 and then Is_First_Subtype (E)
1825 then
1826 return E;
1827 else
1828 return Base_Type (E);
1829 end if;
1830 end Stream_Base_Type;
1831
1832 end Exp_Strm;