145
|
1 /* d-codegen.cc -- Code generation and routines for manipulation of GCC trees.
|
|
2 Copyright (C) 2006-2020 Free Software Foundation, Inc.
|
|
3
|
|
4 GCC is free software; you can redistribute it and/or modify
|
|
5 it under the terms of the GNU General Public License as published by
|
|
6 the Free Software Foundation; either version 3, or (at your option)
|
|
7 any later version.
|
|
8
|
|
9 GCC is distributed in the hope that it will be useful,
|
|
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12 GNU General Public License for more details.
|
|
13
|
|
14 You should have received a copy of the GNU General Public License
|
|
15 along with GCC; see the file COPYING3. If not see
|
|
16 <http://www.gnu.org/licenses/>. */
|
|
17
|
|
18 #include "config.h"
|
|
19 #include "system.h"
|
|
20 #include "coretypes.h"
|
|
21
|
|
22 #include "dmd/aggregate.h"
|
|
23 #include "dmd/ctfe.h"
|
|
24 #include "dmd/declaration.h"
|
|
25 #include "dmd/identifier.h"
|
|
26 #include "dmd/target.h"
|
|
27 #include "dmd/template.h"
|
|
28
|
|
29 #include "tree.h"
|
|
30 #include "tree-iterator.h"
|
|
31 #include "fold-const.h"
|
|
32 #include "diagnostic.h"
|
|
33 #include "langhooks.h"
|
|
34 #include "target.h"
|
|
35 #include "stringpool.h"
|
|
36 #include "varasm.h"
|
|
37 #include "stor-layout.h"
|
|
38 #include "attribs.h"
|
|
39 #include "function.h"
|
|
40
|
|
41 #include "d-tree.h"
|
|
42
|
|
43
|
|
44 /* Return the GCC location for the D frontend location LOC. */
|
|
45
|
|
46 location_t
|
|
47 make_location_t (const Loc& loc)
|
|
48 {
|
|
49 location_t gcc_location = input_location;
|
|
50
|
|
51 if (loc.filename)
|
|
52 {
|
|
53 linemap_add (line_table, LC_ENTER, 0, loc.filename, loc.linnum);
|
|
54 linemap_line_start (line_table, loc.linnum, 0);
|
|
55 gcc_location = linemap_position_for_column (line_table, loc.charnum);
|
|
56 linemap_add (line_table, LC_LEAVE, 0, NULL, 0);
|
|
57 }
|
|
58
|
|
59 return gcc_location;
|
|
60 }
|
|
61
|
|
62 /* Return the DECL_CONTEXT for symbol DSYM. */
|
|
63
|
|
64 tree
|
|
65 d_decl_context (Dsymbol *dsym)
|
|
66 {
|
|
67 Dsymbol *parent = dsym;
|
|
68 Declaration *decl = dsym->isDeclaration ();
|
|
69
|
|
70 while ((parent = parent->toParent2 ()))
|
|
71 {
|
|
72 /* We've reached the top-level module namespace.
|
|
73 Set DECL_CONTEXT as the NAMESPACE_DECL of the enclosing module,
|
|
74 but only for extern(D) symbols. */
|
|
75 if (parent->isModule ())
|
|
76 {
|
|
77 if (decl != NULL && decl->linkage != LINKd)
|
|
78 return NULL_TREE;
|
|
79
|
|
80 return build_import_decl (parent);
|
|
81 }
|
|
82
|
|
83 /* Declarations marked as 'static' or '__gshared' are never
|
|
84 part of any context except at module level. */
|
|
85 if (decl != NULL && decl->isDataseg ())
|
|
86 continue;
|
|
87
|
|
88 /* Nested functions. */
|
|
89 FuncDeclaration *fd = parent->isFuncDeclaration ();
|
|
90 if (fd != NULL)
|
|
91 return get_symbol_decl (fd);
|
|
92
|
|
93 /* Methods of classes or structs. */
|
|
94 AggregateDeclaration *ad = parent->isAggregateDeclaration ();
|
|
95 if (ad != NULL)
|
|
96 {
|
|
97 tree context = build_ctype (ad->type);
|
|
98 /* Want the underlying RECORD_TYPE. */
|
|
99 if (ad->isClassDeclaration ())
|
|
100 context = TREE_TYPE (context);
|
|
101
|
|
102 return context;
|
|
103 }
|
|
104 }
|
|
105
|
|
106 return NULL_TREE;
|
|
107 }
|
|
108
|
|
109 /* Return a copy of record TYPE but safe to modify in any way. */
|
|
110
|
|
111 tree
|
|
112 copy_aggregate_type (tree type)
|
|
113 {
|
|
114 tree newtype = build_distinct_type_copy (type);
|
|
115 TYPE_FIELDS (newtype) = copy_list (TYPE_FIELDS (type));
|
|
116
|
|
117 for (tree f = TYPE_FIELDS (newtype); f; f = DECL_CHAIN (f))
|
|
118 DECL_FIELD_CONTEXT (f) = newtype;
|
|
119
|
|
120 return newtype;
|
|
121 }
|
|
122
|
|
123 /* Return TRUE if declaration DECL is a reference type. */
|
|
124
|
|
125 bool
|
|
126 declaration_reference_p (Declaration *decl)
|
|
127 {
|
|
128 Type *tb = decl->type->toBasetype ();
|
|
129
|
|
130 /* Declaration is a reference type. */
|
|
131 if (tb->ty == Treference || decl->storage_class & (STCout | STCref))
|
|
132 return true;
|
|
133
|
|
134 return false;
|
|
135 }
|
|
136
|
|
137 /* Returns the real type for declaration DECL. */
|
|
138
|
|
139 tree
|
|
140 declaration_type (Declaration *decl)
|
|
141 {
|
|
142 /* Lazy declarations are converted to delegates. */
|
|
143 if (decl->storage_class & STClazy)
|
|
144 {
|
|
145 TypeFunction *tf = TypeFunction::create (NULL, decl->type, false, LINKd);
|
|
146 TypeDelegate *t = TypeDelegate::create (tf);
|
|
147 return build_ctype (t->merge2 ());
|
|
148 }
|
|
149
|
|
150 /* Static array va_list have array->pointer conversions applied. */
|
|
151 if (decl->isParameter () && valist_array_p (decl->type))
|
|
152 {
|
|
153 Type *valist = decl->type->nextOf ()->pointerTo ();
|
|
154 valist = valist->castMod (decl->type->mod);
|
|
155 return build_ctype (valist);
|
|
156 }
|
|
157
|
|
158 tree type = build_ctype (decl->type);
|
|
159
|
|
160 /* Parameter is passed by reference. */
|
|
161 if (declaration_reference_p (decl))
|
|
162 return build_reference_type (type);
|
|
163
|
|
164 /* The 'this' parameter is always const. */
|
|
165 if (decl->isThisDeclaration ())
|
|
166 return insert_type_modifiers (type, MODconst);
|
|
167
|
|
168 return type;
|
|
169 }
|
|
170
|
|
171 /* These should match the Declaration versions above
|
|
172 Return TRUE if parameter ARG is a reference type. */
|
|
173
|
|
174 bool
|
|
175 argument_reference_p (Parameter *arg)
|
|
176 {
|
|
177 Type *tb = arg->type->toBasetype ();
|
|
178
|
|
179 /* Parameter is a reference type. */
|
|
180 if (tb->ty == Treference || arg->storageClass & (STCout | STCref))
|
|
181 return true;
|
|
182
|
|
183 tree type = build_ctype (arg->type);
|
|
184 if (TREE_ADDRESSABLE (type))
|
|
185 return true;
|
|
186
|
|
187 return false;
|
|
188 }
|
|
189
|
|
190 /* Returns the real type for parameter ARG. */
|
|
191
|
|
192 tree
|
|
193 type_passed_as (Parameter *arg)
|
|
194 {
|
|
195 /* Lazy parameters are converted to delegates. */
|
|
196 if (arg->storageClass & STClazy)
|
|
197 {
|
|
198 TypeFunction *tf = TypeFunction::create (NULL, arg->type, false, LINKd);
|
|
199 TypeDelegate *t = TypeDelegate::create (tf);
|
|
200 return build_ctype (t->merge2 ());
|
|
201 }
|
|
202
|
|
203 /* Static array va_list have array->pointer conversions applied. */
|
|
204 if (valist_array_p (arg->type))
|
|
205 {
|
|
206 Type *valist = arg->type->nextOf ()->pointerTo ();
|
|
207 valist = valist->castMod (arg->type->mod);
|
|
208 return build_ctype (valist);
|
|
209 }
|
|
210
|
|
211 tree type = build_ctype (arg->type);
|
|
212
|
|
213 /* Parameter is passed by reference. */
|
|
214 if (argument_reference_p (arg))
|
|
215 return build_reference_type (type);
|
|
216
|
|
217 return type;
|
|
218 }
|
|
219
|
|
220 /* Build INTEGER_CST of type TYPE with the value VALUE. */
|
|
221
|
|
222 tree
|
|
223 build_integer_cst (dinteger_t value, tree type)
|
|
224 {
|
|
225 /* The type is error_mark_node, we can't do anything. */
|
|
226 if (error_operand_p (type))
|
|
227 return type;
|
|
228
|
|
229 return build_int_cst_type (type, value);
|
|
230 }
|
|
231
|
|
232 /* Build REAL_CST of type TOTYPE with the value VALUE. */
|
|
233
|
|
234 tree
|
|
235 build_float_cst (const real_t& value, Type *totype)
|
|
236 {
|
|
237 real_t new_value;
|
|
238 TypeBasic *tb = totype->isTypeBasic ();
|
|
239
|
|
240 gcc_assert (tb != NULL);
|
|
241
|
|
242 tree type_node = build_ctype (tb);
|
|
243 real_convert (&new_value.rv (), TYPE_MODE (type_node), &value.rv ());
|
|
244
|
|
245 return build_real (type_node, new_value.rv ());
|
|
246 }
|
|
247
|
|
248 /* Returns the .length component from the D dynamic array EXP. */
|
|
249
|
|
250 tree
|
|
251 d_array_length (tree exp)
|
|
252 {
|
|
253 if (error_operand_p (exp))
|
|
254 return exp;
|
|
255
|
|
256 gcc_assert (TYPE_DYNAMIC_ARRAY (TREE_TYPE (exp)));
|
|
257
|
|
258 /* Get the back-end type for the array and pick out the array
|
|
259 length field (assumed to be the first field). */
|
|
260 tree len_field = TYPE_FIELDS (TREE_TYPE (exp));
|
|
261 return component_ref (exp, len_field);
|
|
262 }
|
|
263
|
|
264 /* Returns the .ptr component from the D dynamic array EXP. */
|
|
265
|
|
266 tree
|
|
267 d_array_ptr (tree exp)
|
|
268 {
|
|
269 if (error_operand_p (exp))
|
|
270 return exp;
|
|
271
|
|
272 gcc_assert (TYPE_DYNAMIC_ARRAY (TREE_TYPE (exp)));
|
|
273
|
|
274 /* Get the back-end type for the array and pick out the array
|
|
275 data pointer field (assumed to be the second field). */
|
|
276 tree ptr_field = TREE_CHAIN (TYPE_FIELDS (TREE_TYPE (exp)));
|
|
277 return component_ref (exp, ptr_field);
|
|
278 }
|
|
279
|
|
280 /* Returns a constructor for D dynamic array type TYPE of .length LEN
|
|
281 and .ptr pointing to DATA. */
|
|
282
|
|
283 tree
|
|
284 d_array_value (tree type, tree len, tree data)
|
|
285 {
|
|
286 tree len_field, ptr_field;
|
|
287 vec<constructor_elt, va_gc> *ce = NULL;
|
|
288
|
|
289 gcc_assert (TYPE_DYNAMIC_ARRAY (type));
|
|
290 len_field = TYPE_FIELDS (type);
|
|
291 ptr_field = TREE_CHAIN (len_field);
|
|
292
|
|
293 len = convert (TREE_TYPE (len_field), len);
|
|
294 data = convert (TREE_TYPE (ptr_field), data);
|
|
295
|
|
296 CONSTRUCTOR_APPEND_ELT (ce, len_field, len);
|
|
297 CONSTRUCTOR_APPEND_ELT (ce, ptr_field, data);
|
|
298
|
|
299 return build_constructor (type, ce);
|
|
300 }
|
|
301
|
|
302 /* Returns value representing the array length of expression EXP.
|
|
303 TYPE could be a dynamic or static array. */
|
|
304
|
|
305 tree
|
|
306 get_array_length (tree exp, Type *type)
|
|
307 {
|
|
308 Type *tb = type->toBasetype ();
|
|
309
|
|
310 switch (tb->ty)
|
|
311 {
|
|
312 case Tsarray:
|
|
313 return size_int (((TypeSArray *) tb)->dim->toUInteger ());
|
|
314
|
|
315 case Tarray:
|
|
316 return d_array_length (exp);
|
|
317
|
|
318 default:
|
|
319 error ("cannot determine the length of a %qs", type->toChars ());
|
|
320 return error_mark_node;
|
|
321 }
|
|
322 }
|
|
323
|
|
324 /* Create BINFO for a ClassDeclaration's inheritance tree.
|
|
325 InterfaceDeclaration's are not included. */
|
|
326
|
|
327 tree
|
|
328 build_class_binfo (tree super, ClassDeclaration *cd)
|
|
329 {
|
|
330 tree binfo = make_tree_binfo (1);
|
|
331 tree ctype = build_ctype (cd->type);
|
|
332
|
|
333 /* Want RECORD_TYPE, not POINTER_TYPE. */
|
|
334 BINFO_TYPE (binfo) = TREE_TYPE (ctype);
|
|
335 BINFO_INHERITANCE_CHAIN (binfo) = super;
|
|
336 BINFO_OFFSET (binfo) = integer_zero_node;
|
|
337
|
|
338 if (cd->baseClass)
|
|
339 BINFO_BASE_APPEND (binfo, build_class_binfo (binfo, cd->baseClass));
|
|
340
|
|
341 return binfo;
|
|
342 }
|
|
343
|
|
344 /* Create BINFO for an InterfaceDeclaration's inheritance tree.
|
|
345 In order to access all inherited methods in the debugger,
|
|
346 the entire tree must be described.
|
|
347 This function makes assumptions about interface layout. */
|
|
348
|
|
349 tree
|
|
350 build_interface_binfo (tree super, ClassDeclaration *cd, unsigned& offset)
|
|
351 {
|
|
352 tree binfo = make_tree_binfo (cd->baseclasses->dim);
|
|
353 tree ctype = build_ctype (cd->type);
|
|
354
|
|
355 /* Want RECORD_TYPE, not POINTER_TYPE. */
|
|
356 BINFO_TYPE (binfo) = TREE_TYPE (ctype);
|
|
357 BINFO_INHERITANCE_CHAIN (binfo) = super;
|
|
358 BINFO_OFFSET (binfo) = size_int (offset * Target::ptrsize);
|
|
359 BINFO_VIRTUAL_P (binfo) = 1;
|
|
360
|
|
361 for (size_t i = 0; i < cd->baseclasses->dim; i++, offset++)
|
|
362 {
|
|
363 BaseClass *bc = (*cd->baseclasses)[i];
|
|
364 BINFO_BASE_APPEND (binfo, build_interface_binfo (binfo, bc->sym, offset));
|
|
365 }
|
|
366
|
|
367 return binfo;
|
|
368 }
|
|
369
|
|
370 /* Returns the .funcptr component from the D delegate EXP. */
|
|
371
|
|
372 tree
|
|
373 delegate_method (tree exp)
|
|
374 {
|
|
375 /* Get the back-end type for the delegate and pick out the funcptr field
|
|
376 (assumed to be the second field). */
|
|
377 gcc_assert (TYPE_DELEGATE (TREE_TYPE (exp)));
|
|
378 tree method_field = TREE_CHAIN (TYPE_FIELDS (TREE_TYPE (exp)));
|
|
379 return component_ref (exp, method_field);
|
|
380 }
|
|
381
|
|
382 /* Returns the .object component from the delegate EXP. */
|
|
383
|
|
384 tree
|
|
385 delegate_object (tree exp)
|
|
386 {
|
|
387 /* Get the back-end type for the delegate and pick out the object field
|
|
388 (assumed to be the first field). */
|
|
389 gcc_assert (TYPE_DELEGATE (TREE_TYPE (exp)));
|
|
390 tree obj_field = TYPE_FIELDS (TREE_TYPE (exp));
|
|
391 return component_ref (exp, obj_field);
|
|
392 }
|
|
393
|
|
394 /* Build a delegate literal of type TYPE whose pointer function is
|
|
395 METHOD, and hidden object is OBJECT. */
|
|
396
|
|
397 tree
|
|
398 build_delegate_cst (tree method, tree object, Type *type)
|
|
399 {
|
|
400 tree ctor = make_node (CONSTRUCTOR);
|
|
401 tree ctype;
|
|
402
|
|
403 Type *tb = type->toBasetype ();
|
|
404 if (tb->ty == Tdelegate)
|
|
405 ctype = build_ctype (type);
|
|
406 else
|
|
407 {
|
|
408 /* Convert a function method into an anonymous delegate. */
|
|
409 ctype = make_struct_type ("delegate()", 2,
|
|
410 get_identifier ("object"), TREE_TYPE (object),
|
|
411 get_identifier ("func"), TREE_TYPE (method));
|
|
412 TYPE_DELEGATE (ctype) = 1;
|
|
413 }
|
|
414
|
|
415 vec<constructor_elt, va_gc> *ce = NULL;
|
|
416 CONSTRUCTOR_APPEND_ELT (ce, TYPE_FIELDS (ctype), object);
|
|
417 CONSTRUCTOR_APPEND_ELT (ce, TREE_CHAIN (TYPE_FIELDS (ctype)), method);
|
|
418
|
|
419 CONSTRUCTOR_ELTS (ctor) = ce;
|
|
420 TREE_TYPE (ctor) = ctype;
|
|
421
|
|
422 return ctor;
|
|
423 }
|
|
424
|
|
425 /* Builds a temporary tree to store the CALLEE and OBJECT
|
|
426 of a method call expression of type TYPE. */
|
|
427
|
|
428 tree
|
|
429 build_method_call (tree callee, tree object, Type *type)
|
|
430 {
|
|
431 tree t = build_delegate_cst (callee, object, type);
|
|
432 METHOD_CALL_EXPR (t) = 1;
|
|
433 return t;
|
|
434 }
|
|
435
|
|
436 /* Extract callee and object from T and return in to CALLEE and OBJECT. */
|
|
437
|
|
438 void
|
|
439 extract_from_method_call (tree t, tree& callee, tree& object)
|
|
440 {
|
|
441 gcc_assert (METHOD_CALL_EXPR (t));
|
|
442 object = CONSTRUCTOR_ELT (t, 0)->value;
|
|
443 callee = CONSTRUCTOR_ELT (t, 1)->value;
|
|
444 }
|
|
445
|
|
446 /* Build a typeof(null) constant of type TYPE. Handles certain special case
|
|
447 conversions, where the underlying type is an aggregate with a nullable
|
|
448 interior pointer. */
|
|
449
|
|
450 tree
|
|
451 build_typeof_null_value (Type *type)
|
|
452 {
|
|
453 Type *tb = type->toBasetype ();
|
|
454 tree value;
|
|
455
|
|
456 /* For dynamic arrays, set length and pointer fields to zero. */
|
|
457 if (tb->ty == Tarray)
|
|
458 value = d_array_value (build_ctype (type), size_int (0), null_pointer_node);
|
|
459
|
|
460 /* For associative arrays, set the pointer field to null. */
|
|
461 else if (tb->ty == Taarray)
|
|
462 {
|
|
463 tree ctype = build_ctype (type);
|
|
464 gcc_assert (TYPE_ASSOCIATIVE_ARRAY (ctype));
|
|
465
|
|
466 value = build_constructor_single (ctype, TYPE_FIELDS (ctype),
|
|
467 null_pointer_node);
|
|
468 }
|
|
469
|
|
470 /* For delegates, set the frame and function pointer fields to null. */
|
|
471 else if (tb->ty == Tdelegate)
|
|
472 value = build_delegate_cst (null_pointer_node, null_pointer_node, type);
|
|
473
|
|
474 /* Simple zero constant for all other types. */
|
|
475 else
|
|
476 value = build_zero_cst (build_ctype (type));
|
|
477
|
|
478 TREE_CONSTANT (value) = 1;
|
|
479 return value;
|
|
480 }
|
|
481
|
|
482 /* Build a dereference into the virtual table for OBJECT to retrieve
|
|
483 a function pointer of type FNTYPE at position INDEX. */
|
|
484
|
|
485 tree
|
|
486 build_vindex_ref (tree object, tree fntype, size_t index)
|
|
487 {
|
|
488 /* The vtable is the first field. Interface methods are also in the class's
|
|
489 vtable, so we don't need to convert from a class to an interface. */
|
|
490 tree result = build_deref (object);
|
|
491 result = component_ref (result, TYPE_FIELDS (TREE_TYPE (result)));
|
|
492
|
|
493 gcc_assert (POINTER_TYPE_P (fntype));
|
|
494
|
|
495 return build_memref (fntype, result, size_int (Target::ptrsize * index));
|
|
496 }
|
|
497
|
|
498 /* Return TRUE if EXP is a valid lvalue. Lvalue references cannot be
|
|
499 made into temporaries, otherwise any assignments will be lost. */
|
|
500
|
|
501 static bool
|
|
502 lvalue_p (tree exp)
|
|
503 {
|
|
504 const enum tree_code code = TREE_CODE (exp);
|
|
505
|
|
506 switch (code)
|
|
507 {
|
|
508 case SAVE_EXPR:
|
|
509 return false;
|
|
510
|
|
511 case ARRAY_REF:
|
|
512 case INDIRECT_REF:
|
|
513 case VAR_DECL:
|
|
514 case PARM_DECL:
|
|
515 case RESULT_DECL:
|
|
516 return !FUNC_OR_METHOD_TYPE_P (TREE_TYPE (exp));
|
|
517
|
|
518 case IMAGPART_EXPR:
|
|
519 case REALPART_EXPR:
|
|
520 case COMPONENT_REF:
|
|
521 CASE_CONVERT:
|
|
522 return lvalue_p (TREE_OPERAND (exp, 0));
|
|
523
|
|
524 case COND_EXPR:
|
|
525 return (lvalue_p (TREE_OPERAND (exp, 1)
|
|
526 ? TREE_OPERAND (exp, 1)
|
|
527 : TREE_OPERAND (exp, 0))
|
|
528 && lvalue_p (TREE_OPERAND (exp, 2)));
|
|
529
|
|
530 case TARGET_EXPR:
|
|
531 return true;
|
|
532
|
|
533 case COMPOUND_EXPR:
|
|
534 return lvalue_p (TREE_OPERAND (exp, 1));
|
|
535
|
|
536 default:
|
|
537 return false;
|
|
538 }
|
|
539 }
|
|
540
|
|
541 /* Create a SAVE_EXPR if EXP might have unwanted side effects if referenced
|
|
542 more than once in an expression. */
|
|
543
|
|
544 tree
|
|
545 d_save_expr (tree exp)
|
|
546 {
|
|
547 if (TREE_SIDE_EFFECTS (exp))
|
|
548 {
|
|
549 if (lvalue_p (exp))
|
|
550 return stabilize_reference (exp);
|
|
551
|
|
552 return save_expr (exp);
|
|
553 }
|
|
554
|
|
555 return exp;
|
|
556 }
|
|
557
|
|
558 /* VALUEP is an expression we want to pre-evaluate or perform a computation on.
|
|
559 The expression returned by this function is the part whose value we don't
|
|
560 care about, storing the value in VALUEP. Callers must ensure that the
|
|
561 returned expression is evaluated before VALUEP. */
|
|
562
|
|
563 tree
|
|
564 stabilize_expr (tree *valuep)
|
|
565 {
|
|
566 tree expr = *valuep;
|
|
567 const enum tree_code code = TREE_CODE (expr);
|
|
568 tree lhs;
|
|
569 tree rhs;
|
|
570
|
|
571 switch (code)
|
|
572 {
|
|
573 case COMPOUND_EXPR:
|
|
574 /* Given ((e1, ...), eN):
|
|
575 Store the last RHS 'eN' expression in VALUEP. */
|
|
576 lhs = TREE_OPERAND (expr, 0);
|
|
577 rhs = TREE_OPERAND (expr, 1);
|
|
578 lhs = compound_expr (lhs, stabilize_expr (&rhs));
|
|
579 *valuep = rhs;
|
|
580 return lhs;
|
|
581
|
|
582 default:
|
|
583 return NULL_TREE;
|
|
584 }
|
|
585 }
|
|
586
|
|
587 /* Return a TARGET_EXPR, initializing the DECL with EXP. */
|
|
588
|
|
589 tree
|
|
590 build_target_expr (tree decl, tree exp)
|
|
591 {
|
|
592 tree type = TREE_TYPE (decl);
|
|
593 tree result = build4 (TARGET_EXPR, type, decl, exp, NULL_TREE, NULL_TREE);
|
|
594
|
|
595 if (EXPR_HAS_LOCATION (exp))
|
|
596 SET_EXPR_LOCATION (result, EXPR_LOCATION (exp));
|
|
597
|
|
598 /* If decl must always reside in memory. */
|
|
599 if (TREE_ADDRESSABLE (type))
|
|
600 d_mark_addressable (decl);
|
|
601
|
|
602 /* Always set TREE_SIDE_EFFECTS so that expand_expr does not ignore the
|
|
603 TARGET_EXPR. If there really turn out to be no side effects, then the
|
|
604 optimizer should be able to remove it. */
|
|
605 TREE_SIDE_EFFECTS (result) = 1;
|
|
606
|
|
607 return result;
|
|
608 }
|
|
609
|
|
610 /* Like the above function, but initializes a new temporary. */
|
|
611
|
|
612 tree
|
|
613 force_target_expr (tree exp)
|
|
614 {
|
|
615 tree decl = create_temporary_var (TREE_TYPE (exp));
|
|
616
|
|
617 return build_target_expr (decl, exp);
|
|
618 }
|
|
619
|
|
620 /* Returns the address of the expression EXP. */
|
|
621
|
|
622 tree
|
|
623 build_address (tree exp)
|
|
624 {
|
|
625 if (error_operand_p (exp))
|
|
626 return exp;
|
|
627
|
|
628 tree ptrtype;
|
|
629 tree type = TREE_TYPE (exp);
|
|
630
|
|
631 if (TREE_CODE (exp) == STRING_CST)
|
|
632 {
|
|
633 /* Just convert string literals (char[]) to C-style strings (char *),
|
|
634 otherwise the latter method (char[]*) causes conversion problems
|
|
635 during gimplification. */
|
|
636 ptrtype = build_pointer_type (TREE_TYPE (type));
|
|
637 }
|
|
638 else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (va_list_type_node)
|
|
639 && TREE_CODE (TYPE_MAIN_VARIANT (type)) == ARRAY_TYPE)
|
|
640 {
|
|
641 /* Special case for va_list, allow arrays to decay to a pointer. */
|
|
642 ptrtype = build_pointer_type (TREE_TYPE (type));
|
|
643 }
|
|
644 else
|
|
645 ptrtype = build_pointer_type (type);
|
|
646
|
|
647 /* Maybe rewrite: &(e1, e2) => (e1, &e2). */
|
|
648 tree init = stabilize_expr (&exp);
|
|
649
|
|
650 /* Can't take the address of a manifest constant, instead use its value. */
|
|
651 if (TREE_CODE (exp) == CONST_DECL)
|
|
652 exp = DECL_INITIAL (exp);
|
|
653
|
|
654 /* Some expression lowering may request an address of a compile-time constant,
|
|
655 or other non-lvalue expression. Make sure it is assigned to a location we
|
|
656 can reference. */
|
|
657 if ((CONSTANT_CLASS_P (exp) && TREE_CODE (exp) != STRING_CST)
|
|
658 || TREE_CODE (exp) == CALL_EXPR)
|
|
659 exp = force_target_expr (exp);
|
|
660
|
|
661 d_mark_addressable (exp);
|
|
662 exp = build_fold_addr_expr_with_type_loc (input_location, exp, ptrtype);
|
|
663
|
|
664 if (TREE_CODE (exp) == ADDR_EXPR)
|
|
665 TREE_NO_TRAMPOLINE (exp) = 1;
|
|
666
|
|
667 return compound_expr (init, exp);
|
|
668 }
|
|
669
|
|
670 /* Mark EXP saying that we need to be able to take the
|
|
671 address of it; it should not be allocated in a register. */
|
|
672
|
|
673 tree
|
|
674 d_mark_addressable (tree exp)
|
|
675 {
|
|
676 switch (TREE_CODE (exp))
|
|
677 {
|
|
678 case ADDR_EXPR:
|
|
679 case COMPONENT_REF:
|
|
680 case ARRAY_REF:
|
|
681 case REALPART_EXPR:
|
|
682 case IMAGPART_EXPR:
|
|
683 d_mark_addressable (TREE_OPERAND (exp, 0));
|
|
684 break;
|
|
685
|
|
686 case PARM_DECL:
|
|
687 case VAR_DECL:
|
|
688 case RESULT_DECL:
|
|
689 case CONST_DECL:
|
|
690 case FUNCTION_DECL:
|
|
691 TREE_ADDRESSABLE (exp) = 1;
|
|
692 break;
|
|
693
|
|
694 case CONSTRUCTOR:
|
|
695 TREE_ADDRESSABLE (exp) = 1;
|
|
696 break;
|
|
697
|
|
698 case TARGET_EXPR:
|
|
699 TREE_ADDRESSABLE (exp) = 1;
|
|
700 d_mark_addressable (TREE_OPERAND (exp, 0));
|
|
701 break;
|
|
702
|
|
703 default:
|
|
704 break;
|
|
705 }
|
|
706
|
|
707 return exp;
|
|
708 }
|
|
709
|
|
710 /* Mark EXP as "used" in the program for the benefit of
|
|
711 -Wunused warning purposes. */
|
|
712
|
|
713 tree
|
|
714 d_mark_used (tree exp)
|
|
715 {
|
|
716 switch (TREE_CODE (exp))
|
|
717 {
|
|
718 case VAR_DECL:
|
|
719 case CONST_DECL:
|
|
720 case PARM_DECL:
|
|
721 case RESULT_DECL:
|
|
722 case FUNCTION_DECL:
|
|
723 TREE_USED (exp) = 1;
|
|
724 break;
|
|
725
|
|
726 case ARRAY_REF:
|
|
727 case COMPONENT_REF:
|
|
728 case MODIFY_EXPR:
|
|
729 case REALPART_EXPR:
|
|
730 case IMAGPART_EXPR:
|
|
731 case NOP_EXPR:
|
|
732 case CONVERT_EXPR:
|
|
733 case ADDR_EXPR:
|
|
734 d_mark_used (TREE_OPERAND (exp, 0));
|
|
735 break;
|
|
736
|
|
737 case COMPOUND_EXPR:
|
|
738 d_mark_used (TREE_OPERAND (exp, 0));
|
|
739 d_mark_used (TREE_OPERAND (exp, 1));
|
|
740 break;
|
|
741
|
|
742 default:
|
|
743 break;
|
|
744 }
|
|
745 return exp;
|
|
746 }
|
|
747
|
|
748 /* Mark EXP as read, not just set, for set but not used -Wunused
|
|
749 warning purposes. */
|
|
750
|
|
751 tree
|
|
752 d_mark_read (tree exp)
|
|
753 {
|
|
754 switch (TREE_CODE (exp))
|
|
755 {
|
|
756 case VAR_DECL:
|
|
757 case PARM_DECL:
|
|
758 TREE_USED (exp) = 1;
|
|
759 DECL_READ_P (exp) = 1;
|
|
760 break;
|
|
761
|
|
762 case ARRAY_REF:
|
|
763 case COMPONENT_REF:
|
|
764 case MODIFY_EXPR:
|
|
765 case REALPART_EXPR:
|
|
766 case IMAGPART_EXPR:
|
|
767 case NOP_EXPR:
|
|
768 case CONVERT_EXPR:
|
|
769 case ADDR_EXPR:
|
|
770 d_mark_read (TREE_OPERAND (exp, 0));
|
|
771 break;
|
|
772
|
|
773 case COMPOUND_EXPR:
|
|
774 d_mark_read (TREE_OPERAND (exp, 1));
|
|
775 break;
|
|
776
|
|
777 default:
|
|
778 break;
|
|
779 }
|
|
780 return exp;
|
|
781 }
|
|
782
|
|
783 /* Return TRUE if the struct SD is suitable for comparison using memcmp.
|
|
784 This is because we don't guarantee that padding is zero-initialized for
|
|
785 a stack variable, so we can't use memcmp to compare struct values. */
|
|
786
|
|
787 bool
|
|
788 identity_compare_p (StructDeclaration *sd)
|
|
789 {
|
|
790 if (sd->isUnionDeclaration ())
|
|
791 return true;
|
|
792
|
|
793 unsigned offset = 0;
|
|
794
|
|
795 for (size_t i = 0; i < sd->fields.dim; i++)
|
|
796 {
|
|
797 VarDeclaration *vd = sd->fields[i];
|
|
798 Type *tb = vd->type->toBasetype ();
|
|
799
|
|
800 /* Check inner data structures. */
|
|
801 if (tb->ty == Tstruct)
|
|
802 {
|
|
803 TypeStruct *ts = (TypeStruct *) tb;
|
|
804 if (!identity_compare_p (ts->sym))
|
|
805 return false;
|
|
806 }
|
|
807
|
|
808 /* Check for types that may have padding. */
|
|
809 if ((tb->ty == Tcomplex80 || tb->ty == Tfloat80 || tb->ty == Timaginary80)
|
|
810 && Target::realpad != 0)
|
|
811 return false;
|
|
812
|
|
813 if (offset <= vd->offset)
|
|
814 {
|
|
815 /* There's a hole in the struct. */
|
|
816 if (offset != vd->offset)
|
|
817 return false;
|
|
818
|
|
819 offset += vd->type->size ();
|
|
820 }
|
|
821 }
|
|
822
|
|
823 /* Any trailing padding may not be zero. */
|
|
824 if (offset < sd->structsize)
|
|
825 return false;
|
|
826
|
|
827 return true;
|
|
828 }
|
|
829
|
|
830 /* Build a floating-point identity comparison between T1 and T2, ignoring any
|
|
831 excessive padding in the type. CODE is EQ_EXPR or NE_EXPR comparison. */
|
|
832
|
|
833 tree
|
|
834 build_float_identity (tree_code code, tree t1, tree t2)
|
|
835 {
|
|
836 tree tmemcmp = builtin_decl_explicit (BUILT_IN_MEMCMP);
|
|
837 tree size = size_int (TYPE_PRECISION (TREE_TYPE (t1)) / BITS_PER_UNIT);
|
|
838
|
|
839 tree result = build_call_expr (tmemcmp, 3, build_address (t1),
|
|
840 build_address (t2), size);
|
|
841 return build_boolop (code, result, integer_zero_node);
|
|
842 }
|
|
843
|
|
844 /* Lower a field-by-field equality expression between T1 and T2 of type SD.
|
|
845 CODE is the EQ_EXPR or NE_EXPR comparison. */
|
|
846
|
|
847 static tree
|
|
848 lower_struct_comparison (tree_code code, StructDeclaration *sd,
|
|
849 tree t1, tree t2)
|
|
850 {
|
|
851 tree_code tcode = (code == EQ_EXPR) ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR;
|
|
852 tree tmemcmp = NULL_TREE;
|
|
853
|
|
854 /* We can skip the compare if the structs are empty. */
|
|
855 if (sd->fields.dim == 0)
|
|
856 {
|
|
857 tmemcmp = build_boolop (code, integer_zero_node, integer_zero_node);
|
|
858 if (TREE_SIDE_EFFECTS (t2))
|
|
859 tmemcmp = compound_expr (t2, tmemcmp);
|
|
860 if (TREE_SIDE_EFFECTS (t1))
|
|
861 tmemcmp = compound_expr (t1, tmemcmp);
|
|
862
|
|
863 return tmemcmp;
|
|
864 }
|
|
865
|
|
866 /* Let back-end take care of union comparisons. */
|
|
867 if (sd->isUnionDeclaration ())
|
|
868 {
|
|
869 tmemcmp = build_call_expr (builtin_decl_explicit (BUILT_IN_MEMCMP), 3,
|
|
870 build_address (t1), build_address (t2),
|
|
871 size_int (sd->structsize));
|
|
872
|
|
873 return build_boolop (code, tmemcmp, integer_zero_node);
|
|
874 }
|
|
875
|
|
876 for (size_t i = 0; i < sd->fields.dim; i++)
|
|
877 {
|
|
878 VarDeclaration *vd = sd->fields[i];
|
|
879 Type *type = vd->type->toBasetype ();
|
|
880 tree sfield = get_symbol_decl (vd);
|
|
881
|
|
882 tree t1ref = component_ref (t1, sfield);
|
|
883 tree t2ref = component_ref (t2, sfield);
|
|
884 tree tcmp;
|
|
885
|
|
886 if (type->ty == Tstruct)
|
|
887 {
|
|
888 /* Compare inner data structures. */
|
|
889 StructDeclaration *decl = ((TypeStruct *) type)->sym;
|
|
890 tcmp = lower_struct_comparison (code, decl, t1ref, t2ref);
|
|
891 }
|
|
892 else if (type->ty != Tvector && type->isintegral ())
|
|
893 {
|
|
894 /* Integer comparison, no special handling required. */
|
|
895 tcmp = build_boolop (code, t1ref, t2ref);
|
|
896 }
|
|
897 else if (type->ty != Tvector && type->isfloating ())
|
|
898 {
|
|
899 /* Floating-point comparison, don't compare padding in type. */
|
|
900 if (!type->iscomplex ())
|
|
901 tcmp = build_float_identity (code, t1ref, t2ref);
|
|
902 else
|
|
903 {
|
|
904 tree req = build_float_identity (code, real_part (t1ref),
|
|
905 real_part (t2ref));
|
|
906 tree ieq = build_float_identity (code, imaginary_part (t1ref),
|
|
907 imaginary_part (t2ref));
|
|
908
|
|
909 tcmp = build_boolop (tcode, req, ieq);
|
|
910 }
|
|
911 }
|
|
912 else
|
|
913 {
|
|
914 tree stype = build_ctype (type);
|
|
915 opt_scalar_int_mode mode = int_mode_for_mode (TYPE_MODE (stype));
|
|
916
|
|
917 if (mode.exists ())
|
|
918 {
|
|
919 /* Compare field bits as their corresponding integer type.
|
|
920 *((T*) &t1) == *((T*) &t2) */
|
|
921 tree tmode = lang_hooks.types.type_for_mode (mode.require (), 1);
|
|
922
|
|
923 if (tmode == NULL_TREE)
|
|
924 tmode = make_unsigned_type (GET_MODE_BITSIZE (mode.require ()));
|
|
925
|
|
926 t1ref = build_vconvert (tmode, t1ref);
|
|
927 t2ref = build_vconvert (tmode, t2ref);
|
|
928
|
|
929 tcmp = build_boolop (code, t1ref, t2ref);
|
|
930 }
|
|
931 else
|
|
932 {
|
|
933 /* Simple memcmp between types. */
|
|
934 tcmp = build_call_expr (builtin_decl_explicit (BUILT_IN_MEMCMP),
|
|
935 3, build_address (t1ref),
|
|
936 build_address (t2ref),
|
|
937 TYPE_SIZE_UNIT (stype));
|
|
938
|
|
939 tcmp = build_boolop (code, tcmp, integer_zero_node);
|
|
940 }
|
|
941 }
|
|
942
|
|
943 tmemcmp = (tmemcmp) ? build_boolop (tcode, tmemcmp, tcmp) : tcmp;
|
|
944 }
|
|
945
|
|
946 return tmemcmp;
|
|
947 }
|
|
948
|
|
949
|
|
950 /* Build an equality expression between two RECORD_TYPES T1 and T2 of type SD.
|
|
951 If possible, use memcmp, otherwise field-by-field comparison is done.
|
|
952 CODE is the EQ_EXPR or NE_EXPR comparison. */
|
|
953
|
|
954 tree
|
|
955 build_struct_comparison (tree_code code, StructDeclaration *sd,
|
|
956 tree t1, tree t2)
|
|
957 {
|
|
958 /* We can skip the compare if the structs are empty. */
|
|
959 if (sd->fields.dim == 0)
|
|
960 {
|
|
961 tree exp = build_boolop (code, integer_zero_node, integer_zero_node);
|
|
962 if (TREE_SIDE_EFFECTS (t2))
|
|
963 exp = compound_expr (t2, exp);
|
|
964 if (TREE_SIDE_EFFECTS (t1))
|
|
965 exp = compound_expr (t1, exp);
|
|
966
|
|
967 return exp;
|
|
968 }
|
|
969
|
|
970 /* Make temporaries to prevent multiple evaluations. */
|
|
971 tree t1init = stabilize_expr (&t1);
|
|
972 tree t2init = stabilize_expr (&t2);
|
|
973 tree result;
|
|
974
|
|
975 t1 = d_save_expr (t1);
|
|
976 t2 = d_save_expr (t2);
|
|
977
|
|
978 /* Bitwise comparison of structs not returned in memory may not work
|
|
979 due to data holes loosing its zero padding upon return.
|
|
980 As a heuristic, small structs are not compared using memcmp either. */
|
|
981 if (TYPE_MODE (TREE_TYPE (t1)) != BLKmode || !identity_compare_p (sd))
|
|
982 result = lower_struct_comparison (code, sd, t1, t2);
|
|
983 else
|
|
984 {
|
|
985 /* Do bit compare of structs. */
|
|
986 tree size = size_int (sd->structsize);
|
|
987 tree tmemcmp = build_call_expr (builtin_decl_explicit (BUILT_IN_MEMCMP),
|
|
988 3, build_address (t1),
|
|
989 build_address (t2), size);
|
|
990
|
|
991 result = build_boolop (code, tmemcmp, integer_zero_node);
|
|
992 }
|
|
993
|
|
994 return compound_expr (compound_expr (t1init, t2init), result);
|
|
995 }
|
|
996
|
|
997 /* Build an equality expression between two ARRAY_TYPES of size LENGTH.
|
|
998 The pointer references are T1 and T2, and the element type is SD.
|
|
999 CODE is the EQ_EXPR or NE_EXPR comparison. */
|
|
1000
|
|
1001 tree
|
|
1002 build_array_struct_comparison (tree_code code, StructDeclaration *sd,
|
|
1003 tree length, tree t1, tree t2)
|
|
1004 {
|
|
1005 tree_code tcode = (code == EQ_EXPR) ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR;
|
|
1006
|
|
1007 /* Build temporary for the result of the comparison.
|
|
1008 Initialize as either 0 or 1 depending on operation. */
|
|
1009 tree result = build_local_temp (d_bool_type);
|
|
1010 tree init = build_boolop (code, integer_zero_node, integer_zero_node);
|
|
1011 add_stmt (build_assign (INIT_EXPR, result, init));
|
|
1012
|
|
1013 /* Cast pointer-to-array to pointer-to-struct. */
|
|
1014 tree ptrtype = build_ctype (sd->type->pointerTo ());
|
|
1015 tree lentype = TREE_TYPE (length);
|
|
1016
|
|
1017 push_binding_level (level_block);
|
|
1018 push_stmt_list ();
|
|
1019
|
|
1020 /* Build temporary locals for length and pointers. */
|
|
1021 tree t = build_local_temp (size_type_node);
|
|
1022 add_stmt (build_assign (INIT_EXPR, t, length));
|
|
1023 length = t;
|
|
1024
|
|
1025 t = build_local_temp (ptrtype);
|
|
1026 add_stmt (build_assign (INIT_EXPR, t, d_convert (ptrtype, t1)));
|
|
1027 t1 = t;
|
|
1028
|
|
1029 t = build_local_temp (ptrtype);
|
|
1030 add_stmt (build_assign (INIT_EXPR, t, d_convert (ptrtype, t2)));
|
|
1031 t2 = t;
|
|
1032
|
|
1033 /* Build loop for comparing each element. */
|
|
1034 push_stmt_list ();
|
|
1035
|
|
1036 /* Exit logic for the loop.
|
|
1037 if (length == 0 || result OP 0) break; */
|
|
1038 t = build_boolop (EQ_EXPR, length, d_convert (lentype, integer_zero_node));
|
|
1039 t = build_boolop (TRUTH_ORIF_EXPR, t, build_boolop (code, result,
|
|
1040 boolean_false_node));
|
|
1041 t = build1 (EXIT_EXPR, void_type_node, t);
|
|
1042 add_stmt (t);
|
|
1043
|
|
1044 /* Do comparison, caching the value.
|
|
1045 result = result OP (*t1 == *t2); */
|
|
1046 t = build_struct_comparison (code, sd, build_deref (t1), build_deref (t2));
|
|
1047 t = build_boolop (tcode, result, t);
|
|
1048 t = modify_expr (result, t);
|
|
1049 add_stmt (t);
|
|
1050
|
|
1051 /* Move both pointers to next element position.
|
|
1052 t1++, t2++; */
|
|
1053 tree size = d_convert (ptrtype, TYPE_SIZE_UNIT (TREE_TYPE (ptrtype)));
|
|
1054 t = build2 (POSTINCREMENT_EXPR, ptrtype, t1, size);
|
|
1055 add_stmt (t);
|
|
1056 t = build2 (POSTINCREMENT_EXPR, ptrtype, t2, size);
|
|
1057 add_stmt (t);
|
|
1058
|
|
1059 /* Decrease loop counter.
|
|
1060 length -= 1; */
|
|
1061 t = build2 (POSTDECREMENT_EXPR, lentype, length,
|
|
1062 d_convert (lentype, integer_one_node));
|
|
1063 add_stmt (t);
|
|
1064
|
|
1065 /* Pop statements and finish loop. */
|
|
1066 tree body = pop_stmt_list ();
|
|
1067 add_stmt (build1 (LOOP_EXPR, void_type_node, body));
|
|
1068
|
|
1069 /* Wrap it up into a bind expression. */
|
|
1070 tree stmt_list = pop_stmt_list ();
|
|
1071 tree block = pop_binding_level ();
|
|
1072
|
|
1073 body = build3 (BIND_EXPR, void_type_node,
|
|
1074 BLOCK_VARS (block), stmt_list, block);
|
|
1075
|
|
1076 return compound_expr (body, result);
|
|
1077 }
|
|
1078
|
|
1079 /* Create an anonymous field of type ubyte[T] at OFFSET to fill
|
|
1080 the alignment hole between OFFSET and FIELDPOS. */
|
|
1081
|
|
1082 static tree
|
|
1083 build_alignment_field (tree type, HOST_WIDE_INT offset, HOST_WIDE_INT fieldpos)
|
|
1084 {
|
|
1085 tree atype = make_array_type (Type::tuns8, fieldpos - offset);
|
|
1086 tree field = create_field_decl (atype, NULL, 1, 1);
|
|
1087
|
|
1088 SET_DECL_OFFSET_ALIGN (field, TYPE_ALIGN (atype));
|
|
1089 DECL_FIELD_OFFSET (field) = size_int (offset);
|
|
1090 DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node;
|
|
1091 DECL_FIELD_CONTEXT (field) = type;
|
|
1092 DECL_PADDING_P (field) = 1;
|
|
1093
|
|
1094 layout_decl (field, 0);
|
|
1095
|
|
1096 return field;
|
|
1097 }
|
|
1098
|
|
1099 /* Build a constructor for a variable of aggregate type TYPE using the
|
|
1100 initializer INIT, an ordered flat list of fields and values provided
|
|
1101 by the frontend. The returned constructor should be a value that
|
|
1102 matches the layout of TYPE. */
|
|
1103
|
|
1104 tree
|
|
1105 build_struct_literal (tree type, vec<constructor_elt, va_gc> *init)
|
|
1106 {
|
|
1107 /* If the initializer was empty, use default zero initialization. */
|
|
1108 if (vec_safe_is_empty (init))
|
|
1109 return build_constructor (type, NULL);
|
|
1110
|
|
1111 vec<constructor_elt, va_gc> *ve = NULL;
|
|
1112 HOST_WIDE_INT offset = 0;
|
|
1113 bool constant_p = true;
|
|
1114 bool fillholes = true;
|
|
1115 bool finished = false;
|
|
1116
|
|
1117 /* Filling alignment holes this only applies to structs. */
|
|
1118 if (TREE_CODE (type) != RECORD_TYPE
|
|
1119 || CLASS_TYPE_P (type) || TYPE_PACKED (type))
|
|
1120 fillholes = false;
|
|
1121
|
|
1122 /* Walk through each field, matching our initializer list. */
|
|
1123 for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
|
|
1124 {
|
|
1125 bool is_initialized = false;
|
|
1126 tree value;
|
|
1127
|
|
1128 if (DECL_NAME (field) == NULL_TREE
|
|
1129 && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
|
|
1130 && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
|
|
1131 {
|
|
1132 /* Search all nesting aggregates, if nothing is found, then
|
|
1133 this will return an empty initializer to fill the hole. */
|
|
1134 value = build_struct_literal (TREE_TYPE (field), init);
|
|
1135
|
|
1136 if (!initializer_zerop (value))
|
|
1137 is_initialized = true;
|
|
1138 }
|
|
1139 else
|
|
1140 {
|
|
1141 /* Search for the value to initialize the next field. Once found,
|
|
1142 pop it from the init list so we don't look at it again. */
|
|
1143 unsigned HOST_WIDE_INT idx;
|
|
1144 tree index;
|
|
1145
|
|
1146 FOR_EACH_CONSTRUCTOR_ELT (init, idx, index, value)
|
|
1147 {
|
|
1148 /* If the index is NULL, then just assign it to the next field.
|
|
1149 This comes from layout_typeinfo(), which generates a flat
|
|
1150 list of values that we must shape into the record type. */
|
|
1151 if (index == field || index == NULL_TREE)
|
|
1152 {
|
|
1153 init->ordered_remove (idx);
|
|
1154 if (!finished)
|
|
1155 is_initialized = true;
|
|
1156 break;
|
|
1157 }
|
|
1158 }
|
|
1159 }
|
|
1160
|
|
1161 if (is_initialized)
|
|
1162 {
|
|
1163 HOST_WIDE_INT fieldpos = int_byte_position (field);
|
|
1164 gcc_assert (value != NULL_TREE);
|
|
1165
|
|
1166 /* Insert anonymous fields in the constructor for padding out
|
|
1167 alignment holes in-place between fields. */
|
|
1168 if (fillholes && offset < fieldpos)
|
|
1169 {
|
|
1170 tree pfield = build_alignment_field (type, offset, fieldpos);
|
|
1171 tree pvalue = build_zero_cst (TREE_TYPE (pfield));
|
|
1172 CONSTRUCTOR_APPEND_ELT (ve, pfield, pvalue);
|
|
1173 }
|
|
1174
|
|
1175 /* Must not initialize fields that overlap. */
|
|
1176 if (fieldpos < offset)
|
|
1177 {
|
|
1178 /* Find the nearest user defined type and field. */
|
|
1179 tree vtype = type;
|
|
1180 while (ANON_AGGR_TYPE_P (vtype))
|
|
1181 vtype = TYPE_CONTEXT (vtype);
|
|
1182
|
|
1183 tree vfield = field;
|
|
1184 if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (vfield))
|
|
1185 && ANON_AGGR_TYPE_P (TREE_TYPE (vfield)))
|
|
1186 vfield = TYPE_FIELDS (TREE_TYPE (vfield));
|
|
1187
|
|
1188 /* Must not generate errors for compiler generated fields. */
|
|
1189 gcc_assert (TYPE_NAME (vtype) && DECL_NAME (vfield));
|
|
1190 error ("overlapping initializer for field %qT.%qD",
|
|
1191 TYPE_NAME (vtype), DECL_NAME (vfield));
|
|
1192 }
|
|
1193
|
|
1194 if (!TREE_CONSTANT (value))
|
|
1195 constant_p = false;
|
|
1196
|
|
1197 CONSTRUCTOR_APPEND_ELT (ve, field, value);
|
|
1198
|
|
1199 /* For unions, only the first field is initialized, any other field
|
|
1200 initializers found for this union are drained and ignored. */
|
|
1201 if (TREE_CODE (type) == UNION_TYPE)
|
|
1202 finished = true;
|
|
1203 }
|
|
1204
|
|
1205 /* Move offset to the next position in the struct. */
|
|
1206 if (TREE_CODE (type) == RECORD_TYPE)
|
|
1207 {
|
|
1208 offset = int_byte_position (field)
|
|
1209 + int_size_in_bytes (TREE_TYPE (field));
|
|
1210 }
|
|
1211
|
|
1212 /* If all initializers have been assigned, there's nothing else to do. */
|
|
1213 if (vec_safe_is_empty (init))
|
|
1214 break;
|
|
1215 }
|
|
1216
|
|
1217 /* Finally pad out the end of the record. */
|
|
1218 if (fillholes && offset < int_size_in_bytes (type))
|
|
1219 {
|
|
1220 tree pfield = build_alignment_field (type, offset,
|
|
1221 int_size_in_bytes (type));
|
|
1222 tree pvalue = build_zero_cst (TREE_TYPE (pfield));
|
|
1223 CONSTRUCTOR_APPEND_ELT (ve, pfield, pvalue);
|
|
1224 }
|
|
1225
|
|
1226 /* Ensure that we have consumed all values. */
|
|
1227 gcc_assert (vec_safe_is_empty (init) || ANON_AGGR_TYPE_P (type));
|
|
1228
|
|
1229 tree ctor = build_constructor (type, ve);
|
|
1230
|
|
1231 if (constant_p)
|
|
1232 TREE_CONSTANT (ctor) = 1;
|
|
1233
|
|
1234 return ctor;
|
|
1235 }
|
|
1236
|
|
1237 /* Given the TYPE of an anonymous field inside T, return the
|
|
1238 FIELD_DECL for the field. If not found return NULL_TREE.
|
|
1239 Because anonymous types can nest, we must also search all
|
|
1240 anonymous fields that are directly reachable. */
|
|
1241
|
|
1242 static tree
|
|
1243 lookup_anon_field (tree t, tree type)
|
|
1244 {
|
|
1245 t = TYPE_MAIN_VARIANT (t);
|
|
1246
|
|
1247 for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
|
|
1248 {
|
|
1249 if (DECL_NAME (field) == NULL_TREE)
|
|
1250 {
|
|
1251 /* If we find it directly, return the field. */
|
|
1252 if (type == TYPE_MAIN_VARIANT (TREE_TYPE (field)))
|
|
1253 return field;
|
|
1254
|
|
1255 /* Otherwise, it could be nested, search harder. */
|
|
1256 if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
|
|
1257 && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
|
|
1258 {
|
|
1259 tree subfield = lookup_anon_field (TREE_TYPE (field), type);
|
|
1260 if (subfield)
|
|
1261 return subfield;
|
|
1262 }
|
|
1263 }
|
|
1264 }
|
|
1265
|
|
1266 return NULL_TREE;
|
|
1267 }
|
|
1268
|
|
1269 /* Builds OBJECT.FIELD component reference. */
|
|
1270
|
|
1271 tree
|
|
1272 component_ref (tree object, tree field)
|
|
1273 {
|
|
1274 if (error_operand_p (object) || error_operand_p (field))
|
|
1275 return error_mark_node;
|
|
1276
|
|
1277 gcc_assert (TREE_CODE (field) == FIELD_DECL);
|
|
1278
|
|
1279 /* Maybe rewrite: (e1, e2).field => (e1, e2.field) */
|
|
1280 tree init = stabilize_expr (&object);
|
|
1281
|
|
1282 /* If the FIELD is from an anonymous aggregate, generate a reference
|
|
1283 to the anonymous data member, and recur to find FIELD. */
|
|
1284 if (ANON_AGGR_TYPE_P (DECL_CONTEXT (field)))
|
|
1285 {
|
|
1286 tree anonymous_field = lookup_anon_field (TREE_TYPE (object),
|
|
1287 DECL_CONTEXT (field));
|
|
1288 object = component_ref (object, anonymous_field);
|
|
1289 }
|
|
1290
|
|
1291 tree result = fold_build3_loc (input_location, COMPONENT_REF,
|
|
1292 TREE_TYPE (field), object, field, NULL_TREE);
|
|
1293
|
|
1294 return compound_expr (init, result);
|
|
1295 }
|
|
1296
|
|
1297 /* Build an assignment expression of lvalue LHS from value RHS.
|
|
1298 CODE is the code for a binary operator that we use to combine
|
|
1299 the old value of LHS with RHS to get the new value. */
|
|
1300
|
|
1301 tree
|
|
1302 build_assign (tree_code code, tree lhs, tree rhs)
|
|
1303 {
|
|
1304 tree init = stabilize_expr (&lhs);
|
|
1305 init = compound_expr (init, stabilize_expr (&rhs));
|
|
1306
|
|
1307 /* If initializing the LHS using a function that returns via NRVO. */
|
|
1308 if (code == INIT_EXPR && TREE_CODE (rhs) == CALL_EXPR
|
|
1309 && AGGREGATE_TYPE_P (TREE_TYPE (rhs))
|
|
1310 && aggregate_value_p (TREE_TYPE (rhs), rhs))
|
|
1311 {
|
|
1312 /* Mark as addressable here, which should ensure the return slot is the
|
|
1313 address of the LHS expression, taken care of by back-end. */
|
|
1314 d_mark_addressable (lhs);
|
|
1315 CALL_EXPR_RETURN_SLOT_OPT (rhs) = true;
|
|
1316 }
|
|
1317
|
|
1318 /* The LHS assignment replaces the temporary in TARGET_EXPR_SLOT. */
|
|
1319 if (TREE_CODE (rhs) == TARGET_EXPR)
|
|
1320 {
|
|
1321 /* If CODE is not INIT_EXPR, can't initialize LHS directly,
|
|
1322 since that would cause the LHS to be constructed twice.
|
|
1323 So we force the TARGET_EXPR to be expanded without a target. */
|
|
1324 if (code != INIT_EXPR)
|
|
1325 rhs = compound_expr (rhs, TARGET_EXPR_SLOT (rhs));
|
|
1326 else
|
|
1327 {
|
|
1328 d_mark_addressable (lhs);
|
|
1329 rhs = TARGET_EXPR_INITIAL (rhs);
|
|
1330 }
|
|
1331 }
|
|
1332
|
|
1333 tree result = fold_build2_loc (input_location, code,
|
|
1334 TREE_TYPE (lhs), lhs, rhs);
|
|
1335 return compound_expr (init, result);
|
|
1336 }
|
|
1337
|
|
1338 /* Build an assignment expression of lvalue LHS from value RHS. */
|
|
1339
|
|
1340 tree
|
|
1341 modify_expr (tree lhs, tree rhs)
|
|
1342 {
|
|
1343 return build_assign (MODIFY_EXPR, lhs, rhs);
|
|
1344 }
|
|
1345
|
|
1346 /* Return EXP represented as TYPE. */
|
|
1347
|
|
1348 tree
|
|
1349 build_nop (tree type, tree exp)
|
|
1350 {
|
|
1351 if (error_operand_p (exp))
|
|
1352 return exp;
|
|
1353
|
|
1354 /* Maybe rewrite: cast(TYPE)(e1, e2) => (e1, cast(TYPE) e2) */
|
|
1355 tree init = stabilize_expr (&exp);
|
|
1356 exp = fold_build1_loc (input_location, NOP_EXPR, type, exp);
|
|
1357
|
|
1358 return compound_expr (init, exp);
|
|
1359 }
|
|
1360
|
|
1361 /* Return EXP to be viewed as being another type TYPE. Same as build_nop,
|
|
1362 except that EXP is type-punned, rather than a straight-forward cast. */
|
|
1363
|
|
1364 tree
|
|
1365 build_vconvert (tree type, tree exp)
|
|
1366 {
|
|
1367 /* Building *(cast(TYPE *)&e1) directly rather then using VIEW_CONVERT_EXPR
|
|
1368 makes sure this works for vector-to-array viewing, or if EXP ends up being
|
|
1369 used as the LHS of a MODIFY_EXPR. */
|
|
1370 return indirect_ref (type, build_address (exp));
|
|
1371 }
|
|
1372
|
|
1373 /* Maybe warn about ARG being an address that can never be null. */
|
|
1374
|
|
1375 static void
|
|
1376 warn_for_null_address (tree arg)
|
|
1377 {
|
|
1378 if (TREE_CODE (arg) == ADDR_EXPR
|
|
1379 && decl_with_nonnull_addr_p (TREE_OPERAND (arg, 0)))
|
|
1380 warning (OPT_Waddress,
|
|
1381 "the address of %qD will never be %<null%>",
|
|
1382 TREE_OPERAND (arg, 0));
|
|
1383 }
|
|
1384
|
|
1385 /* Build a boolean ARG0 op ARG1 expression. */
|
|
1386
|
|
1387 tree
|
|
1388 build_boolop (tree_code code, tree arg0, tree arg1)
|
|
1389 {
|
|
1390 /* Aggregate comparisons may get lowered to a call to builtin memcmp,
|
|
1391 so need to remove all side effects incase its address is taken. */
|
|
1392 if (AGGREGATE_TYPE_P (TREE_TYPE (arg0)))
|
|
1393 arg0 = d_save_expr (arg0);
|
|
1394 if (AGGREGATE_TYPE_P (TREE_TYPE (arg1)))
|
|
1395 arg1 = d_save_expr (arg1);
|
|
1396
|
|
1397 if (VECTOR_TYPE_P (TREE_TYPE (arg0)) && VECTOR_TYPE_P (TREE_TYPE (arg1)))
|
|
1398 {
|
|
1399 /* Build a vector comparison.
|
|
1400 VEC_COND_EXPR <e1 op e2, { -1, -1, -1, -1 }, { 0, 0, 0, 0 }>; */
|
|
1401 tree type = TREE_TYPE (arg0);
|
|
1402 tree cmptype = truth_type_for (type);
|
|
1403 tree cmp = fold_build2_loc (input_location, code, cmptype, arg0, arg1);
|
|
1404
|
|
1405 return fold_build3_loc (input_location, VEC_COND_EXPR, type, cmp,
|
|
1406 build_minus_one_cst (type),
|
|
1407 build_zero_cst (type));
|
|
1408 }
|
|
1409
|
|
1410 if (code == EQ_EXPR || code == NE_EXPR)
|
|
1411 {
|
|
1412 /* Check if comparing the address of a variable to null. */
|
|
1413 if (POINTER_TYPE_P (TREE_TYPE (arg0)) && integer_zerop (arg1))
|
|
1414 warn_for_null_address (arg0);
|
|
1415 if (POINTER_TYPE_P (TREE_TYPE (arg1)) && integer_zerop (arg0))
|
|
1416 warn_for_null_address (arg1);
|
|
1417 }
|
|
1418
|
|
1419 return fold_build2_loc (input_location, code, d_bool_type,
|
|
1420 arg0, d_convert (TREE_TYPE (arg0), arg1));
|
|
1421 }
|
|
1422
|
|
1423 /* Return a COND_EXPR. ARG0, ARG1, and ARG2 are the three
|
|
1424 arguments to the conditional expression. */
|
|
1425
|
|
1426 tree
|
|
1427 build_condition (tree type, tree arg0, tree arg1, tree arg2)
|
|
1428 {
|
|
1429 if (arg1 == void_node)
|
|
1430 arg1 = build_empty_stmt (input_location);
|
|
1431
|
|
1432 if (arg2 == void_node)
|
|
1433 arg2 = build_empty_stmt (input_location);
|
|
1434
|
|
1435 return fold_build3_loc (input_location, COND_EXPR,
|
|
1436 type, arg0, arg1, arg2);
|
|
1437 }
|
|
1438
|
|
1439 tree
|
|
1440 build_vcondition (tree arg0, tree arg1, tree arg2)
|
|
1441 {
|
|
1442 return build_condition (void_type_node, arg0, arg1, arg2);
|
|
1443 }
|
|
1444
|
|
1445 /* Build a compound expr to join ARG0 and ARG1 together. */
|
|
1446
|
|
1447 tree
|
|
1448 compound_expr (tree arg0, tree arg1)
|
|
1449 {
|
|
1450 if (arg1 == NULL_TREE)
|
|
1451 return arg0;
|
|
1452
|
|
1453 if (arg0 == NULL_TREE || !TREE_SIDE_EFFECTS (arg0))
|
|
1454 return arg1;
|
|
1455
|
|
1456 if (TREE_CODE (arg1) == TARGET_EXPR)
|
|
1457 {
|
|
1458 /* If the rhs is a TARGET_EXPR, then build the compound expression
|
|
1459 inside the target_expr's initializer. This helps the compiler
|
|
1460 to eliminate unnecessary temporaries. */
|
|
1461 tree init = compound_expr (arg0, TARGET_EXPR_INITIAL (arg1));
|
|
1462 TARGET_EXPR_INITIAL (arg1) = init;
|
|
1463
|
|
1464 return arg1;
|
|
1465 }
|
|
1466
|
|
1467 return fold_build2_loc (input_location, COMPOUND_EXPR,
|
|
1468 TREE_TYPE (arg1), arg0, arg1);
|
|
1469 }
|
|
1470
|
|
1471 /* Build a return expression. */
|
|
1472
|
|
1473 tree
|
|
1474 return_expr (tree ret)
|
|
1475 {
|
|
1476 return fold_build1_loc (input_location, RETURN_EXPR,
|
|
1477 void_type_node, ret);
|
|
1478 }
|
|
1479
|
|
1480 /* Return the product of ARG0 and ARG1 as a size_type_node. */
|
|
1481
|
|
1482 tree
|
|
1483 size_mult_expr (tree arg0, tree arg1)
|
|
1484 {
|
|
1485 return fold_build2_loc (input_location, MULT_EXPR, size_type_node,
|
|
1486 d_convert (size_type_node, arg0),
|
|
1487 d_convert (size_type_node, arg1));
|
|
1488
|
|
1489 }
|
|
1490
|
|
1491 /* Return the real part of CE, which should be a complex expression. */
|
|
1492
|
|
1493 tree
|
|
1494 real_part (tree ce)
|
|
1495 {
|
|
1496 return fold_build1_loc (input_location, REALPART_EXPR,
|
|
1497 TREE_TYPE (TREE_TYPE (ce)), ce);
|
|
1498 }
|
|
1499
|
|
1500 /* Return the imaginary part of CE, which should be a complex expression. */
|
|
1501
|
|
1502 tree
|
|
1503 imaginary_part (tree ce)
|
|
1504 {
|
|
1505 return fold_build1_loc (input_location, IMAGPART_EXPR,
|
|
1506 TREE_TYPE (TREE_TYPE (ce)), ce);
|
|
1507 }
|
|
1508
|
|
1509 /* Build a complex expression of type TYPE using RE and IM. */
|
|
1510
|
|
1511 tree
|
|
1512 complex_expr (tree type, tree re, tree im)
|
|
1513 {
|
|
1514 return fold_build2_loc (input_location, COMPLEX_EXPR,
|
|
1515 type, re, im);
|
|
1516 }
|
|
1517
|
|
1518 /* Cast EXP (which should be a pointer) to TYPE* and then indirect.
|
|
1519 The back-end requires this cast in many cases. */
|
|
1520
|
|
1521 tree
|
|
1522 indirect_ref (tree type, tree exp)
|
|
1523 {
|
|
1524 if (error_operand_p (exp))
|
|
1525 return exp;
|
|
1526
|
|
1527 /* Maybe rewrite: *(e1, e2) => (e1, *e2) */
|
|
1528 tree init = stabilize_expr (&exp);
|
|
1529
|
|
1530 if (TREE_CODE (TREE_TYPE (exp)) == REFERENCE_TYPE)
|
|
1531 exp = fold_build1 (INDIRECT_REF, type, exp);
|
|
1532 else
|
|
1533 {
|
|
1534 exp = build_nop (build_pointer_type (type), exp);
|
|
1535 exp = build_deref (exp);
|
|
1536 }
|
|
1537
|
|
1538 return compound_expr (init, exp);
|
|
1539 }
|
|
1540
|
|
1541 /* Returns indirect reference of EXP, which must be a pointer type. */
|
|
1542
|
|
1543 tree
|
|
1544 build_deref (tree exp)
|
|
1545 {
|
|
1546 if (error_operand_p (exp))
|
|
1547 return exp;
|
|
1548
|
|
1549 /* Maybe rewrite: *(e1, e2) => (e1, *e2) */
|
|
1550 tree init = stabilize_expr (&exp);
|
|
1551
|
|
1552 gcc_assert (POINTER_TYPE_P (TREE_TYPE (exp)));
|
|
1553
|
|
1554 if (TREE_CODE (exp) == ADDR_EXPR)
|
|
1555 exp = TREE_OPERAND (exp, 0);
|
|
1556 else
|
|
1557 exp = build_fold_indirect_ref (exp);
|
|
1558
|
|
1559 return compound_expr (init, exp);
|
|
1560 }
|
|
1561
|
|
1562 /* Builds pointer offset expression PTR[INDEX]. */
|
|
1563
|
|
1564 tree
|
|
1565 build_array_index (tree ptr, tree index)
|
|
1566 {
|
|
1567 if (error_operand_p (ptr) || error_operand_p (index))
|
|
1568 return error_mark_node;
|
|
1569
|
|
1570 tree ptr_type = TREE_TYPE (ptr);
|
|
1571 tree target_type = TREE_TYPE (ptr_type);
|
|
1572
|
|
1573 tree type = lang_hooks.types.type_for_size (TYPE_PRECISION (sizetype),
|
|
1574 TYPE_UNSIGNED (sizetype));
|
|
1575
|
|
1576 /* Array element size. */
|
|
1577 tree size_exp = size_in_bytes (target_type);
|
|
1578
|
|
1579 if (integer_zerop (size_exp))
|
|
1580 {
|
|
1581 /* Test for array of void. */
|
|
1582 if (TYPE_MODE (target_type) == TYPE_MODE (void_type_node))
|
|
1583 index = fold_convert (type, index);
|
|
1584 else
|
|
1585 {
|
|
1586 /* Should catch this earlier. */
|
|
1587 error ("invalid use of incomplete type %qD", TYPE_NAME (target_type));
|
|
1588 ptr_type = error_mark_node;
|
|
1589 }
|
|
1590 }
|
|
1591 else if (integer_onep (size_exp))
|
|
1592 {
|
|
1593 /* Array of bytes -- No need to multiply. */
|
|
1594 index = fold_convert (type, index);
|
|
1595 }
|
|
1596 else
|
|
1597 {
|
|
1598 index = d_convert (type, index);
|
|
1599 index = fold_build2 (MULT_EXPR, TREE_TYPE (index),
|
|
1600 index, d_convert (TREE_TYPE (index), size_exp));
|
|
1601 index = fold_convert (type, index);
|
|
1602 }
|
|
1603
|
|
1604 if (integer_zerop (index))
|
|
1605 return ptr;
|
|
1606
|
|
1607 return fold_build2 (POINTER_PLUS_EXPR, ptr_type, ptr, index);
|
|
1608 }
|
|
1609
|
|
1610 /* Builds pointer offset expression *(PTR OP OFFSET)
|
|
1611 OP could be a plus or minus expression. */
|
|
1612
|
|
1613 tree
|
|
1614 build_offset_op (tree_code op, tree ptr, tree offset)
|
|
1615 {
|
|
1616 gcc_assert (op == MINUS_EXPR || op == PLUS_EXPR);
|
|
1617
|
|
1618 tree type = lang_hooks.types.type_for_size (TYPE_PRECISION (sizetype),
|
|
1619 TYPE_UNSIGNED (sizetype));
|
|
1620 offset = fold_convert (type, offset);
|
|
1621
|
|
1622 if (op == MINUS_EXPR)
|
|
1623 offset = fold_build1 (NEGATE_EXPR, type, offset);
|
|
1624
|
|
1625 return fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (ptr), ptr, offset);
|
|
1626 }
|
|
1627
|
|
1628 /* Builds pointer offset expression *(PTR + OFFSET). */
|
|
1629
|
|
1630 tree
|
|
1631 build_offset (tree ptr, tree offset)
|
|
1632 {
|
|
1633 return build_offset_op (PLUS_EXPR, ptr, offset);
|
|
1634 }
|
|
1635
|
|
1636 tree
|
|
1637 build_memref (tree type, tree ptr, tree offset)
|
|
1638 {
|
|
1639 return fold_build2 (MEM_REF, type, ptr, fold_convert (type, offset));
|
|
1640 }
|
|
1641
|
|
1642 /* Create a tree node to set multiple elements to a single value. */
|
|
1643
|
|
1644 tree
|
|
1645 build_array_set (tree ptr, tree length, tree value)
|
|
1646 {
|
|
1647 tree ptrtype = TREE_TYPE (ptr);
|
|
1648 tree lentype = TREE_TYPE (length);
|
|
1649
|
|
1650 push_binding_level (level_block);
|
|
1651 push_stmt_list ();
|
|
1652
|
|
1653 /* Build temporary locals for length and ptr, and maybe value. */
|
|
1654 tree t = build_local_temp (size_type_node);
|
|
1655 add_stmt (build_assign (INIT_EXPR, t, length));
|
|
1656 length = t;
|
|
1657
|
|
1658 t = build_local_temp (ptrtype);
|
|
1659 add_stmt (build_assign (INIT_EXPR, t, ptr));
|
|
1660 ptr = t;
|
|
1661
|
|
1662 if (TREE_SIDE_EFFECTS (value))
|
|
1663 {
|
|
1664 t = build_local_temp (TREE_TYPE (value));
|
|
1665 add_stmt (build_assign (INIT_EXPR, t, value));
|
|
1666 value = t;
|
|
1667 }
|
|
1668
|
|
1669 /* Build loop to initialize { .length=length, .ptr=ptr } with value. */
|
|
1670 push_stmt_list ();
|
|
1671
|
|
1672 /* Exit logic for the loop.
|
|
1673 if (length == 0) break; */
|
|
1674 t = build_boolop (EQ_EXPR, length, d_convert (lentype, integer_zero_node));
|
|
1675 t = build1 (EXIT_EXPR, void_type_node, t);
|
|
1676 add_stmt (t);
|
|
1677
|
|
1678 /* Assign value to the current pointer position.
|
|
1679 *ptr = value; */
|
|
1680 t = modify_expr (build_deref (ptr), value);
|
|
1681 add_stmt (t);
|
|
1682
|
|
1683 /* Move pointer to next element position.
|
|
1684 ptr++; */
|
|
1685 tree size = TYPE_SIZE_UNIT (TREE_TYPE (ptrtype));
|
|
1686 t = build2 (POSTINCREMENT_EXPR, ptrtype, ptr, d_convert (ptrtype, size));
|
|
1687 add_stmt (t);
|
|
1688
|
|
1689 /* Decrease loop counter.
|
|
1690 length -= 1; */
|
|
1691 t = build2 (POSTDECREMENT_EXPR, lentype, length,
|
|
1692 d_convert (lentype, integer_one_node));
|
|
1693 add_stmt (t);
|
|
1694
|
|
1695 /* Pop statements and finish loop. */
|
|
1696 tree loop_body = pop_stmt_list ();
|
|
1697 add_stmt (build1 (LOOP_EXPR, void_type_node, loop_body));
|
|
1698
|
|
1699 /* Wrap it up into a bind expression. */
|
|
1700 tree stmt_list = pop_stmt_list ();
|
|
1701 tree block = pop_binding_level ();
|
|
1702
|
|
1703 return build3 (BIND_EXPR, void_type_node,
|
|
1704 BLOCK_VARS (block), stmt_list, block);
|
|
1705 }
|
|
1706
|
|
1707
|
|
1708 /* Build an array of type TYPE where all the elements are VAL. */
|
|
1709
|
|
1710 tree
|
|
1711 build_array_from_val (Type *type, tree val)
|
|
1712 {
|
|
1713 gcc_assert (type->ty == Tsarray);
|
|
1714
|
|
1715 tree etype = build_ctype (type->nextOf ());
|
|
1716
|
|
1717 /* Initializing a multidimensional array. */
|
|
1718 if (TREE_CODE (etype) == ARRAY_TYPE && TREE_TYPE (val) != etype)
|
|
1719 val = build_array_from_val (type->nextOf (), val);
|
|
1720
|
|
1721 size_t dims = ((TypeSArray *) type)->dim->toInteger ();
|
|
1722 vec<constructor_elt, va_gc> *elms = NULL;
|
|
1723 vec_safe_reserve (elms, dims);
|
|
1724
|
|
1725 val = d_convert (etype, val);
|
|
1726
|
|
1727 for (size_t i = 0; i < dims; i++)
|
|
1728 CONSTRUCTOR_APPEND_ELT (elms, size_int (i), val);
|
|
1729
|
|
1730 return build_constructor (build_ctype (type), elms);
|
|
1731 }
|
|
1732
|
|
1733 /* Implicitly converts void* T to byte* as D allows { void[] a; &a[3]; } */
|
|
1734
|
|
1735 tree
|
|
1736 void_okay_p (tree t)
|
|
1737 {
|
|
1738 tree type = TREE_TYPE (t);
|
|
1739
|
|
1740 if (VOID_TYPE_P (TREE_TYPE (type)))
|
|
1741 {
|
|
1742 tree totype = build_ctype (Type::tuns8->pointerTo ());
|
|
1743 return fold_convert (totype, t);
|
|
1744 }
|
|
1745
|
|
1746 return t;
|
|
1747 }
|
|
1748
|
|
1749 /* Builds a bounds condition checking that INDEX is between 0 and LEN.
|
|
1750 The condition returns the INDEX if true, or throws a RangeError.
|
|
1751 If INCLUSIVE, we allow INDEX == LEN to return true also. */
|
|
1752
|
|
1753 tree
|
|
1754 build_bounds_condition (const Loc& loc, tree index, tree len, bool inclusive)
|
|
1755 {
|
|
1756 if (!array_bounds_check ())
|
|
1757 return index;
|
|
1758
|
|
1759 /* Prevent multiple evaluations of the index. */
|
|
1760 index = d_save_expr (index);
|
|
1761
|
|
1762 /* Generate INDEX >= LEN && throw RangeError.
|
|
1763 No need to check whether INDEX >= 0 as the front-end should
|
|
1764 have already taken care of implicit casts to unsigned. */
|
|
1765 tree condition = fold_build2 (inclusive ? GT_EXPR : GE_EXPR,
|
|
1766 d_bool_type, index, len);
|
|
1767 /* Terminate the program with a trap if no D runtime present. */
|
|
1768 tree boundserr = (global.params.checkAction == CHECKACTION_D)
|
|
1769 ? d_assert_call (loc, LIBCALL_ARRAY_BOUNDS)
|
|
1770 : build_call_expr (builtin_decl_explicit (BUILT_IN_TRAP), 0);
|
|
1771
|
|
1772 return build_condition (TREE_TYPE (index), condition, boundserr, index);
|
|
1773 }
|
|
1774
|
|
1775 /* Returns TRUE if array bounds checking code generation is turned on. */
|
|
1776
|
|
1777 bool
|
|
1778 array_bounds_check (void)
|
|
1779 {
|
|
1780 FuncDeclaration *fd;
|
|
1781
|
|
1782 switch (global.params.useArrayBounds)
|
|
1783 {
|
|
1784 case BOUNDSCHECKoff:
|
|
1785 return false;
|
|
1786
|
|
1787 case BOUNDSCHECKon:
|
|
1788 return true;
|
|
1789
|
|
1790 case BOUNDSCHECKsafeonly:
|
|
1791 /* For D2 safe functions only. */
|
|
1792 fd = d_function_chain->function;
|
|
1793 if (fd && fd->type->ty == Tfunction)
|
|
1794 {
|
|
1795 TypeFunction *tf = (TypeFunction *) fd->type;
|
|
1796 if (tf->trust == TRUSTsafe)
|
|
1797 return true;
|
|
1798 }
|
|
1799 return false;
|
|
1800
|
|
1801 default:
|
|
1802 gcc_unreachable ();
|
|
1803 }
|
|
1804 }
|
|
1805
|
|
1806 /* Return an undeclared local temporary of type TYPE
|
|
1807 for use with BIND_EXPR. */
|
|
1808
|
|
1809 tree
|
|
1810 create_temporary_var (tree type)
|
|
1811 {
|
|
1812 tree decl = build_decl (input_location, VAR_DECL, NULL_TREE, type);
|
|
1813
|
|
1814 DECL_CONTEXT (decl) = current_function_decl;
|
|
1815 DECL_ARTIFICIAL (decl) = 1;
|
|
1816 DECL_IGNORED_P (decl) = 1;
|
|
1817 layout_decl (decl, 0);
|
|
1818
|
|
1819 return decl;
|
|
1820 }
|
|
1821
|
|
1822 /* Return an undeclared local temporary OUT_VAR initialized
|
|
1823 with result of expression EXP. */
|
|
1824
|
|
1825 tree
|
|
1826 maybe_temporary_var (tree exp, tree *out_var)
|
|
1827 {
|
|
1828 tree t = exp;
|
|
1829
|
|
1830 /* Get the base component. */
|
|
1831 while (TREE_CODE (t) == COMPONENT_REF)
|
|
1832 t = TREE_OPERAND (t, 0);
|
|
1833
|
|
1834 if (!DECL_P (t) && !REFERENCE_CLASS_P (t))
|
|
1835 {
|
|
1836 *out_var = create_temporary_var (TREE_TYPE (exp));
|
|
1837 DECL_INITIAL (*out_var) = exp;
|
|
1838 return *out_var;
|
|
1839 }
|
|
1840 else
|
|
1841 {
|
|
1842 *out_var = NULL_TREE;
|
|
1843 return exp;
|
|
1844 }
|
|
1845 }
|
|
1846
|
|
1847 /* Builds a BIND_EXPR around BODY for the variables VAR_CHAIN. */
|
|
1848
|
|
1849 tree
|
|
1850 bind_expr (tree var_chain, tree body)
|
|
1851 {
|
|
1852 /* Only handles one var. */
|
|
1853 gcc_assert (TREE_CHAIN (var_chain) == NULL_TREE);
|
|
1854
|
|
1855 if (DECL_INITIAL (var_chain))
|
|
1856 {
|
|
1857 tree ini = build_assign (INIT_EXPR, var_chain, DECL_INITIAL (var_chain));
|
|
1858 DECL_INITIAL (var_chain) = NULL_TREE;
|
|
1859 body = compound_expr (ini, body);
|
|
1860 }
|
|
1861
|
|
1862 return d_save_expr (build3 (BIND_EXPR, TREE_TYPE (body),
|
|
1863 var_chain, body, NULL_TREE));
|
|
1864 }
|
|
1865
|
|
1866 /* Returns the TypeFunction class for Type T.
|
|
1867 Assumes T is already ->toBasetype(). */
|
|
1868
|
|
1869 TypeFunction *
|
|
1870 get_function_type (Type *t)
|
|
1871 {
|
|
1872 TypeFunction *tf = NULL;
|
|
1873 if (t->ty == Tpointer)
|
|
1874 t = t->nextOf ()->toBasetype ();
|
|
1875 if (t->ty == Tfunction)
|
|
1876 tf = (TypeFunction *) t;
|
|
1877 else if (t->ty == Tdelegate)
|
|
1878 tf = (TypeFunction *) ((TypeDelegate *) t)->next;
|
|
1879 return tf;
|
|
1880 }
|
|
1881
|
|
1882 /* Returns TRUE if CALLEE is a plain nested function outside the scope of
|
|
1883 CALLER. In which case, CALLEE is being called through an alias that was
|
|
1884 passed to CALLER. */
|
|
1885
|
|
1886 bool
|
|
1887 call_by_alias_p (FuncDeclaration *caller, FuncDeclaration *callee)
|
|
1888 {
|
|
1889 if (!callee->isNested ())
|
|
1890 return false;
|
|
1891
|
|
1892 if (caller->toParent () == callee->toParent ())
|
|
1893 return false;
|
|
1894
|
|
1895 Dsymbol *dsym = callee;
|
|
1896
|
|
1897 while (dsym)
|
|
1898 {
|
|
1899 if (dsym->isTemplateInstance ())
|
|
1900 return false;
|
|
1901 else if (dsym->isFuncDeclaration () == caller)
|
|
1902 return false;
|
|
1903 dsym = dsym->toParent ();
|
|
1904 }
|
|
1905
|
|
1906 return true;
|
|
1907 }
|
|
1908
|
|
1909 /* Entry point for call routines. Builds a function call to FD.
|
|
1910 OBJECT is the 'this' reference passed and ARGS are the arguments to FD. */
|
|
1911
|
|
1912 tree
|
|
1913 d_build_call_expr (FuncDeclaration *fd, tree object, Expressions *arguments)
|
|
1914 {
|
|
1915 return d_build_call (get_function_type (fd->type),
|
|
1916 build_address (get_symbol_decl (fd)), object, arguments);
|
|
1917 }
|
|
1918
|
|
1919 /* Builds a CALL_EXPR of type TF to CALLABLE. OBJECT holds the 'this' pointer,
|
|
1920 ARGUMENTS are evaluated in left to right order, saved and promoted
|
|
1921 before passing. */
|
|
1922
|
|
1923 tree
|
|
1924 d_build_call (TypeFunction *tf, tree callable, tree object,
|
|
1925 Expressions *arguments)
|
|
1926 {
|
|
1927 tree ctype = TREE_TYPE (callable);
|
|
1928 tree callee = callable;
|
|
1929
|
|
1930 if (POINTER_TYPE_P (ctype))
|
|
1931 ctype = TREE_TYPE (ctype);
|
|
1932 else
|
|
1933 callee = build_address (callable);
|
|
1934
|
|
1935 gcc_assert (FUNC_OR_METHOD_TYPE_P (ctype));
|
|
1936 gcc_assert (tf != NULL);
|
|
1937 gcc_assert (tf->ty == Tfunction);
|
|
1938
|
|
1939 if (TREE_CODE (ctype) != FUNCTION_TYPE && object == NULL_TREE)
|
|
1940 {
|
|
1941 /* Front-end apparently doesn't check this. */
|
|
1942 if (TREE_CODE (callable) == FUNCTION_DECL)
|
|
1943 {
|
|
1944 error ("need %<this%> to access member %qE", DECL_NAME (callable));
|
|
1945 return error_mark_node;
|
|
1946 }
|
|
1947
|
|
1948 /* Probably an internal error. */
|
|
1949 gcc_unreachable ();
|
|
1950 }
|
|
1951
|
|
1952 /* Build the argument list for the call. */
|
|
1953 vec<tree, va_gc> *args = NULL;
|
|
1954 tree saved_args = NULL_TREE;
|
|
1955
|
|
1956 /* If this is a delegate call or a nested function being called as
|
|
1957 a delegate, the object should not be NULL. */
|
|
1958 if (object != NULL_TREE)
|
|
1959 vec_safe_push (args, object);
|
|
1960
|
|
1961 if (arguments)
|
|
1962 {
|
|
1963 /* First pass, evaluated expanded tuples in function arguments. */
|
|
1964 for (size_t i = 0; i < arguments->dim; ++i)
|
|
1965 {
|
|
1966 Lagain:
|
|
1967 Expression *arg = (*arguments)[i];
|
|
1968 gcc_assert (arg->op != TOKtuple);
|
|
1969
|
|
1970 if (arg->op == TOKcomma)
|
|
1971 {
|
|
1972 CommaExp *ce = (CommaExp *) arg;
|
|
1973 tree tce = build_expr (ce->e1);
|
|
1974 saved_args = compound_expr (saved_args, tce);
|
|
1975 (*arguments)[i] = ce->e2;
|
|
1976 goto Lagain;
|
|
1977 }
|
|
1978 }
|
|
1979
|
|
1980 size_t nparams = Parameter::dim (tf->parameters);
|
|
1981 /* if _arguments[] is the first argument. */
|
|
1982 size_t varargs = (tf->linkage == LINKd && tf->varargs == 1);
|
|
1983
|
|
1984 /* Assumes arguments->dim <= formal_args->dim if (!tf->varargs). */
|
|
1985 for (size_t i = 0; i < arguments->dim; ++i)
|
|
1986 {
|
|
1987 Expression *arg = (*arguments)[i];
|
|
1988 tree targ = build_expr (arg);
|
|
1989
|
|
1990 if (i - varargs < nparams && i >= varargs)
|
|
1991 {
|
|
1992 /* Actual arguments for declared formal arguments. */
|
|
1993 Parameter *parg = Parameter::getNth (tf->parameters, i - varargs);
|
|
1994 targ = convert_for_argument (targ, parg);
|
|
1995 }
|
|
1996
|
|
1997 /* Don't pass empty aggregates by value. */
|
|
1998 if (empty_aggregate_p (TREE_TYPE (targ)) && !TREE_ADDRESSABLE (targ)
|
|
1999 && TREE_CODE (targ) != CONSTRUCTOR)
|
|
2000 {
|
|
2001 tree t = build_constructor (TREE_TYPE (targ), NULL);
|
|
2002 targ = build2 (COMPOUND_EXPR, TREE_TYPE (t), targ, t);
|
|
2003 }
|
|
2004
|
|
2005 vec_safe_push (args, targ);
|
|
2006 }
|
|
2007 }
|
|
2008
|
|
2009 /* Evaluate the callee before calling it. */
|
|
2010 if (TREE_SIDE_EFFECTS (callee))
|
|
2011 {
|
|
2012 callee = d_save_expr (callee);
|
|
2013 saved_args = compound_expr (callee, saved_args);
|
|
2014 }
|
|
2015
|
|
2016 tree result = build_call_vec (TREE_TYPE (ctype), callee, args);
|
|
2017
|
|
2018 /* Enforce left to right evaluation. */
|
|
2019 if (tf->linkage == LINKd)
|
|
2020 CALL_EXPR_ARGS_ORDERED (result) = 1;
|
|
2021
|
|
2022 result = maybe_expand_intrinsic (result);
|
|
2023
|
|
2024 /* Return the value in a temporary slot so that it can be evaluated
|
|
2025 multiple times by the caller. */
|
|
2026 if (TREE_CODE (result) == CALL_EXPR
|
|
2027 && AGGREGATE_TYPE_P (TREE_TYPE (result))
|
|
2028 && TREE_ADDRESSABLE (TREE_TYPE (result)))
|
|
2029 {
|
|
2030 CALL_EXPR_RETURN_SLOT_OPT (result) = true;
|
|
2031 result = force_target_expr (result);
|
|
2032 }
|
|
2033
|
|
2034 return compound_expr (saved_args, result);
|
|
2035 }
|
|
2036
|
|
2037 /* Builds a call to AssertError or AssertErrorMsg. */
|
|
2038
|
|
2039 tree
|
|
2040 d_assert_call (const Loc& loc, libcall_fn libcall, tree msg)
|
|
2041 {
|
|
2042 tree file;
|
|
2043 tree line = size_int (loc.linnum);
|
|
2044
|
|
2045 /* File location is passed as a D string. */
|
|
2046 if (loc.filename)
|
|
2047 {
|
|
2048 unsigned len = strlen (loc.filename);
|
|
2049 tree str = build_string (len, loc.filename);
|
|
2050 TREE_TYPE (str) = make_array_type (Type::tchar, len);
|
|
2051
|
|
2052 file = d_array_value (build_ctype (Type::tchar->arrayOf ()),
|
|
2053 size_int (len), build_address (str));
|
|
2054 }
|
|
2055 else
|
|
2056 file = null_array_node;
|
|
2057
|
|
2058 if (msg != NULL)
|
|
2059 return build_libcall (libcall, Type::tvoid, 3, msg, file, line);
|
|
2060 else
|
|
2061 return build_libcall (libcall, Type::tvoid, 2, file, line);
|
|
2062 }
|
|
2063
|
|
2064 /* Build and return the correct call to fmod depending on TYPE.
|
|
2065 ARG0 and ARG1 are the arguments pass to the function. */
|
|
2066
|
|
2067 tree
|
|
2068 build_float_modulus (tree type, tree arg0, tree arg1)
|
|
2069 {
|
|
2070 tree fmodfn = NULL_TREE;
|
|
2071 tree basetype = type;
|
|
2072
|
|
2073 if (COMPLEX_FLOAT_TYPE_P (basetype))
|
|
2074 basetype = TREE_TYPE (basetype);
|
|
2075
|
|
2076 if (TYPE_MAIN_VARIANT (basetype) == double_type_node
|
|
2077 || TYPE_MAIN_VARIANT (basetype) == idouble_type_node)
|
|
2078 fmodfn = builtin_decl_explicit (BUILT_IN_FMOD);
|
|
2079 else if (TYPE_MAIN_VARIANT (basetype) == float_type_node
|
|
2080 || TYPE_MAIN_VARIANT (basetype) == ifloat_type_node)
|
|
2081 fmodfn = builtin_decl_explicit (BUILT_IN_FMODF);
|
|
2082 else if (TYPE_MAIN_VARIANT (basetype) == long_double_type_node
|
|
2083 || TYPE_MAIN_VARIANT (basetype) == ireal_type_node)
|
|
2084 fmodfn = builtin_decl_explicit (BUILT_IN_FMODL);
|
|
2085
|
|
2086 if (!fmodfn)
|
|
2087 {
|
|
2088 error ("tried to perform floating-point modulo division on %qT", type);
|
|
2089 return error_mark_node;
|
|
2090 }
|
|
2091
|
|
2092 if (COMPLEX_FLOAT_TYPE_P (type))
|
|
2093 {
|
|
2094 tree re = build_call_expr (fmodfn, 2, real_part (arg0), arg1);
|
|
2095 tree im = build_call_expr (fmodfn, 2, imaginary_part (arg0), arg1);
|
|
2096
|
|
2097 return complex_expr (type, re, im);
|
|
2098 }
|
|
2099
|
|
2100 if (SCALAR_FLOAT_TYPE_P (type))
|
|
2101 return build_call_expr (fmodfn, 2, arg0, arg1);
|
|
2102
|
|
2103 /* Should have caught this above. */
|
|
2104 gcc_unreachable ();
|
|
2105 }
|
|
2106
|
|
2107 /* Build a function type whose first argument is a pointer to BASETYPE,
|
|
2108 which is to be used for the 'vthis' context parameter for TYPE.
|
|
2109 The base type may be a record for member functions, or a void for
|
|
2110 nested functions and delegates. */
|
|
2111
|
|
2112 tree
|
|
2113 build_vthis_function (tree basetype, tree type)
|
|
2114 {
|
|
2115 gcc_assert (TREE_CODE (type) == FUNCTION_TYPE);
|
|
2116
|
|
2117 tree argtypes = tree_cons (NULL_TREE, build_pointer_type (basetype),
|
|
2118 TYPE_ARG_TYPES (type));
|
|
2119 tree fntype = build_function_type (TREE_TYPE (type), argtypes);
|
|
2120
|
|
2121 if (RECORD_OR_UNION_TYPE_P (basetype))
|
|
2122 TYPE_METHOD_BASETYPE (fntype) = TYPE_MAIN_VARIANT (basetype);
|
|
2123 else
|
|
2124 gcc_assert (VOID_TYPE_P (basetype));
|
|
2125
|
|
2126 return fntype;
|
|
2127 }
|
|
2128
|
|
2129 /* If SYM is a nested function, return the static chain to be
|
|
2130 used when calling that function from the current function.
|
|
2131
|
|
2132 If SYM is a nested class or struct, return the static chain
|
|
2133 to be used when creating an instance of the class from CFUN. */
|
|
2134
|
|
2135 tree
|
|
2136 get_frame_for_symbol (Dsymbol *sym)
|
|
2137 {
|
|
2138 FuncDeclaration *thisfd
|
|
2139 = d_function_chain ? d_function_chain->function : NULL;
|
|
2140 FuncDeclaration *fd = sym->isFuncDeclaration ();
|
|
2141 FuncDeclaration *fdparent = NULL;
|
|
2142 FuncDeclaration *fdoverride = NULL;
|
|
2143
|
|
2144 if (fd != NULL)
|
|
2145 {
|
|
2146 /* Check that the nested function is properly defined. */
|
|
2147 if (!fd->fbody)
|
|
2148 {
|
|
2149 /* Should instead error on line that references 'fd'. */
|
|
2150 error_at (make_location_t (fd->loc), "nested function missing body");
|
|
2151 return null_pointer_node;
|
|
2152 }
|
|
2153
|
|
2154 fdparent = fd->toParent2 ()->isFuncDeclaration ();
|
|
2155
|
|
2156 /* Special case for __ensure and __require. */
|
|
2157 if ((fd->ident == Identifier::idPool ("__ensure")
|
|
2158 || fd->ident == Identifier::idPool ("__require"))
|
|
2159 && fdparent != thisfd)
|
|
2160 {
|
|
2161 fdoverride = fdparent;
|
|
2162 fdparent = thisfd;
|
|
2163 }
|
|
2164 }
|
|
2165 else
|
|
2166 {
|
|
2167 /* It's a class (or struct). NewExp codegen has already determined its
|
|
2168 outer scope is not another class, so it must be a function. */
|
|
2169 while (sym && !sym->isFuncDeclaration ())
|
|
2170 sym = sym->toParent2 ();
|
|
2171
|
|
2172 fdparent = (FuncDeclaration *) sym;
|
|
2173 }
|
|
2174
|
|
2175 /* Not a nested function, there is no frame pointer to pass. */
|
|
2176 if (fdparent == NULL)
|
|
2177 {
|
|
2178 /* Only delegate literals report as being nested, even if they are in
|
|
2179 global scope. */
|
|
2180 gcc_assert (fd && fd->isFuncLiteralDeclaration ());
|
|
2181 return null_pointer_node;
|
|
2182 }
|
|
2183
|
|
2184 gcc_assert (thisfd != NULL);
|
|
2185
|
|
2186 if (thisfd != fdparent)
|
|
2187 {
|
|
2188 /* If no frame pointer for this function. */
|
|
2189 if (!thisfd->vthis)
|
|
2190 {
|
|
2191 error_at (make_location_t (sym->loc),
|
|
2192 "%qs is a nested function and cannot be accessed from %qs",
|
|
2193 fd->toPrettyChars (), thisfd->toPrettyChars ());
|
|
2194 return null_pointer_node;
|
|
2195 }
|
|
2196
|
|
2197 /* Make sure we can get the frame pointer to the outer function.
|
|
2198 Go up each nesting level until we find the enclosing function. */
|
|
2199 Dsymbol *dsym = thisfd;
|
|
2200
|
|
2201 while (fd != dsym)
|
|
2202 {
|
|
2203 /* Check if enclosing function is a function. */
|
|
2204 FuncDeclaration *fd = dsym->isFuncDeclaration ();
|
|
2205
|
|
2206 if (fd != NULL)
|
|
2207 {
|
|
2208 if (fdparent == fd->toParent2 ())
|
|
2209 break;
|
|
2210
|
|
2211 gcc_assert (fd->isNested () || fd->vthis);
|
|
2212 dsym = dsym->toParent2 ();
|
|
2213 continue;
|
|
2214 }
|
|
2215
|
|
2216 /* Check if enclosed by an aggregate. That means the current
|
|
2217 function must be a member function of that aggregate. */
|
|
2218 AggregateDeclaration *ad = dsym->isAggregateDeclaration ();
|
|
2219
|
|
2220 if (ad == NULL)
|
|
2221 goto Lnoframe;
|
|
2222 if (ad->isClassDeclaration () && fdparent == ad->toParent2 ())
|
|
2223 break;
|
|
2224 if (ad->isStructDeclaration () && fdparent == ad->toParent2 ())
|
|
2225 break;
|
|
2226
|
|
2227 if (!ad->isNested () || !ad->vthis)
|
|
2228 {
|
|
2229 Lnoframe:
|
|
2230 error_at (make_location_t (thisfd->loc),
|
|
2231 "cannot get frame pointer to %qs",
|
|
2232 sym->toPrettyChars ());
|
|
2233 return null_pointer_node;
|
|
2234 }
|
|
2235
|
|
2236 dsym = dsym->toParent2 ();
|
|
2237 }
|
|
2238 }
|
|
2239
|
|
2240 tree ffo = get_frameinfo (fdparent);
|
|
2241 if (FRAMEINFO_CREATES_FRAME (ffo) || FRAMEINFO_STATIC_CHAIN (ffo))
|
|
2242 {
|
|
2243 tree frame_ref = get_framedecl (thisfd, fdparent);
|
|
2244
|
|
2245 /* If 'thisfd' is a derived member function, then 'fdparent' is the
|
|
2246 overridden member function in the base class. Even if there's a
|
|
2247 closure environment, we should give the original stack data as the
|
|
2248 nested function frame. */
|
|
2249 if (fdoverride)
|
|
2250 {
|
|
2251 ClassDeclaration *cdo = fdoverride->isThis ()->isClassDeclaration ();
|
|
2252 ClassDeclaration *cd = thisfd->isThis ()->isClassDeclaration ();
|
|
2253 gcc_assert (cdo && cd);
|
|
2254
|
|
2255 int offset;
|
|
2256 if (cdo->isBaseOf (cd, &offset) && offset != 0)
|
|
2257 {
|
|
2258 /* Generate a new frame to pass to the overriden function that
|
|
2259 has the 'this' pointer adjusted. */
|
|
2260 gcc_assert (offset != OFFSET_RUNTIME);
|
|
2261
|
|
2262 tree type = FRAMEINFO_TYPE (get_frameinfo (fdoverride));
|
|
2263 tree fields = TYPE_FIELDS (type);
|
|
2264 /* The 'this' field comes immediately after the '__chain'. */
|
|
2265 tree thisfield = chain_index (1, fields);
|
|
2266 vec<constructor_elt, va_gc> *ve = NULL;
|
|
2267
|
|
2268 tree framefields = TYPE_FIELDS (FRAMEINFO_TYPE (ffo));
|
|
2269 frame_ref = build_deref (frame_ref);
|
|
2270
|
|
2271 for (tree field = fields; field; field = DECL_CHAIN (field))
|
|
2272 {
|
|
2273 tree value = component_ref (frame_ref, framefields);
|
|
2274 if (field == thisfield)
|
|
2275 value = build_offset (value, size_int (offset));
|
|
2276
|
|
2277 CONSTRUCTOR_APPEND_ELT (ve, field, value);
|
|
2278 framefields = DECL_CHAIN (framefields);
|
|
2279 }
|
|
2280
|
|
2281 frame_ref = build_address (build_constructor (type, ve));
|
|
2282 }
|
|
2283 }
|
|
2284
|
|
2285 return frame_ref;
|
|
2286 }
|
|
2287
|
|
2288 return null_pointer_node;
|
|
2289 }
|
|
2290
|
|
2291 /* Return the parent function of a nested class CD. */
|
|
2292
|
|
2293 static FuncDeclaration *
|
|
2294 d_nested_class (ClassDeclaration *cd)
|
|
2295 {
|
|
2296 FuncDeclaration *fd = NULL;
|
|
2297 while (cd && cd->isNested ())
|
|
2298 {
|
|
2299 Dsymbol *dsym = cd->toParent2 ();
|
|
2300 if ((fd = dsym->isFuncDeclaration ()))
|
|
2301 return fd;
|
|
2302 else
|
|
2303 cd = dsym->isClassDeclaration ();
|
|
2304 }
|
|
2305 return NULL;
|
|
2306 }
|
|
2307
|
|
2308 /* Return the parent function of a nested struct SD. */
|
|
2309
|
|
2310 static FuncDeclaration *
|
|
2311 d_nested_struct (StructDeclaration *sd)
|
|
2312 {
|
|
2313 FuncDeclaration *fd = NULL;
|
|
2314 while (sd && sd->isNested ())
|
|
2315 {
|
|
2316 Dsymbol *dsym = sd->toParent2 ();
|
|
2317 if ((fd = dsym->isFuncDeclaration ()))
|
|
2318 return fd;
|
|
2319 else
|
|
2320 sd = dsym->isStructDeclaration ();
|
|
2321 }
|
|
2322 return NULL;
|
|
2323 }
|
|
2324
|
|
2325
|
|
2326 /* Starting from the current function FD, try to find a suitable value of
|
|
2327 'this' in nested function instances. A suitable 'this' value is an
|
|
2328 instance of OCD or a class that has OCD as a base. */
|
|
2329
|
|
2330 static tree
|
|
2331 find_this_tree (ClassDeclaration *ocd)
|
|
2332 {
|
|
2333 FuncDeclaration *fd = d_function_chain ? d_function_chain->function : NULL;
|
|
2334
|
|
2335 while (fd)
|
|
2336 {
|
|
2337 AggregateDeclaration *ad = fd->isThis ();
|
|
2338 ClassDeclaration *cd = ad ? ad->isClassDeclaration () : NULL;
|
|
2339
|
|
2340 if (cd != NULL)
|
|
2341 {
|
|
2342 if (ocd == cd)
|
|
2343 return get_decl_tree (fd->vthis);
|
|
2344 else if (ocd->isBaseOf (cd, NULL))
|
|
2345 return convert_expr (get_decl_tree (fd->vthis),
|
|
2346 cd->type, ocd->type);
|
|
2347
|
|
2348 fd = d_nested_class (cd);
|
|
2349 }
|
|
2350 else
|
|
2351 {
|
|
2352 if (fd->isNested ())
|
|
2353 {
|
|
2354 fd = fd->toParent2 ()->isFuncDeclaration ();
|
|
2355 continue;
|
|
2356 }
|
|
2357
|
|
2358 fd = NULL;
|
|
2359 }
|
|
2360 }
|
|
2361
|
|
2362 return NULL_TREE;
|
|
2363 }
|
|
2364
|
|
2365 /* Retrieve the outer class/struct 'this' value of DECL from
|
|
2366 the current function. */
|
|
2367
|
|
2368 tree
|
|
2369 build_vthis (AggregateDeclaration *decl)
|
|
2370 {
|
|
2371 ClassDeclaration *cd = decl->isClassDeclaration ();
|
|
2372 StructDeclaration *sd = decl->isStructDeclaration ();
|
|
2373
|
|
2374 /* If an aggregate nested in a function has no methods and there are no
|
|
2375 other nested functions, any static chain created here will never be
|
|
2376 translated. Use a null pointer for the link in this case. */
|
|
2377 tree vthis_value = null_pointer_node;
|
|
2378
|
|
2379 if (cd != NULL || sd != NULL)
|
|
2380 {
|
|
2381 Dsymbol *outer = decl->toParent2 ();
|
|
2382
|
|
2383 /* If the parent is a templated struct, the outer context is instead
|
|
2384 the enclosing symbol of where the instantiation happened. */
|
|
2385 if (outer->isStructDeclaration ())
|
|
2386 {
|
|
2387 gcc_assert (outer->parent && outer->parent->isTemplateInstance ());
|
|
2388 outer = ((TemplateInstance *) outer->parent)->enclosing;
|
|
2389 }
|
|
2390
|
|
2391 /* For outer classes, get a suitable 'this' value.
|
|
2392 For outer functions, get a suitable frame/closure pointer. */
|
|
2393 ClassDeclaration *cdo = outer->isClassDeclaration ();
|
|
2394 FuncDeclaration *fdo = outer->isFuncDeclaration ();
|
|
2395
|
|
2396 if (cdo)
|
|
2397 {
|
|
2398 vthis_value = find_this_tree (cdo);
|
|
2399 gcc_assert (vthis_value != NULL_TREE);
|
|
2400 }
|
|
2401 else if (fdo)
|
|
2402 {
|
|
2403 tree ffo = get_frameinfo (fdo);
|
|
2404 if (FRAMEINFO_CREATES_FRAME (ffo) || FRAMEINFO_STATIC_CHAIN (ffo)
|
|
2405 || fdo->hasNestedFrameRefs ())
|
|
2406 vthis_value = get_frame_for_symbol (decl);
|
|
2407 else if (cd != NULL)
|
|
2408 {
|
|
2409 /* Classes nested in methods are allowed to access any outer
|
|
2410 class fields, use the function chain in this case. */
|
|
2411 if (fdo->vthis && fdo->vthis->type != Type::tvoidptr)
|
|
2412 vthis_value = get_decl_tree (fdo->vthis);
|
|
2413 }
|
|
2414 }
|
|
2415 else
|
|
2416 gcc_unreachable ();
|
|
2417 }
|
|
2418
|
|
2419 return vthis_value;
|
|
2420 }
|
|
2421
|
|
2422 /* Build the RECORD_TYPE that describes the function frame or closure type for
|
|
2423 the function FD. FFI is the tree holding all frame information. */
|
|
2424
|
|
2425 static tree
|
|
2426 build_frame_type (tree ffi, FuncDeclaration *fd)
|
|
2427 {
|
|
2428 if (FRAMEINFO_TYPE (ffi))
|
|
2429 return FRAMEINFO_TYPE (ffi);
|
|
2430
|
|
2431 tree frame_rec_type = make_node (RECORD_TYPE);
|
|
2432 char *name = concat (FRAMEINFO_IS_CLOSURE (ffi) ? "CLOSURE." : "FRAME.",
|
|
2433 fd->toPrettyChars (), NULL);
|
|
2434 TYPE_NAME (frame_rec_type) = get_identifier (name);
|
|
2435 free (name);
|
|
2436
|
|
2437 tree fields = NULL_TREE;
|
|
2438
|
|
2439 /* Function is a member or nested, so must have field for outer context. */
|
|
2440 if (fd->vthis)
|
|
2441 {
|
|
2442 tree ptr_field = build_decl (BUILTINS_LOCATION, FIELD_DECL,
|
|
2443 get_identifier ("__chain"), ptr_type_node);
|
|
2444 DECL_FIELD_CONTEXT (ptr_field) = frame_rec_type;
|
|
2445 fields = chainon (NULL_TREE, ptr_field);
|
|
2446 DECL_NONADDRESSABLE_P (ptr_field) = 1;
|
|
2447 }
|
|
2448
|
|
2449 /* The __ensure and __require are called directly, so never make the outer
|
|
2450 functions closure, but nevertheless could still be referencing parameters
|
|
2451 of the calling function non-locally. So we add all parameters with nested
|
|
2452 refs to the function frame, this should also mean overriding methods will
|
|
2453 have the same frame layout when inheriting a contract. */
|
|
2454 if ((global.params.useIn && fd->frequire)
|
|
2455 || (global.params.useOut && fd->fensure))
|
|
2456 {
|
|
2457 if (fd->parameters)
|
|
2458 {
|
|
2459 for (size_t i = 0; fd->parameters && i < fd->parameters->dim; i++)
|
|
2460 {
|
|
2461 VarDeclaration *v = (*fd->parameters)[i];
|
|
2462 /* Remove if already in closureVars so can push to front. */
|
|
2463 for (size_t j = i; j < fd->closureVars.dim; j++)
|
|
2464 {
|
|
2465 Dsymbol *s = fd->closureVars[j];
|
|
2466 if (s == v)
|
|
2467 {
|
|
2468 fd->closureVars.remove (j);
|
|
2469 break;
|
|
2470 }
|
|
2471 }
|
|
2472 fd->closureVars.insert (i, v);
|
|
2473 }
|
|
2474 }
|
|
2475
|
|
2476 /* Also add hidden 'this' to outer context. */
|
|
2477 if (fd->vthis)
|
|
2478 {
|
|
2479 for (size_t i = 0; i < fd->closureVars.dim; i++)
|
|
2480 {
|
|
2481 Dsymbol *s = fd->closureVars[i];
|
|
2482 if (s == fd->vthis)
|
|
2483 {
|
|
2484 fd->closureVars.remove (i);
|
|
2485 break;
|
|
2486 }
|
|
2487 }
|
|
2488 fd->closureVars.insert (0, fd->vthis);
|
|
2489 }
|
|
2490 }
|
|
2491
|
|
2492 for (size_t i = 0; i < fd->closureVars.dim; i++)
|
|
2493 {
|
|
2494 VarDeclaration *v = fd->closureVars[i];
|
|
2495 tree vsym = get_symbol_decl (v);
|
|
2496 tree ident = v->ident
|
|
2497 ? get_identifier (v->ident->toChars ()) : NULL_TREE;
|
|
2498
|
|
2499 tree field = build_decl (make_location_t (v->loc), FIELD_DECL, ident,
|
|
2500 TREE_TYPE (vsym));
|
|
2501 SET_DECL_LANG_FRAME_FIELD (vsym, field);
|
|
2502 DECL_FIELD_CONTEXT (field) = frame_rec_type;
|
|
2503 fields = chainon (fields, field);
|
|
2504 TREE_USED (vsym) = 1;
|
|
2505
|
|
2506 TREE_ADDRESSABLE (field) = TREE_ADDRESSABLE (vsym);
|
|
2507 DECL_NONADDRESSABLE_P (field) = !TREE_ADDRESSABLE (vsym);
|
|
2508 TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (vsym);
|
|
2509
|
|
2510 /* Can't do nrvo if the variable is put in a frame. */
|
|
2511 if (fd->nrvo_can && fd->nrvo_var == v)
|
|
2512 fd->nrvo_can = 0;
|
|
2513
|
|
2514 if (FRAMEINFO_IS_CLOSURE (ffi))
|
|
2515 {
|
|
2516 /* Because the value needs to survive the end of the scope. */
|
|
2517 if ((v->edtor && (v->storage_class & STCparameter))
|
|
2518 || v->needsScopeDtor ())
|
|
2519 error_at (make_location_t (v->loc),
|
|
2520 "has scoped destruction, cannot build closure");
|
|
2521 }
|
|
2522 }
|
|
2523
|
|
2524 TYPE_FIELDS (frame_rec_type) = fields;
|
|
2525 TYPE_READONLY (frame_rec_type) = 1;
|
|
2526 layout_type (frame_rec_type);
|
|
2527 d_keep (frame_rec_type);
|
|
2528
|
|
2529 return frame_rec_type;
|
|
2530 }
|
|
2531
|
|
2532 /* Closures are implemented by taking the local variables that
|
|
2533 need to survive the scope of the function, and copying them
|
|
2534 into a GC allocated chuck of memory. That chunk, called the
|
|
2535 closure here, is inserted into the linked list of stack
|
|
2536 frames instead of the usual stack frame.
|
|
2537
|
|
2538 If a closure is not required, but FD still needs a frame to lower
|
|
2539 nested refs, then instead build custom static chain decl on stack. */
|
|
2540
|
|
2541 void
|
|
2542 build_closure (FuncDeclaration *fd)
|
|
2543 {
|
|
2544 tree ffi = get_frameinfo (fd);
|
|
2545
|
|
2546 if (!FRAMEINFO_CREATES_FRAME (ffi))
|
|
2547 return;
|
|
2548
|
|
2549 tree type = FRAMEINFO_TYPE (ffi);
|
|
2550 gcc_assert (COMPLETE_TYPE_P (type));
|
|
2551
|
|
2552 tree decl, decl_ref;
|
|
2553
|
|
2554 if (FRAMEINFO_IS_CLOSURE (ffi))
|
|
2555 {
|
|
2556 decl = build_local_temp (build_pointer_type (type));
|
|
2557 DECL_NAME (decl) = get_identifier ("__closptr");
|
|
2558 decl_ref = build_deref (decl);
|
|
2559
|
|
2560 /* Allocate memory for closure. */
|
|
2561 tree arg = convert (build_ctype (Type::tsize_t), TYPE_SIZE_UNIT (type));
|
|
2562 tree init = build_libcall (LIBCALL_ALLOCMEMORY, Type::tvoidptr, 1, arg);
|
|
2563
|
|
2564 tree init_exp = build_assign (INIT_EXPR, decl,
|
|
2565 build_nop (TREE_TYPE (decl), init));
|
|
2566 add_stmt (init_exp);
|
|
2567 }
|
|
2568 else
|
|
2569 {
|
|
2570 decl = build_local_temp (type);
|
|
2571 DECL_NAME (decl) = get_identifier ("__frame");
|
|
2572 decl_ref = decl;
|
|
2573 }
|
|
2574
|
|
2575 /* Set the first entry to the parent closure/frame, if any. */
|
|
2576 if (fd->vthis)
|
|
2577 {
|
|
2578 tree chain_field = component_ref (decl_ref, TYPE_FIELDS (type));
|
|
2579 tree chain_expr = modify_expr (chain_field,
|
|
2580 d_function_chain->static_chain);
|
|
2581 add_stmt (chain_expr);
|
|
2582 }
|
|
2583
|
|
2584 /* Copy parameters that are referenced nonlocally. */
|
|
2585 for (size_t i = 0; i < fd->closureVars.dim; i++)
|
|
2586 {
|
|
2587 VarDeclaration *v = fd->closureVars[i];
|
|
2588
|
|
2589 if (!v->isParameter ())
|
|
2590 continue;
|
|
2591
|
|
2592 tree vsym = get_symbol_decl (v);
|
|
2593
|
|
2594 tree field = component_ref (decl_ref, DECL_LANG_FRAME_FIELD (vsym));
|
|
2595 tree expr = modify_expr (field, vsym);
|
|
2596 add_stmt (expr);
|
|
2597 }
|
|
2598
|
|
2599 if (!FRAMEINFO_IS_CLOSURE (ffi))
|
|
2600 decl = build_address (decl);
|
|
2601
|
|
2602 d_function_chain->static_chain = decl;
|
|
2603 }
|
|
2604
|
|
2605 /* Return the frame of FD. This could be a static chain or a closure
|
|
2606 passed via the hidden 'this' pointer. */
|
|
2607
|
|
2608 tree
|
|
2609 get_frameinfo (FuncDeclaration *fd)
|
|
2610 {
|
|
2611 tree fds = get_symbol_decl (fd);
|
|
2612 if (DECL_LANG_FRAMEINFO (fds))
|
|
2613 return DECL_LANG_FRAMEINFO (fds);
|
|
2614
|
|
2615 tree ffi = make_node (FUNCFRAME_INFO);
|
|
2616
|
|
2617 DECL_LANG_FRAMEINFO (fds) = ffi;
|
|
2618
|
|
2619 if (fd->needsClosure ())
|
|
2620 {
|
|
2621 /* Set-up a closure frame, this will be allocated on the heap. */
|
|
2622 FRAMEINFO_CREATES_FRAME (ffi) = 1;
|
|
2623 FRAMEINFO_IS_CLOSURE (ffi) = 1;
|
|
2624 }
|
|
2625 else if (fd->hasNestedFrameRefs ())
|
|
2626 {
|
|
2627 /* Functions with nested refs must create a static frame for local
|
|
2628 variables to be referenced from. */
|
|
2629 FRAMEINFO_CREATES_FRAME (ffi) = 1;
|
|
2630 }
|
|
2631 else
|
|
2632 {
|
|
2633 /* For nested functions, default to creating a frame. Even if there are
|
|
2634 no fields to populate the frame, create it anyway, as this will be
|
|
2635 used as the record type instead of `void*` for the this parameter. */
|
|
2636 if (fd->vthis && fd->vthis->type == Type::tvoidptr)
|
|
2637 FRAMEINFO_CREATES_FRAME (ffi) = 1;
|
|
2638
|
|
2639 /* In checkNestedReference, references from contracts are not added to the
|
|
2640 closureVars array, so assume all parameters referenced. */
|
|
2641 if ((global.params.useIn && fd->frequire)
|
|
2642 || (global.params.useOut && fd->fensure))
|
|
2643 FRAMEINFO_CREATES_FRAME (ffi) = 1;
|
|
2644
|
|
2645 /* If however `fd` is nested (deeply) in a function that creates a
|
|
2646 closure, then `fd` instead inherits that closure via hidden vthis
|
|
2647 pointer, and doesn't create a stack frame at all. */
|
|
2648 FuncDeclaration *ff = fd;
|
|
2649
|
|
2650 while (ff)
|
|
2651 {
|
|
2652 tree ffo = get_frameinfo (ff);
|
|
2653
|
|
2654 if (ff != fd && FRAMEINFO_CREATES_FRAME (ffo))
|
|
2655 {
|
|
2656 gcc_assert (FRAMEINFO_TYPE (ffo));
|
|
2657 FRAMEINFO_CREATES_FRAME (ffi) = 0;
|
|
2658 FRAMEINFO_STATIC_CHAIN (ffi) = 1;
|
|
2659 FRAMEINFO_IS_CLOSURE (ffi) = FRAMEINFO_IS_CLOSURE (ffo);
|
|
2660 gcc_assert (COMPLETE_TYPE_P (FRAMEINFO_TYPE (ffo)));
|
|
2661 FRAMEINFO_TYPE (ffi) = FRAMEINFO_TYPE (ffo);
|
|
2662 break;
|
|
2663 }
|
|
2664
|
|
2665 /* Stop looking if no frame pointer for this function. */
|
|
2666 if (ff->vthis == NULL)
|
|
2667 break;
|
|
2668
|
|
2669 AggregateDeclaration *ad = ff->isThis ();
|
|
2670 if (ad && ad->isNested ())
|
|
2671 {
|
|
2672 while (ad->isNested ())
|
|
2673 {
|
|
2674 Dsymbol *d = ad->toParent2 ();
|
|
2675 ad = d->isAggregateDeclaration ();
|
|
2676 ff = d->isFuncDeclaration ();
|
|
2677
|
|
2678 if (ad == NULL)
|
|
2679 break;
|
|
2680 }
|
|
2681 }
|
|
2682 else
|
|
2683 ff = ff->toParent2 ()->isFuncDeclaration ();
|
|
2684 }
|
|
2685 }
|
|
2686
|
|
2687 /* Build type now as may be referenced from another module. */
|
|
2688 if (FRAMEINFO_CREATES_FRAME (ffi))
|
|
2689 FRAMEINFO_TYPE (ffi) = build_frame_type (ffi, fd);
|
|
2690
|
|
2691 return ffi;
|
|
2692 }
|
|
2693
|
|
2694 /* Return a pointer to the frame/closure block of OUTER
|
|
2695 so can be accessed from the function INNER. */
|
|
2696
|
|
2697 tree
|
|
2698 get_framedecl (FuncDeclaration *inner, FuncDeclaration *outer)
|
|
2699 {
|
|
2700 tree result = d_function_chain->static_chain;
|
|
2701 FuncDeclaration *fd = inner;
|
|
2702
|
|
2703 while (fd && fd != outer)
|
|
2704 {
|
|
2705 AggregateDeclaration *ad;
|
|
2706 ClassDeclaration *cd;
|
|
2707 StructDeclaration *sd;
|
|
2708
|
|
2709 /* Parent frame link is the first field. */
|
|
2710 if (FRAMEINFO_CREATES_FRAME (get_frameinfo (fd)))
|
|
2711 result = indirect_ref (ptr_type_node, result);
|
|
2712
|
|
2713 if (fd->isNested ())
|
|
2714 fd = fd->toParent2 ()->isFuncDeclaration ();
|
|
2715 /* The frame/closure record always points to the outer function's
|
|
2716 frame, even if there are intervening nested classes or structs.
|
|
2717 So, we can just skip over these. */
|
|
2718 else if ((ad = fd->isThis ()) && (cd = ad->isClassDeclaration ()))
|
|
2719 fd = d_nested_class (cd);
|
|
2720 else if ((ad = fd->isThis ()) && (sd = ad->isStructDeclaration ()))
|
|
2721 fd = d_nested_struct (sd);
|
|
2722 else
|
|
2723 break;
|
|
2724 }
|
|
2725
|
|
2726 /* Go get our frame record. */
|
|
2727 gcc_assert (fd == outer);
|
|
2728 tree frame_type = FRAMEINFO_TYPE (get_frameinfo (outer));
|
|
2729
|
|
2730 if (frame_type != NULL_TREE)
|
|
2731 {
|
|
2732 result = build_nop (build_pointer_type (frame_type), result);
|
|
2733 return result;
|
|
2734 }
|
|
2735 else
|
|
2736 {
|
|
2737 error_at (make_location_t (inner->loc),
|
|
2738 "forward reference to frame of %qs", outer->toChars ());
|
|
2739 return null_pointer_node;
|
|
2740 }
|
|
2741 }
|