]>
Commit | Line | Data |
---|---|---|
70482933 RK |
1 | ------------------------------------------------------------------------------ |
2 | -- -- | |
3 | -- GNAT COMPILER COMPONENTS -- | |
4 | -- -- | |
5 | -- E X P _ C H 4 -- | |
6 | -- -- | |
7 | -- B o d y -- | |
8 | -- -- | |
07fc65c4 | 9 | -- Copyright (C) 1992-2002, Free Software Foundation, Inc. -- |
70482933 RK |
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 2, 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 COPYING. If not, write -- | |
19 | -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- | |
20 | -- MA 02111-1307, USA. -- | |
21 | -- -- | |
22 | -- GNAT was originally developed by the GNAT team at New York University. -- | |
71ff80dc | 23 | -- Extensive contributions were provided by Ada Core Technologies Inc. -- |
70482933 RK |
24 | -- -- |
25 | ------------------------------------------------------------------------------ | |
26 | ||
27 | with Atree; use Atree; | |
28 | with Checks; use Checks; | |
29 | with Einfo; use Einfo; | |
30 | with Elists; use Elists; | |
31 | with Errout; use Errout; | |
32 | with Exp_Aggr; use Exp_Aggr; | |
33 | with Exp_Ch3; use Exp_Ch3; | |
34 | with Exp_Ch7; use Exp_Ch7; | |
35 | with Exp_Ch9; use Exp_Ch9; | |
36 | with Exp_Disp; use Exp_Disp; | |
37 | with Exp_Fixd; use Exp_Fixd; | |
38 | with Exp_Pakd; use Exp_Pakd; | |
39 | with Exp_Tss; use Exp_Tss; | |
40 | with Exp_Util; use Exp_Util; | |
41 | with Exp_VFpt; use Exp_VFpt; | |
42 | with Hostparm; use Hostparm; | |
43 | with Inline; use Inline; | |
44 | with Nlists; use Nlists; | |
45 | with Nmake; use Nmake; | |
46 | with Opt; use Opt; | |
07fc65c4 | 47 | with Restrict; use Restrict; |
70482933 RK |
48 | with Rtsfind; use Rtsfind; |
49 | with Sem; use Sem; | |
50 | with Sem_Cat; use Sem_Cat; | |
51 | with Sem_Ch13; use Sem_Ch13; | |
52 | with Sem_Eval; use Sem_Eval; | |
53 | with Sem_Res; use Sem_Res; | |
54 | with Sem_Type; use Sem_Type; | |
55 | with Sem_Util; use Sem_Util; | |
07fc65c4 | 56 | with Sem_Warn; use Sem_Warn; |
70482933 RK |
57 | with Sinfo; use Sinfo; |
58 | with Sinfo.CN; use Sinfo.CN; | |
59 | with Snames; use Snames; | |
60 | with Stand; use Stand; | |
07fc65c4 | 61 | with Targparm; use Targparm; |
70482933 RK |
62 | with Tbuild; use Tbuild; |
63 | with Ttypes; use Ttypes; | |
64 | with Uintp; use Uintp; | |
65 | with Urealp; use Urealp; | |
66 | with Validsw; use Validsw; | |
67 | ||
68 | package body Exp_Ch4 is | |
69 | ||
70 | ------------------------ | |
71 | -- Local Subprograms -- | |
72 | ------------------------ | |
73 | ||
74 | procedure Binary_Op_Validity_Checks (N : Node_Id); | |
75 | pragma Inline (Binary_Op_Validity_Checks); | |
76 | -- Performs validity checks for a binary operator | |
77 | ||
78 | procedure Expand_Array_Comparison (N : Node_Id); | |
79 | -- This routine handles expansion of the comparison operators (N_Op_Lt, | |
80 | -- N_Op_Le, N_Op_Gt, N_Op_Ge) when operating on an array type. The basic | |
81 | -- code for these operators is similar, differing only in the details of | |
82 | -- the actual comparison call that is made. | |
83 | ||
84 | function Expand_Array_Equality | |
85 | (Nod : Node_Id; | |
86 | Typ : Entity_Id; | |
87 | A_Typ : Entity_Id; | |
88 | Lhs : Node_Id; | |
89 | Rhs : Node_Id; | |
90 | Bodies : List_Id) | |
91 | return Node_Id; | |
92 | -- Expand an array equality into a call to a function implementing this | |
93 | -- equality, and a call to it. Loc is the location for the generated | |
94 | -- nodes. Typ is the type of the array, and Lhs, Rhs are the array | |
95 | -- expressions to be compared. A_Typ is the type of the arguments, | |
96 | -- which may be a private type, in which case Typ is its full view. | |
97 | -- Bodies is a list on which to attach bodies of local functions that | |
98 | -- are created in the process. This is the responsability of the | |
99 | -- caller to insert those bodies at the right place. Nod provides | |
100 | -- the Sloc value for the generated code. | |
101 | ||
102 | procedure Expand_Boolean_Operator (N : Node_Id); | |
103 | -- Common expansion processing for Boolean operators (And, Or, Xor) | |
104 | -- for the case of array type arguments. | |
105 | ||
106 | function Expand_Composite_Equality | |
107 | (Nod : Node_Id; | |
108 | Typ : Entity_Id; | |
109 | Lhs : Node_Id; | |
110 | Rhs : Node_Id; | |
111 | Bodies : List_Id) | |
112 | return Node_Id; | |
113 | -- Local recursive function used to expand equality for nested | |
114 | -- composite types. Used by Expand_Record/Array_Equality, Bodies | |
115 | -- is a list on which to attach bodies of local functions that are | |
116 | -- created in the process. This is the responsability of the caller | |
117 | -- to insert those bodies at the right place. Nod provides the Sloc | |
118 | -- value for generated code. | |
119 | ||
120 | procedure Expand_Concatenate_Other (Cnode : Node_Id; Opnds : List_Id); | |
121 | -- This routine handles expansion of concatenation operations, where | |
122 | -- N is the N_Op_Concat node being expanded and Operands is the list | |
123 | -- of operands (at least two are present). The caller has dealt with | |
124 | -- converting any singleton operands into singleton aggregates. | |
125 | ||
126 | procedure Expand_Concatenate_String (Cnode : Node_Id; Opnds : List_Id); | |
127 | -- Routine to expand concatenation of 2-5 operands (in the list Operands) | |
128 | -- and replace node Cnode with the result of the contatenation. If there | |
129 | -- are two operands, they can be string or character. If there are more | |
130 | -- than two operands, then are always of type string (i.e. the caller has | |
131 | -- already converted character operands to strings in this case). | |
132 | ||
133 | procedure Fixup_Universal_Fixed_Operation (N : Node_Id); | |
134 | -- N is either an N_Op_Divide or N_Op_Multiply node whose result is | |
135 | -- universal fixed. We do not have such a type at runtime, so the | |
136 | -- purpose of this routine is to find the real type by looking up | |
137 | -- the tree. We also determine if the operation must be rounded. | |
138 | ||
139 | procedure Insert_Dereference_Action (N : Node_Id); | |
140 | -- N is an expression whose type is an access. When the type is derived | |
141 | -- from Checked_Pool, expands a call to the primitive 'dereference'. | |
142 | ||
143 | function Make_Array_Comparison_Op | |
144 | (Typ : Entity_Id; | |
145 | Nod : Node_Id) | |
146 | return Node_Id; | |
147 | -- Comparisons between arrays are expanded in line. This function | |
148 | -- produces the body of the implementation of (a > b), where a and b | |
149 | -- are one-dimensional arrays of some discrete type. The original | |
150 | -- node is then expanded into the appropriate call to this function. | |
151 | -- Nod provides the Sloc value for the generated code. | |
152 | ||
153 | function Make_Boolean_Array_Op | |
154 | (Typ : Entity_Id; | |
155 | N : Node_Id) | |
156 | return Node_Id; | |
157 | -- Boolean operations on boolean arrays are expanded in line. This | |
158 | -- function produce the body for the node N, which is (a and b), | |
159 | -- (a or b), or (a xor b). It is used only the normal case and not | |
160 | -- the packed case. The type involved, Typ, is the Boolean array type, | |
161 | -- and the logical operations in the body are simple boolean operations. | |
162 | -- Note that Typ is always a constrained type (the caller has ensured | |
163 | -- this by using Convert_To_Actual_Subtype if necessary). | |
164 | ||
165 | procedure Rewrite_Comparison (N : Node_Id); | |
166 | -- N is the node for a compile time comparison. If this outcome of this | |
167 | -- comparison can be determined at compile time, then the node N can be | |
168 | -- rewritten with True or False. If the outcome cannot be determined at | |
169 | -- compile time, the call has no effect. | |
170 | ||
171 | function Tagged_Membership (N : Node_Id) return Node_Id; | |
172 | -- Construct the expression corresponding to the tagged membership test. | |
173 | -- Deals with a second operand being (or not) a class-wide type. | |
174 | ||
175 | procedure Unary_Op_Validity_Checks (N : Node_Id); | |
176 | pragma Inline (Unary_Op_Validity_Checks); | |
177 | -- Performs validity checks for a unary operator | |
178 | ||
179 | ------------------------------- | |
180 | -- Binary_Op_Validity_Checks -- | |
181 | ------------------------------- | |
182 | ||
183 | procedure Binary_Op_Validity_Checks (N : Node_Id) is | |
184 | begin | |
185 | if Validity_Checks_On and Validity_Check_Operands then | |
186 | Ensure_Valid (Left_Opnd (N)); | |
187 | Ensure_Valid (Right_Opnd (N)); | |
188 | end if; | |
189 | end Binary_Op_Validity_Checks; | |
190 | ||
191 | ----------------------------- | |
192 | -- Expand_Array_Comparison -- | |
193 | ----------------------------- | |
194 | ||
195 | -- Expansion is only required in the case of array types. The form of | |
196 | -- the expansion is: | |
197 | ||
198 | -- [body for greater_nn; boolean_expression] | |
199 | ||
200 | -- The body is built by Make_Array_Comparison_Op, and the form of the | |
201 | -- Boolean expression depends on the operator involved. | |
202 | ||
203 | procedure Expand_Array_Comparison (N : Node_Id) is | |
204 | Loc : constant Source_Ptr := Sloc (N); | |
205 | Op1 : Node_Id := Left_Opnd (N); | |
206 | Op2 : Node_Id := Right_Opnd (N); | |
207 | Typ1 : constant Entity_Id := Base_Type (Etype (Op1)); | |
208 | ||
209 | Expr : Node_Id; | |
210 | Func_Body : Node_Id; | |
211 | Func_Name : Entity_Id; | |
212 | ||
213 | begin | |
214 | -- For (a <= b) we convert to not (a > b) | |
215 | ||
216 | if Chars (N) = Name_Op_Le then | |
217 | Rewrite (N, | |
218 | Make_Op_Not (Loc, | |
219 | Right_Opnd => | |
220 | Make_Op_Gt (Loc, | |
221 | Left_Opnd => Op1, | |
222 | Right_Opnd => Op2))); | |
223 | Analyze_And_Resolve (N, Standard_Boolean); | |
224 | return; | |
225 | ||
226 | -- For < the Boolean expression is | |
227 | -- greater__nn (op2, op1) | |
228 | ||
229 | elsif Chars (N) = Name_Op_Lt then | |
230 | Func_Body := Make_Array_Comparison_Op (Typ1, N); | |
231 | ||
232 | -- Switch operands | |
233 | ||
234 | Op1 := Right_Opnd (N); | |
235 | Op2 := Left_Opnd (N); | |
236 | ||
237 | -- For (a >= b) we convert to not (a < b) | |
238 | ||
239 | elsif Chars (N) = Name_Op_Ge then | |
240 | Rewrite (N, | |
241 | Make_Op_Not (Loc, | |
242 | Right_Opnd => | |
243 | Make_Op_Lt (Loc, | |
244 | Left_Opnd => Op1, | |
245 | Right_Opnd => Op2))); | |
246 | Analyze_And_Resolve (N, Standard_Boolean); | |
247 | return; | |
248 | ||
249 | -- For > the Boolean expression is | |
250 | -- greater__nn (op1, op2) | |
251 | ||
252 | else | |
253 | pragma Assert (Chars (N) = Name_Op_Gt); | |
254 | Func_Body := Make_Array_Comparison_Op (Typ1, N); | |
255 | end if; | |
256 | ||
257 | Func_Name := Defining_Unit_Name (Specification (Func_Body)); | |
258 | Expr := | |
259 | Make_Function_Call (Loc, | |
260 | Name => New_Reference_To (Func_Name, Loc), | |
261 | Parameter_Associations => New_List (Op1, Op2)); | |
262 | ||
263 | Insert_Action (N, Func_Body); | |
264 | Rewrite (N, Expr); | |
265 | Analyze_And_Resolve (N, Standard_Boolean); | |
266 | ||
267 | end Expand_Array_Comparison; | |
268 | ||
269 | --------------------------- | |
270 | -- Expand_Array_Equality -- | |
271 | --------------------------- | |
272 | ||
273 | -- Expand an equality function for multi-dimensional arrays. Here is | |
274 | -- an example of such a function for Nb_Dimension = 2 | |
275 | ||
276 | -- function Enn (A : arr; B : arr) return boolean is | |
277 | -- J1 : integer; | |
278 | -- J2 : integer; | |
279 | -- | |
280 | -- begin | |
281 | -- if A'length (1) /= B'length (1) then | |
282 | -- return false; | |
283 | -- else | |
284 | -- J1 := B'first (1); | |
285 | -- for I1 in A'first (1) .. A'last (1) loop | |
286 | -- if A'length (2) /= B'length (2) then | |
287 | -- return false; | |
288 | -- else | |
289 | -- J2 := B'first (2); | |
290 | -- for I2 in A'first (2) .. A'last (2) loop | |
291 | -- if A (I1, I2) /= B (J1, J2) then | |
292 | -- return false; | |
293 | -- end if; | |
294 | -- J2 := Integer'succ (J2); | |
295 | -- end loop; | |
296 | -- end if; | |
297 | -- J1 := Integer'succ (J1); | |
298 | -- end loop; | |
299 | -- end if; | |
300 | -- return true; | |
301 | -- end Enn; | |
302 | ||
303 | function Expand_Array_Equality | |
304 | (Nod : Node_Id; | |
305 | Typ : Entity_Id; | |
306 | A_Typ : Entity_Id; | |
307 | Lhs : Node_Id; | |
308 | Rhs : Node_Id; | |
309 | Bodies : List_Id) | |
310 | return Node_Id | |
311 | is | |
312 | Loc : constant Source_Ptr := Sloc (Nod); | |
313 | Actuals : List_Id; | |
314 | Decls : List_Id := New_List; | |
315 | Index_List1 : List_Id := New_List; | |
316 | Index_List2 : List_Id := New_List; | |
317 | Formals : List_Id; | |
318 | Stats : Node_Id; | |
319 | Func_Name : Entity_Id; | |
320 | Func_Body : Node_Id; | |
321 | ||
322 | A : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uA); | |
323 | B : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uB); | |
324 | ||
325 | function Component_Equality (Typ : Entity_Id) return Node_Id; | |
326 | -- Create one statement to compare corresponding components, designated | |
327 | -- by a full set of indices. | |
328 | ||
329 | function Loop_One_Dimension | |
330 | (N : Int; | |
331 | Index : Node_Id) | |
332 | return Node_Id; | |
333 | -- Loop over the n'th dimension of the arrays. The single statement | |
334 | -- in the body of the loop is a loop over the next dimension, or | |
335 | -- the comparison of corresponding components. | |
336 | ||
337 | ------------------------ | |
338 | -- Component_Equality -- | |
339 | ------------------------ | |
340 | ||
341 | function Component_Equality (Typ : Entity_Id) return Node_Id is | |
342 | Test : Node_Id; | |
343 | L, R : Node_Id; | |
344 | ||
345 | begin | |
346 | -- if a(i1...) /= b(j1...) then return false; end if; | |
347 | ||
348 | L := | |
349 | Make_Indexed_Component (Loc, | |
350 | Prefix => Make_Identifier (Loc, Chars (A)), | |
351 | Expressions => Index_List1); | |
352 | ||
353 | R := | |
354 | Make_Indexed_Component (Loc, | |
355 | Prefix => Make_Identifier (Loc, Chars (B)), | |
356 | Expressions => Index_List2); | |
357 | ||
358 | Test := Expand_Composite_Equality | |
359 | (Nod, Component_Type (Typ), L, R, Decls); | |
360 | ||
361 | return | |
362 | Make_Implicit_If_Statement (Nod, | |
363 | Condition => Make_Op_Not (Loc, Right_Opnd => Test), | |
364 | Then_Statements => New_List ( | |
365 | Make_Return_Statement (Loc, | |
366 | Expression => New_Occurrence_Of (Standard_False, Loc)))); | |
367 | ||
368 | end Component_Equality; | |
369 | ||
370 | ------------------------ | |
371 | -- Loop_One_Dimension -- | |
372 | ------------------------ | |
373 | ||
374 | function Loop_One_Dimension | |
375 | (N : Int; | |
376 | Index : Node_Id) | |
377 | return Node_Id | |
378 | is | |
379 | I : constant Entity_Id := Make_Defining_Identifier (Loc, | |
380 | New_Internal_Name ('I')); | |
381 | J : constant Entity_Id := Make_Defining_Identifier (Loc, | |
382 | New_Internal_Name ('J')); | |
383 | Index_Type : Entity_Id; | |
384 | Stats : Node_Id; | |
385 | ||
386 | begin | |
387 | if N > Number_Dimensions (Typ) then | |
388 | return Component_Equality (Typ); | |
389 | ||
390 | else | |
391 | -- Generate the following: | |
392 | ||
393 | -- j: index_type; | |
394 | -- ... | |
395 | ||
396 | -- if a'length (n) /= b'length (n) then | |
397 | -- return false; | |
398 | -- else | |
399 | -- j := b'first (n); | |
400 | -- for i in a'range (n) loop | |
401 | -- -- loop over remaining dimensions. | |
402 | -- j := index_type'succ (j); | |
403 | -- end loop; | |
404 | -- end if; | |
405 | ||
406 | -- retrieve index type for current dimension. | |
407 | ||
408 | Index_Type := Base_Type (Etype (Index)); | |
409 | Append (New_Reference_To (I, Loc), Index_List1); | |
410 | Append (New_Reference_To (J, Loc), Index_List2); | |
411 | ||
412 | -- Declare index for j as a local variable to the function. | |
413 | -- Index i is a loop variable. | |
414 | ||
415 | Append_To (Decls, | |
416 | Make_Object_Declaration (Loc, | |
417 | Defining_Identifier => J, | |
418 | Object_Definition => New_Reference_To (Index_Type, Loc))); | |
419 | ||
420 | Stats := | |
421 | Make_Implicit_If_Statement (Nod, | |
422 | Condition => | |
423 | Make_Op_Ne (Loc, | |
424 | Left_Opnd => | |
425 | Make_Attribute_Reference (Loc, | |
426 | Prefix => New_Reference_To (A, Loc), | |
427 | Attribute_Name => Name_Length, | |
428 | Expressions => New_List ( | |
429 | Make_Integer_Literal (Loc, N))), | |
430 | Right_Opnd => | |
431 | Make_Attribute_Reference (Loc, | |
432 | Prefix => New_Reference_To (B, Loc), | |
433 | Attribute_Name => Name_Length, | |
434 | Expressions => New_List ( | |
435 | Make_Integer_Literal (Loc, N)))), | |
436 | ||
437 | Then_Statements => New_List ( | |
438 | Make_Return_Statement (Loc, | |
439 | Expression => New_Occurrence_Of (Standard_False, Loc))), | |
440 | ||
441 | Else_Statements => New_List ( | |
442 | ||
443 | Make_Assignment_Statement (Loc, | |
444 | Name => New_Reference_To (J, Loc), | |
445 | Expression => | |
446 | Make_Attribute_Reference (Loc, | |
447 | Prefix => New_Reference_To (B, Loc), | |
448 | Attribute_Name => Name_First, | |
449 | Expressions => New_List ( | |
450 | Make_Integer_Literal (Loc, N)))), | |
451 | ||
452 | Make_Implicit_Loop_Statement (Nod, | |
453 | Identifier => Empty, | |
454 | Iteration_Scheme => | |
455 | Make_Iteration_Scheme (Loc, | |
456 | Loop_Parameter_Specification => | |
457 | Make_Loop_Parameter_Specification (Loc, | |
458 | Defining_Identifier => I, | |
459 | Discrete_Subtype_Definition => | |
460 | Make_Attribute_Reference (Loc, | |
461 | Prefix => New_Reference_To (A, Loc), | |
462 | Attribute_Name => Name_Range, | |
463 | Expressions => New_List ( | |
464 | Make_Integer_Literal (Loc, N))))), | |
465 | ||
466 | Statements => New_List ( | |
467 | Loop_One_Dimension (N + 1, Next_Index (Index)), | |
468 | Make_Assignment_Statement (Loc, | |
469 | Name => New_Reference_To (J, Loc), | |
470 | Expression => | |
471 | Make_Attribute_Reference (Loc, | |
472 | Prefix => New_Reference_To (Index_Type, Loc), | |
473 | Attribute_Name => Name_Succ, | |
474 | Expressions => New_List ( | |
475 | New_Reference_To (J, Loc)))))))); | |
476 | ||
477 | return Stats; | |
478 | end if; | |
479 | end Loop_One_Dimension; | |
480 | ||
481 | -- Start of processing for Expand_Array_Equality | |
482 | ||
483 | begin | |
484 | Formals := New_List ( | |
485 | Make_Parameter_Specification (Loc, | |
486 | Defining_Identifier => A, | |
487 | Parameter_Type => New_Reference_To (Typ, Loc)), | |
488 | ||
489 | Make_Parameter_Specification (Loc, | |
490 | Defining_Identifier => B, | |
491 | Parameter_Type => New_Reference_To (Typ, Loc))); | |
492 | ||
493 | Func_Name := Make_Defining_Identifier (Loc, New_Internal_Name ('E')); | |
494 | ||
495 | Stats := Loop_One_Dimension (1, First_Index (Typ)); | |
496 | ||
497 | Func_Body := | |
498 | Make_Subprogram_Body (Loc, | |
499 | Specification => | |
500 | Make_Function_Specification (Loc, | |
501 | Defining_Unit_Name => Func_Name, | |
502 | Parameter_Specifications => Formals, | |
503 | Subtype_Mark => New_Reference_To (Standard_Boolean, Loc)), | |
504 | Declarations => Decls, | |
505 | Handled_Statement_Sequence => | |
506 | Make_Handled_Sequence_Of_Statements (Loc, | |
507 | Statements => New_List ( | |
508 | Stats, | |
509 | Make_Return_Statement (Loc, | |
510 | Expression => New_Occurrence_Of (Standard_True, Loc))))); | |
511 | ||
512 | Set_Has_Completion (Func_Name, True); | |
513 | ||
514 | -- If the array type is distinct from the type of the arguments, | |
515 | -- it is the full view of a private type. Apply an unchecked | |
516 | -- conversion to insure that analysis of the call succeeds. | |
517 | ||
518 | if Base_Type (A_Typ) /= Base_Type (Typ) then | |
519 | Actuals := New_List ( | |
520 | OK_Convert_To (Typ, Lhs), | |
521 | OK_Convert_To (Typ, Rhs)); | |
522 | else | |
523 | Actuals := New_List (Lhs, Rhs); | |
524 | end if; | |
525 | ||
526 | Append_To (Bodies, Func_Body); | |
527 | ||
528 | return | |
529 | Make_Function_Call (Loc, | |
530 | Name => New_Reference_To (Func_Name, Loc), | |
531 | Parameter_Associations => Actuals); | |
532 | end Expand_Array_Equality; | |
533 | ||
534 | ----------------------------- | |
535 | -- Expand_Boolean_Operator -- | |
536 | ----------------------------- | |
537 | ||
538 | -- Note that we first get the actual subtypes of the operands, | |
539 | -- since we always want to deal with types that have bounds. | |
540 | ||
541 | procedure Expand_Boolean_Operator (N : Node_Id) is | |
542 | Typ : constant Entity_Id := Etype (N); | |
543 | ||
544 | begin | |
545 | if Is_Bit_Packed_Array (Typ) then | |
546 | Expand_Packed_Boolean_Operator (N); | |
547 | ||
548 | else | |
549 | ||
550 | -- For the normal non-packed case, the expansion is | |
551 | -- to build a function for carrying out the comparison | |
552 | -- (using Make_Boolean_Array_Op) and then inserting it | |
553 | -- into the tree. The original operator node is then | |
554 | -- rewritten as a call to this function. | |
555 | ||
556 | declare | |
557 | Loc : constant Source_Ptr := Sloc (N); | |
558 | L : constant Node_Id := Relocate_Node (Left_Opnd (N)); | |
559 | R : constant Node_Id := Relocate_Node (Right_Opnd (N)); | |
560 | Func_Body : Node_Id; | |
561 | Func_Name : Entity_Id; | |
562 | begin | |
563 | Convert_To_Actual_Subtype (L); | |
564 | Convert_To_Actual_Subtype (R); | |
565 | Ensure_Defined (Etype (L), N); | |
566 | Ensure_Defined (Etype (R), N); | |
567 | Apply_Length_Check (R, Etype (L)); | |
568 | ||
569 | Func_Body := Make_Boolean_Array_Op (Etype (L), N); | |
570 | Func_Name := Defining_Unit_Name (Specification (Func_Body)); | |
571 | Insert_Action (N, Func_Body); | |
572 | ||
573 | -- Now rewrite the expression with a call | |
574 | ||
575 | Rewrite (N, | |
576 | Make_Function_Call (Loc, | |
577 | Name => New_Reference_To (Func_Name, Loc), | |
578 | Parameter_Associations => | |
579 | New_List | |
580 | (L, Make_Type_Conversion | |
581 | (Loc, New_Reference_To (Etype (L), Loc), R)))); | |
582 | ||
583 | Analyze_And_Resolve (N, Typ); | |
584 | end; | |
585 | end if; | |
586 | end Expand_Boolean_Operator; | |
587 | ||
588 | ------------------------------- | |
589 | -- Expand_Composite_Equality -- | |
590 | ------------------------------- | |
591 | ||
592 | -- This function is only called for comparing internal fields of composite | |
593 | -- types when these fields are themselves composites. This is a special | |
594 | -- case because it is not possible to respect normal Ada visibility rules. | |
595 | ||
596 | function Expand_Composite_Equality | |
597 | (Nod : Node_Id; | |
598 | Typ : Entity_Id; | |
599 | Lhs : Node_Id; | |
600 | Rhs : Node_Id; | |
601 | Bodies : List_Id) | |
602 | return Node_Id | |
603 | is | |
604 | Loc : constant Source_Ptr := Sloc (Nod); | |
605 | Full_Type : Entity_Id; | |
606 | Prim : Elmt_Id; | |
607 | Eq_Op : Entity_Id; | |
608 | ||
609 | begin | |
610 | if Is_Private_Type (Typ) then | |
611 | Full_Type := Underlying_Type (Typ); | |
612 | else | |
613 | Full_Type := Typ; | |
614 | end if; | |
615 | ||
616 | -- Defense against malformed private types with no completion | |
617 | -- the error will be diagnosed later by check_completion | |
618 | ||
619 | if No (Full_Type) then | |
620 | return New_Reference_To (Standard_False, Loc); | |
621 | end if; | |
622 | ||
623 | Full_Type := Base_Type (Full_Type); | |
624 | ||
625 | if Is_Array_Type (Full_Type) then | |
626 | ||
627 | -- If the operand is an elementary type other than a floating-point | |
628 | -- type, then we can simply use the built-in block bitwise equality, | |
629 | -- since the predefined equality operators always apply and bitwise | |
630 | -- equality is fine for all these cases. | |
631 | ||
632 | if Is_Elementary_Type (Component_Type (Full_Type)) | |
633 | and then not Is_Floating_Point_Type (Component_Type (Full_Type)) | |
634 | then | |
635 | return Make_Op_Eq (Loc, Left_Opnd => Lhs, Right_Opnd => Rhs); | |
636 | ||
637 | -- For composite component types, and floating-point types, use | |
638 | -- the expansion. This deals with tagged component types (where | |
639 | -- we use the applicable equality routine) and floating-point, | |
640 | -- (where we need to worry about negative zeroes), and also the | |
641 | -- case of any composite type recursively containing such fields. | |
642 | ||
643 | else | |
644 | return Expand_Array_Equality | |
645 | (Nod, Full_Type, Typ, Lhs, Rhs, Bodies); | |
646 | end if; | |
647 | ||
648 | elsif Is_Tagged_Type (Full_Type) then | |
649 | ||
650 | -- Call the primitive operation "=" of this type | |
651 | ||
652 | if Is_Class_Wide_Type (Full_Type) then | |
653 | Full_Type := Root_Type (Full_Type); | |
654 | end if; | |
655 | ||
656 | -- If this is derived from an untagged private type completed | |
657 | -- with a tagged type, it does not have a full view, so we | |
658 | -- use the primitive operations of the private type. | |
659 | -- This check should no longer be necessary when these | |
660 | -- types receive their full views ??? | |
661 | ||
662 | if Is_Private_Type (Typ) | |
663 | and then not Is_Tagged_Type (Typ) | |
664 | and then not Is_Controlled (Typ) | |
665 | and then Is_Derived_Type (Typ) | |
666 | and then No (Full_View (Typ)) | |
667 | then | |
668 | Prim := First_Elmt (Collect_Primitive_Operations (Typ)); | |
669 | else | |
670 | Prim := First_Elmt (Primitive_Operations (Full_Type)); | |
671 | end if; | |
672 | ||
673 | loop | |
674 | Eq_Op := Node (Prim); | |
675 | exit when Chars (Eq_Op) = Name_Op_Eq | |
676 | and then Etype (First_Formal (Eq_Op)) = | |
677 | Etype (Next_Formal (First_Formal (Eq_Op))); | |
678 | Next_Elmt (Prim); | |
679 | pragma Assert (Present (Prim)); | |
680 | end loop; | |
681 | ||
682 | Eq_Op := Node (Prim); | |
683 | ||
684 | return | |
685 | Make_Function_Call (Loc, | |
686 | Name => New_Reference_To (Eq_Op, Loc), | |
687 | Parameter_Associations => | |
688 | New_List | |
689 | (Unchecked_Convert_To (Etype (First_Formal (Eq_Op)), Lhs), | |
690 | Unchecked_Convert_To (Etype (First_Formal (Eq_Op)), Rhs))); | |
691 | ||
692 | elsif Is_Record_Type (Full_Type) then | |
693 | Eq_Op := TSS (Full_Type, Name_uEquality); | |
694 | ||
695 | if Present (Eq_Op) then | |
696 | if Etype (First_Formal (Eq_Op)) /= Full_Type then | |
697 | ||
698 | -- Inherited equality from parent type. Convert the actuals | |
699 | -- to match signature of operation. | |
700 | ||
701 | declare | |
702 | T : Entity_Id := Etype (First_Formal (Eq_Op)); | |
703 | ||
704 | begin | |
705 | return | |
706 | Make_Function_Call (Loc, | |
707 | Name => New_Reference_To (Eq_Op, Loc), | |
708 | Parameter_Associations => | |
709 | New_List (OK_Convert_To (T, Lhs), | |
710 | OK_Convert_To (T, Rhs))); | |
711 | end; | |
712 | ||
713 | else | |
714 | return | |
715 | Make_Function_Call (Loc, | |
716 | Name => New_Reference_To (Eq_Op, Loc), | |
717 | Parameter_Associations => New_List (Lhs, Rhs)); | |
718 | end if; | |
719 | ||
720 | else | |
721 | return Expand_Record_Equality (Nod, Full_Type, Lhs, Rhs, Bodies); | |
722 | end if; | |
723 | ||
724 | else | |
725 | -- It can be a simple record or the full view of a scalar private | |
726 | ||
727 | return Make_Op_Eq (Loc, Left_Opnd => Lhs, Right_Opnd => Rhs); | |
728 | end if; | |
729 | end Expand_Composite_Equality; | |
730 | ||
731 | ------------------------------ | |
732 | -- Expand_Concatenate_Other -- | |
733 | ------------------------------ | |
734 | ||
735 | -- Let n be the number of array operands to be concatenated, Base_Typ | |
736 | -- their base type, Ind_Typ their index type, and Arr_Typ the original | |
737 | -- array type to which the concatenantion operator applies, then the | |
738 | -- following subprogram is constructed: | |
739 | -- | |
740 | -- [function Cnn (S1 : Base_Typ; ...; Sn : Base_Typ) return Base_Typ is | |
741 | -- L : Ind_Typ; | |
742 | -- begin | |
743 | -- if S1'Length /= 0 then | |
744 | -- L := XXX; --> XXX = S1'First if Arr_Typ is unconstrained | |
745 | -- XXX = Arr_Typ'First otherwise | |
746 | -- elsif S2'Length /= 0 then | |
747 | -- L := YYY; --> YYY = S2'First if Arr_Typ is unconstrained | |
748 | -- YYY = Arr_Typ'First otherwise | |
749 | -- ... | |
750 | -- elsif Sn-1'Length /= 0 then | |
751 | -- L := ZZZ; --> ZZZ = Sn-1'First if Arr_Typ is unconstrained | |
752 | -- ZZZ = Arr_Typ'First otherwise | |
753 | -- else | |
754 | -- return Sn; | |
755 | -- end if; | |
756 | -- | |
757 | -- declare | |
758 | -- P : Ind_Typ; | |
759 | -- H : Ind_Typ := | |
760 | -- Ind_Typ'Val ((((S1'Length - 1) + S2'Length) + ... + Sn'Length) | |
761 | -- + Ind_Typ'Pos (L)); | |
762 | -- R : Base_Typ (L .. H); | |
763 | -- begin | |
764 | -- if S1'Length /= 0 then | |
765 | -- P := S1'First; | |
766 | -- loop | |
767 | -- R (L) := S1 (P); | |
768 | -- L := Ind_Typ'Succ (L); | |
769 | -- exit when P = S1'Last; | |
770 | -- P := Ind_Typ'Succ (P); | |
771 | -- end loop; | |
772 | -- end if; | |
773 | -- | |
774 | -- if S2'Length /= 0 then | |
775 | -- L := Ind_Typ'Succ (L); | |
776 | -- loop | |
777 | -- R (L) := S2 (P); | |
778 | -- L := Ind_Typ'Succ (L); | |
779 | -- exit when P = S2'Last; | |
780 | -- P := Ind_Typ'Succ (P); | |
781 | -- end loop; | |
782 | -- end if; | |
783 | -- | |
784 | -- ... | |
785 | -- | |
786 | -- if Sn'Length /= 0 then | |
787 | -- P := Sn'First; | |
788 | -- loop | |
789 | -- R (L) := Sn (P); | |
790 | -- L := Ind_Typ'Succ (L); | |
791 | -- exit when P = Sn'Last; | |
792 | -- P := Ind_Typ'Succ (P); | |
793 | -- end loop; | |
794 | -- end if; | |
795 | -- | |
796 | -- return R; | |
797 | -- end; | |
798 | -- end Cnn;] | |
799 | ||
800 | procedure Expand_Concatenate_Other (Cnode : Node_Id; Opnds : List_Id) is | |
801 | Loc : constant Source_Ptr := Sloc (Cnode); | |
802 | Nb_Opnds : constant Nat := List_Length (Opnds); | |
803 | ||
804 | Arr_Typ : constant Entity_Id := Etype (Entity (Cnode)); | |
805 | Base_Typ : constant Entity_Id := Base_Type (Etype (Cnode)); | |
806 | Ind_Typ : constant Entity_Id := Etype (First_Index (Base_Typ)); | |
807 | ||
808 | Func_Id : Node_Id; | |
809 | Func_Spec : Node_Id; | |
810 | Param_Specs : List_Id; | |
811 | ||
812 | Func_Body : Node_Id; | |
813 | Func_Decls : List_Id; | |
814 | Func_Stmts : List_Id; | |
815 | ||
816 | L_Decl : Node_Id; | |
817 | ||
818 | If_Stmt : Node_Id; | |
819 | Elsif_List : List_Id; | |
820 | ||
821 | Declare_Block : Node_Id; | |
822 | Declare_Decls : List_Id; | |
823 | Declare_Stmts : List_Id; | |
824 | ||
825 | H_Decl : Node_Id; | |
826 | H_Init : Node_Id; | |
827 | P_Decl : Node_Id; | |
828 | R_Decl : Node_Id; | |
829 | R_Constr : Node_Id; | |
830 | R_Range : Node_Id; | |
831 | ||
832 | Params : List_Id; | |
833 | Operand : Node_Id; | |
834 | ||
835 | function Copy_Into_R_S (I : Nat) return List_Id; | |
836 | -- Builds the sequence of statement: | |
837 | -- P := Si'First; | |
838 | -- loop | |
839 | -- R (L) := Si (P); | |
840 | -- L := Ind_Typ'Succ (L); | |
841 | -- exit when P = Si'Last; | |
842 | -- P := Ind_Typ'Succ (P); | |
843 | -- end loop; | |
844 | -- | |
845 | -- where i is the input parameter I given. | |
846 | ||
847 | function Init_L (I : Nat) return Node_Id; | |
848 | -- Builds the statement: | |
849 | -- L := Arr_Typ'First; If Arr_Typ is constrained | |
850 | -- L := Si'First; otherwise (where I is the input param given) | |
851 | ||
852 | function H return Node_Id; | |
853 | -- Builds reference to identifier H. | |
854 | ||
855 | function Ind_Val (E : Node_Id) return Node_Id; | |
856 | -- Builds expression Ind_Typ'Val (E); | |
857 | ||
858 | function L return Node_Id; | |
859 | -- Builds reference to identifier L. | |
860 | ||
861 | function L_Pos return Node_Id; | |
862 | -- Builds expression Ind_Typ'Pos (L). | |
863 | ||
864 | function L_Succ return Node_Id; | |
865 | -- Builds expression Ind_Typ'Succ (L). | |
866 | ||
867 | function One return Node_Id; | |
868 | -- Builds integer literal one. | |
869 | ||
870 | function P return Node_Id; | |
871 | -- Builds reference to identifier P. | |
872 | ||
873 | function P_Succ return Node_Id; | |
874 | -- Builds expression Ind_Typ'Succ (P). | |
875 | ||
876 | function R return Node_Id; | |
877 | -- Builds reference to identifier R. | |
878 | ||
879 | function S (I : Nat) return Node_Id; | |
880 | -- Builds reference to identifier Si, where I is the value given. | |
881 | ||
882 | function S_First (I : Nat) return Node_Id; | |
883 | -- Builds expression Si'First, where I is the value given. | |
884 | ||
885 | function S_Last (I : Nat) return Node_Id; | |
886 | -- Builds expression Si'Last, where I is the value given. | |
887 | ||
888 | function S_Length (I : Nat) return Node_Id; | |
889 | -- Builds expression Si'Length, where I is the value given. | |
890 | ||
891 | function S_Length_Test (I : Nat) return Node_Id; | |
892 | -- Builds expression Si'Length /= 0, where I is the value given. | |
893 | ||
894 | ------------------- | |
895 | -- Copy_Into_R_S -- | |
896 | ------------------- | |
897 | ||
898 | function Copy_Into_R_S (I : Nat) return List_Id is | |
899 | Stmts : List_Id := New_List; | |
900 | P_Start : Node_Id; | |
901 | Loop_Stmt : Node_Id; | |
902 | R_Copy : Node_Id; | |
903 | Exit_Stmt : Node_Id; | |
904 | L_Inc : Node_Id; | |
905 | P_Inc : Node_Id; | |
906 | ||
907 | begin | |
908 | -- First construct the initializations | |
909 | ||
910 | P_Start := Make_Assignment_Statement (Loc, | |
911 | Name => P, | |
912 | Expression => S_First (I)); | |
913 | Append_To (Stmts, P_Start); | |
914 | ||
915 | -- Then build the loop | |
916 | ||
917 | R_Copy := Make_Assignment_Statement (Loc, | |
918 | Name => Make_Indexed_Component (Loc, | |
919 | Prefix => R, | |
920 | Expressions => New_List (L)), | |
921 | Expression => Make_Indexed_Component (Loc, | |
922 | Prefix => S (I), | |
923 | Expressions => New_List (P))); | |
924 | ||
925 | L_Inc := Make_Assignment_Statement (Loc, | |
926 | Name => L, | |
927 | Expression => L_Succ); | |
928 | ||
929 | Exit_Stmt := Make_Exit_Statement (Loc, | |
930 | Condition => Make_Op_Eq (Loc, P, S_Last (I))); | |
931 | ||
932 | P_Inc := Make_Assignment_Statement (Loc, | |
933 | Name => P, | |
934 | Expression => P_Succ); | |
935 | ||
936 | Loop_Stmt := | |
937 | Make_Implicit_Loop_Statement (Cnode, | |
938 | Statements => New_List (R_Copy, L_Inc, Exit_Stmt, P_Inc)); | |
939 | ||
940 | Append_To (Stmts, Loop_Stmt); | |
941 | ||
942 | return Stmts; | |
943 | end Copy_Into_R_S; | |
944 | ||
945 | ------- | |
946 | -- H -- | |
947 | ------- | |
948 | ||
949 | function H return Node_Id is | |
950 | begin | |
951 | return Make_Identifier (Loc, Name_uH); | |
952 | end H; | |
953 | ||
954 | ------------- | |
955 | -- Ind_Val -- | |
956 | ------------- | |
957 | ||
958 | function Ind_Val (E : Node_Id) return Node_Id is | |
959 | begin | |
960 | return | |
961 | Make_Attribute_Reference (Loc, | |
962 | Prefix => New_Reference_To (Ind_Typ, Loc), | |
963 | Attribute_Name => Name_Val, | |
964 | Expressions => New_List (E)); | |
965 | end Ind_Val; | |
966 | ||
967 | ------------ | |
968 | -- Init_L -- | |
969 | ------------ | |
970 | ||
971 | function Init_L (I : Nat) return Node_Id is | |
972 | E : Node_Id; | |
973 | ||
974 | begin | |
975 | if Is_Constrained (Arr_Typ) then | |
976 | E := Make_Attribute_Reference (Loc, | |
977 | Prefix => New_Reference_To (Arr_Typ, Loc), | |
978 | Attribute_Name => Name_First); | |
979 | ||
980 | else | |
981 | E := S_First (I); | |
982 | end if; | |
983 | ||
984 | return Make_Assignment_Statement (Loc, Name => L, Expression => E); | |
985 | end Init_L; | |
986 | ||
987 | ------- | |
988 | -- L -- | |
989 | ------- | |
990 | ||
991 | function L return Node_Id is | |
992 | begin | |
993 | return Make_Identifier (Loc, Name_uL); | |
994 | end L; | |
995 | ||
996 | ----------- | |
997 | -- L_Pos -- | |
998 | ----------- | |
999 | ||
1000 | function L_Pos return Node_Id is | |
1001 | begin | |
1002 | return | |
1003 | Make_Attribute_Reference (Loc, | |
1004 | Prefix => New_Reference_To (Ind_Typ, Loc), | |
1005 | Attribute_Name => Name_Pos, | |
1006 | Expressions => New_List (L)); | |
1007 | end L_Pos; | |
1008 | ||
1009 | ------------ | |
1010 | -- L_Succ -- | |
1011 | ------------ | |
1012 | ||
1013 | function L_Succ return Node_Id is | |
1014 | begin | |
1015 | return | |
1016 | Make_Attribute_Reference (Loc, | |
1017 | Prefix => New_Reference_To (Ind_Typ, Loc), | |
1018 | Attribute_Name => Name_Succ, | |
1019 | Expressions => New_List (L)); | |
1020 | end L_Succ; | |
1021 | ||
1022 | --------- | |
1023 | -- One -- | |
1024 | --------- | |
1025 | ||
1026 | function One return Node_Id is | |
1027 | begin | |
1028 | return Make_Integer_Literal (Loc, 1); | |
1029 | end One; | |
1030 | ||
1031 | ------- | |
1032 | -- P -- | |
1033 | ------- | |
1034 | ||
1035 | function P return Node_Id is | |
1036 | begin | |
1037 | return Make_Identifier (Loc, Name_uP); | |
1038 | end P; | |
1039 | ||
1040 | ------------ | |
1041 | -- P_Succ -- | |
1042 | ------------ | |
1043 | ||
1044 | function P_Succ return Node_Id is | |
1045 | begin | |
1046 | return | |
1047 | Make_Attribute_Reference (Loc, | |
1048 | Prefix => New_Reference_To (Ind_Typ, Loc), | |
1049 | Attribute_Name => Name_Succ, | |
1050 | Expressions => New_List (P)); | |
1051 | end P_Succ; | |
1052 | ||
1053 | ------- | |
1054 | -- R -- | |
1055 | ------- | |
1056 | ||
1057 | function R return Node_Id is | |
1058 | begin | |
1059 | return Make_Identifier (Loc, Name_uR); | |
1060 | end R; | |
1061 | ||
1062 | ------- | |
1063 | -- S -- | |
1064 | ------- | |
1065 | ||
1066 | function S (I : Nat) return Node_Id is | |
1067 | begin | |
1068 | return Make_Identifier (Loc, New_External_Name ('S', I)); | |
1069 | end S; | |
1070 | ||
1071 | ------------- | |
1072 | -- S_First -- | |
1073 | ------------- | |
1074 | ||
1075 | function S_First (I : Nat) return Node_Id is | |
1076 | begin | |
1077 | return Make_Attribute_Reference (Loc, | |
1078 | Prefix => S (I), | |
1079 | Attribute_Name => Name_First); | |
1080 | end S_First; | |
1081 | ||
1082 | ------------ | |
1083 | -- S_Last -- | |
1084 | ------------ | |
1085 | ||
1086 | function S_Last (I : Nat) return Node_Id is | |
1087 | begin | |
1088 | return Make_Attribute_Reference (Loc, | |
1089 | Prefix => S (I), | |
1090 | Attribute_Name => Name_Last); | |
1091 | end S_Last; | |
1092 | ||
1093 | -------------- | |
1094 | -- S_Length -- | |
1095 | -------------- | |
1096 | ||
1097 | function S_Length (I : Nat) return Node_Id is | |
1098 | begin | |
1099 | return Make_Attribute_Reference (Loc, | |
1100 | Prefix => S (I), | |
1101 | Attribute_Name => Name_Length); | |
1102 | end S_Length; | |
1103 | ||
1104 | ------------------- | |
1105 | -- S_Length_Test -- | |
1106 | ------------------- | |
1107 | ||
1108 | function S_Length_Test (I : Nat) return Node_Id is | |
1109 | begin | |
1110 | return | |
1111 | Make_Op_Ne (Loc, | |
1112 | Left_Opnd => S_Length (I), | |
1113 | Right_Opnd => Make_Integer_Literal (Loc, 0)); | |
1114 | end S_Length_Test; | |
1115 | ||
1116 | -- Start of processing for Expand_Concatenate_Other | |
1117 | ||
1118 | begin | |
1119 | -- Construct the parameter specs and the overall function spec | |
1120 | ||
1121 | Param_Specs := New_List; | |
1122 | for I in 1 .. Nb_Opnds loop | |
1123 | Append_To | |
1124 | (Param_Specs, | |
1125 | Make_Parameter_Specification (Loc, | |
1126 | Defining_Identifier => | |
1127 | Make_Defining_Identifier (Loc, New_External_Name ('S', I)), | |
1128 | Parameter_Type => New_Reference_To (Base_Typ, Loc))); | |
1129 | end loop; | |
1130 | ||
1131 | Func_Id := Make_Defining_Identifier (Loc, New_Internal_Name ('C')); | |
1132 | Func_Spec := | |
1133 | Make_Function_Specification (Loc, | |
1134 | Defining_Unit_Name => Func_Id, | |
1135 | Parameter_Specifications => Param_Specs, | |
1136 | Subtype_Mark => New_Reference_To (Base_Typ, Loc)); | |
1137 | ||
1138 | -- Construct L's object declaration | |
1139 | ||
1140 | L_Decl := | |
1141 | Make_Object_Declaration (Loc, | |
1142 | Defining_Identifier => Make_Defining_Identifier (Loc, Name_uL), | |
1143 | Object_Definition => New_Reference_To (Ind_Typ, Loc)); | |
1144 | ||
1145 | Func_Decls := New_List (L_Decl); | |
1146 | ||
1147 | -- Construct the if-then-elsif statements | |
1148 | ||
1149 | Elsif_List := New_List; | |
1150 | for I in 2 .. Nb_Opnds - 1 loop | |
1151 | Append_To (Elsif_List, Make_Elsif_Part (Loc, | |
1152 | Condition => S_Length_Test (I), | |
1153 | Then_Statements => New_List (Init_L (I)))); | |
1154 | end loop; | |
1155 | ||
1156 | If_Stmt := | |
1157 | Make_Implicit_If_Statement (Cnode, | |
1158 | Condition => S_Length_Test (1), | |
1159 | Then_Statements => New_List (Init_L (1)), | |
1160 | Elsif_Parts => Elsif_List, | |
1161 | Else_Statements => New_List (Make_Return_Statement (Loc, | |
1162 | Expression => S (Nb_Opnds)))); | |
1163 | ||
1164 | -- Construct the declaration for H | |
1165 | ||
1166 | P_Decl := | |
1167 | Make_Object_Declaration (Loc, | |
1168 | Defining_Identifier => Make_Defining_Identifier (Loc, Name_uP), | |
1169 | Object_Definition => New_Reference_To (Ind_Typ, Loc)); | |
1170 | ||
1171 | H_Init := Make_Op_Subtract (Loc, S_Length (1), One); | |
1172 | for I in 2 .. Nb_Opnds loop | |
1173 | H_Init := Make_Op_Add (Loc, H_Init, S_Length (I)); | |
1174 | end loop; | |
1175 | H_Init := Ind_Val (Make_Op_Add (Loc, H_Init, L_Pos)); | |
1176 | ||
1177 | H_Decl := | |
1178 | Make_Object_Declaration (Loc, | |
1179 | Defining_Identifier => Make_Defining_Identifier (Loc, Name_uH), | |
1180 | Object_Definition => New_Reference_To (Ind_Typ, Loc), | |
1181 | Expression => H_Init); | |
1182 | ||
1183 | -- Construct the declaration for R | |
1184 | ||
1185 | R_Range := Make_Range (Loc, Low_Bound => L, High_Bound => H); | |
1186 | R_Constr := | |
1187 | Make_Index_Or_Discriminant_Constraint (Loc, | |
1188 | Constraints => New_List (R_Range)); | |
1189 | ||
1190 | R_Decl := | |
1191 | Make_Object_Declaration (Loc, | |
1192 | Defining_Identifier => Make_Defining_Identifier (Loc, Name_uR), | |
1193 | Object_Definition => | |
1194 | Make_Subtype_Indication (Loc, | |
1195 | Subtype_Mark => New_Reference_To (Base_Typ, Loc), | |
1196 | Constraint => R_Constr)); | |
1197 | ||
1198 | -- Construct the declarations for the declare block | |
1199 | ||
1200 | Declare_Decls := New_List (P_Decl, H_Decl, R_Decl); | |
1201 | ||
1202 | -- Construct list of statements for the declare block | |
1203 | ||
1204 | Declare_Stmts := New_List; | |
1205 | for I in 1 .. Nb_Opnds loop | |
1206 | Append_To (Declare_Stmts, | |
1207 | Make_Implicit_If_Statement (Cnode, | |
1208 | Condition => S_Length_Test (I), | |
1209 | Then_Statements => Copy_Into_R_S (I))); | |
1210 | end loop; | |
1211 | ||
1212 | Append_To (Declare_Stmts, Make_Return_Statement (Loc, Expression => R)); | |
1213 | ||
1214 | -- Construct the declare block | |
1215 | ||
1216 | Declare_Block := Make_Block_Statement (Loc, | |
1217 | Declarations => Declare_Decls, | |
1218 | Handled_Statement_Sequence => | |
1219 | Make_Handled_Sequence_Of_Statements (Loc, Declare_Stmts)); | |
1220 | ||
1221 | -- Construct the list of function statements | |
1222 | ||
1223 | Func_Stmts := New_List (If_Stmt, Declare_Block); | |
1224 | ||
1225 | -- Construct the function body | |
1226 | ||
1227 | Func_Body := | |
1228 | Make_Subprogram_Body (Loc, | |
1229 | Specification => Func_Spec, | |
1230 | Declarations => Func_Decls, | |
1231 | Handled_Statement_Sequence => | |
1232 | Make_Handled_Sequence_Of_Statements (Loc, Func_Stmts)); | |
1233 | ||
1234 | -- Insert the newly generated function in the code. This is analyzed | |
1235 | -- with all checks off, since we have completed all the checks. | |
1236 | ||
1237 | -- Note that this does *not* fix the array concatenation bug when the | |
1238 | -- low bound is Integer'first sibce that bug comes from the pointer | |
44d6a706 | 1239 | -- dereferencing an unconstrained array. An there we need a constraint |
70482933 RK |
1240 | -- check to make sure the length of the concatenated array is ok. ??? |
1241 | ||
1242 | Insert_Action (Cnode, Func_Body, Suppress => All_Checks); | |
1243 | ||
1244 | -- Construct list of arguments for the function call | |
1245 | ||
1246 | Params := New_List; | |
1247 | Operand := First (Opnds); | |
1248 | for I in 1 .. Nb_Opnds loop | |
1249 | Append_To (Params, Relocate_Node (Operand)); | |
1250 | Next (Operand); | |
1251 | end loop; | |
1252 | ||
1253 | -- Insert the function call | |
1254 | ||
1255 | Rewrite | |
1256 | (Cnode, | |
1257 | Make_Function_Call (Loc, New_Reference_To (Func_Id, Loc), Params)); | |
1258 | ||
1259 | Analyze_And_Resolve (Cnode, Base_Typ); | |
1260 | Set_Is_Inlined (Func_Id); | |
1261 | end Expand_Concatenate_Other; | |
1262 | ||
1263 | ------------------------------- | |
1264 | -- Expand_Concatenate_String -- | |
1265 | ------------------------------- | |
1266 | ||
1267 | procedure Expand_Concatenate_String (Cnode : Node_Id; Opnds : List_Id) is | |
1268 | Loc : constant Source_Ptr := Sloc (Cnode); | |
1269 | Opnd1 : constant Node_Id := First (Opnds); | |
1270 | Opnd2 : constant Node_Id := Next (Opnd1); | |
1271 | Typ1 : constant Entity_Id := Base_Type (Etype (Opnd1)); | |
1272 | Typ2 : constant Entity_Id := Base_Type (Etype (Opnd2)); | |
1273 | ||
1274 | R : RE_Id; | |
1275 | -- RE_Id value for function to be called | |
1276 | ||
1277 | begin | |
1278 | -- In all cases, we build a call to a routine giving the list of | |
1279 | -- arguments as the parameter list to the routine. | |
1280 | ||
1281 | case List_Length (Opnds) is | |
1282 | when 2 => | |
1283 | if Typ1 = Standard_Character then | |
1284 | if Typ2 = Standard_Character then | |
1285 | R := RE_Str_Concat_CC; | |
1286 | ||
1287 | else | |
1288 | pragma Assert (Typ2 = Standard_String); | |
1289 | R := RE_Str_Concat_CS; | |
1290 | end if; | |
1291 | ||
1292 | elsif Typ1 = Standard_String then | |
1293 | if Typ2 = Standard_Character then | |
1294 | R := RE_Str_Concat_SC; | |
1295 | ||
1296 | else | |
1297 | pragma Assert (Typ2 = Standard_String); | |
1298 | R := RE_Str_Concat; | |
1299 | end if; | |
1300 | ||
1301 | -- If we have anything other than Standard_Character or | |
07fc65c4 GB |
1302 | -- Standard_String, then we must have had a serious error |
1303 | -- earlier, so we just abandon the attempt at expansion. | |
70482933 RK |
1304 | |
1305 | else | |
07fc65c4 | 1306 | pragma Assert (Serious_Errors_Detected > 0); |
70482933 RK |
1307 | return; |
1308 | end if; | |
1309 | ||
1310 | when 3 => | |
1311 | R := RE_Str_Concat_3; | |
1312 | ||
1313 | when 4 => | |
1314 | R := RE_Str_Concat_4; | |
1315 | ||
1316 | when 5 => | |
1317 | R := RE_Str_Concat_5; | |
1318 | ||
1319 | when others => | |
1320 | R := RE_Null; | |
1321 | raise Program_Error; | |
1322 | end case; | |
1323 | ||
1324 | -- Now generate the appropriate call | |
1325 | ||
1326 | Rewrite (Cnode, | |
1327 | Make_Function_Call (Sloc (Cnode), | |
1328 | Name => New_Occurrence_Of (RTE (R), Loc), | |
1329 | Parameter_Associations => Opnds)); | |
1330 | ||
1331 | Analyze_And_Resolve (Cnode, Standard_String); | |
1332 | end Expand_Concatenate_String; | |
1333 | ||
1334 | ------------------------ | |
1335 | -- Expand_N_Allocator -- | |
1336 | ------------------------ | |
1337 | ||
1338 | procedure Expand_N_Allocator (N : Node_Id) is | |
1339 | PtrT : constant Entity_Id := Etype (N); | |
1340 | Desig : Entity_Id; | |
1341 | Loc : constant Source_Ptr := Sloc (N); | |
1342 | Temp : Entity_Id; | |
1343 | Node : Node_Id; | |
1344 | ||
1345 | begin | |
1346 | -- RM E.2.3(22). We enforce that the expected type of an allocator | |
1347 | -- shall not be a remote access-to-class-wide-limited-private type | |
1348 | ||
1349 | -- Why is this being done at expansion time, seems clearly wrong ??? | |
1350 | ||
1351 | Validate_Remote_Access_To_Class_Wide_Type (N); | |
1352 | ||
1353 | -- Set the Storage Pool | |
1354 | ||
1355 | Set_Storage_Pool (N, Associated_Storage_Pool (Root_Type (PtrT))); | |
1356 | ||
1357 | if Present (Storage_Pool (N)) then | |
1358 | if Is_RTE (Storage_Pool (N), RE_SS_Pool) then | |
1359 | if not Java_VM then | |
1360 | Set_Procedure_To_Call (N, RTE (RE_SS_Allocate)); | |
1361 | end if; | |
1362 | else | |
1363 | Set_Procedure_To_Call (N, | |
1364 | Find_Prim_Op (Etype (Storage_Pool (N)), Name_Allocate)); | |
1365 | end if; | |
1366 | end if; | |
1367 | ||
1368 | -- Under certain circumstances we can replace an allocator by an | |
1369 | -- access to statically allocated storage. The conditions, as noted | |
1370 | -- in AARM 3.10 (10c) are as follows: | |
1371 | ||
1372 | -- Size and initial value is known at compile time | |
1373 | -- Access type is access-to-constant | |
1374 | ||
1375 | if Is_Access_Constant (PtrT) | |
1376 | and then Nkind (Expression (N)) = N_Qualified_Expression | |
1377 | and then Compile_Time_Known_Value (Expression (Expression (N))) | |
1378 | and then Size_Known_At_Compile_Time (Etype (Expression | |
1379 | (Expression (N)))) | |
1380 | then | |
1381 | -- Here we can do the optimization. For the allocator | |
1382 | ||
1383 | -- new x'(y) | |
1384 | ||
1385 | -- We insert an object declaration | |
1386 | ||
1387 | -- Tnn : aliased x := y; | |
1388 | ||
1389 | -- and replace the allocator by Tnn'Unrestricted_Access. | |
1390 | -- Tnn is marked as requiring static allocation. | |
1391 | ||
1392 | Temp := | |
1393 | Make_Defining_Identifier (Loc, New_Internal_Name ('T')); | |
1394 | ||
1395 | Desig := Subtype_Mark (Expression (N)); | |
1396 | ||
1397 | -- If context is constrained, use constrained subtype directly, | |
1398 | -- so that the constant is not labelled as having a nomimally | |
1399 | -- unconstrained subtype. | |
1400 | ||
1401 | if Entity (Desig) = Base_Type (Designated_Type (PtrT)) then | |
1402 | Desig := New_Occurrence_Of (Designated_Type (PtrT), Loc); | |
1403 | end if; | |
1404 | ||
1405 | Insert_Action (N, | |
1406 | Make_Object_Declaration (Loc, | |
1407 | Defining_Identifier => Temp, | |
1408 | Aliased_Present => True, | |
1409 | Constant_Present => Is_Access_Constant (PtrT), | |
1410 | Object_Definition => Desig, | |
1411 | Expression => Expression (Expression (N)))); | |
1412 | ||
1413 | Rewrite (N, | |
1414 | Make_Attribute_Reference (Loc, | |
1415 | Prefix => New_Occurrence_Of (Temp, Loc), | |
1416 | Attribute_Name => Name_Unrestricted_Access)); | |
1417 | ||
1418 | Analyze_And_Resolve (N, PtrT); | |
1419 | ||
1420 | -- We set the variable as statically allocated, since we don't | |
1421 | -- want it going on the stack of the current procedure! | |
1422 | ||
1423 | Set_Is_Statically_Allocated (Temp); | |
1424 | return; | |
1425 | end if; | |
1426 | ||
1427 | -- If the allocator is for a type which requires initialization, and | |
1428 | -- there is no initial value (i.e. the operand is a subtype indication | |
1429 | -- rather than a qualifed expression), then we must generate a call to | |
1430 | -- the initialization routine. This is done using an expression actions | |
1431 | -- node: | |
1432 | -- | |
1433 | -- [Pnnn : constant ptr_T := new (T); Init (Pnnn.all,...); Pnnn] | |
1434 | -- | |
1435 | -- Here ptr_T is the pointer type for the allocator, and T is the | |
1436 | -- subtype of the allocator. A special case arises if the designated | |
1437 | -- type of the access type is a task or contains tasks. In this case | |
1438 | -- the call to Init (Temp.all ...) is replaced by code that ensures | |
1439 | -- that the tasks get activated (see Exp_Ch9.Build_Task_Allocate_Block | |
1440 | -- for details). In addition, if the type T is a task T, then the first | |
1441 | -- argument to Init must be converted to the task record type. | |
1442 | ||
1443 | if Nkind (Expression (N)) = N_Qualified_Expression then | |
1444 | declare | |
1445 | Indic : constant Node_Id := Subtype_Mark (Expression (N)); | |
1446 | T : constant Entity_Id := Entity (Indic); | |
1447 | Exp : constant Node_Id := Expression (Expression (N)); | |
1448 | ||
1449 | Aggr_In_Place : constant Boolean := Is_Delayed_Aggregate (Exp); | |
1450 | ||
1451 | Tag_Assign : Node_Id; | |
1452 | Tmp_Node : Node_Id; | |
1453 | ||
1454 | begin | |
1455 | if Is_Tagged_Type (T) or else Controlled_Type (T) then | |
1456 | ||
1457 | -- Actions inserted before: | |
1458 | -- Temp : constant ptr_T := new T'(Expression); | |
1459 | -- <no CW> Temp._tag := T'tag; | |
1460 | -- <CTRL> Adjust (Finalizable (Temp.all)); | |
1461 | -- <CTRL> Attach_To_Final_List (Finalizable (Temp.all)); | |
1462 | ||
1463 | -- We analyze by hand the new internal allocator to avoid | |
1464 | -- any recursion and inappropriate call to Initialize | |
1465 | if not Aggr_In_Place then | |
1466 | Remove_Side_Effects (Exp); | |
1467 | end if; | |
1468 | ||
1469 | Temp := | |
1470 | Make_Defining_Identifier (Loc, New_Internal_Name ('P')); | |
1471 | ||
1472 | -- For a class wide allocation generate the following code: | |
1473 | ||
1474 | -- type Equiv_Record is record ... end record; | |
1475 | -- implicit subtype CW is <Class_Wide_Subytpe>; | |
1476 | -- temp : PtrT := new CW'(CW!(expr)); | |
1477 | ||
1478 | if Is_Class_Wide_Type (T) then | |
1479 | Expand_Subtype_From_Expr (Empty, T, Indic, Exp); | |
1480 | ||
1481 | Set_Expression (Expression (N), | |
1482 | Unchecked_Convert_To (Entity (Indic), Exp)); | |
1483 | ||
1484 | Analyze_And_Resolve (Expression (N), Entity (Indic)); | |
1485 | end if; | |
1486 | ||
1487 | if Aggr_In_Place then | |
1488 | Tmp_Node := | |
1489 | Make_Object_Declaration (Loc, | |
1490 | Defining_Identifier => Temp, | |
1491 | Object_Definition => New_Reference_To (PtrT, Loc), | |
1492 | Expression => Make_Allocator (Loc, | |
1493 | New_Reference_To (Etype (Exp), Loc))); | |
1494 | ||
1495 | Set_No_Initialization (Expression (Tmp_Node)); | |
1496 | Insert_Action (N, Tmp_Node); | |
1497 | Convert_Aggr_In_Allocator (Tmp_Node, Exp); | |
1498 | else | |
1499 | Node := Relocate_Node (N); | |
1500 | Set_Analyzed (Node); | |
1501 | Insert_Action (N, | |
1502 | Make_Object_Declaration (Loc, | |
1503 | Defining_Identifier => Temp, | |
1504 | Constant_Present => True, | |
1505 | Object_Definition => New_Reference_To (PtrT, Loc), | |
1506 | Expression => Node)); | |
1507 | end if; | |
1508 | ||
1509 | -- Suppress the tag assignment when Java_VM because JVM tags | |
1510 | -- are represented implicitly in objects. | |
1511 | ||
1512 | if Is_Tagged_Type (T) | |
1513 | and then not Is_Class_Wide_Type (T) | |
1514 | and then not Java_VM | |
1515 | then | |
1516 | Tag_Assign := | |
1517 | Make_Assignment_Statement (Loc, | |
1518 | Name => | |
1519 | Make_Selected_Component (Loc, | |
1520 | Prefix => New_Reference_To (Temp, Loc), | |
1521 | Selector_Name => | |
1522 | New_Reference_To (Tag_Component (T), Loc)), | |
1523 | ||
1524 | Expression => | |
1525 | Unchecked_Convert_To (RTE (RE_Tag), | |
1526 | New_Reference_To (Access_Disp_Table (T), Loc))); | |
1527 | ||
1528 | -- The previous assignment has to be done in any case | |
1529 | ||
1530 | Set_Assignment_OK (Name (Tag_Assign)); | |
1531 | Insert_Action (N, Tag_Assign); | |
1532 | ||
1533 | elsif Is_Private_Type (T) | |
1534 | and then Is_Tagged_Type (Underlying_Type (T)) | |
1535 | and then not Java_VM | |
1536 | then | |
1537 | declare | |
1538 | Utyp : constant Entity_Id := Underlying_Type (T); | |
1539 | Ref : constant Node_Id := | |
1540 | Unchecked_Convert_To (Utyp, | |
1541 | Make_Explicit_Dereference (Loc, | |
1542 | New_Reference_To (Temp, Loc))); | |
1543 | ||
1544 | begin | |
1545 | Tag_Assign := | |
1546 | Make_Assignment_Statement (Loc, | |
1547 | Name => | |
1548 | Make_Selected_Component (Loc, | |
1549 | Prefix => Ref, | |
1550 | Selector_Name => | |
1551 | New_Reference_To (Tag_Component (Utyp), Loc)), | |
1552 | ||
1553 | Expression => | |
1554 | Unchecked_Convert_To (RTE (RE_Tag), | |
1555 | New_Reference_To ( | |
1556 | Access_Disp_Table (Utyp), Loc))); | |
1557 | ||
1558 | Set_Assignment_OK (Name (Tag_Assign)); | |
1559 | Insert_Action (N, Tag_Assign); | |
1560 | end; | |
1561 | end if; | |
1562 | ||
1563 | if Controlled_Type (Designated_Type (PtrT)) | |
1564 | and then Controlled_Type (T) | |
1565 | then | |
1566 | declare | |
1567 | Flist : Node_Id; | |
1568 | Attach : Node_Id; | |
1569 | Apool : constant Entity_Id := | |
1570 | Associated_Storage_Pool (PtrT); | |
1571 | ||
1572 | begin | |
1573 | -- If it is an allocation on the secondary stack | |
1574 | -- (i.e. a value returned from a function), the object | |
1575 | -- is attached on the caller side as soon as the call | |
1576 | -- is completed (see Expand_Ctrl_Function_Call) | |
1577 | ||
1578 | if Is_RTE (Apool, RE_SS_Pool) then | |
1579 | declare | |
1580 | F : constant Entity_Id := | |
1581 | Make_Defining_Identifier (Loc, | |
1582 | New_Internal_Name ('F')); | |
1583 | begin | |
1584 | Insert_Action (N, | |
1585 | Make_Object_Declaration (Loc, | |
1586 | Defining_Identifier => F, | |
1587 | Object_Definition => New_Reference_To (RTE | |
1588 | (RE_Finalizable_Ptr), Loc))); | |
1589 | ||
1590 | Flist := New_Reference_To (F, Loc); | |
1591 | Attach := Make_Integer_Literal (Loc, 1); | |
1592 | end; | |
1593 | ||
1594 | -- Normal case, not a secondary stack allocation | |
1595 | ||
1596 | else | |
1597 | Flist := Find_Final_List (PtrT); | |
1598 | Attach := Make_Integer_Literal (Loc, 2); | |
1599 | end if; | |
1600 | ||
1601 | if not Aggr_In_Place then | |
1602 | Insert_Actions (N, | |
1603 | Make_Adjust_Call ( | |
1604 | Ref => | |
1605 | ||
1606 | -- An unchecked conversion is needed in the | |
1607 | -- classwide case because the designated type | |
1608 | -- can be an ancestor of the subtype mark of | |
1609 | -- the allocator. | |
1610 | ||
1611 | Unchecked_Convert_To (T, | |
1612 | Make_Explicit_Dereference (Loc, | |
1613 | New_Reference_To (Temp, Loc))), | |
1614 | ||
1615 | Typ => T, | |
1616 | Flist_Ref => Flist, | |
1617 | With_Attach => Attach)); | |
1618 | end if; | |
1619 | end; | |
1620 | end if; | |
1621 | ||
1622 | Rewrite (N, New_Reference_To (Temp, Loc)); | |
1623 | Analyze_And_Resolve (N, PtrT); | |
1624 | ||
1625 | elsif Aggr_In_Place then | |
1626 | Temp := | |
1627 | Make_Defining_Identifier (Loc, New_Internal_Name ('P')); | |
1628 | Tmp_Node := | |
1629 | Make_Object_Declaration (Loc, | |
1630 | Defining_Identifier => Temp, | |
1631 | Object_Definition => New_Reference_To (PtrT, Loc), | |
1632 | Expression => Make_Allocator (Loc, | |
1633 | New_Reference_To (Etype (Exp), Loc))); | |
1634 | ||
1635 | Set_No_Initialization (Expression (Tmp_Node)); | |
1636 | Insert_Action (N, Tmp_Node); | |
1637 | Convert_Aggr_In_Allocator (Tmp_Node, Exp); | |
1638 | Rewrite (N, New_Reference_To (Temp, Loc)); | |
1639 | Analyze_And_Resolve (N, PtrT); | |
1640 | ||
1641 | elsif Is_Access_Type (Designated_Type (PtrT)) | |
1642 | and then Nkind (Exp) = N_Allocator | |
1643 | and then Nkind (Expression (Exp)) /= N_Qualified_Expression | |
1644 | then | |
1645 | -- Apply constraint to designated subtype indication. | |
1646 | ||
1647 | Apply_Constraint_Check (Expression (Exp), | |
1648 | Designated_Type (Designated_Type (PtrT)), | |
1649 | No_Sliding => True); | |
1650 | ||
1651 | if Nkind (Expression (Exp)) = N_Raise_Constraint_Error then | |
1652 | ||
07fc65c4 | 1653 | -- Propagate constraint_error to enclosing allocator |
70482933 | 1654 | |
07fc65c4 | 1655 | Rewrite (Exp, New_Copy (Expression (Exp))); |
70482933 RK |
1656 | end if; |
1657 | else | |
1658 | -- First check against the type of the qualified expression | |
1659 | -- | |
1660 | -- NOTE: The commented call should be correct, but for | |
1661 | -- some reason causes the compiler to bomb (sigsegv) on | |
1662 | -- ACVC test c34007g, so for now we just perform the old | |
1663 | -- (incorrect) test against the designated subtype with | |
1664 | -- no sliding in the else part of the if statement below. | |
1665 | -- ??? | |
1666 | -- | |
1667 | -- Apply_Constraint_Check (Exp, T, No_Sliding => True); | |
1668 | ||
1669 | -- A check is also needed in cases where the designated | |
1670 | -- subtype is constrained and differs from the subtype | |
1671 | -- given in the qualified expression. Note that the check | |
1672 | -- on the qualified expression does not allow sliding, | |
1673 | -- but this check does (a relaxation from Ada 83). | |
1674 | ||
1675 | if Is_Constrained (Designated_Type (PtrT)) | |
1676 | and then not Subtypes_Statically_Match | |
1677 | (T, Designated_Type (PtrT)) | |
1678 | then | |
1679 | Apply_Constraint_Check | |
1680 | (Exp, Designated_Type (PtrT), No_Sliding => False); | |
1681 | ||
1682 | -- The nonsliding check should really be performed | |
1683 | -- (unconditionally) against the subtype of the | |
1684 | -- qualified expression, but that causes a problem | |
1685 | -- with c34007g (see above), so for now we retain this. | |
1686 | ||
1687 | else | |
1688 | Apply_Constraint_Check | |
1689 | (Exp, Designated_Type (PtrT), No_Sliding => True); | |
1690 | end if; | |
1691 | end if; | |
1692 | end; | |
1693 | ||
1694 | -- Here if not qualified expression case. | |
1695 | -- In this case, an initialization routine may be required | |
1696 | ||
1697 | else | |
1698 | declare | |
1699 | T : constant Entity_Id := Entity (Expression (N)); | |
1700 | Init : Entity_Id; | |
1701 | Arg1 : Node_Id; | |
1702 | Args : List_Id; | |
1703 | Decls : List_Id; | |
1704 | Decl : Node_Id; | |
1705 | Discr : Elmt_Id; | |
1706 | Flist : Node_Id; | |
1707 | Temp_Decl : Node_Id; | |
1708 | Temp_Type : Entity_Id; | |
1709 | ||
1710 | begin | |
1711 | ||
1712 | if No_Initialization (N) then | |
1713 | null; | |
1714 | ||
1715 | -- Case of no initialization procedure present | |
1716 | ||
1717 | elsif not Has_Non_Null_Base_Init_Proc (T) then | |
1718 | ||
1719 | -- Case of simple initialization required | |
1720 | ||
1721 | if Needs_Simple_Initialization (T) then | |
1722 | Rewrite (Expression (N), | |
1723 | Make_Qualified_Expression (Loc, | |
1724 | Subtype_Mark => New_Occurrence_Of (T, Loc), | |
1725 | Expression => Get_Simple_Init_Val (T, Loc))); | |
1726 | ||
1727 | Analyze_And_Resolve (Expression (Expression (N)), T); | |
1728 | Analyze_And_Resolve (Expression (N), T); | |
1729 | Set_Paren_Count (Expression (Expression (N)), 1); | |
1730 | Expand_N_Allocator (N); | |
1731 | ||
1732 | -- No initialization required | |
1733 | ||
1734 | else | |
1735 | null; | |
1736 | end if; | |
1737 | ||
1738 | -- Case of initialization procedure present, must be called | |
1739 | ||
1740 | else | |
1741 | Init := Base_Init_Proc (T); | |
1742 | Node := N; | |
1743 | Temp := | |
1744 | Make_Defining_Identifier (Loc, New_Internal_Name ('P')); | |
1745 | ||
1746 | -- Construct argument list for the initialization routine call | |
1747 | -- The CPP constructor needs the address directly | |
1748 | ||
1749 | if Is_CPP_Class (T) then | |
1750 | Arg1 := New_Reference_To (Temp, Loc); | |
1751 | Temp_Type := T; | |
1752 | ||
1753 | else | |
1754 | Arg1 := | |
1755 | Make_Explicit_Dereference (Loc, | |
1756 | Prefix => New_Reference_To (Temp, Loc)); | |
1757 | Set_Assignment_OK (Arg1); | |
1758 | Temp_Type := PtrT; | |
1759 | ||
1760 | -- The initialization procedure expects a specific type. | |
1761 | -- if the context is access to class wide, indicate that | |
1762 | -- the object being allocated has the right specific type. | |
1763 | ||
1764 | if Is_Class_Wide_Type (Designated_Type (PtrT)) then | |
1765 | Arg1 := Unchecked_Convert_To (T, Arg1); | |
1766 | end if; | |
1767 | end if; | |
1768 | ||
1769 | -- If designated type is a concurrent type or if it is a | |
1770 | -- private type whose definition is a concurrent type, | |
1771 | -- the first argument in the Init routine has to be | |
1772 | -- unchecked conversion to the corresponding record type. | |
1773 | -- If the designated type is a derived type, we also | |
1774 | -- convert the argument to its root type. | |
1775 | ||
1776 | if Is_Concurrent_Type (T) then | |
1777 | Arg1 := | |
1778 | Unchecked_Convert_To (Corresponding_Record_Type (T), Arg1); | |
1779 | ||
1780 | elsif Is_Private_Type (T) | |
1781 | and then Present (Full_View (T)) | |
1782 | and then Is_Concurrent_Type (Full_View (T)) | |
1783 | then | |
1784 | Arg1 := | |
1785 | Unchecked_Convert_To | |
1786 | (Corresponding_Record_Type (Full_View (T)), Arg1); | |
1787 | ||
1788 | elsif Etype (First_Formal (Init)) /= Base_Type (T) then | |
1789 | ||
1790 | declare | |
1791 | Ftyp : constant Entity_Id := Etype (First_Formal (Init)); | |
1792 | ||
1793 | begin | |
1794 | Arg1 := OK_Convert_To (Etype (Ftyp), Arg1); | |
1795 | Set_Etype (Arg1, Ftyp); | |
1796 | end; | |
1797 | end if; | |
1798 | ||
1799 | Args := New_List (Arg1); | |
1800 | ||
1801 | -- For the task case, pass the Master_Id of the access type | |
1802 | -- as the value of the _Master parameter, and _Chain as the | |
1803 | -- value of the _Chain parameter (_Chain will be defined as | |
1804 | -- part of the generated code for the allocator). | |
1805 | ||
1806 | if Has_Task (T) then | |
1807 | ||
1808 | if No (Master_Id (Base_Type (PtrT))) then | |
1809 | ||
1810 | -- The designated type was an incomplete type, and | |
1811 | -- the access type did not get expanded. Salvage | |
1812 | -- it now. | |
1813 | ||
1814 | Expand_N_Full_Type_Declaration | |
1815 | (Parent (Base_Type (PtrT))); | |
1816 | end if; | |
1817 | ||
1818 | -- If the context of the allocator is a declaration or | |
1819 | -- an assignment, we can generate a meaningful image for | |
1820 | -- it, even though subsequent assignments might remove | |
7bc1c7df ES |
1821 | -- the connection between task and entity. We build this |
1822 | -- image when the left-hand side is a simple variable, | |
1823 | -- a simple indexed assignment or a simple selected | |
1824 | -- component. | |
70482933 RK |
1825 | |
1826 | if Nkind (Parent (N)) = N_Assignment_Statement then | |
1827 | declare | |
1828 | Nam : constant Node_Id := Name (Parent (N)); | |
1829 | ||
1830 | begin | |
1831 | if Is_Entity_Name (Nam) then | |
1832 | Decls := | |
1833 | Build_Task_Image_Decls ( | |
1834 | Loc, | |
1835 | New_Occurrence_Of | |
1836 | (Entity (Nam), Sloc (Nam)), T); | |
1837 | ||
7bc1c7df ES |
1838 | elsif (Nkind (Nam) = N_Indexed_Component |
1839 | or else Nkind (Nam) = N_Selected_Component) | |
1840 | and then Is_Entity_Name (Prefix (Nam)) | |
1841 | then | |
1842 | Decls := | |
316ad9c5 RD |
1843 | Build_Task_Image_Decls |
1844 | (Loc, Nam, Etype (Prefix (Nam))); | |
70482933 RK |
1845 | else |
1846 | Decls := Build_Task_Image_Decls (Loc, T, T); | |
1847 | end if; | |
1848 | end; | |
1849 | ||
1850 | elsif Nkind (Parent (N)) = N_Object_Declaration then | |
1851 | Decls := | |
1852 | Build_Task_Image_Decls ( | |
1853 | Loc, Defining_Identifier (Parent (N)), T); | |
1854 | ||
1855 | else | |
1856 | Decls := Build_Task_Image_Decls (Loc, T, T); | |
1857 | end if; | |
1858 | ||
1859 | Append_To (Args, | |
1860 | New_Reference_To | |
1861 | (Master_Id (Base_Type (Root_Type (PtrT))), Loc)); | |
1862 | Append_To (Args, Make_Identifier (Loc, Name_uChain)); | |
1863 | ||
1864 | Decl := Last (Decls); | |
1865 | Append_To (Args, | |
1866 | New_Occurrence_Of (Defining_Identifier (Decl), Loc)); | |
1867 | ||
1868 | -- Has_Task is false, Decls not used | |
1869 | ||
1870 | else | |
1871 | Decls := No_List; | |
1872 | end if; | |
1873 | ||
1874 | -- Add discriminants if discriminated type | |
1875 | ||
1876 | if Has_Discriminants (T) then | |
1877 | Discr := First_Elmt (Discriminant_Constraint (T)); | |
1878 | ||
1879 | while Present (Discr) loop | |
1880 | Append (New_Copy (Elists.Node (Discr)), Args); | |
1881 | Next_Elmt (Discr); | |
1882 | end loop; | |
1883 | ||
1884 | elsif Is_Private_Type (T) | |
1885 | and then Present (Full_View (T)) | |
1886 | and then Has_Discriminants (Full_View (T)) | |
1887 | then | |
1888 | Discr := | |
1889 | First_Elmt (Discriminant_Constraint (Full_View (T))); | |
1890 | ||
1891 | while Present (Discr) loop | |
1892 | Append (New_Copy (Elists.Node (Discr)), Args); | |
1893 | Next_Elmt (Discr); | |
1894 | end loop; | |
1895 | end if; | |
1896 | ||
1897 | -- We set the allocator as analyzed so that when we analyze the | |
1898 | -- expression actions node, we do not get an unwanted recursive | |
1899 | -- expansion of the allocator expression. | |
1900 | ||
1901 | Set_Analyzed (N, True); | |
1902 | Node := Relocate_Node (N); | |
1903 | ||
1904 | -- Here is the transformation: | |
1905 | -- input: new T | |
1906 | -- output: Temp : constant ptr_T := new T; | |
1907 | -- Init (Temp.all, ...); | |
1908 | -- <CTRL> Attach_To_Final_List (Finalizable (Temp.all)); | |
1909 | -- <CTRL> Initialize (Finalizable (Temp.all)); | |
1910 | ||
1911 | -- Here ptr_T is the pointer type for the allocator, and T | |
1912 | -- is the subtype of the allocator. | |
1913 | ||
1914 | Temp_Decl := | |
1915 | Make_Object_Declaration (Loc, | |
1916 | Defining_Identifier => Temp, | |
1917 | Constant_Present => True, | |
1918 | Object_Definition => New_Reference_To (Temp_Type, Loc), | |
1919 | Expression => Node); | |
1920 | ||
1921 | Set_Assignment_OK (Temp_Decl); | |
1922 | ||
1923 | if Is_CPP_Class (T) then | |
1924 | Set_Aliased_Present (Temp_Decl); | |
1925 | end if; | |
1926 | ||
1927 | Insert_Action (N, Temp_Decl, Suppress => All_Checks); | |
1928 | ||
1929 | -- Case of designated type is task or contains task | |
1930 | -- Create block to activate created tasks, and insert | |
1931 | -- declaration for Task_Image variable ahead of call. | |
1932 | ||
1933 | if Has_Task (T) then | |
1934 | declare | |
1935 | L : List_Id := New_List; | |
1936 | Blk : Node_Id; | |
1937 | ||
1938 | begin | |
1939 | Build_Task_Allocate_Block (L, Node, Args); | |
1940 | Blk := Last (L); | |
1941 | ||
1942 | Insert_List_Before (First (Declarations (Blk)), Decls); | |
1943 | Insert_Actions (N, L); | |
1944 | end; | |
1945 | ||
1946 | else | |
1947 | Insert_Action (N, | |
1948 | Make_Procedure_Call_Statement (Loc, | |
1949 | Name => New_Reference_To (Init, Loc), | |
1950 | Parameter_Associations => Args)); | |
1951 | end if; | |
1952 | ||
1953 | if Controlled_Type (T) then | |
1954 | ||
1955 | -- If the context is an access parameter, we need to create | |
1956 | -- a non-anonymous access type in order to have a usable | |
1957 | -- final list, because there is otherwise no pool to which | |
1958 | -- the allocated object can belong. We create both the type | |
1959 | -- and the finalization chain here, because freezing an | |
1960 | -- internal type does not create such a chain. | |
1961 | ||
1962 | if Ekind (PtrT) = E_Anonymous_Access_Type then | |
1963 | declare | |
1964 | Acc : Entity_Id := | |
1965 | Make_Defining_Identifier (Loc, | |
1966 | New_Internal_Name ('I')); | |
1967 | begin | |
1968 | Insert_Action (N, | |
1969 | Make_Full_Type_Declaration (Loc, | |
1970 | Defining_Identifier => Acc, | |
1971 | Type_Definition => | |
1972 | Make_Access_To_Object_Definition (Loc, | |
1973 | Subtype_Indication => | |
1974 | New_Occurrence_Of (T, Loc)))); | |
1975 | ||
1976 | Build_Final_List (N, Acc); | |
1977 | Flist := Find_Final_List (Acc); | |
1978 | end; | |
1979 | ||
1980 | else | |
1981 | Flist := Find_Final_List (PtrT); | |
1982 | end if; | |
1983 | ||
1984 | Insert_Actions (N, | |
1985 | Make_Init_Call ( | |
1986 | Ref => New_Copy_Tree (Arg1), | |
1987 | Typ => T, | |
1988 | Flist_Ref => Flist, | |
1989 | With_Attach => Make_Integer_Literal (Loc, 2))); | |
1990 | end if; | |
1991 | ||
1992 | if Is_CPP_Class (T) then | |
1993 | Rewrite (N, | |
1994 | Make_Attribute_Reference (Loc, | |
1995 | Prefix => New_Reference_To (Temp, Loc), | |
1996 | Attribute_Name => Name_Unchecked_Access)); | |
1997 | else | |
1998 | Rewrite (N, New_Reference_To (Temp, Loc)); | |
1999 | end if; | |
2000 | ||
2001 | Analyze_And_Resolve (N, PtrT); | |
2002 | end if; | |
2003 | end; | |
2004 | end if; | |
2005 | end Expand_N_Allocator; | |
2006 | ||
2007 | ----------------------- | |
2008 | -- Expand_N_And_Then -- | |
2009 | ----------------------- | |
2010 | ||
2011 | -- Expand into conditional expression if Actions present, and also | |
2012 | -- deal with optimizing case of arguments being True or False. | |
2013 | ||
2014 | procedure Expand_N_And_Then (N : Node_Id) is | |
2015 | Loc : constant Source_Ptr := Sloc (N); | |
2016 | Typ : constant Entity_Id := Etype (N); | |
2017 | Left : constant Node_Id := Left_Opnd (N); | |
2018 | Right : constant Node_Id := Right_Opnd (N); | |
2019 | Actlist : List_Id; | |
2020 | ||
2021 | begin | |
2022 | -- Deal with non-standard booleans | |
2023 | ||
2024 | if Is_Boolean_Type (Typ) then | |
2025 | Adjust_Condition (Left); | |
2026 | Adjust_Condition (Right); | |
2027 | Set_Etype (N, Standard_Boolean); | |
2028 | end if; | |
2029 | ||
2030 | -- Check for cases of left argument is True or False | |
2031 | ||
2032 | if Nkind (Left) = N_Identifier then | |
2033 | ||
2034 | -- If left argument is True, change (True and then Right) to Right. | |
2035 | -- Any actions associated with Right will be executed unconditionally | |
2036 | -- and can thus be inserted into the tree unconditionally. | |
2037 | ||
2038 | if Entity (Left) = Standard_True then | |
2039 | if Present (Actions (N)) then | |
2040 | Insert_Actions (N, Actions (N)); | |
2041 | end if; | |
2042 | ||
2043 | Rewrite (N, Right); | |
2044 | Adjust_Result_Type (N, Typ); | |
2045 | return; | |
2046 | ||
2047 | -- If left argument is False, change (False and then Right) to | |
2048 | -- False. In this case we can forget the actions associated with | |
2049 | -- Right, since they will never be executed. | |
2050 | ||
2051 | elsif Entity (Left) = Standard_False then | |
2052 | Kill_Dead_Code (Right); | |
2053 | Kill_Dead_Code (Actions (N)); | |
2054 | Rewrite (N, New_Occurrence_Of (Standard_False, Loc)); | |
2055 | Adjust_Result_Type (N, Typ); | |
2056 | return; | |
2057 | end if; | |
2058 | end if; | |
2059 | ||
2060 | -- If Actions are present, we expand | |
2061 | ||
2062 | -- left and then right | |
2063 | ||
2064 | -- into | |
2065 | ||
2066 | -- if left then right else false end | |
2067 | ||
2068 | -- with the actions becoming the Then_Actions of the conditional | |
2069 | -- expression. This conditional expression is then further expanded | |
2070 | -- (and will eventually disappear) | |
2071 | ||
2072 | if Present (Actions (N)) then | |
2073 | Actlist := Actions (N); | |
2074 | Rewrite (N, | |
2075 | Make_Conditional_Expression (Loc, | |
2076 | Expressions => New_List ( | |
2077 | Left, | |
2078 | Right, | |
2079 | New_Occurrence_Of (Standard_False, Loc)))); | |
2080 | ||
2081 | Set_Then_Actions (N, Actlist); | |
2082 | Analyze_And_Resolve (N, Standard_Boolean); | |
2083 | Adjust_Result_Type (N, Typ); | |
2084 | return; | |
2085 | end if; | |
2086 | ||
2087 | -- No actions present, check for cases of right argument True/False | |
2088 | ||
2089 | if Nkind (Right) = N_Identifier then | |
2090 | ||
2091 | -- Change (Left and then True) to Left. Note that we know there | |
2092 | -- are no actions associated with the True operand, since we | |
2093 | -- just checked for this case above. | |
2094 | ||
2095 | if Entity (Right) = Standard_True then | |
2096 | Rewrite (N, Left); | |
2097 | ||
2098 | -- Change (Left and then False) to False, making sure to preserve | |
2099 | -- any side effects associated with the Left operand. | |
2100 | ||
2101 | elsif Entity (Right) = Standard_False then | |
2102 | Remove_Side_Effects (Left); | |
2103 | Rewrite | |
2104 | (N, New_Occurrence_Of (Standard_False, Loc)); | |
2105 | end if; | |
2106 | end if; | |
2107 | ||
2108 | Adjust_Result_Type (N, Typ); | |
2109 | end Expand_N_And_Then; | |
2110 | ||
2111 | ------------------------------------- | |
2112 | -- Expand_N_Conditional_Expression -- | |
2113 | ------------------------------------- | |
2114 | ||
2115 | -- Expand into expression actions if then/else actions present | |
2116 | ||
2117 | procedure Expand_N_Conditional_Expression (N : Node_Id) is | |
2118 | Loc : constant Source_Ptr := Sloc (N); | |
2119 | Cond : constant Node_Id := First (Expressions (N)); | |
2120 | Thenx : constant Node_Id := Next (Cond); | |
2121 | Elsex : constant Node_Id := Next (Thenx); | |
2122 | Typ : constant Entity_Id := Etype (N); | |
2123 | Cnn : Entity_Id; | |
2124 | New_If : Node_Id; | |
2125 | ||
2126 | begin | |
2127 | -- If either then or else actions are present, then given: | |
2128 | ||
2129 | -- if cond then then-expr else else-expr end | |
2130 | ||
2131 | -- we insert the following sequence of actions (using Insert_Actions): | |
2132 | ||
2133 | -- Cnn : typ; | |
2134 | -- if cond then | |
2135 | -- <<then actions>> | |
2136 | -- Cnn := then-expr; | |
2137 | -- else | |
2138 | -- <<else actions>> | |
2139 | -- Cnn := else-expr | |
2140 | -- end if; | |
2141 | ||
2142 | -- and replace the conditional expression by a reference to Cnn. | |
2143 | ||
2144 | if Present (Then_Actions (N)) or else Present (Else_Actions (N)) then | |
2145 | Cnn := Make_Defining_Identifier (Loc, New_Internal_Name ('C')); | |
2146 | ||
2147 | New_If := | |
2148 | Make_Implicit_If_Statement (N, | |
2149 | Condition => Relocate_Node (Cond), | |
2150 | ||
2151 | Then_Statements => New_List ( | |
2152 | Make_Assignment_Statement (Sloc (Thenx), | |
2153 | Name => New_Occurrence_Of (Cnn, Sloc (Thenx)), | |
2154 | Expression => Relocate_Node (Thenx))), | |
2155 | ||
2156 | Else_Statements => New_List ( | |
2157 | Make_Assignment_Statement (Sloc (Elsex), | |
2158 | Name => New_Occurrence_Of (Cnn, Sloc (Elsex)), | |
2159 | Expression => Relocate_Node (Elsex)))); | |
2160 | ||
2161 | if Present (Then_Actions (N)) then | |
2162 | Insert_List_Before | |
2163 | (First (Then_Statements (New_If)), Then_Actions (N)); | |
2164 | end if; | |
2165 | ||
2166 | if Present (Else_Actions (N)) then | |
2167 | Insert_List_Before | |
2168 | (First (Else_Statements (New_If)), Else_Actions (N)); | |
2169 | end if; | |
2170 | ||
2171 | Rewrite (N, New_Occurrence_Of (Cnn, Loc)); | |
2172 | ||
2173 | Insert_Action (N, | |
2174 | Make_Object_Declaration (Loc, | |
2175 | Defining_Identifier => Cnn, | |
2176 | Object_Definition => New_Occurrence_Of (Typ, Loc))); | |
2177 | ||
2178 | Insert_Action (N, New_If); | |
2179 | Analyze_And_Resolve (N, Typ); | |
2180 | end if; | |
2181 | end Expand_N_Conditional_Expression; | |
2182 | ||
2183 | ----------------------------------- | |
2184 | -- Expand_N_Explicit_Dereference -- | |
2185 | ----------------------------------- | |
2186 | ||
2187 | procedure Expand_N_Explicit_Dereference (N : Node_Id) is | |
2188 | begin | |
2189 | -- The only processing required is an insertion of an explicit | |
2190 | -- dereference call for the checked storage pool case. | |
2191 | ||
2192 | Insert_Dereference_Action (Prefix (N)); | |
2193 | end Expand_N_Explicit_Dereference; | |
2194 | ||
2195 | ----------------- | |
2196 | -- Expand_N_In -- | |
2197 | ----------------- | |
2198 | ||
2199 | procedure Expand_N_In (N : Node_Id) is | |
2200 | Loc : constant Source_Ptr := Sloc (N); | |
2201 | Rtyp : constant Entity_Id := Etype (N); | |
2202 | ||
2203 | begin | |
2204 | -- No expansion is required if we have an explicit range | |
2205 | ||
2206 | if Nkind (Right_Opnd (N)) = N_Range then | |
2207 | return; | |
2208 | ||
2209 | -- Here right operand is a subtype mark | |
2210 | ||
2211 | else | |
2212 | declare | |
2213 | Typ : Entity_Id := Etype (Right_Opnd (N)); | |
2214 | Obj : Node_Id := Left_Opnd (N); | |
2215 | Cond : Node_Id := Empty; | |
2216 | Is_Acc : Boolean := Is_Access_Type (Typ); | |
2217 | ||
2218 | begin | |
2219 | Remove_Side_Effects (Obj); | |
2220 | ||
2221 | -- For tagged type, do tagged membership operation | |
2222 | ||
2223 | if Is_Tagged_Type (Typ) then | |
2224 | -- No expansion will be performed when Java_VM, as the | |
2225 | -- JVM back end will handle the membership tests directly | |
2226 | -- (tags are not explicitly represented in Java objects, | |
2227 | -- so the normal tagged membership expansion is not what | |
2228 | -- we want). | |
2229 | ||
2230 | if not Java_VM then | |
2231 | Rewrite (N, Tagged_Membership (N)); | |
2232 | Analyze_And_Resolve (N, Rtyp); | |
2233 | end if; | |
2234 | ||
2235 | return; | |
2236 | ||
2237 | -- If type is scalar type, rewrite as x in t'first .. t'last | |
2238 | -- This reason we do this is that the bounds may have the wrong | |
2239 | -- type if they come from the original type definition. | |
2240 | ||
2241 | elsif Is_Scalar_Type (Typ) then | |
2242 | Rewrite (Right_Opnd (N), | |
2243 | Make_Range (Loc, | |
2244 | Low_Bound => | |
2245 | Make_Attribute_Reference (Loc, | |
2246 | Attribute_Name => Name_First, | |
2247 | Prefix => New_Reference_To (Typ, Loc)), | |
2248 | ||
2249 | High_Bound => | |
2250 | Make_Attribute_Reference (Loc, | |
2251 | Attribute_Name => Name_Last, | |
2252 | Prefix => New_Reference_To (Typ, Loc)))); | |
2253 | Analyze_And_Resolve (N, Rtyp); | |
2254 | return; | |
2255 | end if; | |
2256 | ||
2257 | if Is_Acc then | |
2258 | Typ := Designated_Type (Typ); | |
2259 | end if; | |
2260 | ||
2261 | if not Is_Constrained (Typ) then | |
2262 | Rewrite (N, | |
2263 | New_Reference_To (Standard_True, Loc)); | |
2264 | Analyze_And_Resolve (N, Rtyp); | |
2265 | ||
2266 | -- For the constrained array case, we have to check the | |
2267 | -- subscripts for an exact match if the lengths are | |
2268 | -- non-zero (the lengths must match in any case). | |
2269 | ||
2270 | elsif Is_Array_Type (Typ) then | |
2271 | ||
2272 | declare | |
2273 | function Construct_Attribute_Reference | |
2274 | (E : Node_Id; | |
2275 | Nam : Name_Id; | |
2276 | Dim : Nat) | |
2277 | return Node_Id; | |
2278 | -- Build attribute reference E'Nam(Dim) | |
2279 | ||
2280 | function Construct_Attribute_Reference | |
2281 | (E : Node_Id; | |
2282 | Nam : Name_Id; | |
2283 | Dim : Nat) | |
2284 | return Node_Id | |
2285 | is | |
2286 | begin | |
2287 | return | |
2288 | Make_Attribute_Reference (Loc, | |
2289 | Prefix => E, | |
2290 | Attribute_Name => Nam, | |
2291 | Expressions => New_List ( | |
2292 | Make_Integer_Literal (Loc, Dim))); | |
2293 | end Construct_Attribute_Reference; | |
2294 | ||
2295 | begin | |
2296 | for J in 1 .. Number_Dimensions (Typ) loop | |
2297 | Evolve_And_Then (Cond, | |
2298 | Make_Op_Eq (Loc, | |
2299 | Left_Opnd => | |
2300 | Construct_Attribute_Reference | |
2301 | (Duplicate_Subexpr (Obj), Name_First, J), | |
2302 | Right_Opnd => | |
2303 | Construct_Attribute_Reference | |
2304 | (New_Occurrence_Of (Typ, Loc), Name_First, J))); | |
2305 | ||
2306 | Evolve_And_Then (Cond, | |
2307 | Make_Op_Eq (Loc, | |
2308 | Left_Opnd => | |
2309 | Construct_Attribute_Reference | |
2310 | (Duplicate_Subexpr (Obj), Name_Last, J), | |
2311 | Right_Opnd => | |
2312 | Construct_Attribute_Reference | |
2313 | (New_Occurrence_Of (Typ, Loc), Name_Last, J))); | |
2314 | end loop; | |
2315 | ||
2316 | if Is_Acc then | |
2317 | Cond := Make_Or_Else (Loc, | |
2318 | Left_Opnd => | |
2319 | Make_Op_Eq (Loc, | |
2320 | Left_Opnd => Obj, | |
2321 | Right_Opnd => Make_Null (Loc)), | |
2322 | Right_Opnd => Cond); | |
2323 | end if; | |
2324 | ||
2325 | Rewrite (N, Cond); | |
2326 | Analyze_And_Resolve (N, Rtyp); | |
2327 | end; | |
2328 | ||
2329 | -- These are the cases where constraint checks may be | |
2330 | -- required, e.g. records with possible discriminants | |
2331 | ||
2332 | else | |
2333 | -- Expand the test into a series of discriminant comparisons. | |
2334 | -- The expression that is built is the negation of the one | |
2335 | -- that is used for checking discriminant constraints. | |
2336 | ||
2337 | Obj := Relocate_Node (Left_Opnd (N)); | |
2338 | ||
2339 | if Has_Discriminants (Typ) then | |
2340 | Cond := Make_Op_Not (Loc, | |
2341 | Right_Opnd => Build_Discriminant_Checks (Obj, Typ)); | |
2342 | ||
2343 | if Is_Acc then | |
2344 | Cond := Make_Or_Else (Loc, | |
2345 | Left_Opnd => | |
2346 | Make_Op_Eq (Loc, | |
2347 | Left_Opnd => Obj, | |
2348 | Right_Opnd => Make_Null (Loc)), | |
2349 | Right_Opnd => Cond); | |
2350 | end if; | |
2351 | ||
2352 | else | |
2353 | Cond := New_Occurrence_Of (Standard_True, Loc); | |
2354 | end if; | |
2355 | ||
2356 | Rewrite (N, Cond); | |
2357 | Analyze_And_Resolve (N, Rtyp); | |
2358 | end if; | |
2359 | end; | |
2360 | end if; | |
2361 | end Expand_N_In; | |
2362 | ||
2363 | -------------------------------- | |
2364 | -- Expand_N_Indexed_Component -- | |
2365 | -------------------------------- | |
2366 | ||
2367 | procedure Expand_N_Indexed_Component (N : Node_Id) is | |
2368 | Loc : constant Source_Ptr := Sloc (N); | |
2369 | Typ : constant Entity_Id := Etype (N); | |
2370 | P : constant Node_Id := Prefix (N); | |
2371 | T : constant Entity_Id := Etype (P); | |
2372 | ||
2373 | begin | |
2374 | -- A special optimization, if we have an indexed component that | |
2375 | -- is selecting from a slice, then we can eliminate the slice, | |
2376 | -- since, for example, x (i .. j)(k) is identical to x(k). The | |
2377 | -- only difference is the range check required by the slice. The | |
2378 | -- range check for the slice itself has already been generated. | |
2379 | -- The range check for the subscripting operation is ensured | |
2380 | -- by converting the subject to the subtype of the slice. | |
2381 | ||
2382 | -- This optimization not only generates better code, avoiding | |
2383 | -- slice messing especially in the packed case, but more importantly | |
2384 | -- bypasses some problems in handling this peculiar case, for | |
2385 | -- example, the issue of dealing specially with object renamings. | |
2386 | ||
2387 | if Nkind (P) = N_Slice then | |
2388 | Rewrite (N, | |
2389 | Make_Indexed_Component (Loc, | |
2390 | Prefix => Prefix (P), | |
2391 | Expressions => New_List ( | |
2392 | Convert_To | |
2393 | (Etype (First_Index (Etype (P))), | |
2394 | First (Expressions (N)))))); | |
2395 | Analyze_And_Resolve (N, Typ); | |
2396 | return; | |
2397 | end if; | |
2398 | ||
2399 | -- If the prefix is an access type, then we unconditionally rewrite | |
2400 | -- if as an explicit deference. This simplifies processing for several | |
2401 | -- cases, including packed array cases and certain cases in which | |
2402 | -- checks must be generated. We used to try to do this only when it | |
2403 | -- was necessary, but it cleans up the code to do it all the time. | |
2404 | ||
2405 | if Is_Access_Type (T) then | |
2406 | Rewrite (P, | |
2407 | Make_Explicit_Dereference (Sloc (N), | |
2408 | Prefix => Relocate_Node (P))); | |
2409 | Analyze_And_Resolve (P, Designated_Type (T)); | |
2410 | end if; | |
2411 | ||
2412 | if Validity_Checks_On and then Validity_Check_Subscripts then | |
2413 | Apply_Subscript_Validity_Checks (N); | |
2414 | end if; | |
2415 | ||
2416 | -- All done for the non-packed case | |
2417 | ||
2418 | if not Is_Packed (Etype (Prefix (N))) then | |
2419 | return; | |
2420 | end if; | |
2421 | ||
2422 | -- For packed arrays that are not bit-packed (i.e. the case of an array | |
2423 | -- with one or more index types with a non-coniguous enumeration type), | |
2424 | -- we can always use the normal packed element get circuit. | |
2425 | ||
2426 | if not Is_Bit_Packed_Array (Etype (Prefix (N))) then | |
2427 | Expand_Packed_Element_Reference (N); | |
2428 | return; | |
2429 | end if; | |
2430 | ||
2431 | -- For a reference to a component of a bit packed array, we have to | |
2432 | -- convert it to a reference to the corresponding Packed_Array_Type. | |
2433 | -- We only want to do this for simple references, and not for: | |
2434 | ||
2435 | -- Left side of assignment (or prefix of left side of assignment) | |
2436 | -- This case is handled in Exp_Ch5.Expand_N_Assignment_Statement | |
2437 | ||
2438 | -- Renaming objects in renaming associations | |
2439 | -- This case is handled when a use of the renamed variable occurs | |
2440 | ||
2441 | -- Actual parameters for a procedure call | |
2442 | -- This case is handled in Exp_Ch6.Expand_Actuals | |
2443 | ||
2444 | -- The second expression in a 'Read attribute reference | |
2445 | ||
2446 | -- The prefix of an address or size attribute reference | |
2447 | ||
2448 | -- The following circuit detects these exceptions | |
2449 | ||
2450 | declare | |
2451 | Child : Node_Id := N; | |
2452 | Parnt : Node_Id := Parent (N); | |
2453 | ||
2454 | begin | |
2455 | loop | |
2456 | if Nkind (Parnt) = N_Unchecked_Expression then | |
2457 | null; | |
2458 | ||
2459 | elsif Nkind (Parnt) = N_Object_Renaming_Declaration | |
2460 | or else Nkind (Parnt) = N_Procedure_Call_Statement | |
2461 | or else (Nkind (Parnt) = N_Parameter_Association | |
2462 | and then | |
2463 | Nkind (Parent (Parnt)) = N_Procedure_Call_Statement) | |
2464 | then | |
2465 | return; | |
2466 | ||
2467 | elsif Nkind (Parnt) = N_Attribute_Reference | |
2468 | and then (Attribute_Name (Parnt) = Name_Address | |
2469 | or else | |
2470 | Attribute_Name (Parnt) = Name_Size) | |
2471 | and then Prefix (Parnt) = Child | |
2472 | then | |
2473 | return; | |
2474 | ||
2475 | elsif Nkind (Parnt) = N_Assignment_Statement | |
2476 | and then Name (Parnt) = Child | |
2477 | then | |
2478 | return; | |
2479 | ||
2480 | elsif Nkind (Parnt) = N_Attribute_Reference | |
2481 | and then Attribute_Name (Parnt) = Name_Read | |
2482 | and then Next (First (Expressions (Parnt))) = Child | |
2483 | then | |
2484 | return; | |
2485 | ||
2486 | elsif (Nkind (Parnt) = N_Indexed_Component | |
2487 | or else Nkind (Parnt) = N_Selected_Component) | |
2488 | and then Prefix (Parnt) = Child | |
2489 | then | |
2490 | null; | |
2491 | ||
2492 | else | |
2493 | Expand_Packed_Element_Reference (N); | |
2494 | return; | |
2495 | end if; | |
2496 | ||
2497 | -- Keep looking up tree for unchecked expression, or if we are | |
2498 | -- the prefix of a possible assignment left side. | |
2499 | ||
2500 | Child := Parnt; | |
2501 | Parnt := Parent (Child); | |
2502 | end loop; | |
2503 | end; | |
2504 | ||
2505 | end Expand_N_Indexed_Component; | |
2506 | ||
2507 | --------------------- | |
2508 | -- Expand_N_Not_In -- | |
2509 | --------------------- | |
2510 | ||
2511 | -- Replace a not in b by not (a in b) so that the expansions for (a in b) | |
2512 | -- can be done. This avoids needing to duplicate this expansion code. | |
2513 | ||
2514 | procedure Expand_N_Not_In (N : Node_Id) is | |
2515 | Loc : constant Source_Ptr := Sloc (N); | |
2516 | Typ : constant Entity_Id := Etype (N); | |
2517 | ||
2518 | begin | |
2519 | Rewrite (N, | |
2520 | Make_Op_Not (Loc, | |
2521 | Right_Opnd => | |
2522 | Make_In (Loc, | |
2523 | Left_Opnd => Left_Opnd (N), | |
2524 | Right_Opnd => Right_Opnd (N)))); | |
2525 | Analyze_And_Resolve (N, Typ); | |
2526 | end Expand_N_Not_In; | |
2527 | ||
2528 | ------------------- | |
2529 | -- Expand_N_Null -- | |
2530 | ------------------- | |
2531 | ||
2532 | -- The only replacement required is for the case of a null of type | |
2533 | -- that is an access to protected subprogram. We represent such | |
2534 | -- access values as a record, and so we must replace the occurrence | |
2535 | -- of null by the equivalent record (with a null address and a null | |
2536 | -- pointer in it), so that the backend creates the proper value. | |
2537 | ||
2538 | procedure Expand_N_Null (N : Node_Id) is | |
2539 | Loc : constant Source_Ptr := Sloc (N); | |
2540 | Typ : constant Entity_Id := Etype (N); | |
2541 | Agg : Node_Id; | |
2542 | ||
2543 | begin | |
2544 | if Ekind (Typ) = E_Access_Protected_Subprogram_Type then | |
2545 | Agg := | |
2546 | Make_Aggregate (Loc, | |
2547 | Expressions => New_List ( | |
2548 | New_Occurrence_Of (RTE (RE_Null_Address), Loc), | |
2549 | Make_Null (Loc))); | |
2550 | ||
2551 | Rewrite (N, Agg); | |
2552 | Analyze_And_Resolve (N, Equivalent_Type (Typ)); | |
2553 | ||
2554 | -- For subsequent semantic analysis, the node must retain its | |
2555 | -- type. Gigi in any case replaces this type by the corresponding | |
2556 | -- record type before processing the node. | |
2557 | ||
2558 | Set_Etype (N, Typ); | |
2559 | end if; | |
2560 | end Expand_N_Null; | |
2561 | ||
2562 | --------------------- | |
2563 | -- Expand_N_Op_Abs -- | |
2564 | --------------------- | |
2565 | ||
2566 | procedure Expand_N_Op_Abs (N : Node_Id) is | |
2567 | Loc : constant Source_Ptr := Sloc (N); | |
2568 | Expr : constant Node_Id := Right_Opnd (N); | |
2569 | ||
2570 | begin | |
2571 | Unary_Op_Validity_Checks (N); | |
2572 | ||
2573 | -- Deal with software overflow checking | |
2574 | ||
07fc65c4 | 2575 | if not Backend_Overflow_Checks_On_Target |
70482933 RK |
2576 | and then Is_Signed_Integer_Type (Etype (N)) |
2577 | and then Do_Overflow_Check (N) | |
2578 | then | |
2579 | -- Software overflow checking expands abs (expr) into | |
2580 | ||
2581 | -- (if expr >= 0 then expr else -expr) | |
2582 | ||
2583 | -- with the usual Duplicate_Subexpr use coding for expr | |
2584 | ||
2585 | Rewrite (N, | |
2586 | Make_Conditional_Expression (Loc, | |
2587 | Expressions => New_List ( | |
2588 | Make_Op_Ge (Loc, | |
2589 | Left_Opnd => Duplicate_Subexpr (Expr), | |
2590 | Right_Opnd => Make_Integer_Literal (Loc, 0)), | |
2591 | ||
2592 | Duplicate_Subexpr (Expr), | |
2593 | ||
2594 | Make_Op_Minus (Loc, | |
2595 | Right_Opnd => Duplicate_Subexpr (Expr))))); | |
2596 | ||
2597 | Analyze_And_Resolve (N); | |
2598 | ||
2599 | -- Vax floating-point types case | |
2600 | ||
2601 | elsif Vax_Float (Etype (N)) then | |
2602 | Expand_Vax_Arith (N); | |
2603 | end if; | |
2604 | end Expand_N_Op_Abs; | |
2605 | ||
2606 | --------------------- | |
2607 | -- Expand_N_Op_Add -- | |
2608 | --------------------- | |
2609 | ||
2610 | procedure Expand_N_Op_Add (N : Node_Id) is | |
2611 | Typ : constant Entity_Id := Etype (N); | |
2612 | ||
2613 | begin | |
2614 | Binary_Op_Validity_Checks (N); | |
2615 | ||
2616 | -- N + 0 = 0 + N = N for integer types | |
2617 | ||
2618 | if Is_Integer_Type (Typ) then | |
2619 | if Compile_Time_Known_Value (Right_Opnd (N)) | |
2620 | and then Expr_Value (Right_Opnd (N)) = Uint_0 | |
2621 | then | |
2622 | Rewrite (N, Left_Opnd (N)); | |
2623 | return; | |
2624 | ||
2625 | elsif Compile_Time_Known_Value (Left_Opnd (N)) | |
2626 | and then Expr_Value (Left_Opnd (N)) = Uint_0 | |
2627 | then | |
2628 | Rewrite (N, Right_Opnd (N)); | |
2629 | return; | |
2630 | end if; | |
2631 | end if; | |
2632 | ||
2633 | -- Arithemtic overflow checks for signed integer/fixed point types | |
2634 | ||
2635 | if Is_Signed_Integer_Type (Typ) | |
2636 | or else Is_Fixed_Point_Type (Typ) | |
2637 | then | |
2638 | Apply_Arithmetic_Overflow_Check (N); | |
2639 | return; | |
2640 | ||
2641 | -- Vax floating-point types case | |
2642 | ||
2643 | elsif Vax_Float (Typ) then | |
2644 | Expand_Vax_Arith (N); | |
2645 | end if; | |
2646 | end Expand_N_Op_Add; | |
2647 | ||
2648 | --------------------- | |
2649 | -- Expand_N_Op_And -- | |
2650 | --------------------- | |
2651 | ||
2652 | procedure Expand_N_Op_And (N : Node_Id) is | |
2653 | Typ : constant Entity_Id := Etype (N); | |
2654 | ||
2655 | begin | |
2656 | Binary_Op_Validity_Checks (N); | |
2657 | ||
2658 | if Is_Array_Type (Etype (N)) then | |
2659 | Expand_Boolean_Operator (N); | |
2660 | ||
2661 | elsif Is_Boolean_Type (Etype (N)) then | |
2662 | Adjust_Condition (Left_Opnd (N)); | |
2663 | Adjust_Condition (Right_Opnd (N)); | |
2664 | Set_Etype (N, Standard_Boolean); | |
2665 | Adjust_Result_Type (N, Typ); | |
2666 | end if; | |
2667 | end Expand_N_Op_And; | |
2668 | ||
2669 | ------------------------ | |
2670 | -- Expand_N_Op_Concat -- | |
2671 | ------------------------ | |
2672 | ||
2673 | procedure Expand_N_Op_Concat (N : Node_Id) is | |
2674 | ||
2675 | Opnds : List_Id; | |
2676 | -- List of operands to be concatenated | |
2677 | ||
2678 | Opnd : Node_Id; | |
2679 | -- Single operand for concatenation | |
2680 | ||
2681 | Cnode : Node_Id; | |
2682 | -- Node which is to be replaced by the result of concatenating | |
2683 | -- the nodes in the list Opnds. | |
2684 | ||
2685 | Atyp : Entity_Id; | |
2686 | -- Array type of concatenation result type | |
2687 | ||
2688 | Ctyp : Entity_Id; | |
2689 | -- Component type of concatenation represented by Cnode | |
2690 | ||
2691 | begin | |
2692 | Binary_Op_Validity_Checks (N); | |
2693 | ||
2694 | -- If we are the left operand of a concatenation higher up the | |
2695 | -- tree, then do nothing for now, since we want to deal with a | |
2696 | -- series of concatenations as a unit. | |
2697 | ||
2698 | if Nkind (Parent (N)) = N_Op_Concat | |
2699 | and then N = Left_Opnd (Parent (N)) | |
2700 | then | |
2701 | return; | |
2702 | end if; | |
2703 | ||
2704 | -- We get here with a concatenation whose left operand may be a | |
2705 | -- concatenation itself with a consistent type. We need to process | |
2706 | -- these concatenation operands from left to right, which means | |
2707 | -- from the deepest node in the tree to the highest node. | |
2708 | ||
2709 | Cnode := N; | |
2710 | while Nkind (Left_Opnd (Cnode)) = N_Op_Concat loop | |
2711 | Cnode := Left_Opnd (Cnode); | |
2712 | end loop; | |
2713 | ||
2714 | -- Now Opnd is the deepest Opnd, and its parents are the concatenation | |
2715 | -- nodes above, so now we process bottom up, doing the operations. We | |
2716 | -- gather a string that is as long as possible up to five operands | |
2717 | ||
2718 | -- The outer loop runs more than once if there are more than five | |
2719 | -- concatenations of type Standard.String, the most we handle for | |
2720 | -- this case, or if more than one concatenation type is involved. | |
2721 | ||
2722 | Outer : loop | |
2723 | Opnds := New_List (Left_Opnd (Cnode), Right_Opnd (Cnode)); | |
2724 | Set_Parent (Opnds, N); | |
2725 | ||
2726 | -- The inner loop gathers concatenation operands | |
2727 | ||
2728 | Inner : while Cnode /= N | |
2729 | and then (Base_Type (Etype (Cnode)) /= Standard_String | |
2730 | or else | |
2731 | List_Length (Opnds) < 5) | |
2732 | and then Base_Type (Etype (Cnode)) = | |
2733 | Base_Type (Etype (Parent (Cnode))) | |
2734 | loop | |
2735 | Cnode := Parent (Cnode); | |
2736 | Append (Right_Opnd (Cnode), Opnds); | |
2737 | end loop Inner; | |
2738 | ||
2739 | -- Here we process the collected operands. First we convert | |
2740 | -- singleton operands to singleton aggregates. This is skipped | |
2741 | -- however for the case of two operands of type String, since | |
2742 | -- we have special routines for these cases. | |
2743 | ||
2744 | Atyp := Base_Type (Etype (Cnode)); | |
2745 | Ctyp := Base_Type (Component_Type (Etype (Cnode))); | |
2746 | ||
2747 | if List_Length (Opnds) > 2 or else Atyp /= Standard_String then | |
2748 | Opnd := First (Opnds); | |
2749 | loop | |
2750 | if Base_Type (Etype (Opnd)) = Ctyp then | |
2751 | Rewrite (Opnd, | |
2752 | Make_Aggregate (Sloc (Cnode), | |
2753 | Expressions => New_List (Relocate_Node (Opnd)))); | |
2754 | Analyze_And_Resolve (Opnd, Atyp); | |
2755 | end if; | |
2756 | ||
2757 | Next (Opnd); | |
2758 | exit when No (Opnd); | |
2759 | end loop; | |
2760 | end if; | |
2761 | ||
2762 | -- Now call appropriate continuation routine | |
2763 | ||
2764 | if Atyp = Standard_String then | |
2765 | Expand_Concatenate_String (Cnode, Opnds); | |
2766 | else | |
2767 | Expand_Concatenate_Other (Cnode, Opnds); | |
2768 | end if; | |
2769 | ||
2770 | exit Outer when Cnode = N; | |
2771 | Cnode := Parent (Cnode); | |
2772 | end loop Outer; | |
2773 | end Expand_N_Op_Concat; | |
2774 | ||
2775 | ------------------------ | |
2776 | -- Expand_N_Op_Divide -- | |
2777 | ------------------------ | |
2778 | ||
2779 | procedure Expand_N_Op_Divide (N : Node_Id) is | |
2780 | Loc : constant Source_Ptr := Sloc (N); | |
2781 | Ltyp : constant Entity_Id := Etype (Left_Opnd (N)); | |
2782 | Rtyp : constant Entity_Id := Etype (Right_Opnd (N)); | |
2783 | Typ : Entity_Id := Etype (N); | |
2784 | ||
2785 | begin | |
2786 | Binary_Op_Validity_Checks (N); | |
2787 | ||
2788 | -- Vax_Float is a special case | |
2789 | ||
2790 | if Vax_Float (Typ) then | |
2791 | Expand_Vax_Arith (N); | |
2792 | return; | |
2793 | end if; | |
2794 | ||
2795 | -- N / 1 = N for integer types | |
2796 | ||
2797 | if Is_Integer_Type (Typ) | |
2798 | and then Compile_Time_Known_Value (Right_Opnd (N)) | |
2799 | and then Expr_Value (Right_Opnd (N)) = Uint_1 | |
2800 | then | |
2801 | Rewrite (N, Left_Opnd (N)); | |
2802 | return; | |
2803 | end if; | |
2804 | ||
2805 | -- Convert x / 2 ** y to Shift_Right (x, y). Note that the fact that | |
2806 | -- Is_Power_Of_2_For_Shift is set means that we know that our left | |
2807 | -- operand is an unsigned integer, as required for this to work. | |
2808 | ||
2809 | if Nkind (Right_Opnd (N)) = N_Op_Expon | |
2810 | and then Is_Power_Of_2_For_Shift (Right_Opnd (N)) | |
2811 | then | |
2812 | Rewrite (N, | |
2813 | Make_Op_Shift_Right (Loc, | |
2814 | Left_Opnd => Left_Opnd (N), | |
2815 | Right_Opnd => | |
2816 | Convert_To (Standard_Natural, Right_Opnd (Right_Opnd (N))))); | |
2817 | Analyze_And_Resolve (N, Typ); | |
2818 | return; | |
2819 | end if; | |
2820 | ||
2821 | -- Do required fixup of universal fixed operation | |
2822 | ||
2823 | if Typ = Universal_Fixed then | |
2824 | Fixup_Universal_Fixed_Operation (N); | |
2825 | Typ := Etype (N); | |
2826 | end if; | |
2827 | ||
2828 | -- Divisions with fixed-point results | |
2829 | ||
2830 | if Is_Fixed_Point_Type (Typ) then | |
2831 | ||
2832 | -- No special processing if Treat_Fixed_As_Integer is set, | |
2833 | -- since from a semantic point of view such operations are | |
2834 | -- simply integer operations and will be treated that way. | |
2835 | ||
2836 | if not Treat_Fixed_As_Integer (N) then | |
2837 | if Is_Integer_Type (Rtyp) then | |
2838 | Expand_Divide_Fixed_By_Integer_Giving_Fixed (N); | |
2839 | else | |
2840 | Expand_Divide_Fixed_By_Fixed_Giving_Fixed (N); | |
2841 | end if; | |
2842 | end if; | |
2843 | ||
2844 | -- Other cases of division of fixed-point operands. Again we | |
2845 | -- exclude the case where Treat_Fixed_As_Integer is set. | |
2846 | ||
2847 | elsif (Is_Fixed_Point_Type (Ltyp) or else | |
2848 | Is_Fixed_Point_Type (Rtyp)) | |
2849 | and then not Treat_Fixed_As_Integer (N) | |
2850 | then | |
2851 | if Is_Integer_Type (Typ) then | |
2852 | Expand_Divide_Fixed_By_Fixed_Giving_Integer (N); | |
2853 | else | |
2854 | pragma Assert (Is_Floating_Point_Type (Typ)); | |
2855 | Expand_Divide_Fixed_By_Fixed_Giving_Float (N); | |
2856 | end if; | |
2857 | ||
2858 | -- Mixed-mode operations can appear in a non-static universal | |
2859 | -- context, in which case the integer argument must be converted | |
2860 | -- explicitly. | |
2861 | ||
2862 | elsif Typ = Universal_Real | |
2863 | and then Is_Integer_Type (Rtyp) | |
2864 | then | |
2865 | Rewrite (Right_Opnd (N), | |
2866 | Convert_To (Universal_Real, Relocate_Node (Right_Opnd (N)))); | |
2867 | ||
2868 | Analyze_And_Resolve (Right_Opnd (N), Universal_Real); | |
2869 | ||
2870 | elsif Typ = Universal_Real | |
2871 | and then Is_Integer_Type (Ltyp) | |
2872 | then | |
2873 | Rewrite (Left_Opnd (N), | |
2874 | Convert_To (Universal_Real, Relocate_Node (Left_Opnd (N)))); | |
2875 | ||
2876 | Analyze_And_Resolve (Left_Opnd (N), Universal_Real); | |
2877 | ||
2878 | -- Non-fixed point cases, do zero divide and overflow checks | |
2879 | ||
2880 | elsif Is_Integer_Type (Typ) then | |
2881 | Apply_Divide_Check (N); | |
2882 | end if; | |
2883 | end Expand_N_Op_Divide; | |
2884 | ||
2885 | -------------------- | |
2886 | -- Expand_N_Op_Eq -- | |
2887 | -------------------- | |
2888 | ||
2889 | procedure Expand_N_Op_Eq (N : Node_Id) is | |
2890 | Loc : constant Source_Ptr := Sloc (N); | |
2891 | Typ : constant Entity_Id := Etype (N); | |
2892 | Lhs : constant Node_Id := Left_Opnd (N); | |
2893 | Rhs : constant Node_Id := Right_Opnd (N); | |
2894 | A_Typ : Entity_Id := Etype (Lhs); | |
2895 | Typl : Entity_Id := A_Typ; | |
2896 | Op_Name : Entity_Id; | |
2897 | Prim : Elmt_Id; | |
2898 | Bodies : List_Id := New_List; | |
2899 | ||
2900 | procedure Build_Equality_Call (Eq : Entity_Id); | |
2901 | -- If a constructed equality exists for the type or for its parent, | |
2902 | -- build and analyze call, adding conversions if the operation is | |
2903 | -- inherited. | |
2904 | ||
2905 | ------------------------- | |
2906 | -- Build_Equality_Call -- | |
2907 | ------------------------- | |
2908 | ||
2909 | procedure Build_Equality_Call (Eq : Entity_Id) is | |
2910 | Op_Type : constant Entity_Id := Etype (First_Formal (Eq)); | |
2911 | L_Exp : Node_Id := Relocate_Node (Lhs); | |
2912 | R_Exp : Node_Id := Relocate_Node (Rhs); | |
2913 | ||
2914 | begin | |
2915 | if Base_Type (Op_Type) /= Base_Type (A_Typ) | |
2916 | and then not Is_Class_Wide_Type (A_Typ) | |
2917 | then | |
2918 | L_Exp := OK_Convert_To (Op_Type, L_Exp); | |
2919 | R_Exp := OK_Convert_To (Op_Type, R_Exp); | |
2920 | end if; | |
2921 | ||
2922 | Rewrite (N, | |
2923 | Make_Function_Call (Loc, | |
2924 | Name => New_Reference_To (Eq, Loc), | |
2925 | Parameter_Associations => New_List (L_Exp, R_Exp))); | |
2926 | ||
2927 | Analyze_And_Resolve (N, Standard_Boolean, Suppress => All_Checks); | |
2928 | end Build_Equality_Call; | |
2929 | ||
2930 | -- Start of processing for Expand_N_Op_Eq | |
2931 | ||
2932 | begin | |
2933 | Binary_Op_Validity_Checks (N); | |
2934 | ||
2935 | if Ekind (Typl) = E_Private_Type then | |
2936 | Typl := Underlying_Type (Typl); | |
2937 | ||
2938 | elsif Ekind (Typl) = E_Private_Subtype then | |
2939 | Typl := Underlying_Type (Base_Type (Typl)); | |
2940 | end if; | |
2941 | ||
2942 | -- It may happen in error situations that the underlying type is not | |
2943 | -- set. The error will be detected later, here we just defend the | |
2944 | -- expander code. | |
2945 | ||
2946 | if No (Typl) then | |
2947 | return; | |
2948 | end if; | |
2949 | ||
2950 | Typl := Base_Type (Typl); | |
2951 | ||
2952 | -- Vax float types | |
2953 | ||
2954 | if Vax_Float (Typl) then | |
2955 | Expand_Vax_Comparison (N); | |
2956 | return; | |
2957 | ||
2958 | -- Boolean types (requiring handling of non-standard case) | |
2959 | ||
2960 | elsif Is_Boolean_Type (Typl) then | |
2961 | Adjust_Condition (Left_Opnd (N)); | |
2962 | Adjust_Condition (Right_Opnd (N)); | |
2963 | Set_Etype (N, Standard_Boolean); | |
2964 | Adjust_Result_Type (N, Typ); | |
2965 | ||
2966 | -- Array types | |
2967 | ||
2968 | elsif Is_Array_Type (Typl) then | |
2969 | ||
2970 | -- Packed case | |
2971 | ||
2972 | if Is_Bit_Packed_Array (Typl) then | |
2973 | Expand_Packed_Eq (N); | |
2974 | ||
2975 | -- For non-floating-point elementary types, the primitive equality | |
2976 | -- always applies, and block-bit comparison is fine. Floating-point | |
2977 | -- is an exception because of negative zeroes. | |
2978 | ||
2979 | -- However, we never use block bit comparison in No_Run_Time mode, | |
2980 | -- since this may result in a call to a run time routine | |
2981 | ||
2982 | elsif Is_Elementary_Type (Component_Type (Typl)) | |
2983 | and then not Is_Floating_Point_Type (Component_Type (Typl)) | |
2984 | and then not No_Run_Time | |
2985 | then | |
2986 | null; | |
2987 | ||
2988 | -- For composite and floating-point cases, expand equality loop | |
2989 | -- to make sure of using proper comparisons for tagged types, | |
2990 | -- and correctly handling the floating-point case. | |
2991 | ||
2992 | else | |
2993 | Rewrite (N, | |
2994 | Expand_Array_Equality (N, Typl, A_Typ, | |
2995 | Relocate_Node (Lhs), Relocate_Node (Rhs), Bodies)); | |
2996 | ||
2997 | Insert_Actions (N, Bodies, Suppress => All_Checks); | |
2998 | Analyze_And_Resolve (N, Standard_Boolean, Suppress => All_Checks); | |
2999 | end if; | |
3000 | ||
3001 | -- Record Types | |
3002 | ||
3003 | elsif Is_Record_Type (Typl) then | |
3004 | ||
3005 | -- For tagged types, use the primitive "=" | |
3006 | ||
3007 | if Is_Tagged_Type (Typl) then | |
3008 | ||
3009 | -- If this is derived from an untagged private type completed | |
3010 | -- with a tagged type, it does not have a full view, so we | |
3011 | -- use the primitive operations of the private type. | |
3012 | -- This check should no longer be necessary when these | |
3013 | -- types receive their full views ??? | |
3014 | ||
3015 | if Is_Private_Type (A_Typ) | |
3016 | and then not Is_Tagged_Type (A_Typ) | |
3017 | and then Is_Derived_Type (A_Typ) | |
3018 | and then No (Full_View (A_Typ)) | |
3019 | then | |
3020 | Prim := First_Elmt (Collect_Primitive_Operations (A_Typ)); | |
3021 | ||
3022 | while Chars (Node (Prim)) /= Name_Op_Eq loop | |
3023 | Next_Elmt (Prim); | |
3024 | pragma Assert (Present (Prim)); | |
3025 | end loop; | |
3026 | ||
3027 | Op_Name := Node (Prim); | |
3028 | else | |
3029 | Op_Name := Find_Prim_Op (Typl, Name_Op_Eq); | |
3030 | end if; | |
3031 | ||
3032 | Build_Equality_Call (Op_Name); | |
3033 | ||
3034 | -- If a type support function is present (for complex cases), use it | |
3035 | ||
3036 | elsif Present (TSS (Root_Type (Typl), Name_uEquality)) then | |
3037 | Build_Equality_Call (TSS (Root_Type (Typl), Name_uEquality)); | |
3038 | ||
3039 | -- Otherwise expand the component by component equality. Note that | |
3040 | -- we never use block-bit coparisons for records, because of the | |
3041 | -- problems with gaps. The backend will often be able to recombine | |
3042 | -- the separate comparisons that we generate here. | |
3043 | ||
3044 | else | |
3045 | Remove_Side_Effects (Lhs); | |
3046 | Remove_Side_Effects (Rhs); | |
3047 | Rewrite (N, | |
3048 | Expand_Record_Equality (N, Typl, Lhs, Rhs, Bodies)); | |
3049 | ||
3050 | Insert_Actions (N, Bodies, Suppress => All_Checks); | |
3051 | Analyze_And_Resolve (N, Standard_Boolean, Suppress => All_Checks); | |
3052 | end if; | |
3053 | end if; | |
3054 | ||
3055 | -- If we still have an equality comparison (i.e. it was not rewritten | |
3056 | -- in some way), then we can test if result is needed at compile time). | |
3057 | ||
3058 | if Nkind (N) = N_Op_Eq then | |
3059 | Rewrite_Comparison (N); | |
3060 | end if; | |
3061 | end Expand_N_Op_Eq; | |
3062 | ||
3063 | ----------------------- | |
3064 | -- Expand_N_Op_Expon -- | |
3065 | ----------------------- | |
3066 | ||
3067 | procedure Expand_N_Op_Expon (N : Node_Id) is | |
3068 | Loc : constant Source_Ptr := Sloc (N); | |
3069 | Typ : constant Entity_Id := Etype (N); | |
3070 | Rtyp : constant Entity_Id := Root_Type (Typ); | |
3071 | Base : constant Node_Id := Relocate_Node (Left_Opnd (N)); | |
07fc65c4 | 3072 | Bastyp : constant Node_Id := Etype (Base); |
70482933 RK |
3073 | Exp : constant Node_Id := Relocate_Node (Right_Opnd (N)); |
3074 | Exptyp : constant Entity_Id := Etype (Exp); | |
3075 | Ovflo : constant Boolean := Do_Overflow_Check (N); | |
3076 | Expv : Uint; | |
3077 | Xnode : Node_Id; | |
3078 | Temp : Node_Id; | |
3079 | Rent : RE_Id; | |
3080 | Ent : Entity_Id; | |
3081 | ||
3082 | begin | |
3083 | Binary_Op_Validity_Checks (N); | |
3084 | ||
07fc65c4 GB |
3085 | -- If either operand is of a private type, then we have the use of |
3086 | -- an intrinsic operator, and we get rid of the privateness, by using | |
3087 | -- root types of underlying types for the actual operation. Otherwise | |
3088 | -- the private types will cause trouble if we expand multiplications | |
3089 | -- or shifts etc. We also do this transformation if the result type | |
3090 | -- is different from the base type. | |
3091 | ||
3092 | if Is_Private_Type (Etype (Base)) | |
3093 | or else | |
3094 | Is_Private_Type (Typ) | |
3095 | or else | |
3096 | Is_Private_Type (Exptyp) | |
3097 | or else | |
3098 | Rtyp /= Root_Type (Bastyp) | |
3099 | then | |
3100 | declare | |
3101 | Bt : constant Entity_Id := Root_Type (Underlying_Type (Bastyp)); | |
3102 | Et : constant Entity_Id := Root_Type (Underlying_Type (Exptyp)); | |
3103 | ||
3104 | begin | |
3105 | Rewrite (N, | |
3106 | Unchecked_Convert_To (Typ, | |
3107 | Make_Op_Expon (Loc, | |
3108 | Left_Opnd => Unchecked_Convert_To (Bt, Base), | |
3109 | Right_Opnd => Unchecked_Convert_To (Et, Exp)))); | |
3110 | Analyze_And_Resolve (N, Typ); | |
3111 | return; | |
3112 | end; | |
3113 | end if; | |
3114 | ||
70482933 RK |
3115 | -- At this point the exponentiation must be dynamic since the static |
3116 | -- case has already been folded after Resolve by Eval_Op_Expon. | |
3117 | ||
3118 | -- Test for case of literal right argument | |
3119 | ||
3120 | if Compile_Time_Known_Value (Exp) then | |
3121 | Expv := Expr_Value (Exp); | |
3122 | ||
3123 | -- We only fold small non-negative exponents. You might think we | |
3124 | -- could fold small negative exponents for the real case, but we | |
3125 | -- can't because we are required to raise Constraint_Error for | |
3126 | -- the case of 0.0 ** (negative) even if Machine_Overflows = False. | |
3127 | -- See ACVC test C4A012B. | |
3128 | ||
3129 | if Expv >= 0 and then Expv <= 4 then | |
3130 | ||
3131 | -- X ** 0 = 1 (or 1.0) | |
3132 | ||
3133 | if Expv = 0 then | |
3134 | if Ekind (Typ) in Integer_Kind then | |
3135 | Xnode := Make_Integer_Literal (Loc, Intval => 1); | |
3136 | else | |
3137 | Xnode := Make_Real_Literal (Loc, Ureal_1); | |
3138 | end if; | |
3139 | ||
3140 | -- X ** 1 = X | |
3141 | ||
3142 | elsif Expv = 1 then | |
3143 | Xnode := Base; | |
3144 | ||
3145 | -- X ** 2 = X * X | |
3146 | ||
3147 | elsif Expv = 2 then | |
3148 | Xnode := | |
3149 | Make_Op_Multiply (Loc, | |
3150 | Left_Opnd => Duplicate_Subexpr (Base), | |
3151 | Right_Opnd => Duplicate_Subexpr (Base)); | |
3152 | ||
3153 | -- X ** 3 = X * X * X | |
3154 | ||
3155 | elsif Expv = 3 then | |
3156 | Xnode := | |
3157 | Make_Op_Multiply (Loc, | |
3158 | Left_Opnd => | |
3159 | Make_Op_Multiply (Loc, | |
3160 | Left_Opnd => Duplicate_Subexpr (Base), | |
3161 | Right_Opnd => Duplicate_Subexpr (Base)), | |
3162 | Right_Opnd => Duplicate_Subexpr (Base)); | |
3163 | ||
3164 | -- X ** 4 -> | |
3165 | -- En : constant base'type := base * base; | |
3166 | -- ... | |
3167 | -- En * En | |
3168 | ||
3169 | else -- Expv = 4 | |
3170 | Temp := | |
3171 | Make_Defining_Identifier (Loc, New_Internal_Name ('E')); | |
3172 | ||
3173 | Insert_Actions (N, New_List ( | |
3174 | Make_Object_Declaration (Loc, | |
3175 | Defining_Identifier => Temp, | |
3176 | Constant_Present => True, | |
3177 | Object_Definition => New_Reference_To (Typ, Loc), | |
3178 | Expression => | |
3179 | Make_Op_Multiply (Loc, | |
3180 | Left_Opnd => Duplicate_Subexpr (Base), | |
3181 | Right_Opnd => Duplicate_Subexpr (Base))))); | |
3182 | ||
3183 | Xnode := | |
3184 | Make_Op_Multiply (Loc, | |
3185 | Left_Opnd => New_Reference_To (Temp, Loc), | |
3186 | Right_Opnd => New_Reference_To (Temp, Loc)); | |
3187 | end if; | |
3188 | ||
3189 | Rewrite (N, Xnode); | |
3190 | Analyze_And_Resolve (N, Typ); | |
3191 | return; | |
3192 | end if; | |
3193 | end if; | |
3194 | ||
3195 | -- Case of (2 ** expression) appearing as an argument of an integer | |
3196 | -- multiplication, or as the right argument of a division of a non- | |
3197 | -- negative integer. In such cases we lave the node untouched, setting | |
3198 | -- the flag Is_Natural_Power_Of_2_for_Shift set, then the expansion | |
3199 | -- of the higher level node converts it into a shift. | |
3200 | ||
3201 | if Nkind (Base) = N_Integer_Literal | |
3202 | and then Intval (Base) = 2 | |
3203 | and then Is_Integer_Type (Root_Type (Exptyp)) | |
3204 | and then Esize (Root_Type (Exptyp)) <= Esize (Standard_Integer) | |
3205 | and then Is_Unsigned_Type (Exptyp) | |
3206 | and then not Ovflo | |
3207 | and then Nkind (Parent (N)) in N_Binary_Op | |
3208 | then | |
3209 | declare | |
3210 | P : constant Node_Id := Parent (N); | |
3211 | L : constant Node_Id := Left_Opnd (P); | |
3212 | R : constant Node_Id := Right_Opnd (P); | |
3213 | ||
3214 | begin | |
3215 | if (Nkind (P) = N_Op_Multiply | |
3216 | and then | |
3217 | ((Is_Integer_Type (Etype (L)) and then R = N) | |
3218 | or else | |
3219 | (Is_Integer_Type (Etype (R)) and then L = N)) | |
3220 | and then not Do_Overflow_Check (P)) | |
3221 | ||
3222 | or else | |
3223 | (Nkind (P) = N_Op_Divide | |
3224 | and then Is_Integer_Type (Etype (L)) | |
3225 | and then Is_Unsigned_Type (Etype (L)) | |
3226 | and then R = N | |
3227 | and then not Do_Overflow_Check (P)) | |
3228 | then | |
3229 | Set_Is_Power_Of_2_For_Shift (N); | |
3230 | return; | |
3231 | end if; | |
3232 | end; | |
3233 | end if; | |
3234 | ||
07fc65c4 GB |
3235 | -- Fall through if exponentiation must be done using a runtime routine |
3236 | ||
3237 | if No_Run_Time then | |
3238 | Disallow_In_No_Run_Time_Mode (N); | |
3239 | return; | |
3240 | end if; | |
70482933 | 3241 | |
07fc65c4 | 3242 | -- First deal with modular case |
70482933 RK |
3243 | |
3244 | if Is_Modular_Integer_Type (Rtyp) then | |
3245 | ||
3246 | -- Non-binary case, we call the special exponentiation routine for | |
3247 | -- the non-binary case, converting the argument to Long_Long_Integer | |
3248 | -- and passing the modulus value. Then the result is converted back | |
3249 | -- to the base type. | |
3250 | ||
3251 | if Non_Binary_Modulus (Rtyp) then | |
3252 | ||
3253 | Rewrite (N, | |
3254 | Convert_To (Typ, | |
3255 | Make_Function_Call (Loc, | |
3256 | Name => New_Reference_To (RTE (RE_Exp_Modular), Loc), | |
3257 | Parameter_Associations => New_List ( | |
3258 | Convert_To (Standard_Integer, Base), | |
3259 | Make_Integer_Literal (Loc, Modulus (Rtyp)), | |
3260 | Exp)))); | |
3261 | ||
3262 | -- Binary case, in this case, we call one of two routines, either | |
3263 | -- the unsigned integer case, or the unsigned long long integer | |
3264 | -- case, with a final "and" operation to do the required mod. | |
3265 | ||
3266 | else | |
3267 | if UI_To_Int (Esize (Rtyp)) <= Standard_Integer_Size then | |
3268 | Ent := RTE (RE_Exp_Unsigned); | |
3269 | else | |
3270 | Ent := RTE (RE_Exp_Long_Long_Unsigned); | |
3271 | end if; | |
3272 | ||
3273 | Rewrite (N, | |
3274 | Convert_To (Typ, | |
3275 | Make_Op_And (Loc, | |
3276 | Left_Opnd => | |
3277 | Make_Function_Call (Loc, | |
3278 | Name => New_Reference_To (Ent, Loc), | |
3279 | Parameter_Associations => New_List ( | |
3280 | Convert_To (Etype (First_Formal (Ent)), Base), | |
3281 | Exp)), | |
3282 | Right_Opnd => | |
3283 | Make_Integer_Literal (Loc, Modulus (Rtyp) - 1)))); | |
3284 | ||
3285 | end if; | |
3286 | ||
3287 | -- Common exit point for modular type case | |
3288 | ||
3289 | Analyze_And_Resolve (N, Typ); | |
3290 | return; | |
3291 | ||
3292 | -- Signed integer cases | |
3293 | ||
3294 | elsif Rtyp = Base_Type (Standard_Integer) then | |
3295 | if Ovflo then | |
3296 | Rent := RE_Exp_Integer; | |
3297 | else | |
3298 | Rent := RE_Exn_Integer; | |
3299 | end if; | |
3300 | ||
3301 | elsif Rtyp = Base_Type (Standard_Short_Integer) then | |
3302 | if Ovflo then | |
3303 | Rent := RE_Exp_Short_Integer; | |
3304 | else | |
3305 | Rent := RE_Exn_Short_Integer; | |
3306 | end if; | |
3307 | ||
3308 | elsif Rtyp = Base_Type (Standard_Short_Short_Integer) then | |
3309 | if Ovflo then | |
3310 | Rent := RE_Exp_Short_Short_Integer; | |
3311 | else | |
3312 | Rent := RE_Exn_Short_Short_Integer; | |
3313 | end if; | |
3314 | ||
3315 | elsif Rtyp = Base_Type (Standard_Long_Integer) then | |
3316 | if Ovflo then | |
3317 | Rent := RE_Exp_Long_Integer; | |
3318 | else | |
3319 | Rent := RE_Exn_Long_Integer; | |
3320 | end if; | |
3321 | ||
3322 | elsif (Rtyp = Base_Type (Standard_Long_Long_Integer) | |
3323 | or else Rtyp = Universal_Integer) | |
3324 | then | |
3325 | if Ovflo then | |
3326 | Rent := RE_Exp_Long_Long_Integer; | |
3327 | else | |
3328 | Rent := RE_Exn_Long_Long_Integer; | |
3329 | end if; | |
3330 | ||
3331 | -- Floating-point cases | |
3332 | ||
3333 | elsif Rtyp = Standard_Float then | |
3334 | if Ovflo then | |
3335 | Rent := RE_Exp_Float; | |
3336 | else | |
3337 | Rent := RE_Exn_Float; | |
3338 | end if; | |
3339 | ||
3340 | elsif Rtyp = Standard_Short_Float then | |
3341 | if Ovflo then | |
3342 | Rent := RE_Exp_Short_Float; | |
3343 | else | |
3344 | Rent := RE_Exn_Short_Float; | |
3345 | end if; | |
3346 | ||
3347 | elsif Rtyp = Standard_Long_Float then | |
3348 | if Ovflo then | |
3349 | Rent := RE_Exp_Long_Float; | |
3350 | else | |
3351 | Rent := RE_Exn_Long_Float; | |
3352 | end if; | |
3353 | ||
3354 | else | |
3355 | pragma Assert | |
3356 | (Rtyp = Standard_Long_Long_Float or else Rtyp = Universal_Real); | |
3357 | ||
3358 | if Ovflo then | |
3359 | Rent := RE_Exp_Long_Long_Float; | |
3360 | else | |
3361 | Rent := RE_Exn_Long_Long_Float; | |
3362 | end if; | |
3363 | end if; | |
3364 | ||
3365 | -- Common processing for integer cases and floating-point cases. | |
3366 | -- If we are in the base type, we can call runtime routine directly | |
3367 | ||
3368 | if Typ = Rtyp | |
3369 | and then Rtyp /= Universal_Integer | |
3370 | and then Rtyp /= Universal_Real | |
3371 | then | |
3372 | Rewrite (N, | |
3373 | Make_Function_Call (Loc, | |
3374 | Name => New_Reference_To (RTE (Rent), Loc), | |
3375 | Parameter_Associations => New_List (Base, Exp))); | |
3376 | ||
3377 | -- Otherwise we have to introduce conversions (conversions are also | |
3378 | -- required in the universal cases, since the runtime routine was | |
3379 | -- typed using the largest integer or real case. | |
3380 | ||
3381 | else | |
3382 | Rewrite (N, | |
3383 | Convert_To (Typ, | |
3384 | Make_Function_Call (Loc, | |
3385 | Name => New_Reference_To (RTE (Rent), Loc), | |
3386 | Parameter_Associations => New_List ( | |
3387 | Convert_To (Rtyp, Base), | |
3388 | Exp)))); | |
3389 | end if; | |
3390 | ||
3391 | Analyze_And_Resolve (N, Typ); | |
3392 | return; | |
3393 | ||
3394 | end Expand_N_Op_Expon; | |
3395 | ||
3396 | -------------------- | |
3397 | -- Expand_N_Op_Ge -- | |
3398 | -------------------- | |
3399 | ||
3400 | procedure Expand_N_Op_Ge (N : Node_Id) is | |
3401 | Typ : constant Entity_Id := Etype (N); | |
3402 | Op1 : constant Node_Id := Left_Opnd (N); | |
3403 | Op2 : constant Node_Id := Right_Opnd (N); | |
3404 | Typ1 : constant Entity_Id := Base_Type (Etype (Op1)); | |
3405 | ||
3406 | begin | |
3407 | Binary_Op_Validity_Checks (N); | |
3408 | ||
3409 | if Vax_Float (Typ1) then | |
3410 | Expand_Vax_Comparison (N); | |
3411 | return; | |
3412 | ||
3413 | elsif Is_Array_Type (Typ1) then | |
3414 | Expand_Array_Comparison (N); | |
3415 | return; | |
3416 | end if; | |
3417 | ||
3418 | if Is_Boolean_Type (Typ1) then | |
3419 | Adjust_Condition (Op1); | |
3420 | Adjust_Condition (Op2); | |
3421 | Set_Etype (N, Standard_Boolean); | |
3422 | Adjust_Result_Type (N, Typ); | |
3423 | end if; | |
3424 | ||
3425 | Rewrite_Comparison (N); | |
3426 | end Expand_N_Op_Ge; | |
3427 | ||
3428 | -------------------- | |
3429 | -- Expand_N_Op_Gt -- | |
3430 | -------------------- | |
3431 | ||
3432 | procedure Expand_N_Op_Gt (N : Node_Id) is | |
3433 | Typ : constant Entity_Id := Etype (N); | |
3434 | Op1 : constant Node_Id := Left_Opnd (N); | |
3435 | Op2 : constant Node_Id := Right_Opnd (N); | |
3436 | Typ1 : constant Entity_Id := Base_Type (Etype (Op1)); | |
3437 | ||
3438 | begin | |
3439 | Binary_Op_Validity_Checks (N); | |
3440 | ||
3441 | if Vax_Float (Typ1) then | |
3442 | Expand_Vax_Comparison (N); | |
3443 | return; | |
3444 | ||
3445 | elsif Is_Array_Type (Typ1) then | |
3446 | Expand_Array_Comparison (N); | |
3447 | return; | |
3448 | end if; | |
3449 | ||
3450 | if Is_Boolean_Type (Typ1) then | |
3451 | Adjust_Condition (Op1); | |
3452 | Adjust_Condition (Op2); | |
3453 | Set_Etype (N, Standard_Boolean); | |
3454 | Adjust_Result_Type (N, Typ); | |
3455 | end if; | |
3456 | ||
3457 | Rewrite_Comparison (N); | |
3458 | end Expand_N_Op_Gt; | |
3459 | ||
3460 | -------------------- | |
3461 | -- Expand_N_Op_Le -- | |
3462 | -------------------- | |
3463 | ||
3464 | procedure Expand_N_Op_Le (N : Node_Id) is | |
3465 | Typ : constant Entity_Id := Etype (N); | |
3466 | Op1 : constant Node_Id := Left_Opnd (N); | |
3467 | Op2 : constant Node_Id := Right_Opnd (N); | |
3468 | Typ1 : constant Entity_Id := Base_Type (Etype (Op1)); | |
3469 | ||
3470 | begin | |
3471 | Binary_Op_Validity_Checks (N); | |
3472 | ||
3473 | if Vax_Float (Typ1) then | |
3474 | Expand_Vax_Comparison (N); | |
3475 | return; | |
3476 | ||
3477 | elsif Is_Array_Type (Typ1) then | |
3478 | Expand_Array_Comparison (N); | |
3479 | return; | |
3480 | end if; | |
3481 | ||
3482 | if Is_Boolean_Type (Typ1) then | |
3483 | Adjust_Condition (Op1); | |
3484 | Adjust_Condition (Op2); | |
3485 | Set_Etype (N, Standard_Boolean); | |
3486 | Adjust_Result_Type (N, Typ); | |
3487 | end if; | |
3488 | ||
3489 | Rewrite_Comparison (N); | |
3490 | end Expand_N_Op_Le; | |
3491 | ||
3492 | -------------------- | |
3493 | -- Expand_N_Op_Lt -- | |
3494 | -------------------- | |
3495 | ||
3496 | procedure Expand_N_Op_Lt (N : Node_Id) is | |
3497 | Typ : constant Entity_Id := Etype (N); | |
3498 | Op1 : constant Node_Id := Left_Opnd (N); | |
3499 | Op2 : constant Node_Id := Right_Opnd (N); | |
3500 | Typ1 : constant Entity_Id := Base_Type (Etype (Op1)); | |
3501 | ||
3502 | begin | |
3503 | Binary_Op_Validity_Checks (N); | |
3504 | ||
3505 | if Vax_Float (Typ1) then | |
3506 | Expand_Vax_Comparison (N); | |
3507 | return; | |
3508 | ||
3509 | elsif Is_Array_Type (Typ1) then | |
3510 | Expand_Array_Comparison (N); | |
3511 | return; | |
3512 | end if; | |
3513 | ||
3514 | if Is_Boolean_Type (Typ1) then | |
3515 | Adjust_Condition (Op1); | |
3516 | Adjust_Condition (Op2); | |
3517 | Set_Etype (N, Standard_Boolean); | |
3518 | Adjust_Result_Type (N, Typ); | |
3519 | end if; | |
3520 | ||
3521 | Rewrite_Comparison (N); | |
3522 | end Expand_N_Op_Lt; | |
3523 | ||
3524 | ----------------------- | |
3525 | -- Expand_N_Op_Minus -- | |
3526 | ----------------------- | |
3527 | ||
3528 | procedure Expand_N_Op_Minus (N : Node_Id) is | |
3529 | Loc : constant Source_Ptr := Sloc (N); | |
3530 | Typ : constant Entity_Id := Etype (N); | |
3531 | ||
3532 | begin | |
3533 | Unary_Op_Validity_Checks (N); | |
3534 | ||
07fc65c4 | 3535 | if not Backend_Overflow_Checks_On_Target |
70482933 RK |
3536 | and then Is_Signed_Integer_Type (Etype (N)) |
3537 | and then Do_Overflow_Check (N) | |
3538 | then | |
3539 | -- Software overflow checking expands -expr into (0 - expr) | |
3540 | ||
3541 | Rewrite (N, | |
3542 | Make_Op_Subtract (Loc, | |
3543 | Left_Opnd => Make_Integer_Literal (Loc, 0), | |
3544 | Right_Opnd => Right_Opnd (N))); | |
3545 | ||
3546 | Analyze_And_Resolve (N, Typ); | |
3547 | ||
3548 | -- Vax floating-point types case | |
3549 | ||
3550 | elsif Vax_Float (Etype (N)) then | |
3551 | Expand_Vax_Arith (N); | |
3552 | end if; | |
3553 | end Expand_N_Op_Minus; | |
3554 | ||
3555 | --------------------- | |
3556 | -- Expand_N_Op_Mod -- | |
3557 | --------------------- | |
3558 | ||
3559 | procedure Expand_N_Op_Mod (N : Node_Id) is | |
3560 | Loc : constant Source_Ptr := Sloc (N); | |
3561 | T : constant Entity_Id := Etype (N); | |
3562 | Left : constant Node_Id := Left_Opnd (N); | |
3563 | Right : constant Node_Id := Right_Opnd (N); | |
3564 | DOC : constant Boolean := Do_Overflow_Check (N); | |
3565 | DDC : constant Boolean := Do_Division_Check (N); | |
3566 | ||
3567 | LLB : Uint; | |
3568 | Llo : Uint; | |
3569 | Lhi : Uint; | |
3570 | LOK : Boolean; | |
3571 | Rlo : Uint; | |
3572 | Rhi : Uint; | |
3573 | ROK : Boolean; | |
3574 | ||
3575 | begin | |
3576 | Binary_Op_Validity_Checks (N); | |
3577 | ||
3578 | Determine_Range (Right, ROK, Rlo, Rhi); | |
3579 | Determine_Range (Left, LOK, Llo, Lhi); | |
3580 | ||
3581 | -- Convert mod to rem if operands are known non-negative. We do this | |
3582 | -- since it is quite likely that this will improve the quality of code, | |
3583 | -- (the operation now corresponds to the hardware remainder), and it | |
3584 | -- does not seem likely that it could be harmful. | |
3585 | ||
3586 | if LOK and then Llo >= 0 | |
3587 | and then | |
3588 | ROK and then Rlo >= 0 | |
3589 | then | |
3590 | Rewrite (N, | |
3591 | Make_Op_Rem (Sloc (N), | |
3592 | Left_Opnd => Left_Opnd (N), | |
3593 | Right_Opnd => Right_Opnd (N))); | |
3594 | ||
3595 | -- Instead of reanalyzing the node we do the analysis manually. | |
3596 | -- This avoids anomalies when the replacement is done in an | |
3597 | -- instance and is epsilon more efficient. | |
3598 | ||
3599 | Set_Entity (N, Standard_Entity (S_Op_Rem)); | |
3600 | Set_Etype (N, T); | |
3601 | Set_Do_Overflow_Check (N, DOC); | |
3602 | Set_Do_Division_Check (N, DDC); | |
3603 | Expand_N_Op_Rem (N); | |
3604 | Set_Analyzed (N); | |
3605 | ||
3606 | -- Otherwise, normal mod processing | |
3607 | ||
3608 | else | |
3609 | if Is_Integer_Type (Etype (N)) then | |
3610 | Apply_Divide_Check (N); | |
3611 | end if; | |
3612 | ||
3613 | -- Deal with annoying case of largest negative number remainder | |
3614 | -- minus one. Gigi does not handle this case correctly, because | |
3615 | -- it generates a divide instruction which may trap in this case. | |
3616 | ||
3617 | -- In fact the check is quite easy, if the right operand is -1, | |
3618 | -- then the mod value is always 0, and we can just ignore the | |
3619 | -- left operand completely in this case. | |
3620 | ||
3621 | LLB := Expr_Value (Type_Low_Bound (Base_Type (Etype (Left)))); | |
3622 | ||
3623 | if ((not ROK) or else (Rlo <= (-1) and then (-1) <= Rhi)) | |
3624 | and then | |
3625 | ((not LOK) or else (Llo = LLB)) | |
3626 | then | |
3627 | Rewrite (N, | |
3628 | Make_Conditional_Expression (Loc, | |
3629 | Expressions => New_List ( | |
3630 | Make_Op_Eq (Loc, | |
3631 | Left_Opnd => Duplicate_Subexpr (Right), | |
3632 | Right_Opnd => | |
3633 | Make_Integer_Literal (Loc, -1)), | |
3634 | Make_Integer_Literal (Loc, Uint_0), | |
3635 | Relocate_Node (N)))); | |
3636 | ||
3637 | Set_Analyzed (Next (Next (First (Expressions (N))))); | |
3638 | Analyze_And_Resolve (N, T); | |
3639 | end if; | |
3640 | end if; | |
3641 | end Expand_N_Op_Mod; | |
3642 | ||
3643 | -------------------------- | |
3644 | -- Expand_N_Op_Multiply -- | |
3645 | -------------------------- | |
3646 | ||
3647 | procedure Expand_N_Op_Multiply (N : Node_Id) is | |
3648 | Loc : constant Source_Ptr := Sloc (N); | |
3649 | Lop : constant Node_Id := Left_Opnd (N); | |
3650 | Rop : constant Node_Id := Right_Opnd (N); | |
3651 | Ltyp : constant Entity_Id := Etype (Lop); | |
3652 | Rtyp : constant Entity_Id := Etype (Rop); | |
3653 | Typ : Entity_Id := Etype (N); | |
3654 | ||
3655 | begin | |
3656 | Binary_Op_Validity_Checks (N); | |
3657 | ||
3658 | -- Special optimizations for integer types | |
3659 | ||
3660 | if Is_Integer_Type (Typ) then | |
3661 | ||
3662 | -- N * 0 = 0 * N = 0 for integer types | |
3663 | ||
3664 | if (Compile_Time_Known_Value (Right_Opnd (N)) | |
3665 | and then Expr_Value (Right_Opnd (N)) = Uint_0) | |
3666 | or else | |
3667 | (Compile_Time_Known_Value (Left_Opnd (N)) | |
3668 | and then Expr_Value (Left_Opnd (N)) = Uint_0) | |
3669 | then | |
3670 | Rewrite (N, Make_Integer_Literal (Loc, Uint_0)); | |
3671 | Analyze_And_Resolve (N, Typ); | |
3672 | return; | |
3673 | end if; | |
3674 | ||
3675 | -- N * 1 = 1 * N = N for integer types | |
3676 | ||
3677 | if Compile_Time_Known_Value (Right_Opnd (N)) | |
3678 | and then Expr_Value (Right_Opnd (N)) = Uint_1 | |
3679 | then | |
3680 | Rewrite (N, Left_Opnd (N)); | |
3681 | return; | |
3682 | ||
3683 | elsif Compile_Time_Known_Value (Left_Opnd (N)) | |
3684 | and then Expr_Value (Left_Opnd (N)) = Uint_1 | |
3685 | then | |
3686 | Rewrite (N, Right_Opnd (N)); | |
3687 | return; | |
3688 | end if; | |
3689 | end if; | |
3690 | ||
3691 | -- Deal with VAX float case | |
3692 | ||
3693 | if Vax_Float (Typ) then | |
3694 | Expand_Vax_Arith (N); | |
3695 | return; | |
3696 | end if; | |
3697 | ||
3698 | -- Convert x * 2 ** y to Shift_Left (x, y). Note that the fact that | |
3699 | -- Is_Power_Of_2_For_Shift is set means that we know that our left | |
3700 | -- operand is an integer, as required for this to work. | |
3701 | ||
3702 | if Nkind (Rop) = N_Op_Expon | |
3703 | and then Is_Power_Of_2_For_Shift (Rop) | |
3704 | then | |
3705 | if Nkind (Lop) = N_Op_Expon | |
3706 | and then Is_Power_Of_2_For_Shift (Lop) | |
3707 | then | |
3708 | ||
3709 | -- convert 2 ** A * 2 ** B into 2 ** (A + B) | |
3710 | ||
3711 | Rewrite (N, | |
3712 | Make_Op_Expon (Loc, | |
3713 | Left_Opnd => Make_Integer_Literal (Loc, 2), | |
3714 | Right_Opnd => | |
3715 | Make_Op_Add (Loc, | |
3716 | Left_Opnd => Right_Opnd (Lop), | |
3717 | Right_Opnd => Right_Opnd (Rop)))); | |
3718 | Analyze_And_Resolve (N, Typ); | |
3719 | return; | |
3720 | ||
3721 | else | |
3722 | Rewrite (N, | |
3723 | Make_Op_Shift_Left (Loc, | |
3724 | Left_Opnd => Lop, | |
3725 | Right_Opnd => | |
3726 | Convert_To (Standard_Natural, Right_Opnd (Rop)))); | |
3727 | Analyze_And_Resolve (N, Typ); | |
3728 | return; | |
3729 | end if; | |
3730 | ||
3731 | -- Same processing for the operands the other way round | |
3732 | ||
3733 | elsif Nkind (Lop) = N_Op_Expon | |
3734 | and then Is_Power_Of_2_For_Shift (Lop) | |
3735 | then | |
3736 | Rewrite (N, | |
3737 | Make_Op_Shift_Left (Loc, | |
3738 | Left_Opnd => Rop, | |
3739 | Right_Opnd => | |
3740 | Convert_To (Standard_Natural, Right_Opnd (Lop)))); | |
3741 | Analyze_And_Resolve (N, Typ); | |
3742 | return; | |
3743 | end if; | |
3744 | ||
3745 | -- Do required fixup of universal fixed operation | |
3746 | ||
3747 | if Typ = Universal_Fixed then | |
3748 | Fixup_Universal_Fixed_Operation (N); | |
3749 | Typ := Etype (N); | |
3750 | end if; | |
3751 | ||
3752 | -- Multiplications with fixed-point results | |
3753 | ||
3754 | if Is_Fixed_Point_Type (Typ) then | |
3755 | ||
3756 | -- No special processing if Treat_Fixed_As_Integer is set, | |
3757 | -- since from a semantic point of view such operations are | |
3758 | -- simply integer operations and will be treated that way. | |
3759 | ||
3760 | if not Treat_Fixed_As_Integer (N) then | |
3761 | ||
3762 | -- Case of fixed * integer => fixed | |
3763 | ||
3764 | if Is_Integer_Type (Rtyp) then | |
3765 | Expand_Multiply_Fixed_By_Integer_Giving_Fixed (N); | |
3766 | ||
3767 | -- Case of integer * fixed => fixed | |
3768 | ||
3769 | elsif Is_Integer_Type (Ltyp) then | |
3770 | Expand_Multiply_Integer_By_Fixed_Giving_Fixed (N); | |
3771 | ||
3772 | -- Case of fixed * fixed => fixed | |
3773 | ||
3774 | else | |
3775 | Expand_Multiply_Fixed_By_Fixed_Giving_Fixed (N); | |
3776 | end if; | |
3777 | end if; | |
3778 | ||
3779 | -- Other cases of multiplication of fixed-point operands. Again | |
3780 | -- we exclude the cases where Treat_Fixed_As_Integer flag is set. | |
3781 | ||
3782 | elsif (Is_Fixed_Point_Type (Ltyp) or else Is_Fixed_Point_Type (Rtyp)) | |
3783 | and then not Treat_Fixed_As_Integer (N) | |
3784 | then | |
3785 | if Is_Integer_Type (Typ) then | |
3786 | Expand_Multiply_Fixed_By_Fixed_Giving_Integer (N); | |
3787 | else | |
3788 | pragma Assert (Is_Floating_Point_Type (Typ)); | |
3789 | Expand_Multiply_Fixed_By_Fixed_Giving_Float (N); | |
3790 | end if; | |
3791 | ||
3792 | -- Mixed-mode operations can appear in a non-static universal | |
3793 | -- context, in which case the integer argument must be converted | |
3794 | -- explicitly. | |
3795 | ||
3796 | elsif Typ = Universal_Real | |
3797 | and then Is_Integer_Type (Rtyp) | |
3798 | then | |
3799 | Rewrite (Rop, Convert_To (Universal_Real, Relocate_Node (Rop))); | |
3800 | ||
3801 | Analyze_And_Resolve (Rop, Universal_Real); | |
3802 | ||
3803 | elsif Typ = Universal_Real | |
3804 | and then Is_Integer_Type (Ltyp) | |
3805 | then | |
3806 | Rewrite (Lop, Convert_To (Universal_Real, Relocate_Node (Lop))); | |
3807 | ||
3808 | Analyze_And_Resolve (Lop, Universal_Real); | |
3809 | ||
3810 | -- Non-fixed point cases, check software overflow checking required | |
3811 | ||
3812 | elsif Is_Signed_Integer_Type (Etype (N)) then | |
3813 | Apply_Arithmetic_Overflow_Check (N); | |
3814 | end if; | |
3815 | end Expand_N_Op_Multiply; | |
3816 | ||
3817 | -------------------- | |
3818 | -- Expand_N_Op_Ne -- | |
3819 | -------------------- | |
3820 | ||
3821 | -- Rewrite node as the negation of an equality operation, and reanalyze. | |
3822 | -- The equality to be used is defined in the same scope and has the same | |
3823 | -- signature. It must be set explicitly because in an instance it may not | |
3824 | -- have the same visibility as in the generic unit. | |
3825 | ||
3826 | procedure Expand_N_Op_Ne (N : Node_Id) is | |
3827 | Loc : constant Source_Ptr := Sloc (N); | |
3828 | Neg : Node_Id; | |
3829 | Ne : constant Entity_Id := Entity (N); | |
3830 | ||
3831 | begin | |
3832 | Binary_Op_Validity_Checks (N); | |
3833 | ||
3834 | Neg := | |
3835 | Make_Op_Not (Loc, | |
3836 | Right_Opnd => | |
3837 | Make_Op_Eq (Loc, | |
3838 | Left_Opnd => Left_Opnd (N), | |
3839 | Right_Opnd => Right_Opnd (N))); | |
3840 | Set_Paren_Count (Right_Opnd (Neg), 1); | |
3841 | ||
3842 | if Scope (Ne) /= Standard_Standard then | |
3843 | Set_Entity (Right_Opnd (Neg), Corresponding_Equality (Ne)); | |
3844 | end if; | |
3845 | ||
3846 | Rewrite (N, Neg); | |
3847 | Analyze_And_Resolve (N, Standard_Boolean); | |
3848 | end Expand_N_Op_Ne; | |
3849 | ||
3850 | --------------------- | |
3851 | -- Expand_N_Op_Not -- | |
3852 | --------------------- | |
3853 | ||
3854 | -- If the argument is other than a Boolean array type, there is no | |
3855 | -- special expansion required. | |
3856 | ||
3857 | -- For the packed case, we call the special routine in Exp_Pakd, except | |
3858 | -- that if the component size is greater than one, we use the standard | |
3859 | -- routine generating a gruesome loop (it is so peculiar to have packed | |
3860 | -- arrays with non-standard Boolean representations anyway, so it does | |
3861 | -- not matter that we do not handle this case efficiently). | |
3862 | ||
3863 | -- For the unpacked case (and for the special packed case where we have | |
3864 | -- non standard Booleans, as discussed above), we generate and insert | |
3865 | -- into the tree the following function definition: | |
3866 | ||
3867 | -- function Nnnn (A : arr) is | |
3868 | -- B : arr; | |
3869 | -- begin | |
3870 | -- for J in a'range loop | |
3871 | -- B (J) := not A (J); | |
3872 | -- end loop; | |
3873 | -- return B; | |
3874 | -- end Nnnn; | |
3875 | ||
3876 | -- Here arr is the actual subtype of the parameter (and hence always | |
3877 | -- constrained). Then we replace the not with a call to this function. | |
3878 | ||
3879 | procedure Expand_N_Op_Not (N : Node_Id) is | |
3880 | Loc : constant Source_Ptr := Sloc (N); | |
3881 | Typ : constant Entity_Id := Etype (N); | |
3882 | Opnd : Node_Id; | |
3883 | Arr : Entity_Id; | |
3884 | A : Entity_Id; | |
3885 | B : Entity_Id; | |
3886 | J : Entity_Id; | |
3887 | A_J : Node_Id; | |
3888 | B_J : Node_Id; | |
3889 | ||
3890 | Func_Name : Entity_Id; | |
3891 | Loop_Statement : Node_Id; | |
3892 | ||
3893 | begin | |
3894 | Unary_Op_Validity_Checks (N); | |
3895 | ||
3896 | -- For boolean operand, deal with non-standard booleans | |
3897 | ||
3898 | if Is_Boolean_Type (Typ) then | |
3899 | Adjust_Condition (Right_Opnd (N)); | |
3900 | Set_Etype (N, Standard_Boolean); | |
3901 | Adjust_Result_Type (N, Typ); | |
3902 | return; | |
3903 | end if; | |
3904 | ||
3905 | -- Only array types need any other processing | |
3906 | ||
3907 | if not Is_Array_Type (Typ) then | |
3908 | return; | |
3909 | end if; | |
3910 | ||
3911 | -- Case of array operand. If bit packed, handle it in Exp_Pakd | |
3912 | ||
3913 | if Is_Bit_Packed_Array (Typ) and then Component_Size (Typ) = 1 then | |
3914 | Expand_Packed_Not (N); | |
3915 | return; | |
3916 | end if; | |
3917 | ||
3918 | -- Case of array operand which is not bit-packed | |
3919 | ||
3920 | Opnd := Relocate_Node (Right_Opnd (N)); | |
3921 | Convert_To_Actual_Subtype (Opnd); | |
3922 | Arr := Etype (Opnd); | |
3923 | Ensure_Defined (Arr, N); | |
3924 | ||
3925 | A := Make_Defining_Identifier (Loc, Name_uA); | |
3926 | B := Make_Defining_Identifier (Loc, Name_uB); | |
3927 | J := Make_Defining_Identifier (Loc, Name_uJ); | |
3928 | ||
3929 | A_J := | |
3930 | Make_Indexed_Component (Loc, | |
3931 | Prefix => New_Reference_To (A, Loc), | |
3932 | Expressions => New_List (New_Reference_To (J, Loc))); | |
3933 | ||
3934 | B_J := | |
3935 | Make_Indexed_Component (Loc, | |
3936 | Prefix => New_Reference_To (B, Loc), | |
3937 | Expressions => New_List (New_Reference_To (J, Loc))); | |
3938 | ||
3939 | Loop_Statement := | |
3940 | Make_Implicit_Loop_Statement (N, | |
3941 | Identifier => Empty, | |
3942 | ||
3943 | Iteration_Scheme => | |
3944 | Make_Iteration_Scheme (Loc, | |
3945 | Loop_Parameter_Specification => | |
3946 | Make_Loop_Parameter_Specification (Loc, | |
3947 | Defining_Identifier => J, | |
3948 | Discrete_Subtype_Definition => | |
3949 | Make_Attribute_Reference (Loc, | |
3950 | Prefix => Make_Identifier (Loc, Chars (A)), | |
3951 | Attribute_Name => Name_Range))), | |
3952 | ||
3953 | Statements => New_List ( | |
3954 | Make_Assignment_Statement (Loc, | |
3955 | Name => B_J, | |
3956 | Expression => Make_Op_Not (Loc, A_J)))); | |
3957 | ||
3958 | Func_Name := Make_Defining_Identifier (Loc, New_Internal_Name ('N')); | |
3959 | Set_Is_Inlined (Func_Name); | |
3960 | ||
3961 | Insert_Action (N, | |
3962 | Make_Subprogram_Body (Loc, | |
3963 | Specification => | |
3964 | Make_Function_Specification (Loc, | |
3965 | Defining_Unit_Name => Func_Name, | |
3966 | Parameter_Specifications => New_List ( | |
3967 | Make_Parameter_Specification (Loc, | |
3968 | Defining_Identifier => A, | |
3969 | Parameter_Type => New_Reference_To (Typ, Loc))), | |
3970 | Subtype_Mark => New_Reference_To (Typ, Loc)), | |
3971 | ||
3972 | Declarations => New_List ( | |
3973 | Make_Object_Declaration (Loc, | |
3974 | Defining_Identifier => B, | |
3975 | Object_Definition => New_Reference_To (Arr, Loc))), | |
3976 | ||
3977 | Handled_Statement_Sequence => | |
3978 | Make_Handled_Sequence_Of_Statements (Loc, | |
3979 | Statements => New_List ( | |
3980 | Loop_Statement, | |
3981 | Make_Return_Statement (Loc, | |
3982 | Expression => | |
3983 | Make_Identifier (Loc, Chars (B))))))); | |
3984 | ||
3985 | Rewrite (N, | |
3986 | Make_Function_Call (Loc, | |
3987 | Name => New_Reference_To (Func_Name, Loc), | |
3988 | Parameter_Associations => New_List (Opnd))); | |
3989 | ||
3990 | Analyze_And_Resolve (N, Typ); | |
3991 | end Expand_N_Op_Not; | |
3992 | ||
3993 | -------------------- | |
3994 | -- Expand_N_Op_Or -- | |
3995 | -------------------- | |
3996 | ||
3997 | procedure Expand_N_Op_Or (N : Node_Id) is | |
3998 | Typ : constant Entity_Id := Etype (N); | |
3999 | ||
4000 | begin | |
4001 | Binary_Op_Validity_Checks (N); | |
4002 | ||
4003 | if Is_Array_Type (Etype (N)) then | |
4004 | Expand_Boolean_Operator (N); | |
4005 | ||
4006 | elsif Is_Boolean_Type (Etype (N)) then | |
4007 | Adjust_Condition (Left_Opnd (N)); | |
4008 | Adjust_Condition (Right_Opnd (N)); | |
4009 | Set_Etype (N, Standard_Boolean); | |
4010 | Adjust_Result_Type (N, Typ); | |
4011 | end if; | |
4012 | end Expand_N_Op_Or; | |
4013 | ||
4014 | ---------------------- | |
4015 | -- Expand_N_Op_Plus -- | |
4016 | ---------------------- | |
4017 | ||
4018 | procedure Expand_N_Op_Plus (N : Node_Id) is | |
4019 | begin | |
4020 | Unary_Op_Validity_Checks (N); | |
4021 | end Expand_N_Op_Plus; | |
4022 | ||
4023 | --------------------- | |
4024 | -- Expand_N_Op_Rem -- | |
4025 | --------------------- | |
4026 | ||
4027 | procedure Expand_N_Op_Rem (N : Node_Id) is | |
4028 | Loc : constant Source_Ptr := Sloc (N); | |
4029 | ||
4030 | Left : constant Node_Id := Left_Opnd (N); | |
4031 | Right : constant Node_Id := Right_Opnd (N); | |
4032 | ||
4033 | LLB : Uint; | |
4034 | Llo : Uint; | |
4035 | Lhi : Uint; | |
4036 | LOK : Boolean; | |
4037 | Rlo : Uint; | |
4038 | Rhi : Uint; | |
4039 | ROK : Boolean; | |
4040 | Typ : Entity_Id; | |
4041 | ||
4042 | begin | |
4043 | Binary_Op_Validity_Checks (N); | |
4044 | ||
4045 | if Is_Integer_Type (Etype (N)) then | |
4046 | Apply_Divide_Check (N); | |
4047 | end if; | |
4048 | ||
4049 | -- Deal with annoying case of largest negative number remainder | |
4050 | -- minus one. Gigi does not handle this case correctly, because | |
4051 | -- it generates a divide instruction which may trap in this case. | |
4052 | ||
4053 | -- In fact the check is quite easy, if the right operand is -1, | |
4054 | -- then the remainder is always 0, and we can just ignore the | |
4055 | -- left operand completely in this case. | |
4056 | ||
4057 | Determine_Range (Right, ROK, Rlo, Rhi); | |
4058 | Determine_Range (Left, LOK, Llo, Lhi); | |
4059 | LLB := Expr_Value (Type_Low_Bound (Base_Type (Etype (Left)))); | |
4060 | Typ := Etype (N); | |
4061 | ||
4062 | if ((not ROK) or else (Rlo <= (-1) and then (-1) <= Rhi)) | |
4063 | and then | |
4064 | ((not LOK) or else (Llo = LLB)) | |
4065 | then | |
4066 | Rewrite (N, | |
4067 | Make_Conditional_Expression (Loc, | |
4068 | Expressions => New_List ( | |
4069 | Make_Op_Eq (Loc, | |
4070 | Left_Opnd => Duplicate_Subexpr (Right), | |
4071 | Right_Opnd => | |
4072 | Make_Integer_Literal (Loc, -1)), | |
4073 | ||
4074 | Make_Integer_Literal (Loc, Uint_0), | |
4075 | ||
4076 | Relocate_Node (N)))); | |
4077 | ||
4078 | Set_Analyzed (Next (Next (First (Expressions (N))))); | |
4079 | Analyze_And_Resolve (N, Typ); | |
4080 | end if; | |
4081 | end Expand_N_Op_Rem; | |
4082 | ||
4083 | ----------------------------- | |
4084 | -- Expand_N_Op_Rotate_Left -- | |
4085 | ----------------------------- | |
4086 | ||
4087 | procedure Expand_N_Op_Rotate_Left (N : Node_Id) is | |
4088 | begin | |
4089 | Binary_Op_Validity_Checks (N); | |
4090 | end Expand_N_Op_Rotate_Left; | |
4091 | ||
4092 | ------------------------------ | |
4093 | -- Expand_N_Op_Rotate_Right -- | |
4094 | ------------------------------ | |
4095 | ||
4096 | procedure Expand_N_Op_Rotate_Right (N : Node_Id) is | |
4097 | begin | |
4098 | Binary_Op_Validity_Checks (N); | |
4099 | end Expand_N_Op_Rotate_Right; | |
4100 | ||
4101 | ---------------------------- | |
4102 | -- Expand_N_Op_Shift_Left -- | |
4103 | ---------------------------- | |
4104 | ||
4105 | procedure Expand_N_Op_Shift_Left (N : Node_Id) is | |
4106 | begin | |
4107 | Binary_Op_Validity_Checks (N); | |
4108 | end Expand_N_Op_Shift_Left; | |
4109 | ||
4110 | ----------------------------- | |
4111 | -- Expand_N_Op_Shift_Right -- | |
4112 | ----------------------------- | |
4113 | ||
4114 | procedure Expand_N_Op_Shift_Right (N : Node_Id) is | |
4115 | begin | |
4116 | Binary_Op_Validity_Checks (N); | |
4117 | end Expand_N_Op_Shift_Right; | |
4118 | ||
4119 | ---------------------------------------- | |
4120 | -- Expand_N_Op_Shift_Right_Arithmetic -- | |
4121 | ---------------------------------------- | |
4122 | ||
4123 | procedure Expand_N_Op_Shift_Right_Arithmetic (N : Node_Id) is | |
4124 | begin | |
4125 | Binary_Op_Validity_Checks (N); | |
4126 | end Expand_N_Op_Shift_Right_Arithmetic; | |
4127 | ||
4128 | -------------------------- | |
4129 | -- Expand_N_Op_Subtract -- | |
4130 | -------------------------- | |
4131 | ||
4132 | procedure Expand_N_Op_Subtract (N : Node_Id) is | |
4133 | Typ : constant Entity_Id := Etype (N); | |
4134 | ||
4135 | begin | |
4136 | Binary_Op_Validity_Checks (N); | |
4137 | ||
4138 | -- N - 0 = N for integer types | |
4139 | ||
4140 | if Is_Integer_Type (Typ) | |
4141 | and then Compile_Time_Known_Value (Right_Opnd (N)) | |
4142 | and then Expr_Value (Right_Opnd (N)) = 0 | |
4143 | then | |
4144 | Rewrite (N, Left_Opnd (N)); | |
4145 | return; | |
4146 | end if; | |
4147 | ||
4148 | -- Arithemtic overflow checks for signed integer/fixed point types | |
4149 | ||
4150 | if Is_Signed_Integer_Type (Typ) | |
4151 | or else Is_Fixed_Point_Type (Typ) | |
4152 | then | |
4153 | Apply_Arithmetic_Overflow_Check (N); | |
4154 | ||
4155 | -- Vax floating-point types case | |
4156 | ||
4157 | elsif Vax_Float (Typ) then | |
4158 | Expand_Vax_Arith (N); | |
4159 | end if; | |
4160 | end Expand_N_Op_Subtract; | |
4161 | ||
4162 | --------------------- | |
4163 | -- Expand_N_Op_Xor -- | |
4164 | --------------------- | |
4165 | ||
4166 | procedure Expand_N_Op_Xor (N : Node_Id) is | |
4167 | Typ : constant Entity_Id := Etype (N); | |
4168 | ||
4169 | begin | |
4170 | Binary_Op_Validity_Checks (N); | |
4171 | ||
4172 | if Is_Array_Type (Etype (N)) then | |
4173 | Expand_Boolean_Operator (N); | |
4174 | ||
4175 | elsif Is_Boolean_Type (Etype (N)) then | |
4176 | Adjust_Condition (Left_Opnd (N)); | |
4177 | Adjust_Condition (Right_Opnd (N)); | |
4178 | Set_Etype (N, Standard_Boolean); | |
4179 | Adjust_Result_Type (N, Typ); | |
4180 | end if; | |
4181 | end Expand_N_Op_Xor; | |
4182 | ||
4183 | ---------------------- | |
4184 | -- Expand_N_Or_Else -- | |
4185 | ---------------------- | |
4186 | ||
4187 | -- Expand into conditional expression if Actions present, and also | |
4188 | -- deal with optimizing case of arguments being True or False. | |
4189 | ||
4190 | procedure Expand_N_Or_Else (N : Node_Id) is | |
4191 | Loc : constant Source_Ptr := Sloc (N); | |
4192 | Typ : constant Entity_Id := Etype (N); | |
4193 | Left : constant Node_Id := Left_Opnd (N); | |
4194 | Right : constant Node_Id := Right_Opnd (N); | |
4195 | Actlist : List_Id; | |
4196 | ||
4197 | begin | |
4198 | -- Deal with non-standard booleans | |
4199 | ||
4200 | if Is_Boolean_Type (Typ) then | |
4201 | Adjust_Condition (Left); | |
4202 | Adjust_Condition (Right); | |
4203 | Set_Etype (N, Standard_Boolean); | |
4204 | ||
4205 | -- Check for cases of left argument is True or False | |
4206 | ||
4207 | elsif Nkind (Left) = N_Identifier then | |
4208 | ||
4209 | -- If left argument is False, change (False or else Right) to Right. | |
4210 | -- Any actions associated with Right will be executed unconditionally | |
4211 | -- and can thus be inserted into the tree unconditionally. | |
4212 | ||
4213 | if Entity (Left) = Standard_False then | |
4214 | if Present (Actions (N)) then | |
4215 | Insert_Actions (N, Actions (N)); | |
4216 | end if; | |
4217 | ||
4218 | Rewrite (N, Right); | |
4219 | Adjust_Result_Type (N, Typ); | |
4220 | return; | |
4221 | ||
4222 | -- If left argument is True, change (True and then Right) to | |
4223 | -- True. In this case we can forget the actions associated with | |
4224 | -- Right, since they will never be executed. | |
4225 | ||
4226 | elsif Entity (Left) = Standard_True then | |
4227 | Kill_Dead_Code (Right); | |
4228 | Kill_Dead_Code (Actions (N)); | |
4229 | Rewrite (N, New_Occurrence_Of (Standard_True, Loc)); | |
4230 | Adjust_Result_Type (N, Typ); | |
4231 | return; | |
4232 | end if; | |
4233 | end if; | |
4234 | ||
4235 | -- If Actions are present, we expand | |
4236 | ||
4237 | -- left or else right | |
4238 | ||
4239 | -- into | |
4240 | ||
4241 | -- if left then True else right end | |
4242 | ||
4243 | -- with the actions becoming the Else_Actions of the conditional | |
4244 | -- expression. This conditional expression is then further expanded | |
4245 | -- (and will eventually disappear) | |
4246 | ||
4247 | if Present (Actions (N)) then | |
4248 | Actlist := Actions (N); | |
4249 | Rewrite (N, | |
4250 | Make_Conditional_Expression (Loc, | |
4251 | Expressions => New_List ( | |
4252 | Left, | |
4253 | New_Occurrence_Of (Standard_True, Loc), | |
4254 | Right))); | |
4255 | ||
4256 | Set_Else_Actions (N, Actlist); | |
4257 | Analyze_And_Resolve (N, Standard_Boolean); | |
4258 | Adjust_Result_Type (N, Typ); | |
4259 | return; | |
4260 | end if; | |
4261 | ||
4262 | -- No actions present, check for cases of right argument True/False | |
4263 | ||
4264 | if Nkind (Right) = N_Identifier then | |
4265 | ||
4266 | -- Change (Left or else False) to Left. Note that we know there | |
4267 | -- are no actions associated with the True operand, since we | |
4268 | -- just checked for this case above. | |
4269 | ||
4270 | if Entity (Right) = Standard_False then | |
4271 | Rewrite (N, Left); | |
4272 | ||
4273 | -- Change (Left or else True) to True, making sure to preserve | |
4274 | -- any side effects associated with the Left operand. | |
4275 | ||
4276 | elsif Entity (Right) = Standard_True then | |
4277 | Remove_Side_Effects (Left); | |
4278 | Rewrite | |
4279 | (N, New_Occurrence_Of (Standard_True, Loc)); | |
4280 | end if; | |
4281 | end if; | |
4282 | ||
4283 | Adjust_Result_Type (N, Typ); | |
4284 | end Expand_N_Or_Else; | |
4285 | ||
4286 | ----------------------------------- | |
4287 | -- Expand_N_Qualified_Expression -- | |
4288 | ----------------------------------- | |
4289 | ||
4290 | procedure Expand_N_Qualified_Expression (N : Node_Id) is | |
4291 | Operand : constant Node_Id := Expression (N); | |
4292 | Target_Type : constant Entity_Id := Entity (Subtype_Mark (N)); | |
4293 | ||
4294 | begin | |
4295 | Apply_Constraint_Check (Operand, Target_Type, No_Sliding => True); | |
4296 | end Expand_N_Qualified_Expression; | |
4297 | ||
4298 | --------------------------------- | |
4299 | -- Expand_N_Selected_Component -- | |
4300 | --------------------------------- | |
4301 | ||
4302 | -- If the selector is a discriminant of a concurrent object, rewrite the | |
4303 | -- prefix to denote the corresponding record type. | |
4304 | ||
4305 | procedure Expand_N_Selected_Component (N : Node_Id) is | |
4306 | Loc : constant Source_Ptr := Sloc (N); | |
4307 | Par : constant Node_Id := Parent (N); | |
4308 | P : constant Node_Id := Prefix (N); | |
4309 | Disc : Entity_Id; | |
4310 | Ptyp : Entity_Id := Underlying_Type (Etype (P)); | |
4311 | New_N : Node_Id; | |
4312 | ||
4313 | function In_Left_Hand_Side (Comp : Node_Id) return Boolean; | |
4314 | -- Gigi needs a temporary for prefixes that depend on a discriminant, | |
4315 | -- unless the context of an assignment can provide size information. | |
4316 | ||
4317 | function In_Left_Hand_Side (Comp : Node_Id) return Boolean is | |
4318 | begin | |
4319 | return | |
4320 | (Nkind (Parent (Comp)) = N_Assignment_Statement | |
4321 | and then Comp = Name (Parent (Comp))) | |
4322 | or else | |
4323 | (Present (Parent (Comp)) | |
4324 | and then Nkind (Parent (Comp)) in N_Subexpr | |
4325 | and then In_Left_Hand_Side (Parent (Comp))); | |
4326 | end In_Left_Hand_Side; | |
4327 | ||
4328 | begin | |
4329 | if Do_Discriminant_Check (N) then | |
4330 | ||
4331 | -- Present the discrminant checking function to the backend, | |
4332 | -- so that it can inline the call to the function. | |
4333 | ||
4334 | Add_Inlined_Body | |
4335 | (Discriminant_Checking_Func | |
4336 | (Original_Record_Component (Entity (Selector_Name (N))))); | |
4337 | end if; | |
4338 | ||
4339 | -- Insert explicit dereference call for the checked storage pool case | |
4340 | ||
4341 | if Is_Access_Type (Ptyp) then | |
4342 | Insert_Dereference_Action (P); | |
4343 | return; | |
4344 | end if; | |
4345 | ||
4346 | -- Gigi cannot handle unchecked conversions that are the prefix of | |
4347 | -- a selected component with discriminants. This must be checked | |
4348 | -- during expansion, because during analysis the type of the selector | |
4349 | -- is not known at the point the prefix is analyzed. If the conversion | |
4350 | -- is the target of an assignment, we cannot force the evaluation, of | |
4351 | -- course. | |
4352 | ||
4353 | if Nkind (Prefix (N)) = N_Unchecked_Type_Conversion | |
4354 | and then Has_Discriminants (Etype (N)) | |
4355 | and then not In_Left_Hand_Side (N) | |
4356 | then | |
4357 | Force_Evaluation (Prefix (N)); | |
4358 | end if; | |
4359 | ||
4360 | -- Remaining processing applies only if selector is a discriminant | |
4361 | ||
4362 | if Ekind (Entity (Selector_Name (N))) = E_Discriminant then | |
4363 | ||
4364 | -- If the selector is a discriminant of a constrained record type, | |
4365 | -- rewrite the expression with the actual value of the discriminant. | |
4366 | -- Don't do this on the left hand of an assignment statement (this | |
4367 | -- happens in generated code, and means we really want to set it!) | |
4368 | -- We also only do this optimization for discrete types, and not | |
4369 | -- for access types (access discriminants get us into trouble!) | |
4370 | -- We also do not expand the prefix of an attribute or the | |
4371 | -- operand of an object renaming declaration. | |
4372 | ||
4373 | if Is_Record_Type (Ptyp) | |
4374 | and then Has_Discriminants (Ptyp) | |
4375 | and then Is_Constrained (Ptyp) | |
4376 | and then Is_Discrete_Type (Etype (N)) | |
4377 | and then (Nkind (Par) /= N_Assignment_Statement | |
4378 | or else Name (Par) /= N) | |
4379 | and then (Nkind (Par) /= N_Attribute_Reference | |
4380 | or else Prefix (Par) /= N) | |
4381 | and then not Is_Renamed_Object (N) | |
4382 | then | |
4383 | declare | |
4384 | D : Entity_Id; | |
4385 | E : Elmt_Id; | |
4386 | ||
4387 | begin | |
4388 | D := First_Discriminant (Ptyp); | |
4389 | E := First_Elmt (Discriminant_Constraint (Ptyp)); | |
4390 | ||
4391 | while Present (E) loop | |
4392 | if D = Entity (Selector_Name (N)) then | |
4393 | ||
4394 | -- In the context of a case statement, the expression | |
4395 | -- may have the base type of the discriminant, and we | |
4396 | -- need to preserve the constraint to avoid spurious | |
4397 | -- errors on missing cases. | |
4398 | ||
4399 | if Nkind (Parent (N)) = N_Case_Statement | |
4400 | and then Etype (Node (E)) /= Etype (D) | |
4401 | then | |
4402 | Rewrite (N, | |
4403 | Make_Qualified_Expression (Loc, | |
4404 | Subtype_Mark => New_Occurrence_Of (Etype (D), Loc), | |
4405 | Expression => New_Copy (Node (E)))); | |
4406 | Analyze (N); | |
4407 | else | |
4408 | Rewrite (N, New_Copy (Node (E))); | |
4409 | end if; | |
4410 | ||
4411 | Set_Is_Static_Expression (N, False); | |
4412 | return; | |
4413 | end if; | |
4414 | ||
4415 | Next_Elmt (E); | |
4416 | Next_Discriminant (D); | |
4417 | end loop; | |
4418 | ||
4419 | -- Note: the above loop should always terminate, but if | |
4420 | -- it does not, we just missed an optimization due to | |
4421 | -- some glitch (perhaps a previous error), so ignore! | |
4422 | end; | |
4423 | end if; | |
4424 | ||
4425 | -- The only remaining processing is in the case of a discriminant of | |
4426 | -- a concurrent object, where we rewrite the prefix to denote the | |
4427 | -- corresponding record type. If the type is derived and has renamed | |
4428 | -- discriminants, use corresponding discriminant, which is the one | |
4429 | -- that appears in the corresponding record. | |
4430 | ||
4431 | if not Is_Concurrent_Type (Ptyp) then | |
4432 | return; | |
4433 | end if; | |
4434 | ||
4435 | Disc := Entity (Selector_Name (N)); | |
4436 | ||
4437 | if Is_Derived_Type (Ptyp) | |
4438 | and then Present (Corresponding_Discriminant (Disc)) | |
4439 | then | |
4440 | Disc := Corresponding_Discriminant (Disc); | |
4441 | end if; | |
4442 | ||
4443 | New_N := | |
4444 | Make_Selected_Component (Loc, | |
4445 | Prefix => | |
4446 | Unchecked_Convert_To (Corresponding_Record_Type (Ptyp), | |
4447 | New_Copy_Tree (P)), | |
4448 | Selector_Name => Make_Identifier (Loc, Chars (Disc))); | |
4449 | ||
4450 | Rewrite (N, New_N); | |
4451 | Analyze (N); | |
4452 | end if; | |
4453 | ||
4454 | end Expand_N_Selected_Component; | |
4455 | ||
4456 | -------------------- | |
4457 | -- Expand_N_Slice -- | |
4458 | -------------------- | |
4459 | ||
4460 | procedure Expand_N_Slice (N : Node_Id) is | |
4461 | Loc : constant Source_Ptr := Sloc (N); | |
4462 | Typ : constant Entity_Id := Etype (N); | |
4463 | Pfx : constant Node_Id := Prefix (N); | |
4464 | Ptp : Entity_Id := Etype (Pfx); | |
4465 | Ent : Entity_Id; | |
4466 | Decl : Node_Id; | |
4467 | ||
4468 | begin | |
4469 | -- Special handling for access types | |
4470 | ||
4471 | if Is_Access_Type (Ptp) then | |
4472 | ||
4473 | -- Check for explicit dereference required for checked pool | |
4474 | ||
4475 | Insert_Dereference_Action (Pfx); | |
4476 | ||
4477 | -- If we have an access to a packed array type, then put in an | |
4478 | -- explicit dereference. We do this in case the slice must be | |
4479 | -- expanded, and we want to make sure we get an access check. | |
4480 | ||
4481 | Ptp := Designated_Type (Ptp); | |
4482 | ||
4483 | if Is_Array_Type (Ptp) and then Is_Packed (Ptp) then | |
4484 | Rewrite (Pfx, | |
4485 | Make_Explicit_Dereference (Sloc (N), | |
4486 | Prefix => Relocate_Node (Pfx))); | |
4487 | ||
4488 | Analyze_And_Resolve (Pfx, Ptp); | |
4489 | ||
4490 | -- The prefix will now carry the Access_Check flag for the back | |
4491 | -- end, remove it from slice itself. | |
4492 | ||
4493 | Set_Do_Access_Check (N, False); | |
4494 | end if; | |
4495 | end if; | |
4496 | ||
4497 | -- Range checks are potentially also needed for cases involving | |
4498 | -- a slice indexed by a subtype indication, but Do_Range_Check | |
4499 | -- can currently only be set for expressions ??? | |
4500 | ||
4501 | if not Index_Checks_Suppressed (Ptp) | |
4502 | and then (not Is_Entity_Name (Pfx) | |
4503 | or else not Index_Checks_Suppressed (Entity (Pfx))) | |
4504 | and then Nkind (Discrete_Range (N)) /= N_Subtype_Indication | |
4505 | then | |
4506 | Enable_Range_Check (Discrete_Range (N)); | |
4507 | end if; | |
4508 | ||
4509 | -- The remaining case to be handled is packed slices. We can leave | |
4510 | -- packed slices as they are in the following situations: | |
4511 | ||
4512 | -- 1. Right or left side of an assignment (we can handle this | |
4513 | -- situation correctly in the assignment statement expansion). | |
4514 | ||
4515 | -- 2. Prefix of indexed component (the slide is optimized away | |
4516 | -- in this case, see the start of Expand_N_Slice. | |
4517 | ||
4518 | -- 3. Object renaming declaration, since we want the name of | |
4519 | -- the slice, not the value. | |
4520 | ||
4521 | -- 4. Argument to procedure call, since copy-in/copy-out handling | |
4522 | -- may be required, and this is handled in the expansion of | |
4523 | -- call itself. | |
4524 | ||
4525 | -- 5. Prefix of an address attribute (this is an error which | |
4526 | -- is caught elsewhere, and the expansion would intefere | |
4527 | -- with generating the error message). | |
4528 | ||
4529 | if Is_Packed (Typ) | |
4530 | and then Nkind (Parent (N)) /= N_Assignment_Statement | |
4531 | and then Nkind (Parent (N)) /= N_Indexed_Component | |
4532 | and then not Is_Renamed_Object (N) | |
4533 | and then Nkind (Parent (N)) /= N_Procedure_Call_Statement | |
4534 | and then (Nkind (Parent (N)) /= N_Attribute_Reference | |
4535 | or else | |
4536 | Attribute_Name (Parent (N)) /= Name_Address) | |
4537 | then | |
4538 | Ent := | |
4539 | Make_Defining_Identifier (Loc, New_Internal_Name ('T')); | |
4540 | ||
4541 | Decl := | |
4542 | Make_Object_Declaration (Loc, | |
4543 | Defining_Identifier => Ent, | |
4544 | Object_Definition => New_Occurrence_Of (Typ, Loc)); | |
4545 | ||
4546 | Set_No_Initialization (Decl); | |
4547 | ||
4548 | Insert_Actions (N, New_List ( | |
4549 | Decl, | |
4550 | Make_Assignment_Statement (Loc, | |
4551 | Name => New_Occurrence_Of (Ent, Loc), | |
4552 | Expression => Relocate_Node (N)))); | |
4553 | ||
4554 | Rewrite (N, New_Occurrence_Of (Ent, Loc)); | |
4555 | Analyze_And_Resolve (N, Typ); | |
4556 | end if; | |
4557 | end Expand_N_Slice; | |
4558 | ||
4559 | ------------------------------ | |
4560 | -- Expand_N_Type_Conversion -- | |
4561 | ------------------------------ | |
4562 | ||
4563 | procedure Expand_N_Type_Conversion (N : Node_Id) is | |
4564 | Loc : constant Source_Ptr := Sloc (N); | |
4565 | Operand : constant Node_Id := Expression (N); | |
4566 | Target_Type : constant Entity_Id := Etype (N); | |
4567 | Operand_Type : Entity_Id := Etype (Operand); | |
4568 | ||
4569 | procedure Handle_Changed_Representation; | |
4570 | -- This is called in the case of record and array type conversions | |
4571 | -- to see if there is a change of representation to be handled. | |
4572 | -- Change of representation is actually handled at the assignment | |
4573 | -- statement level, and what this procedure does is rewrite node N | |
4574 | -- conversion as an assignment to temporary. If there is no change | |
4575 | -- of representation, then the conversion node is unchanged. | |
4576 | ||
4577 | procedure Real_Range_Check; | |
4578 | -- Handles generation of range check for real target value | |
4579 | ||
4580 | ----------------------------------- | |
4581 | -- Handle_Changed_Representation -- | |
4582 | ----------------------------------- | |
4583 | ||
4584 | procedure Handle_Changed_Representation is | |
4585 | Temp : Entity_Id; | |
4586 | Decl : Node_Id; | |
4587 | Odef : Node_Id; | |
4588 | Disc : Node_Id; | |
4589 | N_Ix : Node_Id; | |
4590 | Cons : List_Id; | |
4591 | ||
4592 | begin | |
4593 | -- Nothing to do if no change of representation | |
4594 | ||
4595 | if Same_Representation (Operand_Type, Target_Type) then | |
4596 | return; | |
4597 | ||
4598 | -- The real change of representation work is done by the assignment | |
4599 | -- statement processing. So if this type conversion is appearing as | |
4600 | -- the expression of an assignment statement, nothing needs to be | |
4601 | -- done to the conversion. | |
4602 | ||
4603 | elsif Nkind (Parent (N)) = N_Assignment_Statement then | |
4604 | return; | |
4605 | ||
4606 | -- Otherwise we need to generate a temporary variable, and do the | |
4607 | -- change of representation assignment into that temporary variable. | |
4608 | -- The conversion is then replaced by a reference to this variable. | |
4609 | ||
4610 | else | |
4611 | Cons := No_List; | |
4612 | ||
4613 | -- If type is unconstrained we have to add a constraint, | |
4614 | -- copied from the actual value of the left hand side. | |
4615 | ||
4616 | if not Is_Constrained (Target_Type) then | |
4617 | if Has_Discriminants (Operand_Type) then | |
4618 | Disc := First_Discriminant (Operand_Type); | |
4619 | Cons := New_List; | |
4620 | while Present (Disc) loop | |
4621 | Append_To (Cons, | |
4622 | Make_Selected_Component (Loc, | |
4623 | Prefix => Duplicate_Subexpr (Operand), | |
4624 | Selector_Name => | |
4625 | Make_Identifier (Loc, Chars (Disc)))); | |
4626 | Next_Discriminant (Disc); | |
4627 | end loop; | |
4628 | ||
4629 | elsif Is_Array_Type (Operand_Type) then | |
4630 | N_Ix := First_Index (Target_Type); | |
4631 | Cons := New_List; | |
4632 | ||
4633 | for J in 1 .. Number_Dimensions (Operand_Type) loop | |
4634 | ||
4635 | -- We convert the bounds explicitly. We use an unchecked | |
4636 | -- conversion because bounds checks are done elsewhere. | |
4637 | ||
4638 | Append_To (Cons, | |
4639 | Make_Range (Loc, | |
4640 | Low_Bound => | |
4641 | Unchecked_Convert_To (Etype (N_Ix), | |
4642 | Make_Attribute_Reference (Loc, | |
4643 | Prefix => | |
4644 | Duplicate_Subexpr | |
4645 | (Operand, Name_Req => True), | |
4646 | Attribute_Name => Name_First, | |
4647 | Expressions => New_List ( | |
4648 | Make_Integer_Literal (Loc, J)))), | |
4649 | ||
4650 | High_Bound => | |
4651 | Unchecked_Convert_To (Etype (N_Ix), | |
4652 | Make_Attribute_Reference (Loc, | |
4653 | Prefix => | |
4654 | Duplicate_Subexpr | |
4655 | (Operand, Name_Req => True), | |
4656 | Attribute_Name => Name_Last, | |
4657 | Expressions => New_List ( | |
4658 | Make_Integer_Literal (Loc, J)))))); | |
4659 | ||
4660 | Next_Index (N_Ix); | |
4661 | end loop; | |
4662 | end if; | |
4663 | end if; | |
4664 | ||
4665 | Odef := New_Occurrence_Of (Target_Type, Loc); | |
4666 | ||
4667 | if Present (Cons) then | |
4668 | Odef := | |
4669 | Make_Subtype_Indication (Loc, | |
4670 | Subtype_Mark => Odef, | |
4671 | Constraint => | |
4672 | Make_Index_Or_Discriminant_Constraint (Loc, | |
4673 | Constraints => Cons)); | |
4674 | end if; | |
4675 | ||
4676 | Temp := Make_Defining_Identifier (Loc, New_Internal_Name ('C')); | |
4677 | Decl := | |
4678 | Make_Object_Declaration (Loc, | |
4679 | Defining_Identifier => Temp, | |
4680 | Object_Definition => Odef); | |
4681 | ||
4682 | Set_No_Initialization (Decl, True); | |
4683 | ||
4684 | -- Insert required actions. It is essential to suppress checks | |
4685 | -- since we have suppressed default initialization, which means | |
4686 | -- that the variable we create may have no discriminants. | |
4687 | ||
4688 | Insert_Actions (N, | |
4689 | New_List ( | |
4690 | Decl, | |
4691 | Make_Assignment_Statement (Loc, | |
4692 | Name => New_Occurrence_Of (Temp, Loc), | |
4693 | Expression => Relocate_Node (N))), | |
4694 | Suppress => All_Checks); | |
4695 | ||
4696 | Rewrite (N, New_Occurrence_Of (Temp, Loc)); | |
4697 | return; | |
4698 | end if; | |
4699 | end Handle_Changed_Representation; | |
4700 | ||
4701 | ---------------------- | |
4702 | -- Real_Range_Check -- | |
4703 | ---------------------- | |
4704 | ||
4705 | -- Case of conversions to floating-point or fixed-point. If range | |
4706 | -- checks are enabled and the target type has a range constraint, | |
4707 | -- we convert: | |
4708 | ||
4709 | -- typ (x) | |
4710 | ||
4711 | -- to | |
4712 | ||
4713 | -- Tnn : typ'Base := typ'Base (x); | |
4714 | -- [constraint_error when Tnn < typ'First or else Tnn > typ'Last] | |
4715 | -- Tnn | |
4716 | ||
4717 | procedure Real_Range_Check is | |
4718 | Btyp : constant Entity_Id := Base_Type (Target_Type); | |
4719 | Lo : constant Node_Id := Type_Low_Bound (Target_Type); | |
4720 | Hi : constant Node_Id := Type_High_Bound (Target_Type); | |
4721 | Conv : Node_Id; | |
4722 | Tnn : Entity_Id; | |
4723 | ||
4724 | begin | |
4725 | -- Nothing to do if conversion was rewritten | |
4726 | ||
4727 | if Nkind (N) /= N_Type_Conversion then | |
4728 | return; | |
4729 | end if; | |
4730 | ||
4731 | -- Nothing to do if range checks suppressed, or target has the | |
4732 | -- same range as the base type (or is the base type). | |
4733 | ||
4734 | if Range_Checks_Suppressed (Target_Type) | |
4735 | or else (Lo = Type_Low_Bound (Btyp) | |
4736 | and then | |
4737 | Hi = Type_High_Bound (Btyp)) | |
4738 | then | |
4739 | return; | |
4740 | end if; | |
4741 | ||
4742 | -- Nothing to do if expression is an entity on which checks | |
4743 | -- have been suppressed. | |
4744 | ||
4745 | if Is_Entity_Name (Expression (N)) | |
4746 | and then Range_Checks_Suppressed (Entity (Expression (N))) | |
4747 | then | |
4748 | return; | |
4749 | end if; | |
4750 | ||
4751 | -- Here we rewrite the conversion as described above | |
4752 | ||
4753 | Conv := Relocate_Node (N); | |
4754 | Rewrite | |
4755 | (Subtype_Mark (Conv), New_Occurrence_Of (Btyp, Loc)); | |
4756 | Set_Etype (Conv, Btyp); | |
4757 | ||
4758 | -- Skip overflow check for integer to float conversions, | |
4759 | -- since it is not needed, and in any case gigi generates | |
4760 | -- incorrect code for such overflow checks ??? | |
4761 | ||
4762 | if not Is_Integer_Type (Etype (Expression (N))) then | |
4763 | Set_Do_Overflow_Check (Conv, True); | |
4764 | end if; | |
4765 | ||
4766 | Tnn := | |
4767 | Make_Defining_Identifier (Loc, | |
4768 | Chars => New_Internal_Name ('T')); | |
4769 | ||
4770 | Insert_Actions (N, New_List ( | |
4771 | Make_Object_Declaration (Loc, | |
4772 | Defining_Identifier => Tnn, | |
4773 | Object_Definition => New_Occurrence_Of (Btyp, Loc), | |
4774 | Expression => Conv), | |
4775 | ||
4776 | Make_Raise_Constraint_Error (Loc, | |
07fc65c4 GB |
4777 | Condition => |
4778 | Make_Or_Else (Loc, | |
4779 | Left_Opnd => | |
4780 | Make_Op_Lt (Loc, | |
4781 | Left_Opnd => New_Occurrence_Of (Tnn, Loc), | |
4782 | Right_Opnd => | |
4783 | Make_Attribute_Reference (Loc, | |
4784 | Attribute_Name => Name_First, | |
4785 | Prefix => | |
4786 | New_Occurrence_Of (Target_Type, Loc))), | |
70482933 | 4787 | |
07fc65c4 GB |
4788 | Right_Opnd => |
4789 | Make_Op_Gt (Loc, | |
4790 | Left_Opnd => New_Occurrence_Of (Tnn, Loc), | |
4791 | Right_Opnd => | |
4792 | Make_Attribute_Reference (Loc, | |
4793 | Attribute_Name => Name_Last, | |
4794 | Prefix => | |
4795 | New_Occurrence_Of (Target_Type, Loc)))), | |
4796 | Reason => CE_Range_Check_Failed))); | |
70482933 RK |
4797 | |
4798 | Rewrite (N, New_Occurrence_Of (Tnn, Loc)); | |
4799 | Analyze_And_Resolve (N, Btyp); | |
4800 | end Real_Range_Check; | |
4801 | ||
4802 | -- Start of processing for Expand_N_Type_Conversion | |
4803 | ||
4804 | begin | |
4805 | -- Nothing at all to do if conversion is to the identical type | |
4806 | -- so remove the conversion completely, it is useless. | |
4807 | ||
4808 | if Operand_Type = Target_Type then | |
4809 | Rewrite (N, Relocate_Node (Expression (N))); | |
4810 | return; | |
4811 | end if; | |
4812 | ||
4813 | -- Deal with Vax floating-point cases | |
4814 | ||
4815 | if Vax_Float (Operand_Type) or else Vax_Float (Target_Type) then | |
4816 | Expand_Vax_Conversion (N); | |
4817 | return; | |
4818 | end if; | |
4819 | ||
4820 | -- Nothing to do if this is the second argument of read. This | |
4821 | -- is a "backwards" conversion that will be handled by the | |
4822 | -- specialized code in attribute processing. | |
4823 | ||
4824 | if Nkind (Parent (N)) = N_Attribute_Reference | |
4825 | and then Attribute_Name (Parent (N)) = Name_Read | |
4826 | and then Next (First (Expressions (Parent (N)))) = N | |
4827 | then | |
4828 | return; | |
4829 | end if; | |
4830 | ||
4831 | -- Here if we may need to expand conversion | |
4832 | ||
4833 | -- Special case of converting from non-standard boolean type | |
4834 | ||
4835 | if Is_Boolean_Type (Operand_Type) | |
4836 | and then (Nonzero_Is_True (Operand_Type)) | |
4837 | then | |
4838 | Adjust_Condition (Operand); | |
4839 | Set_Etype (Operand, Standard_Boolean); | |
4840 | Operand_Type := Standard_Boolean; | |
4841 | end if; | |
4842 | ||
4843 | -- Case of converting to an access type | |
4844 | ||
4845 | if Is_Access_Type (Target_Type) then | |
4846 | ||
4847 | -- Apply an accessibility check if the operand is an | |
4848 | -- access parameter. Note that other checks may still | |
4849 | -- need to be applied below (such as tagged type checks). | |
4850 | ||
4851 | if Is_Entity_Name (Operand) | |
4852 | and then Ekind (Entity (Operand)) in Formal_Kind | |
4853 | and then Ekind (Etype (Operand)) = E_Anonymous_Access_Type | |
4854 | then | |
4855 | Apply_Accessibility_Check (Operand, Target_Type); | |
4856 | ||
4857 | -- If the level of the operand type is statically deeper | |
4858 | -- then the level of the target type, then force Program_Error. | |
4859 | -- Note that this can only occur for cases where the attribute | |
4860 | -- is within the body of an instantiation (otherwise the | |
4861 | -- conversion will already have been rejected as illegal). | |
4862 | -- Note: warnings are issued by the analyzer for the instance | |
4863 | -- cases. | |
4864 | ||
4865 | elsif In_Instance_Body | |
07fc65c4 GB |
4866 | and then Type_Access_Level (Operand_Type) > |
4867 | Type_Access_Level (Target_Type) | |
70482933 | 4868 | then |
07fc65c4 GB |
4869 | Rewrite (N, |
4870 | Make_Raise_Program_Error (Sloc (N), | |
4871 | Reason => PE_Accessibility_Check_Failed)); | |
70482933 RK |
4872 | Set_Etype (N, Target_Type); |
4873 | ||
4874 | -- When the operand is a selected access discriminant | |
4875 | -- the check needs to be made against the level of the | |
4876 | -- object denoted by the prefix of the selected name. | |
4877 | -- Force Program_Error for this case as well (this | |
4878 | -- accessibility violation can only happen if within | |
4879 | -- the body of an instantiation). | |
4880 | ||
4881 | elsif In_Instance_Body | |
4882 | and then Ekind (Operand_Type) = E_Anonymous_Access_Type | |
4883 | and then Nkind (Operand) = N_Selected_Component | |
4884 | and then Object_Access_Level (Operand) > | |
4885 | Type_Access_Level (Target_Type) | |
4886 | then | |
07fc65c4 GB |
4887 | Rewrite (N, |
4888 | Make_Raise_Program_Error (Sloc (N), | |
4889 | Reason => PE_Accessibility_Check_Failed)); | |
70482933 RK |
4890 | Set_Etype (N, Target_Type); |
4891 | end if; | |
4892 | end if; | |
4893 | ||
4894 | -- Case of conversions of tagged types and access to tagged types | |
4895 | ||
4896 | -- When needed, that is to say when the expression is class-wide, | |
4897 | -- Add runtime a tag check for (strict) downward conversion by using | |
4898 | -- the membership test, generating: | |
4899 | ||
4900 | -- [constraint_error when Operand not in Target_Type'Class] | |
4901 | ||
4902 | -- or in the access type case | |
4903 | ||
4904 | -- [constraint_error | |
4905 | -- when Operand /= null | |
4906 | -- and then Operand.all not in | |
4907 | -- Designated_Type (Target_Type)'Class] | |
4908 | ||
4909 | if (Is_Access_Type (Target_Type) | |
4910 | and then Is_Tagged_Type (Designated_Type (Target_Type))) | |
4911 | or else Is_Tagged_Type (Target_Type) | |
4912 | then | |
4913 | -- Do not do any expansion in the access type case if the | |
4914 | -- parent is a renaming, since this is an error situation | |
4915 | -- which will be caught by Sem_Ch8, and the expansion can | |
4916 | -- intefere with this error check. | |
4917 | ||
4918 | if Is_Access_Type (Target_Type) | |
4919 | and then Is_Renamed_Object (N) | |
4920 | then | |
4921 | return; | |
4922 | end if; | |
4923 | ||
4924 | -- Oherwise, proceed with processing tagged conversion | |
4925 | ||
4926 | declare | |
4927 | Actual_Operand_Type : Entity_Id; | |
4928 | Actual_Target_Type : Entity_Id; | |
4929 | ||
4930 | Cond : Node_Id; | |
4931 | ||
4932 | begin | |
4933 | if Is_Access_Type (Target_Type) then | |
4934 | Actual_Operand_Type := Designated_Type (Operand_Type); | |
4935 | Actual_Target_Type := Designated_Type (Target_Type); | |
4936 | ||
4937 | else | |
4938 | Actual_Operand_Type := Operand_Type; | |
4939 | Actual_Target_Type := Target_Type; | |
4940 | end if; | |
4941 | ||
4942 | if Is_Class_Wide_Type (Actual_Operand_Type) | |
4943 | and then Root_Type (Actual_Operand_Type) /= Actual_Target_Type | |
4944 | and then Is_Ancestor | |
4945 | (Root_Type (Actual_Operand_Type), | |
4946 | Actual_Target_Type) | |
4947 | and then not Tag_Checks_Suppressed (Actual_Target_Type) | |
4948 | then | |
4949 | -- The conversion is valid for any descendant of the | |
4950 | -- target type | |
4951 | ||
4952 | Actual_Target_Type := Class_Wide_Type (Actual_Target_Type); | |
4953 | ||
4954 | if Is_Access_Type (Target_Type) then | |
4955 | Cond := | |
4956 | Make_And_Then (Loc, | |
4957 | Left_Opnd => | |
4958 | Make_Op_Ne (Loc, | |
4959 | Left_Opnd => Duplicate_Subexpr (Operand), | |
4960 | Right_Opnd => Make_Null (Loc)), | |
4961 | ||
4962 | Right_Opnd => | |
4963 | Make_Not_In (Loc, | |
4964 | Left_Opnd => | |
4965 | Make_Explicit_Dereference (Loc, | |
4966 | Prefix => Duplicate_Subexpr (Operand)), | |
4967 | Right_Opnd => | |
4968 | New_Reference_To (Actual_Target_Type, Loc))); | |
4969 | ||
4970 | else | |
4971 | Cond := | |
4972 | Make_Not_In (Loc, | |
4973 | Left_Opnd => Duplicate_Subexpr (Operand), | |
4974 | Right_Opnd => | |
4975 | New_Reference_To (Actual_Target_Type, Loc)); | |
4976 | end if; | |
4977 | ||
4978 | Insert_Action (N, | |
4979 | Make_Raise_Constraint_Error (Loc, | |
07fc65c4 GB |
4980 | Condition => Cond, |
4981 | Reason => CE_Tag_Check_Failed)); | |
70482933 RK |
4982 | |
4983 | Change_Conversion_To_Unchecked (N); | |
4984 | Analyze_And_Resolve (N, Target_Type); | |
4985 | end if; | |
4986 | end; | |
4987 | ||
4988 | -- Case of other access type conversions | |
4989 | ||
4990 | elsif Is_Access_Type (Target_Type) then | |
4991 | Apply_Constraint_Check (Operand, Target_Type); | |
4992 | ||
4993 | -- Case of conversions from a fixed-point type | |
4994 | ||
4995 | -- These conversions require special expansion and processing, found | |
4996 | -- in the Exp_Fixd package. We ignore cases where Conversion_OK is | |
4997 | -- set, since from a semantic point of view, these are simple integer | |
4998 | -- conversions, which do not need further processing. | |
4999 | ||
5000 | elsif Is_Fixed_Point_Type (Operand_Type) | |
5001 | and then not Conversion_OK (N) | |
5002 | then | |
5003 | -- We should never see universal fixed at this case, since the | |
5004 | -- expansion of the constituent divide or multiply should have | |
5005 | -- eliminated the explicit mention of universal fixed. | |
5006 | ||
5007 | pragma Assert (Operand_Type /= Universal_Fixed); | |
5008 | ||
5009 | -- Check for special case of the conversion to universal real | |
5010 | -- that occurs as a result of the use of a round attribute. | |
5011 | -- In this case, the real type for the conversion is taken | |
5012 | -- from the target type of the Round attribute and the | |
5013 | -- result must be marked as rounded. | |
5014 | ||
5015 | if Target_Type = Universal_Real | |
5016 | and then Nkind (Parent (N)) = N_Attribute_Reference | |
5017 | and then Attribute_Name (Parent (N)) = Name_Round | |
5018 | then | |
5019 | Set_Rounded_Result (N); | |
5020 | Set_Etype (N, Etype (Parent (N))); | |
5021 | end if; | |
5022 | ||
5023 | -- Otherwise do correct fixed-conversion, but skip these if the | |
5024 | -- Conversion_OK flag is set, because from a semantic point of | |
5025 | -- view these are simple integer conversions needing no further | |
5026 | -- processing (the backend will simply treat them as integers) | |
5027 | ||
5028 | if not Conversion_OK (N) then | |
5029 | if Is_Fixed_Point_Type (Etype (N)) then | |
5030 | Expand_Convert_Fixed_To_Fixed (N); | |
5031 | Real_Range_Check; | |
5032 | ||
5033 | elsif Is_Integer_Type (Etype (N)) then | |
5034 | Expand_Convert_Fixed_To_Integer (N); | |
5035 | ||
5036 | else | |
5037 | pragma Assert (Is_Floating_Point_Type (Etype (N))); | |
5038 | Expand_Convert_Fixed_To_Float (N); | |
5039 | Real_Range_Check; | |
5040 | end if; | |
5041 | end if; | |
5042 | ||
5043 | -- Case of conversions to a fixed-point type | |
5044 | ||
5045 | -- These conversions require special expansion and processing, found | |
5046 | -- in the Exp_Fixd package. Again, ignore cases where Conversion_OK | |
5047 | -- is set, since from a semantic point of view, these are simple | |
5048 | -- integer conversions, which do not need further processing. | |
5049 | ||
5050 | elsif Is_Fixed_Point_Type (Target_Type) | |
5051 | and then not Conversion_OK (N) | |
5052 | then | |
5053 | if Is_Integer_Type (Operand_Type) then | |
5054 | Expand_Convert_Integer_To_Fixed (N); | |
5055 | Real_Range_Check; | |
5056 | else | |
5057 | pragma Assert (Is_Floating_Point_Type (Operand_Type)); | |
5058 | Expand_Convert_Float_To_Fixed (N); | |
5059 | Real_Range_Check; | |
5060 | end if; | |
5061 | ||
5062 | -- Case of float-to-integer conversions | |
5063 | ||
5064 | -- We also handle float-to-fixed conversions with Conversion_OK set | |
5065 | -- since semantically the fixed-point target is treated as though it | |
5066 | -- were an integer in such cases. | |
5067 | ||
5068 | elsif Is_Floating_Point_Type (Operand_Type) | |
5069 | and then | |
5070 | (Is_Integer_Type (Target_Type) | |
5071 | or else | |
5072 | (Is_Fixed_Point_Type (Target_Type) and then Conversion_OK (N))) | |
5073 | then | |
5074 | -- Special processing required if the conversion is the expression | |
5075 | -- of a Truncation attribute reference. In this case we replace: | |
5076 | ||
5077 | -- ityp (ftyp'Truncation (x)) | |
5078 | ||
5079 | -- by | |
5080 | ||
5081 | -- ityp (x) | |
5082 | ||
5083 | -- with the Float_Truncate flag set. This is clearly more efficient. | |
5084 | ||
5085 | if Nkind (Operand) = N_Attribute_Reference | |
5086 | and then Attribute_Name (Operand) = Name_Truncation | |
5087 | then | |
5088 | Rewrite (Operand, | |
5089 | Relocate_Node (First (Expressions (Operand)))); | |
5090 | Set_Float_Truncate (N, True); | |
5091 | end if; | |
5092 | ||
5093 | -- One more check here, gcc is still not able to do conversions of | |
5094 | -- this type with proper overflow checking, and so gigi is doing an | |
5095 | -- approximation of what is required by doing floating-point compares | |
5096 | -- with the end-point. But that can lose precision in some cases, and | |
5097 | -- give a wrong result. Converting the operand to Long_Long_Float is | |
5098 | -- helpful, but still does not catch all cases with 64-bit integers | |
5099 | -- on targets with only 64-bit floats ??? | |
5100 | ||
5101 | if Do_Range_Check (Expression (N)) then | |
5102 | Rewrite (Expression (N), | |
5103 | Make_Type_Conversion (Loc, | |
5104 | Subtype_Mark => | |
5105 | New_Occurrence_Of (Standard_Long_Long_Float, Loc), | |
5106 | Expression => | |
5107 | Relocate_Node (Expression (N)))); | |
5108 | ||
5109 | Set_Etype (Expression (N), Standard_Long_Long_Float); | |
5110 | Enable_Range_Check (Expression (N)); | |
5111 | Set_Do_Range_Check (Expression (Expression (N)), False); | |
5112 | end if; | |
5113 | ||
5114 | -- Case of array conversions | |
5115 | ||
5116 | -- Expansion of array conversions, add required length/range checks | |
5117 | -- but only do this if there is no change of representation. For | |
5118 | -- handling of this case, see Handle_Changed_Representation. | |
5119 | ||
5120 | elsif Is_Array_Type (Target_Type) then | |
5121 | ||
5122 | if Is_Constrained (Target_Type) then | |
5123 | Apply_Length_Check (Operand, Target_Type); | |
5124 | else | |
5125 | Apply_Range_Check (Operand, Target_Type); | |
5126 | end if; | |
5127 | ||
5128 | Handle_Changed_Representation; | |
5129 | ||
5130 | -- Case of conversions of discriminated types | |
5131 | ||
5132 | -- Add required discriminant checks if target is constrained. Again | |
5133 | -- this change is skipped if we have a change of representation. | |
5134 | ||
5135 | elsif Has_Discriminants (Target_Type) | |
5136 | and then Is_Constrained (Target_Type) | |
5137 | then | |
5138 | Apply_Discriminant_Check (Operand, Target_Type); | |
5139 | Handle_Changed_Representation; | |
5140 | ||
5141 | -- Case of all other record conversions. The only processing required | |
5142 | -- is to check for a change of representation requiring the special | |
5143 | -- assignment processing. | |
5144 | ||
5145 | elsif Is_Record_Type (Target_Type) then | |
5146 | Handle_Changed_Representation; | |
5147 | ||
5148 | -- Case of conversions of enumeration types | |
5149 | ||
5150 | elsif Is_Enumeration_Type (Target_Type) then | |
5151 | ||
5152 | -- Special processing is required if there is a change of | |
5153 | -- representation (from enumeration representation clauses) | |
5154 | ||
5155 | if not Same_Representation (Target_Type, Operand_Type) then | |
5156 | ||
5157 | -- Convert: x(y) to x'val (ytyp'val (y)) | |
5158 | ||
5159 | Rewrite (N, | |
5160 | Make_Attribute_Reference (Loc, | |
5161 | Prefix => New_Occurrence_Of (Target_Type, Loc), | |
5162 | Attribute_Name => Name_Val, | |
5163 | Expressions => New_List ( | |
5164 | Make_Attribute_Reference (Loc, | |
5165 | Prefix => New_Occurrence_Of (Operand_Type, Loc), | |
5166 | Attribute_Name => Name_Pos, | |
5167 | Expressions => New_List (Operand))))); | |
5168 | ||
5169 | Analyze_And_Resolve (N, Target_Type); | |
5170 | end if; | |
5171 | ||
5172 | -- Case of conversions to floating-point | |
5173 | ||
5174 | elsif Is_Floating_Point_Type (Target_Type) then | |
5175 | Real_Range_Check; | |
5176 | ||
5177 | -- The remaining cases require no front end processing | |
5178 | ||
5179 | else | |
5180 | null; | |
5181 | end if; | |
5182 | ||
5183 | -- At this stage, either the conversion node has been transformed | |
5184 | -- into some other equivalent expression, or left as a conversion | |
5185 | -- that can be handled by Gigi. The conversions that Gigi can handle | |
5186 | -- are the following: | |
5187 | ||
5188 | -- Conversions with no change of representation or type | |
5189 | ||
5190 | -- Numeric conversions involving integer values, floating-point | |
5191 | -- values, and fixed-point values. Fixed-point values are allowed | |
5192 | -- only if Conversion_OK is set, i.e. if the fixed-point values | |
5193 | -- are to be treated as integers. | |
5194 | ||
5195 | -- No other conversions should be passed to Gigi. | |
5196 | ||
5197 | end Expand_N_Type_Conversion; | |
5198 | ||
5199 | ----------------------------------- | |
5200 | -- Expand_N_Unchecked_Expression -- | |
5201 | ----------------------------------- | |
5202 | ||
5203 | -- Remove the unchecked expression node from the tree. It's job was simply | |
5204 | -- to make sure that its constituent expression was handled with checks | |
5205 | -- off, and now that that is done, we can remove it from the tree, and | |
5206 | -- indeed must, since gigi does not expect to see these nodes. | |
5207 | ||
5208 | procedure Expand_N_Unchecked_Expression (N : Node_Id) is | |
5209 | Exp : constant Node_Id := Expression (N); | |
5210 | ||
5211 | begin | |
5212 | Set_Assignment_OK (Exp, Assignment_OK (N) or Assignment_OK (Exp)); | |
5213 | Rewrite (N, Exp); | |
5214 | end Expand_N_Unchecked_Expression; | |
5215 | ||
5216 | ---------------------------------------- | |
5217 | -- Expand_N_Unchecked_Type_Conversion -- | |
5218 | ---------------------------------------- | |
5219 | ||
5220 | -- If this cannot be handled by Gigi and we haven't already made | |
5221 | -- a temporary for it, do it now. | |
5222 | ||
5223 | procedure Expand_N_Unchecked_Type_Conversion (N : Node_Id) is | |
5224 | Target_Type : constant Entity_Id := Etype (N); | |
5225 | Operand : constant Node_Id := Expression (N); | |
5226 | Operand_Type : constant Entity_Id := Etype (Operand); | |
5227 | ||
5228 | begin | |
5229 | -- If we have a conversion of a compile time known value to a target | |
5230 | -- type and the value is in range of the target type, then we can simply | |
5231 | -- replace the construct by an integer literal of the correct type. We | |
5232 | -- only apply this to integer types being converted. Possibly it may | |
5233 | -- apply in other cases, but it is too much trouble to worry about. | |
5234 | ||
5235 | -- Note that we do not do this transformation if the Kill_Range_Check | |
5236 | -- flag is set, since then the value may be outside the expected range. | |
5237 | -- This happens in the Normalize_Scalars case. | |
5238 | ||
5239 | if Is_Integer_Type (Target_Type) | |
5240 | and then Is_Integer_Type (Operand_Type) | |
5241 | and then Compile_Time_Known_Value (Operand) | |
5242 | and then not Kill_Range_Check (N) | |
5243 | then | |
5244 | declare | |
5245 | Val : constant Uint := Expr_Value (Operand); | |
5246 | ||
5247 | begin | |
5248 | if Compile_Time_Known_Value (Type_Low_Bound (Target_Type)) | |
5249 | and then | |
5250 | Compile_Time_Known_Value (Type_High_Bound (Target_Type)) | |
5251 | and then | |
5252 | Val >= Expr_Value (Type_Low_Bound (Target_Type)) | |
5253 | and then | |
5254 | Val <= Expr_Value (Type_High_Bound (Target_Type)) | |
5255 | then | |
5256 | Rewrite (N, Make_Integer_Literal (Sloc (N), Val)); | |
5257 | Analyze_And_Resolve (N, Target_Type); | |
5258 | return; | |
5259 | end if; | |
5260 | end; | |
5261 | end if; | |
5262 | ||
5263 | -- Nothing to do if conversion is safe | |
5264 | ||
5265 | if Safe_Unchecked_Type_Conversion (N) then | |
5266 | return; | |
5267 | end if; | |
5268 | ||
5269 | -- Otherwise force evaluation unless Assignment_OK flag is set (this | |
5270 | -- flag indicates ??? -- more comments needed here) | |
5271 | ||
5272 | if Assignment_OK (N) then | |
5273 | null; | |
5274 | else | |
5275 | Force_Evaluation (N); | |
5276 | end if; | |
5277 | end Expand_N_Unchecked_Type_Conversion; | |
5278 | ||
5279 | ---------------------------- | |
5280 | -- Expand_Record_Equality -- | |
5281 | ---------------------------- | |
5282 | ||
5283 | -- For non-variant records, Equality is expanded when needed into: | |
5284 | ||
5285 | -- and then Lhs.Discr1 = Rhs.Discr1 | |
5286 | -- and then ... | |
5287 | -- and then Lhs.Discrn = Rhs.Discrn | |
5288 | -- and then Lhs.Cmp1 = Rhs.Cmp1 | |
5289 | -- and then ... | |
5290 | -- and then Lhs.Cmpn = Rhs.Cmpn | |
5291 | ||
5292 | -- The expression is folded by the back-end for adjacent fields. This | |
5293 | -- function is called for tagged record in only one occasion: for imple- | |
5294 | -- menting predefined primitive equality (see Predefined_Primitives_Bodies) | |
5295 | -- otherwise the primitive "=" is used directly. | |
5296 | ||
5297 | function Expand_Record_Equality | |
5298 | (Nod : Node_Id; | |
5299 | Typ : Entity_Id; | |
5300 | Lhs : Node_Id; | |
5301 | Rhs : Node_Id; | |
5302 | Bodies : List_Id) | |
5303 | return Node_Id | |
5304 | is | |
5305 | Loc : constant Source_Ptr := Sloc (Nod); | |
5306 | ||
5307 | function Suitable_Element (C : Entity_Id) return Entity_Id; | |
5308 | -- Return the first field to compare beginning with C, skipping the | |
5309 | -- inherited components | |
5310 | ||
5311 | function Suitable_Element (C : Entity_Id) return Entity_Id is | |
5312 | begin | |
5313 | if No (C) then | |
5314 | return Empty; | |
5315 | ||
5316 | elsif Ekind (C) /= E_Discriminant | |
5317 | and then Ekind (C) /= E_Component | |
5318 | then | |
5319 | return Suitable_Element (Next_Entity (C)); | |
5320 | ||
5321 | elsif Is_Tagged_Type (Typ) | |
5322 | and then C /= Original_Record_Component (C) | |
5323 | then | |
5324 | return Suitable_Element (Next_Entity (C)); | |
5325 | ||
5326 | elsif Chars (C) = Name_uController | |
5327 | or else Chars (C) = Name_uTag | |
5328 | then | |
5329 | return Suitable_Element (Next_Entity (C)); | |
5330 | ||
5331 | else | |
5332 | return C; | |
5333 | end if; | |
5334 | end Suitable_Element; | |
5335 | ||
5336 | Result : Node_Id; | |
5337 | C : Entity_Id; | |
5338 | ||
5339 | First_Time : Boolean := True; | |
5340 | ||
5341 | -- Start of processing for Expand_Record_Equality | |
5342 | ||
5343 | begin | |
5344 | -- Special processing for the unchecked union case, which will occur | |
5345 | -- only in the context of tagged types and dynamic dispatching, since | |
5346 | -- other cases are handled statically. We return True, but insert a | |
5347 | -- raise Program_Error statement. | |
5348 | ||
5349 | if Is_Unchecked_Union (Typ) then | |
5350 | ||
5351 | -- If this is a component of an enclosing record, return the Raise | |
5352 | -- statement directly. | |
5353 | ||
5354 | if No (Parent (Lhs)) then | |
07fc65c4 GB |
5355 | Result := |
5356 | Make_Raise_Program_Error (Loc, | |
5357 | Reason => PE_Unchecked_Union_Restriction); | |
70482933 RK |
5358 | Set_Etype (Result, Standard_Boolean); |
5359 | return Result; | |
5360 | ||
5361 | else | |
5362 | Insert_Action (Lhs, | |
07fc65c4 GB |
5363 | Make_Raise_Program_Error (Loc, |
5364 | Reason => PE_Unchecked_Union_Restriction)); | |
70482933 RK |
5365 | return New_Occurrence_Of (Standard_True, Loc); |
5366 | end if; | |
5367 | end if; | |
5368 | ||
5369 | -- Generates the following code: (assuming that Typ has one Discr and | |
5370 | -- component C2 is also a record) | |
5371 | ||
5372 | -- True | |
5373 | -- and then Lhs.Discr1 = Rhs.Discr1 | |
5374 | -- and then Lhs.C1 = Rhs.C1 | |
5375 | -- and then Lhs.C2.C1=Rhs.C2.C1 and then ... Lhs.C2.Cn=Rhs.C2.Cn | |
5376 | -- and then ... | |
5377 | -- and then Lhs.Cmpn = Rhs.Cmpn | |
5378 | ||
5379 | Result := New_Reference_To (Standard_True, Loc); | |
5380 | C := Suitable_Element (First_Entity (Typ)); | |
5381 | ||
5382 | while Present (C) loop | |
5383 | ||
5384 | declare | |
5385 | New_Lhs : Node_Id; | |
5386 | New_Rhs : Node_Id; | |
5387 | ||
5388 | begin | |
5389 | if First_Time then | |
5390 | First_Time := False; | |
5391 | New_Lhs := Lhs; | |
5392 | New_Rhs := Rhs; | |
5393 | ||
5394 | else | |
5395 | New_Lhs := New_Copy_Tree (Lhs); | |
5396 | New_Rhs := New_Copy_Tree (Rhs); | |
5397 | end if; | |
5398 | ||
5399 | Result := | |
5400 | Make_And_Then (Loc, | |
5401 | Left_Opnd => Result, | |
5402 | Right_Opnd => | |
5403 | Expand_Composite_Equality (Nod, Etype (C), | |
5404 | Lhs => | |
5405 | Make_Selected_Component (Loc, | |
5406 | Prefix => New_Lhs, | |
5407 | Selector_Name => New_Reference_To (C, Loc)), | |
5408 | Rhs => | |
5409 | Make_Selected_Component (Loc, | |
5410 | Prefix => New_Rhs, | |
5411 | Selector_Name => New_Reference_To (C, Loc)), | |
5412 | Bodies => Bodies)); | |
5413 | end; | |
5414 | ||
5415 | C := Suitable_Element (Next_Entity (C)); | |
5416 | end loop; | |
5417 | ||
5418 | return Result; | |
5419 | end Expand_Record_Equality; | |
5420 | ||
5421 | ------------------------------------- | |
5422 | -- Fixup_Universal_Fixed_Operation -- | |
5423 | ------------------------------------- | |
5424 | ||
5425 | procedure Fixup_Universal_Fixed_Operation (N : Node_Id) is | |
5426 | Conv : constant Node_Id := Parent (N); | |
5427 | ||
5428 | begin | |
5429 | -- We must have a type conversion immediately above us | |
5430 | ||
5431 | pragma Assert (Nkind (Conv) = N_Type_Conversion); | |
5432 | ||
5433 | -- Normally the type conversion gives our target type. The exception | |
5434 | -- occurs in the case of the Round attribute, where the conversion | |
5435 | -- will be to universal real, and our real type comes from the Round | |
5436 | -- attribute (as well as an indication that we must round the result) | |
5437 | ||
5438 | if Nkind (Parent (Conv)) = N_Attribute_Reference | |
5439 | and then Attribute_Name (Parent (Conv)) = Name_Round | |
5440 | then | |
5441 | Set_Etype (N, Etype (Parent (Conv))); | |
5442 | Set_Rounded_Result (N); | |
5443 | ||
5444 | -- Normal case where type comes from conversion above us | |
5445 | ||
5446 | else | |
5447 | Set_Etype (N, Etype (Conv)); | |
5448 | end if; | |
5449 | end Fixup_Universal_Fixed_Operation; | |
5450 | ||
5451 | ------------------------------- | |
5452 | -- Insert_Dereference_Action -- | |
5453 | ------------------------------- | |
5454 | ||
5455 | procedure Insert_Dereference_Action (N : Node_Id) is | |
5456 | Loc : constant Source_Ptr := Sloc (N); | |
5457 | Typ : constant Entity_Id := Etype (N); | |
5458 | Pool : constant Entity_Id := Associated_Storage_Pool (Typ); | |
5459 | ||
5460 | function Is_Checked_Storage_Pool (P : Entity_Id) return Boolean; | |
5461 | -- return true if type of P is derived from Checked_Pool; | |
5462 | ||
5463 | function Is_Checked_Storage_Pool (P : Entity_Id) return Boolean is | |
5464 | T : Entity_Id; | |
5465 | ||
5466 | begin | |
5467 | if No (P) then | |
5468 | return False; | |
5469 | end if; | |
5470 | ||
5471 | T := Etype (P); | |
5472 | while T /= Etype (T) loop | |
5473 | if Is_RTE (T, RE_Checked_Pool) then | |
5474 | return True; | |
5475 | else | |
5476 | T := Etype (T); | |
5477 | end if; | |
5478 | end loop; | |
5479 | ||
5480 | return False; | |
5481 | end Is_Checked_Storage_Pool; | |
5482 | ||
5483 | -- Start of processing for Insert_Dereference_Action | |
5484 | ||
5485 | begin | |
5486 | if not Comes_From_Source (Parent (N)) then | |
5487 | return; | |
5488 | ||
5489 | elsif not Is_Checked_Storage_Pool (Pool) then | |
5490 | return; | |
5491 | end if; | |
5492 | ||
5493 | Insert_Action (N, | |
5494 | Make_Procedure_Call_Statement (Loc, | |
5495 | Name => New_Reference_To ( | |
5496 | Find_Prim_Op (Etype (Pool), Name_Dereference), Loc), | |
5497 | ||
5498 | Parameter_Associations => New_List ( | |
5499 | ||
5500 | -- Pool | |
5501 | ||
5502 | New_Reference_To (Pool, Loc), | |
5503 | ||
5504 | -- Storage_Address | |
5505 | ||
5506 | Make_Attribute_Reference (Loc, | |
5507 | Prefix => | |
5508 | Make_Explicit_Dereference (Loc, Duplicate_Subexpr (N)), | |
5509 | Attribute_Name => Name_Address), | |
5510 | ||
5511 | -- Size_In_Storage_Elements | |
5512 | ||
5513 | Make_Op_Divide (Loc, | |
5514 | Left_Opnd => | |
5515 | Make_Attribute_Reference (Loc, | |
5516 | Prefix => | |
5517 | Make_Explicit_Dereference (Loc, Duplicate_Subexpr (N)), | |
5518 | Attribute_Name => Name_Size), | |
5519 | Right_Opnd => | |
5520 | Make_Integer_Literal (Loc, System_Storage_Unit)), | |
5521 | ||
5522 | -- Alignment | |
5523 | ||
5524 | Make_Attribute_Reference (Loc, | |
5525 | Prefix => | |
5526 | Make_Explicit_Dereference (Loc, Duplicate_Subexpr (N)), | |
5527 | Attribute_Name => Name_Alignment)))); | |
5528 | ||
5529 | end Insert_Dereference_Action; | |
5530 | ||
5531 | ------------------------------ | |
5532 | -- Make_Array_Comparison_Op -- | |
5533 | ------------------------------ | |
5534 | ||
5535 | -- This is a hand-coded expansion of the following generic function: | |
5536 | ||
5537 | -- generic | |
5538 | -- type elem is (<>); | |
5539 | -- type index is (<>); | |
5540 | -- type a is array (index range <>) of elem; | |
5541 | -- | |
5542 | -- function Gnnn (X : a; Y: a) return boolean is | |
5543 | -- J : index := Y'first; | |
5544 | -- | |
5545 | -- begin | |
5546 | -- if X'length = 0 then | |
5547 | -- return false; | |
5548 | -- | |
5549 | -- elsif Y'length = 0 then | |
5550 | -- return true; | |
5551 | -- | |
5552 | -- else | |
5553 | -- for I in X'range loop | |
5554 | -- if X (I) = Y (J) then | |
5555 | -- if J = Y'last then | |
5556 | -- exit; | |
5557 | -- else | |
5558 | -- J := index'succ (J); | |
5559 | -- end if; | |
5560 | -- | |
5561 | -- else | |
5562 | -- return X (I) > Y (J); | |
5563 | -- end if; | |
5564 | -- end loop; | |
5565 | -- | |
5566 | -- return X'length > Y'length; | |
5567 | -- end if; | |
5568 | -- end Gnnn; | |
5569 | ||
5570 | -- Note that since we are essentially doing this expansion by hand, we | |
5571 | -- do not need to generate an actual or formal generic part, just the | |
5572 | -- instantiated function itself. | |
5573 | ||
5574 | function Make_Array_Comparison_Op | |
5575 | (Typ : Entity_Id; | |
5576 | Nod : Node_Id) | |
5577 | return Node_Id | |
5578 | is | |
5579 | Loc : constant Source_Ptr := Sloc (Nod); | |
5580 | ||
5581 | X : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uX); | |
5582 | Y : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uY); | |
5583 | I : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uI); | |
5584 | J : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uJ); | |
5585 | ||
5586 | Index : constant Entity_Id := Base_Type (Etype (First_Index (Typ))); | |
5587 | ||
5588 | Loop_Statement : Node_Id; | |
5589 | Loop_Body : Node_Id; | |
5590 | If_Stat : Node_Id; | |
5591 | Inner_If : Node_Id; | |
5592 | Final_Expr : Node_Id; | |
5593 | Func_Body : Node_Id; | |
5594 | Func_Name : Entity_Id; | |
5595 | Formals : List_Id; | |
5596 | Length1 : Node_Id; | |
5597 | Length2 : Node_Id; | |
5598 | ||
5599 | begin | |
5600 | -- if J = Y'last then | |
5601 | -- exit; | |
5602 | -- else | |
5603 | -- J := index'succ (J); | |
5604 | -- end if; | |
5605 | ||
5606 | Inner_If := | |
5607 | Make_Implicit_If_Statement (Nod, | |
5608 | Condition => | |
5609 | Make_Op_Eq (Loc, | |
5610 | Left_Opnd => New_Reference_To (J, Loc), | |
5611 | Right_Opnd => | |
5612 | Make_Attribute_Reference (Loc, | |
5613 | Prefix => New_Reference_To (Y, Loc), | |
5614 | Attribute_Name => Name_Last)), | |
5615 | ||
5616 | Then_Statements => New_List ( | |
5617 | Make_Exit_Statement (Loc)), | |
5618 | ||
5619 | Else_Statements => | |
5620 | New_List ( | |
5621 | Make_Assignment_Statement (Loc, | |
5622 | Name => New_Reference_To (J, Loc), | |
5623 | Expression => | |
5624 | Make_Attribute_Reference (Loc, | |
5625 | Prefix => New_Reference_To (Index, Loc), | |
5626 | Attribute_Name => Name_Succ, | |
5627 | Expressions => New_List (New_Reference_To (J, Loc)))))); | |
5628 | ||
5629 | -- if X (I) = Y (J) then | |
5630 | -- if ... end if; | |
5631 | -- else | |
5632 | -- return X (I) > Y (J); | |
5633 | -- end if; | |
5634 | ||
5635 | Loop_Body := | |
5636 | Make_Implicit_If_Statement (Nod, | |
5637 | Condition => | |
5638 | Make_Op_Eq (Loc, | |
5639 | Left_Opnd => | |
5640 | Make_Indexed_Component (Loc, | |
5641 | Prefix => New_Reference_To (X, Loc), | |
5642 | Expressions => New_List (New_Reference_To (I, Loc))), | |
5643 | ||
5644 | Right_Opnd => | |
5645 | Make_Indexed_Component (Loc, | |
5646 | Prefix => New_Reference_To (Y, Loc), | |
5647 | Expressions => New_List (New_Reference_To (J, Loc)))), | |
5648 | ||
5649 | Then_Statements => New_List (Inner_If), | |
5650 | ||
5651 | Else_Statements => New_List ( | |
5652 | Make_Return_Statement (Loc, | |
5653 | Expression => | |
5654 | Make_Op_Gt (Loc, | |
5655 | Left_Opnd => | |
5656 | Make_Indexed_Component (Loc, | |
5657 | Prefix => New_Reference_To (X, Loc), | |
5658 | Expressions => New_List (New_Reference_To (I, Loc))), | |
5659 | ||
5660 | Right_Opnd => | |
5661 | Make_Indexed_Component (Loc, | |
5662 | Prefix => New_Reference_To (Y, Loc), | |
5663 | Expressions => New_List ( | |
5664 | New_Reference_To (J, Loc))))))); | |
5665 | ||
5666 | -- for I in X'range loop | |
5667 | -- if ... end if; | |
5668 | -- end loop; | |
5669 | ||
5670 | Loop_Statement := | |
5671 | Make_Implicit_Loop_Statement (Nod, | |
5672 | Identifier => Empty, | |
5673 | ||
5674 | Iteration_Scheme => | |
5675 | Make_Iteration_Scheme (Loc, | |
5676 | Loop_Parameter_Specification => | |
5677 | Make_Loop_Parameter_Specification (Loc, | |
5678 | Defining_Identifier => I, | |
5679 | Discrete_Subtype_Definition => | |
5680 | Make_Attribute_Reference (Loc, | |
5681 | Prefix => New_Reference_To (X, Loc), | |
5682 | Attribute_Name => Name_Range))), | |
5683 | ||
5684 | Statements => New_List (Loop_Body)); | |
5685 | ||
5686 | -- if X'length = 0 then | |
5687 | -- return false; | |
5688 | -- elsif Y'length = 0 then | |
5689 | -- return true; | |
5690 | -- else | |
5691 | -- for ... loop ... end loop; | |
5692 | -- return X'length > Y'length; | |
5693 | -- end if; | |
5694 | ||
5695 | Length1 := | |
5696 | Make_Attribute_Reference (Loc, | |
5697 | Prefix => New_Reference_To (X, Loc), | |
5698 | Attribute_Name => Name_Length); | |
5699 | ||
5700 | Length2 := | |
5701 | Make_Attribute_Reference (Loc, | |
5702 | Prefix => New_Reference_To (Y, Loc), | |
5703 | Attribute_Name => Name_Length); | |
5704 | ||
5705 | Final_Expr := | |
5706 | Make_Op_Gt (Loc, | |
5707 | Left_Opnd => Length1, | |
5708 | Right_Opnd => Length2); | |
5709 | ||
5710 | If_Stat := | |
5711 | Make_Implicit_If_Statement (Nod, | |
5712 | Condition => | |
5713 | Make_Op_Eq (Loc, | |
5714 | Left_Opnd => | |
5715 | Make_Attribute_Reference (Loc, | |
5716 | Prefix => New_Reference_To (X, Loc), | |
5717 | Attribute_Name => Name_Length), | |
5718 | Right_Opnd => | |
5719 | Make_Integer_Literal (Loc, 0)), | |
5720 | ||
5721 | Then_Statements => | |
5722 | New_List ( | |
5723 | Make_Return_Statement (Loc, | |
5724 | Expression => New_Reference_To (Standard_False, Loc))), | |
5725 | ||
5726 | Elsif_Parts => New_List ( | |
5727 | Make_Elsif_Part (Loc, | |
5728 | Condition => | |
5729 | Make_Op_Eq (Loc, | |
5730 | Left_Opnd => | |
5731 | Make_Attribute_Reference (Loc, | |
5732 | Prefix => New_Reference_To (Y, Loc), | |
5733 | Attribute_Name => Name_Length), | |
5734 | Right_Opnd => | |
5735 | Make_Integer_Literal (Loc, 0)), | |
5736 | ||
5737 | Then_Statements => | |
5738 | New_List ( | |
5739 | Make_Return_Statement (Loc, | |
5740 | Expression => New_Reference_To (Standard_True, Loc))))), | |
5741 | ||
5742 | Else_Statements => New_List ( | |
5743 | Loop_Statement, | |
5744 | Make_Return_Statement (Loc, | |
5745 | Expression => Final_Expr))); | |
5746 | ||
5747 | -- (X : a; Y: a) | |
5748 | ||
5749 | Formals := New_List ( | |
5750 | Make_Parameter_Specification (Loc, | |
5751 | Defining_Identifier => X, | |
5752 | Parameter_Type => New_Reference_To (Typ, Loc)), | |
5753 | ||
5754 | Make_Parameter_Specification (Loc, | |
5755 | Defining_Identifier => Y, | |
5756 | Parameter_Type => New_Reference_To (Typ, Loc))); | |
5757 | ||
5758 | -- function Gnnn (...) return boolean is | |
5759 | -- J : index := Y'first; | |
5760 | -- begin | |
5761 | -- if ... end if; | |
5762 | -- end Gnnn; | |
5763 | ||
5764 | Func_Name := Make_Defining_Identifier (Loc, New_Internal_Name ('G')); | |
5765 | ||
5766 | Func_Body := | |
5767 | Make_Subprogram_Body (Loc, | |
5768 | Specification => | |
5769 | Make_Function_Specification (Loc, | |
5770 | Defining_Unit_Name => Func_Name, | |
5771 | Parameter_Specifications => Formals, | |
5772 | Subtype_Mark => New_Reference_To (Standard_Boolean, Loc)), | |
5773 | ||
5774 | Declarations => New_List ( | |
5775 | Make_Object_Declaration (Loc, | |
5776 | Defining_Identifier => J, | |
5777 | Object_Definition => New_Reference_To (Index, Loc), | |
5778 | Expression => | |
5779 | Make_Attribute_Reference (Loc, | |
5780 | Prefix => New_Reference_To (Y, Loc), | |
5781 | Attribute_Name => Name_First))), | |
5782 | ||
5783 | Handled_Statement_Sequence => | |
5784 | Make_Handled_Sequence_Of_Statements (Loc, | |
5785 | Statements => New_List (If_Stat))); | |
5786 | ||
5787 | return Func_Body; | |
5788 | ||
5789 | end Make_Array_Comparison_Op; | |
5790 | ||
5791 | --------------------------- | |
5792 | -- Make_Boolean_Array_Op -- | |
5793 | --------------------------- | |
5794 | ||
5795 | -- For logical operations on boolean arrays, expand in line the | |
5796 | -- following, replacing 'and' with 'or' or 'xor' where needed: | |
5797 | ||
5798 | -- function Annn (A : typ; B: typ) return typ is | |
5799 | -- C : typ; | |
5800 | -- begin | |
5801 | -- for J in A'range loop | |
5802 | -- C (J) := A (J) op B (J); | |
5803 | -- end loop; | |
5804 | -- return C; | |
5805 | -- end Annn; | |
5806 | ||
5807 | -- Here typ is the boolean array type | |
5808 | ||
5809 | function Make_Boolean_Array_Op | |
5810 | (Typ : Entity_Id; | |
5811 | N : Node_Id) | |
5812 | return Node_Id | |
5813 | is | |
5814 | Loc : constant Source_Ptr := Sloc (N); | |
5815 | ||
5816 | A : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uA); | |
5817 | B : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uB); | |
5818 | C : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uC); | |
5819 | J : constant Entity_Id := Make_Defining_Identifier (Loc, Name_uJ); | |
5820 | ||
5821 | A_J : Node_Id; | |
5822 | B_J : Node_Id; | |
5823 | C_J : Node_Id; | |
5824 | Op : Node_Id; | |
5825 | ||
5826 | Formals : List_Id; | |
5827 | Func_Name : Entity_Id; | |
5828 | Func_Body : Node_Id; | |
5829 | Loop_Statement : Node_Id; | |
5830 | ||
5831 | begin | |
5832 | A_J := | |
5833 | Make_Indexed_Component (Loc, | |
5834 | Prefix => New_Reference_To (A, Loc), | |
5835 | Expressions => New_List (New_Reference_To (J, Loc))); | |
5836 | ||
5837 | B_J := | |
5838 | Make_Indexed_Component (Loc, | |
5839 | Prefix => New_Reference_To (B, Loc), | |
5840 | Expressions => New_List (New_Reference_To (J, Loc))); | |
5841 | ||
5842 | C_J := | |
5843 | Make_Indexed_Component (Loc, | |
5844 | Prefix => New_Reference_To (C, Loc), | |
5845 | Expressions => New_List (New_Reference_To (J, Loc))); | |
5846 | ||
5847 | if Nkind (N) = N_Op_And then | |
5848 | Op := | |
5849 | Make_Op_And (Loc, | |
5850 | Left_Opnd => A_J, | |
5851 | Right_Opnd => B_J); | |
5852 | ||
5853 | elsif Nkind (N) = N_Op_Or then | |
5854 | Op := | |
5855 | Make_Op_Or (Loc, | |
5856 | Left_Opnd => A_J, | |
5857 | Right_Opnd => B_J); | |
5858 | ||
5859 | else | |
5860 | Op := | |
5861 | Make_Op_Xor (Loc, | |
5862 | Left_Opnd => A_J, | |
5863 | Right_Opnd => B_J); | |
5864 | end if; | |
5865 | ||
5866 | Loop_Statement := | |
5867 | Make_Implicit_Loop_Statement (N, | |
5868 | Identifier => Empty, | |
5869 | ||
5870 | Iteration_Scheme => | |
5871 | Make_Iteration_Scheme (Loc, | |
5872 | Loop_Parameter_Specification => | |
5873 | Make_Loop_Parameter_Specification (Loc, | |
5874 | Defining_Identifier => J, | |
5875 | Discrete_Subtype_Definition => | |
5876 | Make_Attribute_Reference (Loc, | |
5877 | Prefix => New_Reference_To (A, Loc), | |
5878 | Attribute_Name => Name_Range))), | |
5879 | ||
5880 | Statements => New_List ( | |
5881 | Make_Assignment_Statement (Loc, | |
5882 | Name => C_J, | |
5883 | Expression => Op))); | |
5884 | ||
5885 | Formals := New_List ( | |
5886 | Make_Parameter_Specification (Loc, | |
5887 | Defining_Identifier => A, | |
5888 | Parameter_Type => New_Reference_To (Typ, Loc)), | |
5889 | ||
5890 | Make_Parameter_Specification (Loc, | |
5891 | Defining_Identifier => B, | |
5892 | Parameter_Type => New_Reference_To (Typ, Loc))); | |
5893 | ||
5894 | Func_Name := | |
5895 | Make_Defining_Identifier (Loc, New_Internal_Name ('A')); | |
5896 | Set_Is_Inlined (Func_Name); | |
5897 | ||
5898 | Func_Body := | |
5899 | Make_Subprogram_Body (Loc, | |
5900 | Specification => | |
5901 | Make_Function_Specification (Loc, | |
5902 | Defining_Unit_Name => Func_Name, | |
5903 | Parameter_Specifications => Formals, | |
5904 | Subtype_Mark => New_Reference_To (Typ, Loc)), | |
5905 | ||
5906 | Declarations => New_List ( | |
5907 | Make_Object_Declaration (Loc, | |
5908 | Defining_Identifier => C, | |
5909 | Object_Definition => New_Reference_To (Typ, Loc))), | |
5910 | ||
5911 | Handled_Statement_Sequence => | |
5912 | Make_Handled_Sequence_Of_Statements (Loc, | |
5913 | Statements => New_List ( | |
5914 | Loop_Statement, | |
5915 | Make_Return_Statement (Loc, | |
5916 | Expression => New_Reference_To (C, Loc))))); | |
5917 | ||
5918 | return Func_Body; | |
5919 | end Make_Boolean_Array_Op; | |
5920 | ||
5921 | ------------------------ | |
5922 | -- Rewrite_Comparison -- | |
5923 | ------------------------ | |
5924 | ||
5925 | procedure Rewrite_Comparison (N : Node_Id) is | |
5926 | Typ : constant Entity_Id := Etype (N); | |
5927 | Op1 : constant Node_Id := Left_Opnd (N); | |
5928 | Op2 : constant Node_Id := Right_Opnd (N); | |
5929 | ||
5930 | Res : constant Compare_Result := Compile_Time_Compare (Op1, Op2); | |
5931 | -- Res indicates if compare outcome can be determined at compile time | |
5932 | ||
5933 | True_Result : Boolean; | |
5934 | False_Result : Boolean; | |
5935 | ||
5936 | begin | |
5937 | case N_Op_Compare (Nkind (N)) is | |
5938 | when N_Op_Eq => | |
5939 | True_Result := Res = EQ; | |
5940 | False_Result := Res = LT or else Res = GT or else Res = NE; | |
5941 | ||
5942 | when N_Op_Ge => | |
5943 | True_Result := Res in Compare_GE; | |
5944 | False_Result := Res = LT; | |
5945 | ||
5946 | when N_Op_Gt => | |
5947 | True_Result := Res = GT; | |
5948 | False_Result := Res in Compare_LE; | |
5949 | ||
5950 | when N_Op_Lt => | |
5951 | True_Result := Res = LT; | |
5952 | False_Result := Res in Compare_GE; | |
5953 | ||
5954 | when N_Op_Le => | |
5955 | True_Result := Res in Compare_LE; | |
5956 | False_Result := Res = GT; | |
5957 | ||
5958 | when N_Op_Ne => | |
5959 | True_Result := Res = NE; | |
5960 | False_Result := Res = LT or else Res = GT or else Res = EQ; | |
5961 | end case; | |
5962 | ||
5963 | if True_Result then | |
5964 | Rewrite (N, | |
5965 | Convert_To (Typ, New_Occurrence_Of (Standard_True, Sloc (N)))); | |
5966 | Analyze_And_Resolve (N, Typ); | |
07fc65c4 | 5967 | Warn_On_Known_Condition (N); |
70482933 RK |
5968 | |
5969 | elsif False_Result then | |
5970 | Rewrite (N, | |
5971 | Convert_To (Typ, New_Occurrence_Of (Standard_False, Sloc (N)))); | |
5972 | Analyze_And_Resolve (N, Typ); | |
07fc65c4 | 5973 | Warn_On_Known_Condition (N); |
70482933 RK |
5974 | end if; |
5975 | end Rewrite_Comparison; | |
5976 | ||
5977 | ----------------------- | |
5978 | -- Tagged_Membership -- | |
5979 | ----------------------- | |
5980 | ||
5981 | -- There are two different cases to consider depending on whether | |
5982 | -- the right operand is a class-wide type or not. If not we just | |
5983 | -- compare the actual tag of the left expr to the target type tag: | |
5984 | -- | |
5985 | -- Left_Expr.Tag = Right_Type'Tag; | |
5986 | -- | |
5987 | -- If it is a class-wide type we use the RT function CW_Membership which | |
5988 | -- is usually implemented by looking in the ancestor tables contained in | |
5989 | -- the dispatch table pointed by Left_Expr.Tag for Typ'Tag | |
5990 | ||
5991 | function Tagged_Membership (N : Node_Id) return Node_Id is | |
5992 | Left : constant Node_Id := Left_Opnd (N); | |
5993 | Right : constant Node_Id := Right_Opnd (N); | |
5994 | Loc : constant Source_Ptr := Sloc (N); | |
5995 | ||
5996 | Left_Type : Entity_Id; | |
5997 | Right_Type : Entity_Id; | |
5998 | Obj_Tag : Node_Id; | |
5999 | ||
6000 | begin | |
6001 | Left_Type := Etype (Left); | |
6002 | Right_Type := Etype (Right); | |
6003 | ||
6004 | if Is_Class_Wide_Type (Left_Type) then | |
6005 | Left_Type := Root_Type (Left_Type); | |
6006 | end if; | |
6007 | ||
6008 | Obj_Tag := | |
6009 | Make_Selected_Component (Loc, | |
6010 | Prefix => Relocate_Node (Left), | |
6011 | Selector_Name => New_Reference_To (Tag_Component (Left_Type), Loc)); | |
6012 | ||
6013 | if Is_Class_Wide_Type (Right_Type) then | |
6014 | return | |
6015 | Make_DT_Access_Action (Left_Type, | |
6016 | Action => CW_Membership, | |
6017 | Args => New_List ( | |
6018 | Obj_Tag, | |
6019 | New_Reference_To ( | |
6020 | Access_Disp_Table (Root_Type (Right_Type)), Loc))); | |
6021 | else | |
6022 | return | |
6023 | Make_Op_Eq (Loc, | |
6024 | Left_Opnd => Obj_Tag, | |
6025 | Right_Opnd => | |
6026 | New_Reference_To (Access_Disp_Table (Right_Type), Loc)); | |
6027 | end if; | |
6028 | ||
6029 | end Tagged_Membership; | |
6030 | ||
6031 | ------------------------------ | |
6032 | -- Unary_Op_Validity_Checks -- | |
6033 | ------------------------------ | |
6034 | ||
6035 | procedure Unary_Op_Validity_Checks (N : Node_Id) is | |
6036 | begin | |
6037 | if Validity_Checks_On and Validity_Check_Operands then | |
6038 | Ensure_Valid (Right_Opnd (N)); | |
6039 | end if; | |
6040 | end Unary_Op_Validity_Checks; | |
6041 | ||
6042 | end Exp_Ch4; |