145
|
1 /* expr.cc -- Lower D frontend expressions to GCC trees.
|
|
2 Copyright (C) 2015-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/expression.h"
|
|
26 #include "dmd/identifier.h"
|
|
27 #include "dmd/init.h"
|
|
28 #include "dmd/module.h"
|
|
29 #include "dmd/mtype.h"
|
|
30 #include "dmd/template.h"
|
|
31
|
|
32 #include "tree.h"
|
|
33 #include "fold-const.h"
|
|
34 #include "diagnostic.h"
|
|
35 #include "langhooks.h"
|
|
36 #include "tm.h"
|
|
37 #include "function.h"
|
|
38 #include "toplev.h"
|
|
39 #include "varasm.h"
|
|
40 #include "predict.h"
|
|
41 #include "stor-layout.h"
|
|
42
|
|
43 #include "d-tree.h"
|
|
44
|
|
45
|
|
46 /* Implements the visitor interface to build the GCC trees of all Expression
|
|
47 AST classes emitted from the D Front-end.
|
|
48 All visit methods accept one parameter E, which holds the frontend AST
|
|
49 of the expression to compile. They also don't return any value, instead
|
|
50 generated code is cached in RESULT_ and returned from the caller. */
|
|
51
|
|
52 class ExprVisitor : public Visitor
|
|
53 {
|
|
54 using Visitor::visit;
|
|
55
|
|
56 tree result_;
|
|
57 bool constp_;
|
|
58
|
|
59 /* Determine if type is a struct that has a postblit. */
|
|
60
|
|
61 bool needs_postblit (Type *t)
|
|
62 {
|
|
63 t = t->baseElemOf ();
|
|
64
|
|
65 if (t->ty == Tstruct)
|
|
66 {
|
|
67 StructDeclaration *sd = ((TypeStruct *) t)->sym;
|
|
68 if (sd->postblit)
|
|
69 return true;
|
|
70 }
|
|
71
|
|
72 return false;
|
|
73 }
|
|
74
|
|
75 /* Determine if type is a struct that has a destructor. */
|
|
76
|
|
77 bool needs_dtor (Type *t)
|
|
78 {
|
|
79 t = t->baseElemOf ();
|
|
80
|
|
81 if (t->ty == Tstruct)
|
|
82 {
|
|
83 StructDeclaration *sd = ((TypeStruct *) t)->sym;
|
|
84 if (sd->dtor)
|
|
85 return true;
|
|
86 }
|
|
87
|
|
88 return false;
|
|
89 }
|
|
90
|
|
91 /* Determine if expression is suitable lvalue. */
|
|
92
|
|
93 bool lvalue_p (Expression *e)
|
|
94 {
|
|
95 return ((e->op != TOKslice && e->isLvalue ())
|
|
96 || (e->op == TOKslice && ((UnaExp *) e)->e1->isLvalue ())
|
|
97 || (e->op == TOKcast && ((UnaExp *) e)->e1->isLvalue ()));
|
|
98 }
|
|
99
|
|
100 /* Build an expression of code CODE, data type TYPE, and operands ARG0 and
|
|
101 ARG1. Perform relevant conversions needed for correct code operations. */
|
|
102
|
|
103 tree binary_op (tree_code code, tree type, tree arg0, tree arg1)
|
|
104 {
|
|
105 tree t0 = TREE_TYPE (arg0);
|
|
106 tree t1 = TREE_TYPE (arg1);
|
|
107 tree ret = NULL_TREE;
|
|
108
|
|
109 bool unsignedp = TYPE_UNSIGNED (t0) || TYPE_UNSIGNED (t1);
|
|
110
|
|
111 /* Deal with float mod expressions immediately. */
|
|
112 if (code == FLOAT_MOD_EXPR)
|
|
113 return build_float_modulus (type, arg0, arg1);
|
|
114
|
|
115 if (POINTER_TYPE_P (t0) && INTEGRAL_TYPE_P (t1))
|
|
116 return build_nop (type, build_offset_op (code, arg0, arg1));
|
|
117
|
|
118 if (INTEGRAL_TYPE_P (t0) && POINTER_TYPE_P (t1))
|
|
119 return build_nop (type, build_offset_op (code, arg1, arg0));
|
|
120
|
|
121 if (POINTER_TYPE_P (t0) && POINTER_TYPE_P (t1))
|
|
122 {
|
|
123 gcc_assert (code == MINUS_EXPR);
|
|
124 tree ptrtype = lang_hooks.types.type_for_mode (ptr_mode, 0);
|
|
125
|
|
126 /* POINTER_DIFF_EXPR requires a signed integer type of the same size as
|
|
127 pointers. If some platform cannot provide that, or has a larger
|
|
128 ptrdiff_type to support differences larger than half the address
|
|
129 space, cast the pointers to some larger integer type and do the
|
|
130 computations in that type. */
|
|
131 if (TYPE_PRECISION (ptrtype) > TYPE_PRECISION (t0))
|
|
132 ret = fold_build2 (MINUS_EXPR, ptrtype,
|
|
133 d_convert (ptrtype, arg0),
|
|
134 d_convert (ptrtype, arg1));
|
|
135 else
|
|
136 ret = fold_build2 (POINTER_DIFF_EXPR, ptrtype, arg0, arg1);
|
|
137 }
|
|
138 else if (INTEGRAL_TYPE_P (type) && (TYPE_UNSIGNED (type) != unsignedp))
|
|
139 {
|
|
140 tree inttype = (unsignedp)
|
|
141 ? d_unsigned_type (type) : d_signed_type (type);
|
|
142 ret = fold_build2 (code, inttype, arg0, arg1);
|
|
143 }
|
|
144 else
|
|
145 {
|
|
146 /* If the operation needs excess precision. */
|
|
147 tree eptype = excess_precision_type (type);
|
|
148 if (eptype != NULL_TREE)
|
|
149 {
|
|
150 arg0 = d_convert (eptype, arg0);
|
|
151 arg1 = d_convert (eptype, arg1);
|
|
152 }
|
|
153 else
|
|
154 {
|
|
155 /* Front-end does not do this conversion and GCC does not
|
|
156 always do it right. */
|
|
157 if (COMPLEX_FLOAT_TYPE_P (t0) && !COMPLEX_FLOAT_TYPE_P (t1))
|
|
158 arg1 = d_convert (t0, arg1);
|
|
159 else if (COMPLEX_FLOAT_TYPE_P (t1) && !COMPLEX_FLOAT_TYPE_P (t0))
|
|
160 arg0 = d_convert (t1, arg0);
|
|
161
|
|
162 eptype = type;
|
|
163 }
|
|
164
|
|
165 ret = fold_build2 (code, eptype, arg0, arg1);
|
|
166 }
|
|
167
|
|
168 return d_convert (type, ret);
|
|
169 }
|
|
170
|
|
171 /* Build a binary expression of code CODE, assigning the result into E1. */
|
|
172
|
|
173 tree binop_assignment (tree_code code, Expression *e1, Expression *e2)
|
|
174 {
|
|
175 /* Skip casts for lhs assignment. */
|
|
176 Expression *e1b = e1;
|
|
177 while (e1b->op == TOKcast)
|
|
178 {
|
|
179 CastExp *ce = (CastExp *) e1b;
|
|
180 gcc_assert (same_type_p (ce->type, ce->to));
|
|
181 e1b = ce->e1;
|
|
182 }
|
|
183
|
|
184 /* Stabilize LHS for assignment. */
|
|
185 tree lhs = build_expr (e1b);
|
|
186 tree lexpr = stabilize_expr (&lhs);
|
|
187
|
|
188 /* The LHS expression could be an assignment, to which its operation gets
|
|
189 lost during gimplification. */
|
|
190 if (TREE_CODE (lhs) == MODIFY_EXPR)
|
|
191 {
|
|
192 /* If LHS has side effects, call stabilize_reference on it, so it can
|
|
193 be evaluated multiple times. */
|
|
194 if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0)))
|
|
195 lhs = build_assign (MODIFY_EXPR,
|
|
196 stabilize_reference (TREE_OPERAND (lhs, 0)),
|
|
197 TREE_OPERAND (lhs, 1));
|
|
198
|
|
199 lexpr = compound_expr (lexpr, lhs);
|
|
200 lhs = TREE_OPERAND (lhs, 0);
|
|
201 }
|
|
202
|
|
203 lhs = stabilize_reference (lhs);
|
|
204
|
|
205 /* Save RHS, to ensure that the expression is evaluated before LHS. */
|
|
206 tree rhs = build_expr (e2);
|
|
207 tree rexpr = d_save_expr (rhs);
|
|
208
|
|
209 rhs = this->binary_op (code, build_ctype (e1->type),
|
|
210 convert_expr (lhs, e1b->type, e1->type), rexpr);
|
|
211 if (TREE_SIDE_EFFECTS (rhs))
|
|
212 rhs = compound_expr (rexpr, rhs);
|
|
213
|
|
214 tree expr = modify_expr (lhs, convert_expr (rhs, e1->type, e1b->type));
|
|
215 return compound_expr (lexpr, expr);
|
|
216 }
|
|
217
|
|
218 public:
|
|
219 ExprVisitor (bool constp)
|
|
220 {
|
|
221 this->result_ = NULL_TREE;
|
|
222 this->constp_ = constp;
|
|
223 }
|
|
224
|
|
225 tree result (void)
|
|
226 {
|
|
227 return this->result_;
|
|
228 }
|
|
229
|
|
230 /* Visitor interfaces, each Expression class should have
|
|
231 overridden the default. */
|
|
232
|
|
233 void visit (Expression *)
|
|
234 {
|
|
235 gcc_unreachable ();
|
|
236 }
|
|
237
|
|
238 /* Build a conditional expression. If either the second or third
|
|
239 expression is void, then the resulting type is void. Otherwise
|
|
240 they are implicitly converted to a common type. */
|
|
241
|
|
242 void visit (CondExp *e)
|
|
243 {
|
|
244 tree cond = convert_for_condition (build_expr (e->econd),
|
|
245 e->econd->type);
|
|
246 tree t1 = build_expr (e->e1);
|
|
247 tree t2 = build_expr (e->e2);
|
|
248
|
|
249 if (e->type->ty != Tvoid)
|
|
250 {
|
|
251 t1 = convert_expr (t1, e->e1->type, e->type);
|
|
252 t2 = convert_expr (t2, e->e2->type, e->type);
|
|
253 }
|
|
254
|
|
255 this->result_ = build_condition (build_ctype (e->type), cond, t1, t2);
|
|
256 }
|
|
257
|
|
258 /* Build an identity comparison expression. Operands go through the
|
|
259 usual conversions to bring them to a common type before comparison.
|
|
260 The result type is bool. */
|
|
261
|
|
262 void visit (IdentityExp *e)
|
|
263 {
|
|
264 tree_code code = (e->op == TOKidentity) ? EQ_EXPR : NE_EXPR;
|
|
265 Type *tb1 = e->e1->type->toBasetype ();
|
|
266 Type *tb2 = e->e2->type->toBasetype ();
|
|
267
|
|
268 if ((tb1->ty == Tsarray || tb1->ty == Tarray)
|
|
269 && (tb2->ty == Tsarray || tb2->ty == Tarray))
|
|
270 {
|
|
271 /* For static and dynamic arrays, identity is defined as referring to
|
|
272 the same array elements and the same number of elements. */
|
|
273 tree t1 = d_array_convert (e->e1);
|
|
274 tree t2 = d_array_convert (e->e2);
|
|
275 this->result_ = d_convert (build_ctype (e->type),
|
|
276 build_boolop (code, t1, t2));
|
|
277 }
|
|
278 else if (tb1->isfloating () && tb1->ty != Tvector)
|
|
279 {
|
|
280 /* For floating-point values, identity is defined as the bits in the
|
|
281 operands being identical. */
|
|
282 tree t1 = d_save_expr (build_expr (e->e1));
|
|
283 tree t2 = d_save_expr (build_expr (e->e2));
|
|
284
|
|
285 if (!tb1->iscomplex ())
|
|
286 this->result_ = build_float_identity (code, t1, t2);
|
|
287 else
|
|
288 {
|
|
289 /* Compare the real and imaginary parts separately. */
|
|
290 tree req = build_float_identity (code, real_part (t1),
|
|
291 real_part (t2));
|
|
292 tree ieq = build_float_identity (code, imaginary_part (t1),
|
|
293 imaginary_part (t2));
|
|
294
|
|
295 if (code == EQ_EXPR)
|
|
296 this->result_ = build_boolop (TRUTH_ANDIF_EXPR, req, ieq);
|
|
297 else
|
|
298 this->result_ = build_boolop (TRUTH_ORIF_EXPR, req, ieq);
|
|
299 }
|
|
300 }
|
|
301 else if (tb1->ty == Tstruct)
|
|
302 {
|
|
303 /* For struct objects, identity is defined as bits in operands being
|
|
304 identical also. Alignment holes in structs are ignored. */
|
|
305 StructDeclaration *sd = ((TypeStruct *) tb1)->sym;
|
|
306 tree t1 = build_expr (e->e1);
|
|
307 tree t2 = build_expr (e->e2);
|
|
308
|
|
309 gcc_assert (same_type_p (tb1, tb2));
|
|
310
|
|
311 this->result_ = build_struct_comparison (code, sd, t1, t2);
|
|
312 }
|
|
313 else
|
|
314 {
|
|
315 /* For operands of other types, identity is defined as being the
|
|
316 same as equality expressions. */
|
|
317 tree t1 = build_expr (e->e1);
|
|
318 tree t2 = build_expr (e->e2);
|
|
319 this->result_ = d_convert (build_ctype (e->type),
|
|
320 build_boolop (code, t1, t2));
|
|
321 }
|
|
322 }
|
|
323
|
|
324 /* Build an equality expression, which compare the two operands for either
|
|
325 equality or inequality. Operands go through the usual conversions to bring
|
|
326 them to a common type before comparison. The result type is bool. */
|
|
327
|
|
328 void visit (EqualExp *e)
|
|
329 {
|
|
330 Type *tb1 = e->e1->type->toBasetype ();
|
|
331 Type *tb2 = e->e2->type->toBasetype ();
|
|
332 tree_code code = (e->op == TOKequal) ? EQ_EXPR : NE_EXPR;
|
|
333
|
|
334 if ((tb1->ty == Tsarray || tb1->ty == Tarray)
|
|
335 && (tb2->ty == Tsarray || tb2->ty == Tarray))
|
|
336 {
|
|
337 /* For static and dynamic arrays, equality is defined as the lengths of
|
|
338 the arrays matching, and all the elements are equal. */
|
|
339 Type *t1elem = tb1->nextOf ()->toBasetype ();
|
|
340 Type *t2elem = tb1->nextOf ()->toBasetype ();
|
|
341
|
|
342 /* Check if comparisons of arrays can be optimized using memcmp.
|
|
343 This will inline EQ expressions as:
|
|
344 e1.length == e2.length && memcmp(e1.ptr, e2.ptr, size) == 0;
|
|
345 Or when generating a NE expression:
|
|
346 e1.length != e2.length || memcmp(e1.ptr, e2.ptr, size) != 0; */
|
|
347 if ((t1elem->isintegral () || t1elem->ty == Tvoid
|
|
348 || (t1elem->ty == Tstruct && !((TypeStruct *)t1elem)->sym->xeq))
|
|
349 && t1elem->ty == t2elem->ty)
|
|
350 {
|
|
351 tree t1 = d_array_convert (e->e1);
|
|
352 tree t2 = d_array_convert (e->e2);
|
|
353 tree result;
|
|
354
|
|
355 /* Make temporaries to prevent multiple evaluations. */
|
|
356 tree t1saved = d_save_expr (t1);
|
|
357 tree t2saved = d_save_expr (t2);
|
|
358
|
|
359 /* Length of arrays, for comparisons done before calling memcmp. */
|
|
360 tree t1len = d_array_length (t1saved);
|
|
361 tree t2len = d_array_length (t2saved);
|
|
362
|
|
363 /* Reference to array data. */
|
|
364 tree t1ptr = d_array_ptr (t1saved);
|
|
365 tree t2ptr = d_array_ptr (t2saved);
|
|
366
|
|
367 /* Compare arrays using memcmp if possible, otherwise for structs,
|
|
368 each field is compared inline. */
|
|
369 if (t1elem->ty != Tstruct
|
|
370 || identity_compare_p (((TypeStruct *) t1elem)->sym))
|
|
371 {
|
|
372 tree size = size_mult_expr (t1len, size_int (t1elem->size ()));
|
|
373 tree tmemcmp = builtin_decl_explicit (BUILT_IN_MEMCMP);
|
|
374
|
|
375 result = build_call_expr (tmemcmp, 3, t1ptr, t2ptr, size);
|
|
376 result = build_boolop (code, result, integer_zero_node);
|
|
377 }
|
|
378 else
|
|
379 {
|
|
380 StructDeclaration *sd = ((TypeStruct *) t1elem)->sym;
|
|
381
|
|
382 result = build_array_struct_comparison (code, sd, t1len,
|
|
383 t1ptr, t2ptr);
|
|
384 }
|
|
385
|
|
386 /* Check array length first before passing to memcmp.
|
|
387 For equality expressions, this becomes:
|
|
388 (e1.length == 0 || memcmp);
|
|
389 Otherwise for inequality:
|
|
390 (e1.length != 0 && memcmp); */
|
|
391 tree tsizecmp = build_boolop (code, t1len, size_zero_node);
|
|
392 if (e->op == TOKequal)
|
|
393 result = build_boolop (TRUTH_ORIF_EXPR, tsizecmp, result);
|
|
394 else
|
|
395 result = build_boolop (TRUTH_ANDIF_EXPR, tsizecmp, result);
|
|
396
|
|
397 /* Finally, check if lengths of both arrays match if dynamic.
|
|
398 The frontend should have already guaranteed that static arrays
|
|
399 have same size. */
|
|
400 if (tb1->ty == Tsarray && tb2->ty == Tsarray)
|
|
401 gcc_assert (tb1->size () == tb2->size ());
|
|
402 else
|
|
403 {
|
|
404 tree tlencmp = build_boolop (code, t1len, t2len);
|
|
405 if (e->op == TOKequal)
|
|
406 result = build_boolop (TRUTH_ANDIF_EXPR, tlencmp, result);
|
|
407 else
|
|
408 result = build_boolop (TRUTH_ORIF_EXPR, tlencmp, result);
|
|
409 }
|
|
410
|
|
411 /* Ensure left-to-right order of evaluation. */
|
|
412 if (TREE_SIDE_EFFECTS (t2))
|
|
413 result = compound_expr (t2saved, result);
|
|
414
|
|
415 if (TREE_SIDE_EFFECTS (t1))
|
|
416 result = compound_expr (t1saved, result);
|
|
417
|
|
418 this->result_ = result;
|
|
419 }
|
|
420 else
|
|
421 {
|
|
422 /* Use _adEq2() to compare each element. */
|
|
423 Type *t1array = t1elem->arrayOf ();
|
|
424 tree result = build_libcall (LIBCALL_ADEQ2, e->type, 3,
|
|
425 d_array_convert (e->e1),
|
|
426 d_array_convert (e->e2),
|
|
427 build_typeinfo (e->loc, t1array));
|
|
428
|
|
429 if (e->op == TOKnotequal)
|
|
430 result = build1 (TRUTH_NOT_EXPR, build_ctype (e->type), result);
|
|
431
|
|
432 this->result_ = result;
|
|
433 }
|
|
434 }
|
|
435 else if (tb1->ty == Tstruct)
|
|
436 {
|
|
437 /* Equality for struct objects means the logical product of all
|
|
438 equality results of the corresponding object fields. */
|
|
439 StructDeclaration *sd = ((TypeStruct *) tb1)->sym;
|
|
440 tree t1 = build_expr (e->e1);
|
|
441 tree t2 = build_expr (e->e2);
|
|
442
|
|
443 gcc_assert (same_type_p (tb1, tb2));
|
|
444
|
|
445 this->result_ = build_struct_comparison (code, sd, t1, t2);
|
|
446 }
|
|
447 else if (tb1->ty == Taarray && tb2->ty == Taarray)
|
|
448 {
|
|
449 /* Use _aaEqual() for associative arrays. */
|
|
450 TypeAArray *taa1 = (TypeAArray *) tb1;
|
|
451 tree result = build_libcall (LIBCALL_AAEQUAL, e->type, 3,
|
|
452 build_typeinfo (e->loc, taa1),
|
|
453 build_expr (e->e1),
|
|
454 build_expr (e->e2));
|
|
455
|
|
456 if (e->op == TOKnotequal)
|
|
457 result = build1 (TRUTH_NOT_EXPR, build_ctype (e->type), result);
|
|
458
|
|
459 this->result_ = result;
|
|
460 }
|
|
461 else
|
|
462 {
|
|
463 /* For operands of other types, equality is defined as the bit pattern
|
|
464 of the type matches exactly. */
|
|
465 tree t1 = build_expr (e->e1);
|
|
466 tree t2 = build_expr (e->e2);
|
|
467
|
|
468 this->result_ = d_convert (build_ctype (e->type),
|
|
469 build_boolop (code, t1, t2));
|
|
470 }
|
|
471 }
|
|
472
|
|
473 /* Build an `in' expression. This is a condition to see if an element
|
|
474 exists in an associative array. The result is a pointer to the
|
|
475 element, or null if false. */
|
|
476
|
|
477 void visit (InExp *e)
|
|
478 {
|
|
479 Type *tb2 = e->e2->type->toBasetype ();
|
|
480 gcc_assert (tb2->ty == Taarray);
|
|
481
|
|
482 Type *tkey = ((TypeAArray *) tb2)->index->toBasetype ();
|
|
483 tree key = convert_expr (build_expr (e->e1), e->e1->type, tkey);
|
|
484
|
|
485 /* Build a call to _aaInX(). */
|
|
486 this->result_ = build_libcall (LIBCALL_AAINX, e->type, 3,
|
|
487 build_expr (e->e2),
|
|
488 build_typeinfo (e->loc, tkey),
|
|
489 build_address (key));
|
|
490 }
|
|
491
|
|
492 /* Build a relational expression. The result type is bool. */
|
|
493
|
|
494 void visit (CmpExp *e)
|
|
495 {
|
|
496 Type *tb1 = e->e1->type->toBasetype ();
|
|
497 Type *tb2 = e->e2->type->toBasetype ();
|
|
498
|
|
499 tree result;
|
|
500 tree_code code;
|
|
501
|
|
502 switch (e->op)
|
|
503 {
|
|
504 case TOKle:
|
|
505 code = LE_EXPR;
|
|
506 break;
|
|
507
|
|
508 case TOKlt:
|
|
509 code = LT_EXPR;
|
|
510 break;
|
|
511
|
|
512 case TOKge:
|
|
513 code = GE_EXPR;
|
|
514 break;
|
|
515
|
|
516 case TOKgt:
|
|
517 code = GT_EXPR;
|
|
518 break;
|
|
519
|
|
520 default:
|
|
521 gcc_unreachable ();
|
|
522 }
|
|
523
|
|
524 if ((tb1->ty == Tsarray || tb1->ty == Tarray)
|
|
525 && (tb2->ty == Tsarray || tb2->ty == Tarray))
|
|
526 {
|
|
527 /* For static and dynamic arrays, the result of the relational op is
|
|
528 the result of the operator applied to the first non-equal element
|
|
529 of the array. If two arrays compare equal, but are of different
|
|
530 lengths, the shorter array compares as less than the longer. */
|
|
531 Type *telem = tb1->nextOf ()->toBasetype ();
|
|
532
|
|
533 tree call = build_libcall (LIBCALL_ADCMP2, Type::tint32, 3,
|
|
534 d_array_convert (e->e1),
|
|
535 d_array_convert (e->e2),
|
|
536 build_typeinfo (e->loc, telem->arrayOf ()));
|
|
537 result = build_boolop (code, call, integer_zero_node);
|
|
538
|
|
539 this->result_ = d_convert (build_ctype (e->type), result);
|
|
540 return;
|
|
541 }
|
|
542
|
|
543 /* Simple comparison. */
|
|
544 result = build_boolop (code, build_expr (e->e1), build_expr (e->e2));
|
|
545 this->result_ = d_convert (build_ctype (e->type), result);
|
|
546 }
|
|
547
|
|
548 /* Build an `and if' expression. If the right operand expression is void,
|
|
549 then the resulting type is void. Otherwise the result is bool. */
|
|
550
|
|
551 void visit (AndAndExp *e)
|
|
552 {
|
|
553 if (e->e2->type->toBasetype ()->ty != Tvoid)
|
|
554 {
|
|
555 tree t1 = build_expr (e->e1);
|
|
556 tree t2 = build_expr (e->e2);
|
|
557
|
|
558 t1 = convert_for_condition (t1, e->e1->type);
|
|
559 t2 = convert_for_condition (t2, e->e2->type);
|
|
560
|
|
561 this->result_ = d_convert (build_ctype (e->type),
|
|
562 build_boolop (TRUTH_ANDIF_EXPR, t1, t2));
|
|
563 }
|
|
564 else
|
|
565 {
|
|
566 tree t1 = convert_for_condition (build_expr (e->e1), e->e1->type);
|
|
567 tree t2 = build_expr_dtor (e->e2);
|
|
568
|
|
569 this->result_ = build_condition (build_ctype (e->type),
|
|
570 t1, t2, void_node);
|
|
571 }
|
|
572 }
|
|
573
|
|
574 /* Build an `or if' expression. If the right operand expression is void,
|
|
575 then the resulting type is void. Otherwise the result is bool. */
|
|
576
|
|
577 void visit (OrOrExp *e)
|
|
578 {
|
|
579 if (e->e2->type->toBasetype ()->ty != Tvoid)
|
|
580 {
|
|
581 tree t1 = convert_for_condition (build_expr (e->e1), e->e1->type);
|
|
582 tree t2 = convert_for_condition (build_expr (e->e2), e->e2->type);
|
|
583
|
|
584 this->result_ = d_convert (build_ctype (e->type),
|
|
585 build_boolop (TRUTH_ORIF_EXPR, t1, t2));
|
|
586 }
|
|
587 else
|
|
588 {
|
|
589 tree t1 = convert_for_condition (build_expr (e->e1), e->e1->type);
|
|
590 tree t2 = build_expr_dtor (e->e2);
|
|
591 tree cond = build1 (TRUTH_NOT_EXPR, d_bool_type, t1);
|
|
592
|
|
593 this->result_ = build_condition (build_ctype (e->type),
|
|
594 cond, t2, void_node);
|
|
595 }
|
|
596 }
|
|
597
|
|
598 /* Build a binary operand expression. Operands go through usual arithmetic
|
|
599 conversions to bring them to a common type before evaluating. */
|
|
600
|
|
601 void visit (BinExp *e)
|
|
602 {
|
|
603 tree_code code;
|
|
604
|
|
605 switch (e->op)
|
|
606 {
|
|
607 case TOKadd:
|
|
608 case TOKmin:
|
|
609 if ((e->e1->type->isreal () && e->e2->type->isimaginary ())
|
|
610 || (e->e1->type->isimaginary () && e->e2->type->isreal ()))
|
|
611 {
|
|
612 /* If the result is complex, then we can shortcut binary_op.
|
|
613 Frontend should have already validated types and sizes. */
|
|
614 tree t1 = build_expr (e->e1);
|
|
615 tree t2 = build_expr (e->e2);
|
|
616
|
|
617 if (e->op == TOKmin)
|
|
618 t2 = build1 (NEGATE_EXPR, TREE_TYPE (t2), t2);
|
|
619
|
|
620 if (e->e1->type->isreal ())
|
|
621 this->result_ = complex_expr (build_ctype (e->type), t1, t2);
|
|
622 else
|
|
623 this->result_ = complex_expr (build_ctype (e->type), t2, t1);
|
|
624
|
|
625 return;
|
|
626 }
|
|
627 else
|
|
628 code = (e->op == TOKadd)
|
|
629 ? PLUS_EXPR : MINUS_EXPR;
|
|
630 break;
|
|
631
|
|
632 case TOKmul:
|
|
633 code = MULT_EXPR;
|
|
634 break;
|
|
635
|
|
636 case TOKdiv:
|
|
637 code = e->e1->type->isintegral ()
|
|
638 ? TRUNC_DIV_EXPR : RDIV_EXPR;
|
|
639 break;
|
|
640
|
|
641 case TOKmod:
|
|
642 code = e->e1->type->isfloating ()
|
|
643 ? FLOAT_MOD_EXPR : TRUNC_MOD_EXPR;
|
|
644 break;
|
|
645
|
|
646 case TOKand:
|
|
647 code = BIT_AND_EXPR;
|
|
648 break;
|
|
649
|
|
650 case TOKor:
|
|
651 code = BIT_IOR_EXPR;
|
|
652 break;
|
|
653
|
|
654 case TOKxor:
|
|
655 code = BIT_XOR_EXPR;
|
|
656 break;
|
|
657
|
|
658 case TOKshl:
|
|
659 code = LSHIFT_EXPR;
|
|
660 break;
|
|
661
|
|
662 case TOKshr:
|
|
663 code = RSHIFT_EXPR;
|
|
664 break;
|
|
665
|
|
666 case TOKushr:
|
|
667 code = UNSIGNED_RSHIFT_EXPR;
|
|
668 break;
|
|
669
|
|
670 default:
|
|
671 gcc_unreachable ();
|
|
672 }
|
|
673
|
|
674 this->result_ = this->binary_op (code, build_ctype (e->type),
|
|
675 build_expr (e->e1), build_expr (e->e2));
|
|
676 }
|
|
677
|
|
678
|
|
679 /* Build a concat expression, which concatenates two or more arrays of the
|
|
680 same type, producing a dynamic array with the result. If one operand
|
|
681 is an element type, that element is converted to an array of length 1. */
|
|
682
|
|
683 void visit (CatExp *e)
|
|
684 {
|
|
685 Type *tb1 = e->e1->type->toBasetype ();
|
|
686 Type *tb2 = e->e2->type->toBasetype ();
|
|
687 Type *etype;
|
|
688
|
|
689 if (tb1->ty == Tarray || tb1->ty == Tsarray)
|
|
690 etype = tb1->nextOf ();
|
|
691 else
|
|
692 etype = tb2->nextOf ();
|
|
693
|
|
694 vec<tree, va_gc> *elemvars = NULL;
|
|
695 tree result;
|
|
696
|
|
697 if (e->e1->op == TOKcat)
|
|
698 {
|
|
699 /* Flatten multiple concatenations to an array.
|
|
700 So the expression ((a ~ b) ~ c) becomes [a, b, c] */
|
|
701 int ndims = 2;
|
|
702
|
|
703 for (Expression *ex = e->e1; ex->op == TOKcat;)
|
|
704 {
|
|
705 if (ex->op == TOKcat)
|
|
706 {
|
|
707 ex = ((CatExp *) ex)->e1;
|
|
708 ndims++;
|
|
709 }
|
|
710 }
|
|
711
|
|
712 /* Store all concatenation args to a temporary byte[][ndims] array. */
|
|
713 Type *targselem = Type::tint8->arrayOf ();
|
|
714 tree var = create_temporary_var (make_array_type (targselem, ndims));
|
|
715 tree init = build_constructor (TREE_TYPE (var), NULL);
|
|
716 vec_safe_push (elemvars, var);
|
|
717
|
|
718 /* Loop through each concatenation from right to left. */
|
|
719 vec<constructor_elt, va_gc> *elms = NULL;
|
|
720 CatExp *ce = e;
|
|
721 int dim = ndims - 1;
|
|
722
|
|
723 for (Expression *oe = ce->e2; oe != NULL;
|
|
724 (ce->e1->op != TOKcat
|
|
725 ? (oe = ce->e1)
|
|
726 : (ce = (CatExp *)ce->e1, oe = ce->e2)))
|
|
727 {
|
|
728 tree arg = d_array_convert (etype, oe, &elemvars);
|
|
729 tree index = size_int (dim);
|
|
730 CONSTRUCTOR_APPEND_ELT (elms, index, d_save_expr (arg));
|
|
731
|
|
732 /* Finished pushing all arrays. */
|
|
733 if (oe == ce->e1)
|
|
734 break;
|
|
735
|
|
736 dim -= 1;
|
|
737 }
|
|
738
|
|
739 /* Check there is no logic bug in constructing byte[][] of arrays. */
|
|
740 gcc_assert (dim == 0);
|
|
741 CONSTRUCTOR_ELTS (init) = elms;
|
|
742 DECL_INITIAL (var) = init;
|
|
743
|
|
744 tree arrs = d_array_value (build_ctype (targselem->arrayOf ()),
|
|
745 size_int (ndims), build_address (var));
|
|
746
|
|
747 result = build_libcall (LIBCALL_ARRAYCATNTX, e->type, 2,
|
|
748 build_typeinfo (e->loc, e->type), arrs);
|
|
749 }
|
|
750 else
|
|
751 {
|
|
752 /* Handle single concatenation (a ~ b). */
|
|
753 result = build_libcall (LIBCALL_ARRAYCATT, e->type, 3,
|
|
754 build_typeinfo (e->loc, e->type),
|
|
755 d_array_convert (etype, e->e1, &elemvars),
|
|
756 d_array_convert (etype, e->e2, &elemvars));
|
|
757 }
|
|
758
|
|
759 for (size_t i = 0; i < vec_safe_length (elemvars); ++i)
|
|
760 result = bind_expr ((*elemvars)[i], result);
|
|
761
|
|
762 this->result_ = result;
|
|
763 }
|
|
764
|
|
765 /* Build an assignment operator expression. The right operand is implicitly
|
|
766 converted to the type of the left operand, and assigned to it. */
|
|
767
|
|
768 void visit (BinAssignExp *e)
|
|
769 {
|
|
770 tree_code code;
|
|
771 Expression *e1b = e->e1;
|
|
772
|
|
773 switch (e->op)
|
|
774 {
|
|
775 case TOKaddass:
|
|
776 code = PLUS_EXPR;
|
|
777 break;
|
|
778
|
|
779 case TOKminass:
|
|
780 code = MINUS_EXPR;
|
|
781 break;
|
|
782
|
|
783 case TOKmulass:
|
|
784 code = MULT_EXPR;
|
|
785 break;
|
|
786
|
|
787 case TOKdivass:
|
|
788 code = e->e1->type->isintegral ()
|
|
789 ? TRUNC_DIV_EXPR : RDIV_EXPR;
|
|
790 break;
|
|
791
|
|
792 case TOKmodass:
|
|
793 code = e->e1->type->isfloating ()
|
|
794 ? FLOAT_MOD_EXPR : TRUNC_MOD_EXPR;
|
|
795 break;
|
|
796
|
|
797 case TOKandass:
|
|
798 code = BIT_AND_EXPR;
|
|
799 break;
|
|
800
|
|
801 case TOKorass:
|
|
802 code = BIT_IOR_EXPR;
|
|
803 break;
|
|
804
|
|
805 case TOKxorass:
|
|
806 code = BIT_XOR_EXPR;
|
|
807 break;
|
|
808
|
|
809 case TOKpowass:
|
|
810 gcc_unreachable ();
|
|
811
|
|
812 case TOKshlass:
|
|
813 code = LSHIFT_EXPR;
|
|
814 break;
|
|
815
|
|
816 case TOKshrass:
|
|
817 case TOKushrass:
|
|
818 /* Use the original lhs type before it was promoted. The left operand
|
|
819 of `>>>=' does not undergo integral promotions before shifting.
|
|
820 Strip off casts just incase anyway. */
|
|
821 while (e1b->op == TOKcast)
|
|
822 {
|
|
823 CastExp *ce = (CastExp *) e1b;
|
|
824 gcc_assert (same_type_p (ce->type, ce->to));
|
|
825 e1b = ce->e1;
|
|
826 }
|
|
827 code = (e->op == TOKshrass) ? RSHIFT_EXPR : UNSIGNED_RSHIFT_EXPR;
|
|
828 break;
|
|
829
|
|
830 default:
|
|
831 gcc_unreachable ();
|
|
832 }
|
|
833
|
|
834 tree exp = this->binop_assignment (code, e1b, e->e2);
|
|
835 this->result_ = convert_expr (exp, e1b->type, e->type);
|
|
836 }
|
|
837
|
|
838 /* Build a concat assignment expression. The right operand is appended
|
|
839 to the the left operand. */
|
|
840
|
|
841 void visit (CatAssignExp *e)
|
|
842 {
|
|
843 Type *tb1 = e->e1->type->toBasetype ();
|
|
844 Type *tb2 = e->e2->type->toBasetype ();
|
|
845 Type *etype = tb1->nextOf ()->toBasetype ();
|
|
846
|
|
847 if (tb1->ty == Tarray && tb2->ty == Tdchar
|
|
848 && (etype->ty == Tchar || etype->ty == Twchar))
|
|
849 {
|
|
850 /* Append a dchar to a char[] or wchar[] */
|
|
851 libcall_fn libcall = (etype->ty == Tchar)
|
|
852 ? LIBCALL_ARRAYAPPENDCD : LIBCALL_ARRAYAPPENDWD;
|
|
853
|
|
854 this->result_ = build_libcall (libcall, e->type, 2,
|
|
855 build_address (build_expr (e->e1)),
|
|
856 build_expr (e->e2));
|
|
857 }
|
|
858 else
|
|
859 {
|
|
860 gcc_assert (tb1->ty == Tarray || tb2->ty == Tsarray);
|
|
861
|
|
862 tree tinfo = build_typeinfo (e->loc, e->type);
|
|
863 tree ptr = build_address (build_expr (e->e1));
|
|
864
|
|
865 if ((tb2->ty == Tarray || tb2->ty == Tsarray)
|
|
866 && same_type_p (etype, tb2->nextOf ()->toBasetype ()))
|
|
867 {
|
|
868 /* Append an array. */
|
|
869 this->result_ = build_libcall (LIBCALL_ARRAYAPPENDT, e->type, 3,
|
|
870 tinfo, ptr, d_array_convert (e->e2));
|
|
871
|
|
872 }
|
|
873 else if (same_type_p (etype, tb2))
|
|
874 {
|
|
875 /* Append an element. */
|
|
876 tree result = build_libcall (LIBCALL_ARRAYAPPENDCTX, e->type, 3,
|
|
877 tinfo, ptr, size_one_node);
|
|
878 result = d_save_expr (result);
|
|
879
|
|
880 /* Assign e2 to last element. */
|
|
881 tree offexp = d_array_length (result);
|
|
882 offexp = build2 (MINUS_EXPR, TREE_TYPE (offexp),
|
|
883 offexp, size_one_node);
|
|
884 offexp = d_save_expr (offexp);
|
|
885
|
|
886 tree ptrexp = d_array_ptr (result);
|
|
887 ptrexp = void_okay_p (ptrexp);
|
|
888 ptrexp = build_array_index (ptrexp, offexp);
|
|
889
|
|
890 /* Evaluate expression before appending. */
|
|
891 tree t2 = build_expr (e->e2);
|
|
892 tree expr = stabilize_expr (&t2);
|
|
893
|
|
894 t2 = d_save_expr (t2);
|
|
895 result = modify_expr (build_deref (ptrexp), t2);
|
|
896 result = compound_expr (t2, result);
|
|
897
|
|
898 this->result_ = compound_expr (expr, result);
|
|
899 }
|
|
900 else
|
|
901 gcc_unreachable ();
|
|
902 }
|
|
903 }
|
|
904
|
|
905 /* Build an assignment expression. The right operand is implicitly
|
|
906 converted to the type of the left operand, and assigned to it. */
|
|
907
|
|
908 void visit (AssignExp *e)
|
|
909 {
|
|
910 /* First, handle special assignment semantics. */
|
|
911
|
|
912 /* Look for array.length = n; */
|
|
913 if (e->e1->op == TOKarraylength)
|
|
914 {
|
|
915 /* Assignment to an array's length property; resize the array. */
|
|
916 ArrayLengthExp *ale = (ArrayLengthExp *) e->e1;
|
|
917 tree newlength = convert_expr (build_expr (e->e2), e->e2->type,
|
|
918 Type::tsize_t);
|
|
919 tree ptr = build_address (build_expr (ale->e1));
|
|
920
|
|
921 /* Don't want the basetype for the element type. */
|
|
922 Type *etype = ale->e1->type->toBasetype ()->nextOf ();
|
|
923 libcall_fn libcall = etype->isZeroInit ()
|
|
924 ? LIBCALL_ARRAYSETLENGTHT : LIBCALL_ARRAYSETLENGTHIT;
|
|
925
|
|
926 tree result = build_libcall (libcall, ale->e1->type, 3,
|
|
927 build_typeinfo (ale->loc, ale->e1->type),
|
|
928 newlength, ptr);
|
|
929
|
|
930 this->result_ = d_array_length (result);
|
|
931 return;
|
|
932 }
|
|
933
|
|
934 /* Look for array[] = n; */
|
|
935 if (e->e1->op == TOKslice)
|
|
936 {
|
|
937 SliceExp *se = (SliceExp *) e->e1;
|
|
938 Type *stype = se->e1->type->toBasetype ();
|
|
939 Type *etype = stype->nextOf ()->toBasetype ();
|
|
940
|
|
941 /* Determine if we need to run postblit or dtor. */
|
|
942 bool postblit = this->needs_postblit (etype) && this->lvalue_p (e->e2);
|
|
943 bool destructor = this->needs_dtor (etype);
|
|
944
|
|
945 if (e->memset & blockAssign)
|
|
946 {
|
|
947 /* Set a range of elements to one value. */
|
|
948 tree t1 = d_save_expr (build_expr (e->e1));
|
|
949 tree t2 = build_expr (e->e2);
|
|
950 tree result;
|
|
951
|
|
952 if ((postblit || destructor) && e->op != TOKblit)
|
|
953 {
|
|
954 libcall_fn libcall = (e->op == TOKconstruct)
|
|
955 ? LIBCALL_ARRAYSETCTOR : LIBCALL_ARRAYSETASSIGN;
|
|
956 /* So we can call postblits on const/immutable objects. */
|
|
957 Type *tm = etype->unSharedOf ()->mutableOf ();
|
|
958 tree ti = build_typeinfo (e->loc, tm);
|
|
959
|
|
960 tree result = build_libcall (libcall, Type::tvoid, 4,
|
|
961 d_array_ptr (t1),
|
|
962 build_address (t2),
|
|
963 d_array_length (t1), ti);
|
|
964 this->result_ = compound_expr (result, t1);
|
|
965 return;
|
|
966 }
|
|
967
|
|
968 if (integer_zerop (t2))
|
|
969 {
|
|
970 tree tmemset = builtin_decl_explicit (BUILT_IN_MEMSET);
|
|
971 tree size = size_mult_expr (d_array_length (t1),
|
|
972 size_int (etype->size ()));
|
|
973
|
|
974 result = build_call_expr (tmemset, 3, d_array_ptr (t1),
|
|
975 integer_zero_node, size);
|
|
976 }
|
|
977 else
|
|
978 result = build_array_set (d_array_ptr (t1),
|
|
979 d_array_length (t1), t2);
|
|
980
|
|
981 this->result_ = compound_expr (result, t1);
|
|
982 }
|
|
983 else
|
|
984 {
|
|
985 /* Perform a memcpy operation. */
|
|
986 gcc_assert (e->e2->type->ty != Tpointer);
|
|
987
|
|
988 if (!postblit && !destructor && !array_bounds_check ())
|
|
989 {
|
|
990 tree t1 = d_save_expr (d_array_convert (e->e1));
|
|
991 tree t2 = d_array_convert (e->e2);
|
|
992 tree tmemcpy = builtin_decl_explicit (BUILT_IN_MEMCPY);
|
|
993 tree size = size_mult_expr (d_array_length (t1),
|
|
994 size_int (etype->size ()));
|
|
995
|
|
996 tree result = build_call_expr (tmemcpy, 3, d_array_ptr (t1),
|
|
997 d_array_ptr (t2), size);
|
|
998 this->result_ = compound_expr (result, t1);
|
|
999 }
|
|
1000 else if ((postblit || destructor) && e->op != TOKblit)
|
|
1001 {
|
|
1002 /* Generate: _d_arrayassign(ti, from, to)
|
|
1003 or: _d_arrayctor(ti, from, to) */
|
|
1004 libcall_fn libcall = (e->op == TOKconstruct)
|
|
1005 ? LIBCALL_ARRAYCTOR : LIBCALL_ARRAYASSIGN;
|
|
1006
|
|
1007 this->result_ = build_libcall (libcall, e->type, 3,
|
|
1008 build_typeinfo (e->loc, etype),
|
|
1009 d_array_convert (e->e2),
|
|
1010 d_array_convert (e->e1));
|
|
1011 }
|
|
1012 else
|
|
1013 {
|
|
1014 /* Generate: _d_arraycopy() */
|
|
1015 this->result_ = build_libcall (LIBCALL_ARRAYCOPY, e->type, 3,
|
|
1016 size_int (etype->size ()),
|
|
1017 d_array_convert (e->e2),
|
|
1018 d_array_convert (e->e1));
|
|
1019 }
|
|
1020 }
|
|
1021
|
|
1022 return;
|
|
1023 }
|
|
1024
|
|
1025 /* Look for reference initializations. */
|
|
1026 if (e->memset & referenceInit)
|
|
1027 {
|
|
1028 gcc_assert (e->op == TOKconstruct || e->op == TOKblit);
|
|
1029 gcc_assert (e->e1->op == TOKvar);
|
|
1030
|
|
1031 Declaration *decl = ((VarExp *) e->e1)->var;
|
|
1032 if (decl->storage_class & (STCout | STCref))
|
|
1033 {
|
|
1034 tree t2 = convert_for_assignment (build_expr (e->e2),
|
|
1035 e->e2->type, e->e1->type);
|
|
1036 tree t1 = build_expr (e->e1);
|
|
1037 /* Want reference to lhs, not indirect ref. */
|
|
1038 t1 = TREE_OPERAND (t1, 0);
|
|
1039 t2 = build_address (t2);
|
|
1040
|
|
1041 this->result_ = indirect_ref (build_ctype (e->type),
|
|
1042 build_assign (INIT_EXPR, t1, t2));
|
|
1043 return;
|
|
1044 }
|
|
1045 }
|
|
1046
|
|
1047 /* Other types of assignments that may require post construction. */
|
|
1048 Type *tb1 = e->e1->type->toBasetype ();
|
|
1049 tree_code modifycode = (e->op == TOKconstruct) ? INIT_EXPR : MODIFY_EXPR;
|
|
1050
|
|
1051 /* Look for struct assignment. */
|
|
1052 if (tb1->ty == Tstruct)
|
|
1053 {
|
|
1054 tree t1 = build_expr (e->e1);
|
|
1055 tree t2 = convert_for_assignment (build_expr (e->e2),
|
|
1056 e->e2->type, e->e1->type);
|
|
1057
|
|
1058 /* Look for struct = 0. */
|
|
1059 if (e->e2->op == TOKint64)
|
|
1060 {
|
|
1061 /* Use memset to fill struct. */
|
|
1062 gcc_assert (e->op == TOKblit);
|
|
1063 StructDeclaration *sd = ((TypeStruct *) tb1)->sym;
|
|
1064
|
|
1065 tree tmemset = builtin_decl_explicit (BUILT_IN_MEMSET);
|
|
1066 tree result = build_call_expr (tmemset, 3, build_address (t1),
|
|
1067 t2, size_int (sd->structsize));
|
|
1068
|
|
1069 /* Maybe set-up hidden pointer to outer scope context. */
|
|
1070 if (sd->isNested ())
|
|
1071 {
|
|
1072 tree field = get_symbol_decl (sd->vthis);
|
|
1073 tree value = build_vthis (sd);
|
|
1074
|
|
1075 tree vthis_exp = modify_expr (component_ref (t1, field), value);
|
|
1076 result = compound_expr (result, vthis_exp);
|
|
1077 }
|
|
1078
|
|
1079 this->result_ = compound_expr (result, t1);
|
|
1080 }
|
|
1081 else
|
|
1082 this->result_ = build_assign (modifycode, t1, t2);
|
|
1083
|
|
1084 return;
|
|
1085 }
|
|
1086
|
|
1087 /* Look for static array assignment. */
|
|
1088 if (tb1->ty == Tsarray)
|
|
1089 {
|
|
1090 /* Look for array = 0. */
|
|
1091 if (e->e2->op == TOKint64)
|
|
1092 {
|
|
1093 /* Use memset to fill the array. */
|
|
1094 gcc_assert (e->op == TOKblit);
|
|
1095
|
|
1096 tree t1 = build_expr (e->e1);
|
|
1097 tree t2 = convert_for_assignment (build_expr (e->e2),
|
|
1098 e->e2->type, e->e1->type);
|
|
1099 tree size = size_int (e->e1->type->size ());
|
|
1100
|
|
1101 tree tmemset = builtin_decl_explicit (BUILT_IN_MEMSET);
|
|
1102 this->result_ = build_call_expr (tmemset, 3, build_address (t1),
|
|
1103 t2, size);
|
|
1104 return;
|
|
1105 }
|
|
1106
|
|
1107 Type *etype = tb1->nextOf ();
|
|
1108 gcc_assert (e->e2->type->toBasetype ()->ty == Tsarray);
|
|
1109
|
|
1110 /* Determine if we need to run postblit. */
|
|
1111 bool postblit = this->needs_postblit (etype);
|
|
1112 bool destructor = this->needs_dtor (etype);
|
|
1113 bool lvalue_p = this->lvalue_p (e->e2);
|
|
1114
|
|
1115 /* Even if the elements in rhs are all rvalues and don't have
|
|
1116 to call postblits, this assignment should call dtors on old
|
|
1117 assigned elements. */
|
|
1118 if ((!postblit && !destructor)
|
|
1119 || (e->op == TOKconstruct && !lvalue_p && postblit)
|
|
1120 || (e->op == TOKblit || e->e1->type->size () == 0))
|
|
1121 {
|
|
1122 tree t1 = build_expr (e->e1);
|
|
1123 tree t2 = convert_for_assignment (build_expr (e->e2),
|
|
1124 e->e2->type, e->e1->type);
|
|
1125
|
|
1126 this->result_ = build_assign (modifycode, t1, t2);
|
|
1127 return;
|
|
1128 }
|
|
1129
|
|
1130 Type *arrtype = (e->type->ty == Tsarray) ? etype->arrayOf () : e->type;
|
|
1131 tree result;
|
|
1132
|
|
1133 if (e->op == TOKconstruct)
|
|
1134 {
|
|
1135 /* Generate: _d_arrayctor(ti, from, to) */
|
|
1136 result = build_libcall (LIBCALL_ARRAYCTOR, arrtype, 3,
|
|
1137 build_typeinfo (e->loc, etype),
|
|
1138 d_array_convert (e->e2),
|
|
1139 d_array_convert (e->e1));
|
|
1140 }
|
|
1141 else
|
|
1142 {
|
|
1143 /* Generate: _d_arrayassign_l()
|
|
1144 or: _d_arrayassign_r() */
|
|
1145 libcall_fn libcall = (lvalue_p)
|
|
1146 ? LIBCALL_ARRAYASSIGN_L : LIBCALL_ARRAYASSIGN_R;
|
|
1147 tree elembuf = build_local_temp (build_ctype (etype));
|
|
1148
|
|
1149 result = build_libcall (libcall, arrtype, 4,
|
|
1150 build_typeinfo (e->loc, etype),
|
|
1151 d_array_convert (e->e2),
|
|
1152 d_array_convert (e->e1),
|
|
1153 build_address (elembuf));
|
|
1154 }
|
|
1155
|
|
1156 /* Cast the libcall result back to a static array. */
|
|
1157 if (e->type->ty == Tsarray)
|
|
1158 result = indirect_ref (build_ctype (e->type),
|
|
1159 d_array_ptr (result));
|
|
1160
|
|
1161 this->result_ = result;
|
|
1162 return;
|
|
1163 }
|
|
1164
|
|
1165 /* Simple assignment. */
|
|
1166 tree t1 = build_expr (e->e1);
|
|
1167 tree t2 = convert_for_assignment (build_expr (e->e2),
|
|
1168 e->e2->type, e->e1->type);
|
|
1169
|
|
1170 this->result_ = build_assign (modifycode, t1, t2);
|
|
1171 }
|
|
1172
|
|
1173 /* Build a postfix expression. */
|
|
1174
|
|
1175 void visit (PostExp *e)
|
|
1176 {
|
|
1177 tree result;
|
|
1178
|
|
1179 if (e->op == TOKplusplus)
|
|
1180 {
|
|
1181 result = build2 (POSTINCREMENT_EXPR, build_ctype (e->type),
|
|
1182 build_expr (e->e1), build_expr (e->e2));
|
|
1183 }
|
|
1184 else if (e->op == TOKminusminus)
|
|
1185 {
|
|
1186 result = build2 (POSTDECREMENT_EXPR, build_ctype (e->type),
|
|
1187 build_expr (e->e1), build_expr (e->e2));
|
|
1188 }
|
|
1189 else
|
|
1190 gcc_unreachable ();
|
|
1191
|
|
1192 TREE_SIDE_EFFECTS (result) = 1;
|
|
1193 this->result_ = result;
|
|
1194 }
|
|
1195
|
|
1196 /* Build an index expression. */
|
|
1197
|
|
1198 void visit (IndexExp *e)
|
|
1199 {
|
|
1200 Type *tb1 = e->e1->type->toBasetype ();
|
|
1201
|
|
1202 if (tb1->ty == Taarray)
|
|
1203 {
|
|
1204 /* Get the key for the associative array. */
|
|
1205 Type *tkey = ((TypeAArray *) tb1)->index->toBasetype ();
|
|
1206 tree key = convert_expr (build_expr (e->e2), e->e2->type, tkey);
|
|
1207 libcall_fn libcall;
|
|
1208 tree tinfo, ptr;
|
|
1209
|
|
1210 if (e->modifiable)
|
|
1211 {
|
|
1212 libcall = LIBCALL_AAGETY;
|
|
1213 ptr = build_address (build_expr (e->e1));
|
|
1214 tinfo = build_typeinfo (e->loc, tb1->unSharedOf ()->mutableOf ());
|
|
1215 }
|
|
1216 else
|
|
1217 {
|
|
1218 libcall = LIBCALL_AAGETRVALUEX;
|
|
1219 ptr = build_expr (e->e1);
|
|
1220 tinfo = build_typeinfo (e->loc, tkey);
|
|
1221 }
|
|
1222
|
|
1223 /* Index the associative array. */
|
|
1224 tree result = build_libcall (libcall, e->type->pointerTo (), 4,
|
|
1225 ptr, tinfo,
|
|
1226 size_int (tb1->nextOf ()->size ()),
|
|
1227 build_address (key));
|
|
1228
|
|
1229 if (!e->indexIsInBounds && array_bounds_check ())
|
|
1230 {
|
|
1231 tree tassert = (global.params.checkAction == CHECKACTION_D)
|
|
1232 ? d_assert_call (e->loc, LIBCALL_ARRAY_BOUNDS)
|
|
1233 : build_call_expr (builtin_decl_explicit (BUILT_IN_TRAP), 0);
|
|
1234
|
|
1235 result = d_save_expr (result);
|
|
1236 result = build_condition (TREE_TYPE (result),
|
|
1237 d_truthvalue_conversion (result),
|
|
1238 result, tassert);
|
|
1239 }
|
|
1240
|
|
1241 this->result_ = indirect_ref (build_ctype (e->type), result);
|
|
1242 }
|
|
1243 else
|
|
1244 {
|
|
1245 /* Get the data pointer and length for static and dynamic arrays. */
|
|
1246 tree array = d_save_expr (build_expr (e->e1));
|
|
1247 tree ptr = convert_expr (array, tb1, tb1->nextOf ()->pointerTo ());
|
|
1248
|
|
1249 tree length = NULL_TREE;
|
|
1250 if (tb1->ty != Tpointer)
|
|
1251 length = get_array_length (array, tb1);
|
|
1252 else
|
|
1253 gcc_assert (e->lengthVar == NULL);
|
|
1254
|
|
1255 /* The __dollar variable just becomes a placeholder for the
|
|
1256 actual length. */
|
|
1257 if (e->lengthVar)
|
|
1258 e->lengthVar->csym = length;
|
|
1259
|
|
1260 /* Generate the index. */
|
|
1261 tree index = build_expr (e->e2);
|
|
1262
|
|
1263 /* If it's a static array and the index is constant, the front end has
|
|
1264 already checked the bounds. */
|
|
1265 if (tb1->ty != Tpointer && !e->indexIsInBounds)
|
|
1266 index = build_bounds_condition (e->e2->loc, index, length, false);
|
|
1267
|
|
1268 /* Index the .ptr. */
|
|
1269 ptr = void_okay_p (ptr);
|
|
1270 this->result_ = indirect_ref (TREE_TYPE (TREE_TYPE (ptr)),
|
|
1271 build_array_index (ptr, index));
|
|
1272 }
|
|
1273 }
|
|
1274
|
|
1275 /* Build a comma expression. The type is the type of the right operand. */
|
|
1276
|
|
1277 void visit (CommaExp *e)
|
|
1278 {
|
|
1279 tree t1 = build_expr (e->e1);
|
|
1280 tree t2 = build_expr (e->e2);
|
|
1281 tree type = e->type ? build_ctype (e->type) : void_type_node;
|
|
1282
|
|
1283 this->result_ = build2 (COMPOUND_EXPR, type, t1, t2);
|
|
1284 }
|
|
1285
|
|
1286 /* Build an array length expression. Returns the number of elements
|
|
1287 in the array. The result is of type size_t. */
|
|
1288
|
|
1289 void visit (ArrayLengthExp *e)
|
|
1290 {
|
|
1291 if (e->e1->type->toBasetype ()->ty == Tarray)
|
|
1292 this->result_ = d_array_length (build_expr (e->e1));
|
|
1293 else
|
|
1294 {
|
|
1295 /* Static arrays have already been handled by the front-end. */
|
|
1296 error ("unexpected type for array length: %qs", e->type->toChars ());
|
|
1297 this->result_ = error_mark_node;
|
|
1298 }
|
|
1299 }
|
|
1300
|
|
1301 /* Build a delegate pointer expression. This will return the frame
|
|
1302 pointer value as a type void*. */
|
|
1303
|
|
1304 void visit (DelegatePtrExp *e)
|
|
1305 {
|
|
1306 tree t1 = build_expr (e->e1);
|
|
1307 this->result_ = delegate_object (t1);
|
|
1308 }
|
|
1309
|
|
1310 /* Build a delegate function pointer expression. This will return the
|
|
1311 function pointer value as a function type. */
|
|
1312
|
|
1313 void visit (DelegateFuncptrExp *e)
|
|
1314 {
|
|
1315 tree t1 = build_expr (e->e1);
|
|
1316 this->result_ = delegate_method (t1);
|
|
1317 }
|
|
1318
|
|
1319 /* Build a slice expression. */
|
|
1320
|
|
1321 void visit (SliceExp *e)
|
|
1322 {
|
|
1323 Type *tb = e->type->toBasetype ();
|
|
1324 Type *tb1 = e->e1->type->toBasetype ();
|
|
1325 gcc_assert (tb->ty == Tarray || tb->ty == Tsarray);
|
|
1326
|
|
1327 /* Use convert-to-dynamic-array code if possible. */
|
|
1328 if (!e->lwr)
|
|
1329 {
|
|
1330 tree result = build_expr (e->e1);
|
|
1331 if (e->e1->type->toBasetype ()->ty == Tsarray)
|
|
1332 result = convert_expr (result, e->e1->type, e->type);
|
|
1333
|
|
1334 this->result_ = result;
|
|
1335 return;
|
|
1336 }
|
|
1337 else
|
|
1338 gcc_assert (e->upr != NULL);
|
|
1339
|
|
1340 /* Get the data pointer and length for static and dynamic arrays. */
|
|
1341 tree array = d_save_expr (build_expr (e->e1));
|
|
1342 tree ptr = convert_expr (array, tb1, tb1->nextOf ()->pointerTo ());
|
|
1343 tree length = NULL_TREE;
|
|
1344
|
|
1345 /* Our array is already a SAVE_EXPR if necessary, so we don't make length
|
|
1346 a SAVE_EXPR which is, at most, a COMPONENT_REF on top of array. */
|
|
1347 if (tb1->ty != Tpointer)
|
|
1348 length = get_array_length (array, tb1);
|
|
1349 else
|
|
1350 gcc_assert (e->lengthVar == NULL);
|
|
1351
|
|
1352 /* The __dollar variable just becomes a placeholder for the
|
|
1353 actual length. */
|
|
1354 if (e->lengthVar)
|
|
1355 e->lengthVar->csym = length;
|
|
1356
|
|
1357 /* Generate upper and lower bounds. */
|
|
1358 tree lwr_tree = d_save_expr (build_expr (e->lwr));
|
|
1359 tree upr_tree = d_save_expr (build_expr (e->upr));
|
|
1360
|
|
1361 /* If the upper bound has any side effects, then the lower bound should be
|
|
1362 copied to a temporary always. */
|
|
1363 if (TREE_CODE (upr_tree) == SAVE_EXPR && TREE_CODE (lwr_tree) != SAVE_EXPR)
|
|
1364 lwr_tree = save_expr (lwr_tree);
|
|
1365
|
|
1366 /* Adjust the .ptr offset. */
|
|
1367 if (!integer_zerop (lwr_tree))
|
|
1368 {
|
|
1369 tree ptrtype = TREE_TYPE (ptr);
|
|
1370 ptr = build_array_index (void_okay_p (ptr), lwr_tree);
|
|
1371 ptr = build_nop (ptrtype, ptr);
|
|
1372 }
|
|
1373 else
|
|
1374 lwr_tree = NULL_TREE;
|
|
1375
|
|
1376 /* Nothing more to do for static arrays, their bounds checking has been
|
|
1377 done at compile-time. */
|
|
1378 if (tb->ty == Tsarray)
|
|
1379 {
|
|
1380 this->result_ = indirect_ref (build_ctype (e->type), ptr);
|
|
1381 return;
|
|
1382 }
|
|
1383 else
|
|
1384 gcc_assert (tb->ty == Tarray);
|
|
1385
|
|
1386 /* Generate bounds checking code. */
|
|
1387 tree newlength;
|
|
1388
|
|
1389 if (!e->upperIsInBounds)
|
|
1390 {
|
|
1391 if (length)
|
|
1392 {
|
|
1393 newlength = build_bounds_condition (e->upr->loc, upr_tree,
|
|
1394 length, true);
|
|
1395 }
|
|
1396 else
|
|
1397 {
|
|
1398 /* Still need to check bounds lwr <= upr for pointers. */
|
|
1399 gcc_assert (tb1->ty == Tpointer);
|
|
1400 newlength = upr_tree;
|
|
1401 }
|
|
1402 }
|
|
1403 else
|
|
1404 newlength = upr_tree;
|
|
1405
|
|
1406 if (lwr_tree)
|
|
1407 {
|
|
1408 /* Enforces lwr <= upr. No need to check lwr <= length as
|
|
1409 we've already ensured that upr <= length. */
|
|
1410 if (!e->lowerIsLessThanUpper)
|
|
1411 {
|
|
1412 tree cond = build_bounds_condition (e->lwr->loc, lwr_tree,
|
|
1413 upr_tree, true);
|
|
1414
|
|
1415 /* When bounds checking is off, the index value is
|
|
1416 returned directly. */
|
|
1417 if (cond != lwr_tree)
|
|
1418 newlength = compound_expr (cond, newlength);
|
|
1419 }
|
|
1420
|
|
1421 /* Need to ensure lwr always gets evaluated first, as it may be a
|
|
1422 function call. Generates (lwr, upr) - lwr. */
|
|
1423 newlength = fold_build2 (MINUS_EXPR, TREE_TYPE (newlength),
|
|
1424 compound_expr (lwr_tree, newlength), lwr_tree);
|
|
1425 }
|
|
1426
|
|
1427 tree result = d_array_value (build_ctype (e->type), newlength, ptr);
|
|
1428 this->result_ = compound_expr (array, result);
|
|
1429 }
|
|
1430
|
|
1431 /* Build a cast expression, which converts the given unary expression to the
|
|
1432 type of result. */
|
|
1433
|
|
1434 void visit (CastExp *e)
|
|
1435 {
|
|
1436 Type *ebtype = e->e1->type->toBasetype ();
|
|
1437 Type *tbtype = e->to->toBasetype ();
|
|
1438 tree result = build_expr (e->e1, this->constp_);
|
|
1439
|
|
1440 /* Just evaluate e1 if it has any side effects. */
|
|
1441 if (tbtype->ty == Tvoid)
|
|
1442 this->result_ = build_nop (build_ctype (tbtype), result);
|
|
1443 else
|
|
1444 this->result_ = convert_expr (result, ebtype, tbtype);
|
|
1445 }
|
|
1446
|
|
1447 /* Build a delete expression. */
|
|
1448
|
|
1449 void visit (DeleteExp *e)
|
|
1450 {
|
|
1451 tree t1 = build_expr (e->e1);
|
|
1452 Type *tb1 = e->e1->type->toBasetype ();
|
|
1453
|
|
1454 if (tb1->ty == Tclass)
|
|
1455 {
|
|
1456 /* For class object references, if there is a destructor for that class,
|
|
1457 the destructor is called for the object instance. */
|
|
1458 libcall_fn libcall;
|
|
1459
|
|
1460 if (e->e1->op == TOKvar)
|
|
1461 {
|
|
1462 VarDeclaration *v = ((VarExp *) e->e1)->var->isVarDeclaration ();
|
|
1463 if (v && v->onstack)
|
|
1464 {
|
|
1465 libcall = tb1->isClassHandle ()->isInterfaceDeclaration ()
|
|
1466 ? LIBCALL_CALLINTERFACEFINALIZER : LIBCALL_CALLFINALIZER;
|
|
1467
|
|
1468 this->result_ = build_libcall (libcall, Type::tvoid, 1, t1);
|
|
1469 return;
|
|
1470 }
|
|
1471 }
|
|
1472
|
|
1473 /* Otherwise, the garbage collector is called to immediately free the
|
|
1474 memory allocated for the class instance. */
|
|
1475 libcall = tb1->isClassHandle ()->isInterfaceDeclaration ()
|
|
1476 ? LIBCALL_DELINTERFACE : LIBCALL_DELCLASS;
|
|
1477
|
|
1478 t1 = build_address (t1);
|
|
1479 this->result_ = build_libcall (libcall, Type::tvoid, 1, t1);
|
|
1480 }
|
|
1481 else if (tb1->ty == Tarray)
|
|
1482 {
|
|
1483 /* For dynamic arrays, the garbage collector is called to immediately
|
|
1484 release the memory. */
|
|
1485 Type *telem = tb1->nextOf ()->baseElemOf ();
|
|
1486 tree ti = null_pointer_node;
|
|
1487
|
|
1488 if (telem->ty == Tstruct)
|
|
1489 {
|
|
1490 /* Might need to run destructor on array contents. */
|
|
1491 TypeStruct *ts = (TypeStruct *) telem;
|
|
1492 if (ts->sym->dtor)
|
|
1493 ti = build_typeinfo (e->loc, tb1->nextOf ());
|
|
1494 }
|
|
1495
|
|
1496 /* Generate: _delarray_t (&t1, ti); */
|
|
1497 this->result_ = build_libcall (LIBCALL_DELARRAYT, Type::tvoid, 2,
|
|
1498 build_address (t1), ti);
|
|
1499 }
|
|
1500 else if (tb1->ty == Tpointer)
|
|
1501 {
|
|
1502 /* For pointers to a struct instance, if the struct has overloaded
|
|
1503 operator delete, then that operator is called. */
|
|
1504 t1 = build_address (t1);
|
|
1505 Type *tnext = ((TypePointer *)tb1)->next->toBasetype ();
|
|
1506
|
|
1507 if (tnext->ty == Tstruct)
|
|
1508 {
|
|
1509 TypeStruct *ts = (TypeStruct *)tnext;
|
|
1510 if (ts->sym->dtor)
|
|
1511 {
|
|
1512 tree ti = build_typeinfo (e->loc, tnext);
|
|
1513 this->result_ = build_libcall (LIBCALL_DELSTRUCT, Type::tvoid,
|
|
1514 2, t1, ti);
|
|
1515 return;
|
|
1516 }
|
|
1517 }
|
|
1518
|
|
1519 /* Otherwise, the garbage collector is called to immediately free the
|
|
1520 memory allocated for the pointer. */
|
|
1521 this->result_ = build_libcall (LIBCALL_DELMEMORY, Type::tvoid, 1, t1);
|
|
1522 }
|
|
1523 else
|
|
1524 {
|
|
1525 error ("don%'t know how to delete %qs", e->e1->toChars ());
|
|
1526 this->result_ = error_mark_node;
|
|
1527 }
|
|
1528 }
|
|
1529
|
|
1530 /* Build a remove expression, which removes a particular key from an
|
|
1531 associative array. */
|
|
1532
|
|
1533 void visit (RemoveExp *e)
|
|
1534 {
|
|
1535 /* Check that the array is actually an associative array. */
|
|
1536 if (e->e1->type->toBasetype ()->ty == Taarray)
|
|
1537 {
|
|
1538 Type *tb = e->e1->type->toBasetype ();
|
|
1539 Type *tkey = ((TypeAArray *) tb)->index->toBasetype ();
|
|
1540 tree index = convert_expr (build_expr (e->e2), e->e2->type, tkey);
|
|
1541
|
|
1542 this->result_ = build_libcall (LIBCALL_AADELX, Type::tbool, 3,
|
|
1543 build_expr (e->e1),
|
|
1544 build_typeinfo (e->loc, tkey),
|
|
1545 build_address (index));
|
|
1546 }
|
|
1547 else
|
|
1548 {
|
|
1549 error ("%qs is not an associative array", e->e1->toChars ());
|
|
1550 this->result_ = error_mark_node;
|
|
1551 }
|
|
1552 }
|
|
1553
|
|
1554 /* Build an unary not expression. */
|
|
1555
|
|
1556 void visit (NotExp *e)
|
|
1557 {
|
|
1558 tree result = convert_for_condition (build_expr (e->e1), e->e1->type);
|
|
1559 /* Need to convert to boolean type or this will fail. */
|
|
1560 result = fold_build1 (TRUTH_NOT_EXPR, d_bool_type, result);
|
|
1561
|
|
1562 this->result_ = d_convert (build_ctype (e->type), result);
|
|
1563 }
|
|
1564
|
|
1565 /* Build a compliment expression, where all the bits in the value are
|
|
1566 complemented. Note: unlike in C, the usual integral promotions
|
|
1567 are not performed prior to the complement operation. */
|
|
1568
|
|
1569 void visit (ComExp *e)
|
|
1570 {
|
|
1571 TY ty1 = e->e1->type->toBasetype ()->ty;
|
|
1572 gcc_assert (ty1 != Tarray && ty1 != Tsarray);
|
|
1573
|
|
1574 this->result_ = fold_build1 (BIT_NOT_EXPR, build_ctype (e->type),
|
|
1575 build_expr (e->e1));
|
|
1576 }
|
|
1577
|
|
1578 /* Build an unary negation expression. */
|
|
1579
|
|
1580 void visit (NegExp *e)
|
|
1581 {
|
|
1582 TY ty1 = e->e1->type->toBasetype ()->ty;
|
|
1583 gcc_assert (ty1 != Tarray && ty1 != Tsarray);
|
|
1584
|
|
1585 tree type = build_ctype (e->type);
|
|
1586 tree expr = build_expr (e->e1);
|
|
1587
|
|
1588 /* If the operation needs excess precision. */
|
|
1589 tree eptype = excess_precision_type (type);
|
|
1590 if (eptype != NULL_TREE)
|
|
1591 expr = d_convert (eptype, expr);
|
|
1592 else
|
|
1593 eptype = type;
|
|
1594
|
|
1595 tree ret = fold_build1 (NEGATE_EXPR, eptype, expr);
|
|
1596 this->result_ = d_convert (type, ret);
|
|
1597 }
|
|
1598
|
|
1599 /* Build a pointer index expression. */
|
|
1600
|
|
1601 void visit (PtrExp *e)
|
|
1602 {
|
|
1603 Type *tnext = NULL;
|
|
1604 size_t offset;
|
|
1605 tree result;
|
|
1606
|
|
1607 if (e->e1->op == TOKadd)
|
|
1608 {
|
|
1609 BinExp *be = (BinExp *) e->e1;
|
|
1610 if (be->e1->op == TOKaddress
|
|
1611 && be->e2->isConst () && be->e2->type->isintegral ())
|
|
1612 {
|
|
1613 Expression *ae = ((AddrExp *) be->e1)->e1;
|
|
1614 tnext = ae->type->toBasetype ();
|
|
1615 result = build_expr (ae);
|
|
1616 offset = be->e2->toUInteger ();
|
|
1617 }
|
|
1618 }
|
|
1619 else if (e->e1->op == TOKsymoff)
|
|
1620 {
|
|
1621 SymOffExp *se = (SymOffExp *) e->e1;
|
|
1622 if (!declaration_reference_p (se->var))
|
|
1623 {
|
|
1624 tnext = se->var->type->toBasetype ();
|
|
1625 result = get_decl_tree (se->var);
|
|
1626 offset = se->offset;
|
|
1627 }
|
|
1628 }
|
|
1629
|
|
1630 /* Produce better code by converting *(#record + n) to
|
|
1631 COMPONENT_REFERENCE. Otherwise, the variable will always be
|
|
1632 allocated in memory because its address is taken. */
|
|
1633 if (tnext && tnext->ty == Tstruct)
|
|
1634 {
|
|
1635 StructDeclaration *sd = ((TypeStruct *) tnext)->sym;
|
|
1636
|
|
1637 for (size_t i = 0; i < sd->fields.dim; i++)
|
|
1638 {
|
|
1639 VarDeclaration *field = sd->fields[i];
|
|
1640
|
|
1641 if (field->offset == offset
|
|
1642 && same_type_p (field->type, e->type))
|
|
1643 {
|
|
1644 /* Catch errors, backend will ICE otherwise. */
|
|
1645 if (error_operand_p (result))
|
|
1646 this->result_ = result;
|
|
1647 else
|
|
1648 {
|
|
1649 result = component_ref (result, get_symbol_decl (field));
|
|
1650 this->result_ = result;
|
|
1651 }
|
|
1652 return;
|
|
1653 }
|
|
1654 else if (field->offset > offset)
|
|
1655 break;
|
|
1656 }
|
|
1657 }
|
|
1658
|
|
1659 this->result_ = indirect_ref (build_ctype (e->type), build_expr (e->e1));
|
|
1660 }
|
|
1661
|
|
1662 /* Build an unary address expression. */
|
|
1663
|
|
1664 void visit (AddrExp *e)
|
|
1665 {
|
|
1666 tree type = build_ctype (e->type);
|
|
1667 tree exp;
|
|
1668
|
|
1669 /* The frontend optimizer can convert const symbol into a struct literal.
|
|
1670 Taking the address of a struct literal is otherwise illegal. */
|
|
1671 if (e->e1->op == TOKstructliteral)
|
|
1672 {
|
|
1673 StructLiteralExp *sle = ((StructLiteralExp *) e->e1)->origin;
|
|
1674 gcc_assert (sle != NULL);
|
|
1675
|
|
1676 /* Build the reference symbol, the decl is built first as the
|
|
1677 initializer may have recursive references. */
|
|
1678 if (!sle->sym)
|
|
1679 {
|
|
1680 sle->sym = build_artificial_decl (build_ctype (sle->type),
|
|
1681 NULL_TREE, "S");
|
|
1682 DECL_INITIAL (sle->sym) = build_expr (sle, true);
|
|
1683 d_pushdecl (sle->sym);
|
|
1684 rest_of_decl_compilation (sle->sym, 1, 0);
|
|
1685 }
|
|
1686
|
|
1687 exp = sle->sym;
|
|
1688 }
|
|
1689 else
|
|
1690 exp = build_expr (e->e1, this->constp_);
|
|
1691
|
|
1692 TREE_CONSTANT (exp) = 0;
|
|
1693 this->result_ = d_convert (type, build_address (exp));
|
|
1694 }
|
|
1695
|
|
1696 /* Build a function call expression. */
|
|
1697
|
|
1698 void visit (CallExp *e)
|
|
1699 {
|
|
1700 Type *tb = e->e1->type->toBasetype ();
|
|
1701 Expression *e1b = e->e1;
|
|
1702
|
|
1703 tree callee = NULL_TREE;
|
|
1704 tree object = NULL_TREE;
|
|
1705 tree cleanup = NULL_TREE;
|
|
1706 TypeFunction *tf = NULL;
|
|
1707
|
|
1708 /* Calls to delegates can sometimes look like this. */
|
|
1709 if (e1b->op == TOKcomma)
|
|
1710 {
|
|
1711 e1b = ((CommaExp *) e1b)->e2;
|
|
1712 gcc_assert (e1b->op == TOKvar);
|
|
1713
|
|
1714 Declaration *var = ((VarExp *) e1b)->var;
|
|
1715 gcc_assert (var->isFuncDeclaration () && !var->needThis ());
|
|
1716 }
|
|
1717
|
|
1718 if (e1b->op == TOKdotvar && tb->ty != Tdelegate)
|
|
1719 {
|
|
1720 DotVarExp *dve = (DotVarExp *) e1b;
|
|
1721
|
|
1722 /* Don't modify the static initializer for struct literals. */
|
|
1723 if (dve->e1->op == TOKstructliteral)
|
|
1724 {
|
|
1725 StructLiteralExp *sle = (StructLiteralExp *) dve->e1;
|
|
1726 sle->useStaticInit = false;
|
|
1727 }
|
|
1728
|
|
1729 FuncDeclaration *fd = dve->var->isFuncDeclaration ();
|
|
1730 if (fd != NULL)
|
|
1731 {
|
|
1732 /* Get the correct callee from the DotVarExp object. */
|
|
1733 tree fndecl = get_symbol_decl (fd);
|
|
1734 AggregateDeclaration *ad = fd->isThis ();
|
|
1735
|
|
1736 /* Static method; ignore the object instance. */
|
|
1737 if (!ad)
|
|
1738 callee = build_address (fndecl);
|
|
1739 else
|
|
1740 {
|
|
1741 tree thisexp = build_expr (dve->e1);
|
|
1742
|
|
1743 /* When constructing temporaries, if the constructor throws,
|
|
1744 then the object is destructed even though it is not a fully
|
|
1745 constructed object yet. And so this call will need to be
|
|
1746 moved inside the TARGET_EXPR_INITIAL slot. */
|
|
1747 if (fd->isCtorDeclaration ()
|
|
1748 && TREE_CODE (thisexp) == COMPOUND_EXPR
|
|
1749 && TREE_CODE (TREE_OPERAND (thisexp, 0)) == TARGET_EXPR
|
|
1750 && TARGET_EXPR_CLEANUP (TREE_OPERAND (thisexp, 0)))
|
|
1751 {
|
|
1752 cleanup = TREE_OPERAND (thisexp, 0);
|
|
1753 thisexp = TREE_OPERAND (thisexp, 1);
|
|
1754 }
|
|
1755
|
|
1756 /* Want reference to 'this' object. */
|
|
1757 if (!POINTER_TYPE_P (TREE_TYPE (thisexp)))
|
|
1758 thisexp = build_address (thisexp);
|
|
1759
|
|
1760 /* Make the callee a virtual call. */
|
|
1761 if (fd->isVirtual () && !fd->isFinalFunc () && !e->directcall)
|
|
1762 {
|
|
1763 tree fntype = build_pointer_type (TREE_TYPE (fndecl));
|
|
1764 tree thistype = build_ctype (ad->handleType ());
|
|
1765 thisexp = build_nop (thistype, d_save_expr (thisexp));
|
|
1766 fndecl = build_vindex_ref (thisexp, fntype, fd->vtblIndex);
|
|
1767 }
|
|
1768 else
|
|
1769 fndecl = build_address (fndecl);
|
|
1770
|
|
1771 callee = build_method_call (fndecl, thisexp, fd->type);
|
|
1772 }
|
|
1773 }
|
|
1774 }
|
|
1775
|
|
1776 if (callee == NULL_TREE)
|
|
1777 callee = build_expr (e1b);
|
|
1778
|
|
1779 if (METHOD_CALL_EXPR (callee))
|
|
1780 {
|
|
1781 /* This could be a delegate expression (TY == Tdelegate), but not
|
|
1782 actually a delegate variable. */
|
|
1783 if (e1b->op == TOKdotvar)
|
|
1784 {
|
|
1785 /* This gets the true function type, getting the function type
|
|
1786 from e1->type can sometimes be incorrect, such as when calling
|
|
1787 a 'ref' return function. */
|
|
1788 tf = get_function_type (((DotVarExp *) e1b)->var->type);
|
|
1789 }
|
|
1790 else
|
|
1791 tf = get_function_type (tb);
|
|
1792
|
|
1793 extract_from_method_call (callee, callee, object);
|
|
1794 }
|
|
1795 else if (tb->ty == Tdelegate)
|
|
1796 {
|
|
1797 /* Delegate call, extract .object and .funcptr from var. */
|
|
1798 callee = d_save_expr (callee);
|
|
1799 tf = get_function_type (tb);
|
|
1800 object = delegate_object (callee);
|
|
1801 callee = delegate_method (callee);
|
|
1802 }
|
|
1803 else if (e1b->op == TOKvar)
|
|
1804 {
|
|
1805 FuncDeclaration *fd = ((VarExp *) e1b)->var->isFuncDeclaration ();
|
|
1806 gcc_assert (fd != NULL);
|
|
1807 tf = get_function_type (fd->type);
|
|
1808
|
|
1809 if (fd->isNested ())
|
|
1810 {
|
|
1811 /* Maybe re-evaluate symbol storage treating 'fd' as public. */
|
|
1812 if (call_by_alias_p (d_function_chain->function, fd))
|
|
1813 TREE_PUBLIC (callee) = 1;
|
|
1814
|
|
1815 object = get_frame_for_symbol (fd);
|
|
1816 }
|
|
1817 else if (fd->needThis ())
|
|
1818 {
|
|
1819 error_at (make_location_t (e1b->loc),
|
|
1820 "need %<this%> to access member %qs", fd->toChars ());
|
|
1821 /* Continue compiling... */
|
|
1822 object = null_pointer_node;
|
|
1823 }
|
|
1824 }
|
|
1825 else
|
|
1826 {
|
|
1827 /* Normal direct function call. */
|
|
1828 tf = get_function_type (tb);
|
|
1829 }
|
|
1830
|
|
1831 gcc_assert (tf != NULL);
|
|
1832
|
|
1833 /* Now we have the type, callee and maybe object reference,
|
|
1834 build the call expression. */
|
|
1835 tree exp = d_build_call (tf, callee, object, e->arguments);
|
|
1836
|
|
1837 if (tf->isref)
|
|
1838 exp = build_deref (exp);
|
|
1839
|
|
1840 /* Some library calls are defined to return a generic type.
|
|
1841 this->type is the real type we want to return. */
|
|
1842 if (e->type->isTypeBasic ())
|
|
1843 exp = d_convert (build_ctype (e->type), exp);
|
|
1844
|
|
1845 /* If this call was found to be a constructor for a temporary with a
|
|
1846 cleanup, then move the call inside the TARGET_EXPR. The original
|
|
1847 initializer is turned into an assignment, to keep its side effect. */
|
|
1848 if (cleanup != NULL_TREE)
|
|
1849 {
|
|
1850 tree init = TARGET_EXPR_INITIAL (cleanup);
|
|
1851 tree slot = TARGET_EXPR_SLOT (cleanup);
|
|
1852 d_mark_addressable (slot);
|
|
1853 init = build_assign (INIT_EXPR, slot, init);
|
|
1854
|
|
1855 TARGET_EXPR_INITIAL (cleanup) = compound_expr (init, exp);
|
|
1856 exp = cleanup;
|
|
1857 }
|
|
1858
|
|
1859 this->result_ = exp;
|
|
1860 }
|
|
1861
|
|
1862 /* Build a delegate expression. */
|
|
1863
|
|
1864 void visit (DelegateExp *e)
|
|
1865 {
|
|
1866 if (e->func->semanticRun == PASSsemantic3done)
|
|
1867 {
|
|
1868 /* Add the function as nested function if it belongs to this module.
|
|
1869 ie: it is a member of this module, or it is a template instance. */
|
|
1870 Dsymbol *owner = e->func->toParent ();
|
|
1871 while (!owner->isTemplateInstance () && owner->toParent ())
|
|
1872 owner = owner->toParent ();
|
|
1873 if (owner->isTemplateInstance () || owner == d_function_chain->module)
|
|
1874 build_decl_tree (e->func);
|
|
1875 }
|
|
1876
|
|
1877 tree fndecl;
|
|
1878 tree object;
|
|
1879
|
|
1880 if (e->func->isNested ())
|
|
1881 {
|
|
1882 if (e->e1->op == TOKnull)
|
|
1883 object = build_expr (e->e1);
|
|
1884 else
|
|
1885 object = get_frame_for_symbol (e->func);
|
|
1886
|
|
1887 fndecl = build_address (get_symbol_decl (e->func));
|
|
1888 }
|
|
1889 else
|
|
1890 {
|
|
1891 if (!e->func->isThis ())
|
|
1892 {
|
|
1893 error ("delegates are only for non-static functions");
|
|
1894 this->result_ = error_mark_node;
|
|
1895 return;
|
|
1896 }
|
|
1897
|
|
1898 object = build_expr (e->e1);
|
|
1899
|
|
1900 /* Want reference to `this' object. */
|
|
1901 if (e->e1->type->ty != Tclass && e->e1->type->ty != Tpointer)
|
|
1902 object = build_address (object);
|
|
1903
|
|
1904 /* Object reference could be the outer `this' field of a class or
|
|
1905 closure of type `void*'. Cast it to the right type. */
|
|
1906 if (e->e1->type->ty == Tclass)
|
|
1907 object = d_convert (build_ctype (e->e1->type), object);
|
|
1908
|
|
1909 fndecl = get_symbol_decl (e->func);
|
|
1910
|
|
1911 /* Get pointer to function out of the virtual table. */
|
|
1912 if (e->func->isVirtual () && !e->func->isFinalFunc ()
|
|
1913 && e->e1->op != TOKsuper && e->e1->op != TOKdottype)
|
|
1914 {
|
|
1915 tree fntype = build_pointer_type (TREE_TYPE (fndecl));
|
|
1916 object = d_save_expr (object);
|
|
1917 fndecl = build_vindex_ref (object, fntype, e->func->vtblIndex);
|
|
1918 }
|
|
1919 else
|
|
1920 fndecl = build_address (fndecl);
|
|
1921 }
|
|
1922
|
|
1923 this->result_ = build_method_call (fndecl, object, e->type);
|
|
1924 }
|
|
1925
|
|
1926 /* Build a type component expression. */
|
|
1927
|
|
1928 void visit (DotTypeExp *e)
|
|
1929 {
|
|
1930 /* Just a pass through to underlying expression. */
|
|
1931 this->result_ = build_expr (e->e1);
|
|
1932 }
|
|
1933
|
|
1934 /* Build a component reference expression. */
|
|
1935
|
|
1936 void visit (DotVarExp *e)
|
|
1937 {
|
|
1938 VarDeclaration *vd = e->var->isVarDeclaration ();
|
|
1939
|
|
1940 /* This could also be a function, but relying on that being taken
|
|
1941 care of by the visitor interface for CallExp. */
|
|
1942 if (vd != NULL)
|
|
1943 {
|
|
1944 if (!vd->isField ())
|
|
1945 this->result_ = get_decl_tree (vd);
|
|
1946 else
|
|
1947 {
|
|
1948 tree object = build_expr (e->e1);
|
|
1949
|
|
1950 if (e->e1->type->toBasetype ()->ty != Tstruct)
|
|
1951 object = build_deref (object);
|
|
1952
|
|
1953 this->result_ = component_ref (object, get_symbol_decl (vd));
|
|
1954 }
|
|
1955 }
|
|
1956 else
|
|
1957 {
|
|
1958 error ("%qs is not a field, but a %qs",
|
|
1959 e->var->toChars (), e->var->kind ());
|
|
1960 this->result_ = error_mark_node;
|
|
1961 }
|
|
1962 }
|
|
1963
|
|
1964 /* Build an assert expression, used to declare conditions that must hold at
|
|
1965 that a given point in the program. */
|
|
1966
|
|
1967 void visit (AssertExp *e)
|
|
1968 {
|
|
1969 Type *tb1 = e->e1->type->toBasetype ();
|
|
1970 tree arg = build_expr (e->e1);
|
|
1971 tree tmsg = NULL_TREE;
|
|
1972 tree assert_pass = void_node;
|
|
1973 tree assert_fail;
|
|
1974
|
|
1975 if (global.params.useAssert
|
|
1976 && global.params.checkAction == CHECKACTION_D)
|
|
1977 {
|
|
1978 /* Generate: ((bool) e1 ? (void)0 : _d_assert (...))
|
|
1979 or: (e1 != null ? e1._invariant() : _d_assert (...)) */
|
|
1980 bool unittest_p = d_function_chain->function->isUnitTestDeclaration ();
|
|
1981 libcall_fn libcall;
|
|
1982
|
|
1983 if (e->msg)
|
|
1984 {
|
|
1985 tmsg = build_expr_dtor (e->msg);
|
|
1986 libcall = unittest_p ? LIBCALL_UNITTEST_MSG : LIBCALL_ASSERT_MSG;
|
|
1987 }
|
|
1988 else
|
|
1989 libcall = unittest_p ? LIBCALL_UNITTEST : LIBCALL_ASSERT;
|
|
1990
|
|
1991 /* Build a call to _d_assert(). */
|
|
1992 assert_fail = d_assert_call (e->loc, libcall, tmsg);
|
|
1993
|
|
1994 if (global.params.useInvariants)
|
|
1995 {
|
|
1996 /* If the condition is a D class or struct object with an invariant,
|
|
1997 call it if the condition result is true. */
|
|
1998 if (tb1->ty == Tclass)
|
|
1999 {
|
|
2000 ClassDeclaration *cd = tb1->isClassHandle ();
|
|
2001 if (!cd->isInterfaceDeclaration () && !cd->isCPPclass ())
|
|
2002 {
|
|
2003 arg = d_save_expr (arg);
|
|
2004 assert_pass = build_libcall (LIBCALL_INVARIANT,
|
|
2005 Type::tvoid, 1, arg);
|
|
2006 }
|
|
2007 }
|
|
2008 else if (tb1->ty == Tpointer && tb1->nextOf ()->ty == Tstruct)
|
|
2009 {
|
|
2010 StructDeclaration *sd = ((TypeStruct *) tb1->nextOf ())->sym;
|
|
2011 if (sd->inv != NULL)
|
|
2012 {
|
|
2013 Expressions args;
|
|
2014 arg = d_save_expr (arg);
|
|
2015 assert_pass = d_build_call_expr (sd->inv, arg, &args);
|
|
2016 }
|
|
2017 }
|
|
2018 }
|
|
2019 }
|
|
2020 else if (global.params.useAssert
|
|
2021 && global.params.checkAction == CHECKACTION_C)
|
|
2022 {
|
|
2023 /* Generate: __builtin_trap() */
|
|
2024 tree fn = builtin_decl_explicit (BUILT_IN_TRAP);
|
|
2025 assert_fail = build_call_expr (fn, 0);
|
|
2026 }
|
|
2027 else
|
|
2028 {
|
|
2029 /* Assert contracts are turned off, if the contract condition has no
|
|
2030 side effects can still use it as a predicate for the optimizer. */
|
|
2031 if (TREE_SIDE_EFFECTS (arg))
|
|
2032 {
|
|
2033 this->result_ = void_node;
|
|
2034 return;
|
|
2035 }
|
|
2036
|
|
2037 assert_fail = build_predict_expr (PRED_NORETURN, NOT_TAKEN);
|
|
2038 }
|
|
2039
|
|
2040 /* Build condition that we are asserting in this contract. */
|
|
2041 tree condition = convert_for_condition (arg, e->e1->type);
|
|
2042
|
|
2043 /* We expect the condition to always be true, as what happens if an assert
|
|
2044 contract is false is undefined behavior. */
|
|
2045 tree fn = builtin_decl_explicit (BUILT_IN_EXPECT);
|
|
2046 tree arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn));
|
|
2047 tree pred_type = TREE_VALUE (arg_types);
|
|
2048 tree expected_type = TREE_VALUE (TREE_CHAIN (arg_types));
|
|
2049
|
|
2050 condition = build_call_expr (fn, 2, d_convert (pred_type, condition),
|
|
2051 build_int_cst (expected_type, 1));
|
|
2052 condition = d_truthvalue_conversion (condition);
|
|
2053
|
|
2054 this->result_ = build_vcondition (condition, assert_pass, assert_fail);
|
|
2055 }
|
|
2056
|
|
2057 /* Build a declaration expression. */
|
|
2058
|
|
2059 void visit (DeclarationExp *e)
|
|
2060 {
|
|
2061 /* Compile the declaration. */
|
|
2062 push_stmt_list ();
|
|
2063 build_decl_tree (e->declaration);
|
|
2064 tree result = pop_stmt_list ();
|
|
2065
|
|
2066 /* Construction of an array for typesafe-variadic function arguments
|
|
2067 can cause an empty STMT_LIST here. This can causes problems
|
|
2068 during gimplification. */
|
|
2069 if (TREE_CODE (result) == STATEMENT_LIST && !STATEMENT_LIST_HEAD (result))
|
|
2070 result = build_empty_stmt (input_location);
|
|
2071
|
|
2072 this->result_ = result;
|
|
2073 }
|
|
2074
|
|
2075 /* Build a typeid expression. Returns an instance of class TypeInfo
|
|
2076 corresponding to. */
|
|
2077
|
|
2078 void visit (TypeidExp *e)
|
|
2079 {
|
|
2080 if (Type *tid = isType (e->obj))
|
|
2081 {
|
|
2082 tree ti = build_typeinfo (e->loc, tid);
|
|
2083
|
|
2084 /* If the typeinfo is at an offset. */
|
|
2085 if (tid->vtinfo->offset)
|
|
2086 ti = build_offset (ti, size_int (tid->vtinfo->offset));
|
|
2087
|
|
2088 this->result_ = build_nop (build_ctype (e->type), ti);
|
|
2089 }
|
|
2090 else if (Expression *tid = isExpression (e->obj))
|
|
2091 {
|
|
2092 Type *type = tid->type->toBasetype ();
|
|
2093 assert (type->ty == Tclass);
|
|
2094
|
|
2095 /* Generate **classptr to get the classinfo. */
|
|
2096 tree ci = build_expr (tid);
|
|
2097 ci = indirect_ref (ptr_type_node, ci);
|
|
2098 ci = indirect_ref (ptr_type_node, ci);
|
|
2099
|
|
2100 /* Add extra indirection for interfaces. */
|
|
2101 if (((TypeClass *) type)->sym->isInterfaceDeclaration ())
|
|
2102 ci = indirect_ref (ptr_type_node, ci);
|
|
2103
|
|
2104 this->result_ = build_nop (build_ctype (e->type), ci);
|
|
2105 }
|
|
2106 else
|
|
2107 gcc_unreachable ();
|
|
2108 }
|
|
2109
|
|
2110 /* Build a function/lambda expression. */
|
|
2111
|
|
2112 void visit (FuncExp *e)
|
|
2113 {
|
|
2114 Type *ftype = e->type->toBasetype ();
|
|
2115
|
|
2116 /* This check is for lambda's, remove 'vthis' as function isn't nested. */
|
|
2117 if (e->fd->tok == TOKreserved && ftype->ty == Tpointer)
|
|
2118 {
|
|
2119 e->fd->tok = TOKfunction;
|
|
2120 e->fd->vthis = NULL;
|
|
2121 }
|
|
2122
|
|
2123 /* Compile the function literal body. */
|
|
2124 build_decl_tree (e->fd);
|
|
2125
|
|
2126 /* If nested, this will be a trampoline. */
|
|
2127 if (e->fd->isNested ())
|
|
2128 {
|
|
2129 tree func = build_address (get_symbol_decl (e->fd));
|
|
2130 tree object;
|
|
2131
|
|
2132 if (this->constp_)
|
|
2133 {
|
|
2134 /* Static delegate variables have no context pointer. */
|
|
2135 object = null_pointer_node;
|
|
2136 this->result_ = build_method_call (func, object, e->fd->type);
|
|
2137 TREE_CONSTANT (this->result_) = 1;
|
|
2138 }
|
|
2139 else
|
|
2140 {
|
|
2141 object = get_frame_for_symbol (e->fd);
|
|
2142 this->result_ = build_method_call (func, object, e->fd->type);
|
|
2143 }
|
|
2144 }
|
|
2145 else
|
|
2146 {
|
|
2147 this->result_ = build_nop (build_ctype (e->type),
|
|
2148 build_address (get_symbol_decl (e->fd)));
|
|
2149 }
|
|
2150 }
|
|
2151
|
|
2152 /* Build a halt expression. */
|
|
2153
|
|
2154 void visit (HaltExp *)
|
|
2155 {
|
|
2156 /* Should we use trap() or abort()? */
|
|
2157 tree ttrap = builtin_decl_explicit (BUILT_IN_TRAP);
|
|
2158 this->result_ = build_call_expr (ttrap, 0);
|
|
2159 }
|
|
2160
|
|
2161 /* Build a symbol pointer offset expression. */
|
|
2162
|
|
2163 void visit (SymOffExp *e)
|
|
2164 {
|
|
2165 /* Build the address and offset of the symbol. */
|
|
2166 size_t soffset = ((SymOffExp *) e)->offset;
|
|
2167 tree result = get_decl_tree (e->var);
|
|
2168 TREE_USED (result) = 1;
|
|
2169
|
|
2170 if (declaration_reference_p (e->var))
|
|
2171 gcc_assert (POINTER_TYPE_P (TREE_TYPE (result)));
|
|
2172 else
|
|
2173 result = build_address (result);
|
|
2174
|
|
2175 if (!soffset)
|
|
2176 result = d_convert (build_ctype (e->type), result);
|
|
2177 else
|
|
2178 {
|
|
2179 tree offset = size_int (soffset);
|
|
2180 result = build_nop (build_ctype (e->type),
|
|
2181 build_offset (result, offset));
|
|
2182 }
|
|
2183
|
|
2184 this->result_ = result;
|
|
2185 }
|
|
2186
|
|
2187 /* Build a variable expression. */
|
|
2188
|
|
2189 void visit (VarExp *e)
|
|
2190 {
|
|
2191 if (e->var->needThis ())
|
|
2192 {
|
|
2193 error ("need %<this%> to access member %qs", e->var->ident->toChars ());
|
|
2194 this->result_ = error_mark_node;
|
|
2195 return;
|
|
2196 }
|
|
2197 else if (e->var->ident == Identifier::idPool ("__ctfe"))
|
|
2198 {
|
|
2199 /* __ctfe is always false at run-time. */
|
|
2200 this->result_ = integer_zero_node;
|
|
2201 return;
|
|
2202 }
|
|
2203
|
|
2204 /* This check is same as is done in FuncExp for lambdas. */
|
|
2205 FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration ();
|
|
2206 if (fld != NULL)
|
|
2207 {
|
|
2208 if (fld->tok == TOKreserved)
|
|
2209 {
|
|
2210 fld->tok = TOKfunction;
|
|
2211 fld->vthis = NULL;
|
|
2212 }
|
|
2213
|
|
2214 /* Compiler the function literal body. */
|
|
2215 build_decl_tree (fld);
|
|
2216 }
|
|
2217
|
|
2218 if (this->constp_)
|
|
2219 {
|
|
2220 /* Want the initializer, not the expression. */
|
|
2221 VarDeclaration *var = e->var->isVarDeclaration ();
|
|
2222 SymbolDeclaration *sd = e->var->isSymbolDeclaration ();
|
|
2223 tree init = NULL_TREE;
|
|
2224
|
|
2225 if (var && (var->isConst () || var->isImmutable ())
|
|
2226 && e->type->toBasetype ()->ty != Tsarray && var->_init)
|
|
2227 {
|
|
2228 if (var->inuse)
|
|
2229 error_at (make_location_t (e->loc), "recursive reference %qs",
|
|
2230 e->toChars ());
|
|
2231 else
|
|
2232 {
|
|
2233 var->inuse++;
|
|
2234 init = build_expr (initializerToExpression (var->_init), true);
|
|
2235 var->inuse--;
|
|
2236 }
|
|
2237 }
|
|
2238 else if (sd && sd->dsym)
|
|
2239 init = layout_struct_initializer (sd->dsym);
|
|
2240 else
|
|
2241 error_at (make_location_t (e->loc), "non-constant expression %qs",
|
|
2242 e->toChars ());
|
|
2243
|
|
2244 if (init != NULL_TREE)
|
|
2245 this->result_ = init;
|
|
2246 else
|
|
2247 this->result_ = error_mark_node;
|
|
2248 }
|
|
2249 else
|
|
2250 {
|
|
2251 tree result = get_decl_tree (e->var);
|
|
2252 TREE_USED (result) = 1;
|
|
2253
|
|
2254 /* For variables that are references - currently only out/inout
|
|
2255 arguments; objects don't count - evaluating the variable means
|
|
2256 we want what it refers to. */
|
|
2257 if (declaration_reference_p (e->var))
|
|
2258 result = indirect_ref (build_ctype (e->var->type), result);
|
|
2259
|
|
2260 this->result_ = result;
|
|
2261 }
|
|
2262 }
|
|
2263
|
|
2264 /* Build a this variable expression. */
|
|
2265
|
|
2266 void visit (ThisExp *e)
|
|
2267 {
|
|
2268 FuncDeclaration *fd = d_function_chain ? d_function_chain->function : NULL;
|
|
2269 tree result = NULL_TREE;
|
|
2270
|
|
2271 if (e->var)
|
|
2272 result = get_decl_tree (e->var);
|
|
2273 else
|
|
2274 {
|
|
2275 gcc_assert (fd && fd->vthis);
|
|
2276 result = get_decl_tree (fd->vthis);
|
|
2277 }
|
|
2278
|
|
2279 if (e->type->ty == Tstruct)
|
|
2280 result = build_deref (result);
|
|
2281
|
|
2282 this->result_ = result;
|
|
2283 }
|
|
2284
|
|
2285 /* Build a new expression, which allocates memory either on the garbage
|
|
2286 collected heap or by using a class or struct specific allocator. */
|
|
2287
|
|
2288 void visit (NewExp *e)
|
|
2289 {
|
|
2290 Type *tb = e->type->toBasetype ();
|
|
2291 tree result;
|
|
2292
|
|
2293 if (e->allocator)
|
|
2294 gcc_assert (e->newargs);
|
|
2295
|
|
2296 if (tb->ty == Tclass)
|
|
2297 {
|
|
2298 /* Allocating a new class. */
|
|
2299 tb = e->newtype->toBasetype ();
|
|
2300 gcc_assert (tb->ty == Tclass);
|
|
2301
|
|
2302 ClassDeclaration *cd = ((TypeClass *) tb)->sym;
|
|
2303 tree type = build_ctype (tb);
|
|
2304 tree setup_exp = NULL_TREE;
|
|
2305 tree new_call;
|
|
2306
|
|
2307 if (e->onstack)
|
|
2308 {
|
|
2309 /* If being used as an initializer for a local variable with scope
|
|
2310 storage class, then the instance is allocated on the stack
|
|
2311 rather than the heap or using the class specific allocator. */
|
|
2312 tree var = build_local_temp (TREE_TYPE (type));
|
|
2313 new_call = build_nop (type, build_address (var));
|
|
2314 setup_exp = modify_expr (var, aggregate_initializer_decl (cd));
|
|
2315 }
|
|
2316 else if (e->allocator)
|
|
2317 {
|
|
2318 /* Call class allocator, and copy the initializer into memory. */
|
|
2319 new_call = d_build_call_expr (e->allocator, NULL_TREE, e->newargs);
|
|
2320 new_call = d_save_expr (new_call);
|
|
2321 new_call = build_nop (type, new_call);
|
|
2322 setup_exp = modify_expr (build_deref (new_call),
|
|
2323 aggregate_initializer_decl (cd));
|
|
2324 }
|
|
2325 else
|
|
2326 {
|
|
2327 /* Generate: _d_newclass() */
|
|
2328 tree arg = build_address (get_classinfo_decl (cd));
|
|
2329 new_call = build_libcall (LIBCALL_NEWCLASS, tb, 1, arg);
|
|
2330 }
|
|
2331
|
|
2332 /* Set the context pointer for nested classes. */
|
|
2333 if (cd->isNested ())
|
|
2334 {
|
|
2335 tree field = get_symbol_decl (cd->vthis);
|
|
2336 tree value = NULL_TREE;
|
|
2337
|
|
2338 if (e->thisexp)
|
|
2339 {
|
|
2340 ClassDeclaration *tcd = e->thisexp->type->isClassHandle ();
|
|
2341 Dsymbol *outer = cd->toParent2 ();
|
|
2342 int offset = 0;
|
|
2343
|
|
2344 value = build_expr (e->thisexp);
|
|
2345 if (outer != tcd)
|
|
2346 {
|
|
2347 ClassDeclaration *ocd = outer->isClassDeclaration ();
|
|
2348 gcc_assert (ocd->isBaseOf (tcd, &offset));
|
|
2349 /* Could just add offset... */
|
|
2350 value = convert_expr (value, e->thisexp->type, ocd->type);
|
|
2351 }
|
|
2352 }
|
|
2353 else
|
|
2354 value = build_vthis (cd);
|
|
2355
|
|
2356 if (value != NULL_TREE)
|
|
2357 {
|
|
2358 /* Generate: (new())->vthis = this; */
|
|
2359 new_call = d_save_expr (new_call);
|
|
2360 field = component_ref (build_deref (new_call), field);
|
|
2361 setup_exp = compound_expr (setup_exp,
|
|
2362 modify_expr (field, value));
|
|
2363 }
|
|
2364 }
|
|
2365 new_call = compound_expr (setup_exp, new_call);
|
|
2366
|
|
2367 /* Call the class constructor. */
|
|
2368 if (e->member)
|
|
2369 result = d_build_call_expr (e->member, new_call, e->arguments);
|
|
2370 else
|
|
2371 result = new_call;
|
|
2372
|
|
2373 if (e->argprefix)
|
|
2374 result = compound_expr (build_expr (e->argprefix), result);
|
|
2375 }
|
|
2376 else if (tb->ty == Tpointer && tb->nextOf ()->toBasetype ()->ty == Tstruct)
|
|
2377 {
|
|
2378 /* Allocating memory for a new struct. */
|
|
2379 Type *htype = e->newtype->toBasetype ();
|
|
2380 gcc_assert (htype->ty == Tstruct);
|
|
2381 gcc_assert (!e->onstack);
|
|
2382
|
|
2383 TypeStruct *stype = (TypeStruct *) htype;
|
|
2384 StructDeclaration *sd = stype->sym;
|
|
2385 tree new_call;
|
|
2386
|
|
2387 /* Cannot new an opaque struct. */
|
|
2388 if (sd->size (e->loc) == 0)
|
|
2389 {
|
|
2390 this->result_ = d_convert (build_ctype (e->type),
|
|
2391 integer_zero_node);
|
|
2392 return;
|
|
2393 }
|
|
2394
|
|
2395 if (e->allocator)
|
|
2396 {
|
|
2397 /* Call struct allocator. */
|
|
2398 new_call = d_build_call_expr (e->allocator, NULL_TREE, e->newargs);
|
|
2399 new_call = build_nop (build_ctype (tb), new_call);
|
|
2400 }
|
|
2401 else
|
|
2402 {
|
|
2403 /* Generate: _d_newitemT() */
|
|
2404 libcall_fn libcall = htype->isZeroInit ()
|
|
2405 ? LIBCALL_NEWITEMT : LIBCALL_NEWITEMIT;
|
|
2406 tree arg = build_typeinfo (e->loc, e->newtype);
|
|
2407 new_call = build_libcall (libcall, tb, 1, arg);
|
|
2408 }
|
|
2409
|
|
2410 if (e->member || !e->arguments)
|
|
2411 {
|
|
2412 /* Set the context pointer for nested structs. */
|
|
2413 if (sd->isNested ())
|
|
2414 {
|
|
2415 tree value = build_vthis (sd);
|
|
2416 tree field = get_symbol_decl (sd->vthis);
|
|
2417 tree type = build_ctype (stype);
|
|
2418
|
|
2419 new_call = d_save_expr (new_call);
|
|
2420 field = component_ref (indirect_ref (type, new_call), field);
|
|
2421 new_call = compound_expr (modify_expr (field, value), new_call);
|
|
2422 }
|
|
2423
|
|
2424 /* Call the struct constructor. */
|
|
2425 if (e->member)
|
|
2426 result = d_build_call_expr (e->member, new_call, e->arguments);
|
|
2427 else
|
|
2428 result = new_call;
|
|
2429 }
|
|
2430 else
|
|
2431 {
|
|
2432 /* If we have a user supplied initializer, then set-up with a
|
|
2433 struct literal. */
|
|
2434 if (e->arguments != NULL && sd->fields.dim != 0)
|
|
2435 {
|
|
2436 StructLiteralExp *se = StructLiteralExp::create (e->loc, sd,
|
|
2437 e->arguments,
|
|
2438 htype);
|
|
2439 new_call = d_save_expr (new_call);
|
|
2440 se->type = sd->type;
|
|
2441 se->sym = new_call;
|
|
2442 result = compound_expr (build_expr (se), new_call);
|
|
2443 }
|
|
2444 else
|
|
2445 result = new_call;
|
|
2446 }
|
|
2447
|
|
2448 if (e->argprefix)
|
|
2449 result = compound_expr (build_expr (e->argprefix), result);
|
|
2450 }
|
|
2451 else if (tb->ty == Tarray)
|
|
2452 {
|
|
2453 /* Allocating memory for a new D array. */
|
|
2454 tb = e->newtype->toBasetype ();
|
|
2455 gcc_assert (tb->ty == Tarray);
|
|
2456 TypeDArray *tarray = (TypeDArray *) tb;
|
|
2457
|
|
2458 gcc_assert (!e->allocator);
|
|
2459 gcc_assert (e->arguments && e->arguments->dim >= 1);
|
|
2460
|
|
2461 if (e->arguments->dim == 1)
|
|
2462 {
|
|
2463 /* Single dimension array allocations. */
|
|
2464 Expression *arg = (*e->arguments)[0];
|
|
2465
|
|
2466 if (tarray->next->size () == 0)
|
|
2467 {
|
|
2468 /* Array element size is unknown. */
|
|
2469 this->result_ = d_array_value (build_ctype (e->type),
|
|
2470 size_int (0), null_pointer_node);
|
|
2471 return;
|
|
2472 }
|
|
2473
|
|
2474 libcall_fn libcall = tarray->next->isZeroInit ()
|
|
2475 ? LIBCALL_NEWARRAYT : LIBCALL_NEWARRAYIT;
|
|
2476 result = build_libcall (libcall, tb, 2,
|
|
2477 build_typeinfo (e->loc, e->type),
|
|
2478 build_expr (arg));
|
|
2479 }
|
|
2480 else
|
|
2481 {
|
|
2482 /* Multidimensional array allocations. */
|
|
2483 vec<constructor_elt, va_gc> *elms = NULL;
|
|
2484 Type *telem = e->newtype->toBasetype ();
|
|
2485 tree tarray = make_array_type (Type::tsize_t, e->arguments->dim);
|
|
2486 tree var = create_temporary_var (tarray);
|
|
2487 tree init = build_constructor (TREE_TYPE (var), NULL);
|
|
2488
|
|
2489 for (size_t i = 0; i < e->arguments->dim; i++)
|
|
2490 {
|
|
2491 Expression *arg = (*e->arguments)[i];
|
|
2492 CONSTRUCTOR_APPEND_ELT (elms, size_int (i), build_expr (arg));
|
|
2493
|
|
2494 gcc_assert (telem->ty == Tarray);
|
|
2495 telem = telem->toBasetype ()->nextOf ();
|
|
2496 gcc_assert (telem);
|
|
2497 }
|
|
2498
|
|
2499 CONSTRUCTOR_ELTS (init) = elms;
|
|
2500 DECL_INITIAL (var) = init;
|
|
2501
|
|
2502 /* Generate: _d_newarraymTX(ti, dims)
|
|
2503 or: _d_newarraymiTX(ti, dims) */
|
|
2504 libcall_fn libcall = telem->isZeroInit ()
|
|
2505 ? LIBCALL_NEWARRAYMTX : LIBCALL_NEWARRAYMITX;
|
|
2506
|
|
2507 tree tinfo = build_typeinfo (e->loc, e->type);
|
|
2508 tree dims = d_array_value (build_ctype (Type::tsize_t->arrayOf ()),
|
|
2509 size_int (e->arguments->dim),
|
|
2510 build_address (var));
|
|
2511
|
|
2512 result = build_libcall (libcall, tb, 2, tinfo, dims);
|
|
2513 result = bind_expr (var, result);
|
|
2514 }
|
|
2515
|
|
2516 if (e->argprefix)
|
|
2517 result = compound_expr (build_expr (e->argprefix), result);
|
|
2518 }
|
|
2519 else if (tb->ty == Tpointer)
|
|
2520 {
|
|
2521 /* Allocating memory for a new pointer. */
|
|
2522 TypePointer *tpointer = (TypePointer *) tb;
|
|
2523
|
|
2524 if (tpointer->next->size () == 0)
|
|
2525 {
|
|
2526 /* Pointer element size is unknown. */
|
|
2527 this->result_ = d_convert (build_ctype (e->type),
|
|
2528 integer_zero_node);
|
|
2529 return;
|
|
2530 }
|
|
2531
|
|
2532 libcall_fn libcall = tpointer->next->isZeroInit (e->loc)
|
|
2533 ? LIBCALL_NEWITEMT : LIBCALL_NEWITEMIT;
|
|
2534
|
|
2535 tree arg = build_typeinfo (e->loc, e->newtype);
|
|
2536 result = build_libcall (libcall, tb, 1, arg);
|
|
2537
|
|
2538 if (e->arguments && e->arguments->dim == 1)
|
|
2539 {
|
|
2540 result = d_save_expr (result);
|
|
2541 tree init = modify_expr (build_deref (result),
|
|
2542 build_expr ((*e->arguments)[0]));
|
|
2543 result = compound_expr (init, result);
|
|
2544 }
|
|
2545
|
|
2546 if (e->argprefix)
|
|
2547 result = compound_expr (build_expr (e->argprefix), result);
|
|
2548 }
|
|
2549 else
|
|
2550 gcc_unreachable ();
|
|
2551
|
|
2552 this->result_ = convert_expr (result, tb, e->type);
|
|
2553 }
|
|
2554
|
|
2555 /* Build an integer literal. */
|
|
2556
|
|
2557 void visit (IntegerExp *e)
|
|
2558 {
|
|
2559 tree ctype = build_ctype (e->type->toBasetype ());
|
|
2560 this->result_ = build_integer_cst (e->value, ctype);
|
|
2561 }
|
|
2562
|
|
2563 /* Build a floating-point literal. */
|
|
2564
|
|
2565 void visit (RealExp *e)
|
|
2566 {
|
|
2567 this->result_ = build_float_cst (e->value, e->type->toBasetype ());
|
|
2568 }
|
|
2569
|
|
2570 /* Build a complex literal. */
|
|
2571
|
|
2572 void visit (ComplexExp *e)
|
|
2573 {
|
|
2574 Type *tnext;
|
|
2575
|
|
2576 switch (e->type->toBasetype ()->ty)
|
|
2577 {
|
|
2578 case Tcomplex32:
|
|
2579 tnext = (TypeBasic *) Type::tfloat32;
|
|
2580 break;
|
|
2581
|
|
2582 case Tcomplex64:
|
|
2583 tnext = (TypeBasic *) Type::tfloat64;
|
|
2584 break;
|
|
2585
|
|
2586 case Tcomplex80:
|
|
2587 tnext = (TypeBasic *) Type::tfloat80;
|
|
2588 break;
|
|
2589
|
|
2590 default:
|
|
2591 gcc_unreachable ();
|
|
2592 }
|
|
2593
|
|
2594 this->result_ = build_complex (build_ctype (e->type),
|
|
2595 build_float_cst (creall (e->value), tnext),
|
|
2596 build_float_cst (cimagl (e->value), tnext));
|
|
2597 }
|
|
2598
|
|
2599 /* Build a string literal, all strings are null terminated except for
|
|
2600 static arrays. */
|
|
2601
|
|
2602 void visit (StringExp *e)
|
|
2603 {
|
|
2604 Type *tb = e->type->toBasetype ();
|
|
2605 tree type = build_ctype (e->type);
|
|
2606
|
|
2607 if (tb->ty == Tsarray)
|
|
2608 {
|
|
2609 /* Turn the string into a constructor for the static array. */
|
|
2610 vec<constructor_elt, va_gc> *elms = NULL;
|
|
2611 vec_safe_reserve (elms, e->len);
|
|
2612 tree etype = TREE_TYPE (type);
|
|
2613
|
|
2614 for (size_t i = 0; i < e->len; i++)
|
|
2615 {
|
|
2616 tree value = build_integer_cst (e->charAt (i), etype);
|
|
2617 CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
|
|
2618 }
|
|
2619
|
|
2620 tree ctor = build_constructor (type, elms);
|
|
2621 TREE_CONSTANT (ctor) = 1;
|
|
2622 this->result_ = ctor;
|
|
2623 }
|
|
2624 else
|
|
2625 {
|
|
2626 /* Copy the string contents to a null terminated string. */
|
|
2627 dinteger_t length = (e->len * e->sz);
|
|
2628 char *string = XALLOCAVEC (char, length + 1);
|
|
2629 memcpy (string, e->string, length);
|
|
2630 string[length] = '\0';
|
|
2631
|
|
2632 /* String value and type includes the null terminator. */
|
|
2633 tree value = build_string (length, string);
|
|
2634 TREE_TYPE (value) = make_array_type (tb->nextOf (), length + 1);
|
|
2635 value = build_address (value);
|
|
2636
|
|
2637 if (tb->ty == Tarray)
|
|
2638 value = d_array_value (type, size_int (e->len), value);
|
|
2639
|
|
2640 TREE_CONSTANT (value) = 1;
|
|
2641 this->result_ = d_convert (type, value);
|
|
2642 }
|
|
2643 }
|
|
2644
|
|
2645 /* Build a tuple literal. Just an argument list that may have
|
|
2646 side effects that need evaluation. */
|
|
2647
|
|
2648 void visit (TupleExp *e)
|
|
2649 {
|
|
2650 tree result = NULL_TREE;
|
|
2651
|
|
2652 if (e->e0)
|
|
2653 result = build_expr (e->e0);
|
|
2654
|
|
2655 for (size_t i = 0; i < e->exps->dim; ++i)
|
|
2656 {
|
|
2657 Expression *exp = (*e->exps)[i];
|
|
2658 result = compound_expr (result, build_expr (exp));
|
|
2659 }
|
|
2660
|
|
2661 if (result == NULL_TREE)
|
|
2662 result = void_node;
|
|
2663
|
|
2664 this->result_ = result;
|
|
2665 }
|
|
2666
|
|
2667 /* Build an array literal. The common type of the all elements is taken to
|
|
2668 be the type of the array element, and all elements are implicitly
|
|
2669 converted to that type. */
|
|
2670
|
|
2671 void visit (ArrayLiteralExp *e)
|
|
2672 {
|
|
2673 Type *tb = e->type->toBasetype ();
|
|
2674
|
|
2675 /* Implicitly convert void[n] to ubyte[n]. */
|
|
2676 if (tb->ty == Tsarray && tb->nextOf ()->toBasetype ()->ty == Tvoid)
|
|
2677 tb = Type::tuns8->sarrayOf (((TypeSArray *) tb)->dim->toUInteger ());
|
|
2678
|
|
2679 gcc_assert (tb->ty == Tarray || tb->ty == Tsarray || tb->ty == Tpointer);
|
|
2680
|
|
2681 /* Handle empty array literals. */
|
|
2682 if (e->elements->dim == 0)
|
|
2683 {
|
|
2684 if (tb->ty == Tarray)
|
|
2685 this->result_ = d_array_value (build_ctype (e->type),
|
|
2686 size_int (0), null_pointer_node);
|
|
2687 else
|
|
2688 this->result_ = build_constructor (make_array_type (tb->nextOf (), 0),
|
|
2689 NULL);
|
|
2690
|
|
2691 return;
|
|
2692 }
|
|
2693
|
|
2694 /* Build an expression that assigns the expressions in ELEMENTS to
|
|
2695 a constructor. */
|
|
2696 vec<constructor_elt, va_gc> *elms = NULL;
|
|
2697 vec_safe_reserve (elms, e->elements->dim);
|
|
2698 bool constant_p = true;
|
|
2699 tree saved_elems = NULL_TREE;
|
|
2700
|
|
2701 Type *etype = tb->nextOf ();
|
|
2702 tree satype = make_array_type (etype, e->elements->dim);
|
|
2703
|
|
2704 for (size_t i = 0; i < e->elements->dim; i++)
|
|
2705 {
|
|
2706 Expression *expr = e->getElement (i);
|
|
2707 tree value = build_expr (expr, this->constp_);
|
|
2708
|
|
2709 /* Only append nonzero values, the backend will zero out the rest
|
|
2710 of the constructor as we don't set CONSTRUCTOR_NO_CLEARING. */
|
|
2711 if (!initializer_zerop (value))
|
|
2712 {
|
|
2713 if (!TREE_CONSTANT (value))
|
|
2714 constant_p = false;
|
|
2715
|
|
2716 /* Split construction of values out of the constructor if there
|
|
2717 may be side effects. */
|
|
2718 tree init = stabilize_expr (&value);
|
|
2719 if (init != NULL_TREE)
|
|
2720 saved_elems = compound_expr (saved_elems, init);
|
|
2721
|
|
2722 CONSTRUCTOR_APPEND_ELT (elms, size_int (i),
|
|
2723 convert_expr (value, expr->type, etype));
|
|
2724 }
|
|
2725 }
|
|
2726
|
|
2727 /* Now return the constructor as the correct type. For static arrays there
|
|
2728 is nothing else to do. For dynamic arrays, return a two field struct.
|
|
2729 For pointers, return the address. */
|
|
2730 tree ctor = build_constructor (satype, elms);
|
|
2731 tree type = build_ctype (e->type);
|
|
2732
|
|
2733 /* Nothing else to do for static arrays. */
|
|
2734 if (tb->ty == Tsarray || this->constp_)
|
|
2735 {
|
|
2736 /* Can't take the address of the constructor, so create an anonymous
|
|
2737 static symbol, and then refer to it. */
|
|
2738 if (tb->ty != Tsarray)
|
|
2739 {
|
|
2740 tree decl = build_artificial_decl (TREE_TYPE (ctor), ctor, "A");
|
|
2741 ctor = build_address (decl);
|
|
2742 if (tb->ty == Tarray)
|
|
2743 ctor = d_array_value (type, size_int (e->elements->dim), ctor);
|
|
2744
|
|
2745 d_pushdecl (decl);
|
|
2746 rest_of_decl_compilation (decl, 1, 0);
|
|
2747 }
|
|
2748
|
|
2749 /* If the array literal is readonly or static. */
|
|
2750 if (constant_p)
|
|
2751 TREE_CONSTANT (ctor) = 1;
|
|
2752 if (constant_p && initializer_constant_valid_p (ctor, TREE_TYPE (ctor)))
|
|
2753 TREE_STATIC (ctor) = 1;
|
|
2754
|
|
2755 this->result_ = compound_expr (saved_elems, d_convert (type, ctor));
|
|
2756 }
|
|
2757 else
|
|
2758 {
|
|
2759 /* Allocate space on the memory managed heap. */
|
|
2760 tree mem = build_libcall (LIBCALL_ARRAYLITERALTX,
|
|
2761 etype->pointerTo (), 2,
|
|
2762 build_typeinfo (e->loc, etype->arrayOf ()),
|
|
2763 size_int (e->elements->dim));
|
|
2764 mem = d_save_expr (mem);
|
|
2765
|
|
2766 /* Now copy the constructor into memory. */
|
|
2767 tree tmemcpy = builtin_decl_explicit (BUILT_IN_MEMCPY);
|
|
2768 tree size = size_mult_expr (size_int (e->elements->dim),
|
|
2769 size_int (tb->nextOf ()->size ()));
|
|
2770
|
|
2771 tree result = build_call_expr (tmemcpy, 3, mem,
|
|
2772 build_address (ctor), size);
|
|
2773
|
|
2774 /* Return the array pointed to by MEM. */
|
|
2775 result = compound_expr (result, mem);
|
|
2776
|
|
2777 if (tb->ty == Tarray)
|
|
2778 result = d_array_value (type, size_int (e->elements->dim), result);
|
|
2779
|
|
2780 this->result_ = compound_expr (saved_elems, result);
|
|
2781 }
|
|
2782 }
|
|
2783
|
|
2784 /* Build an associative array literal. The common type of the all keys is
|
|
2785 taken to be the key type, and common type of all values the value type.
|
|
2786 All keys and values are then implicitly converted as needed. */
|
|
2787
|
|
2788 void visit (AssocArrayLiteralExp *e)
|
|
2789 {
|
|
2790 /* Want the mutable type for typeinfo reference. */
|
|
2791 Type *tb = e->type->toBasetype ()->mutableOf ();
|
|
2792 gcc_assert (tb->ty == Taarray);
|
|
2793
|
|
2794 /* Handle empty assoc array literals. */
|
|
2795 TypeAArray *ta = (TypeAArray *) tb;
|
|
2796 if (e->keys->dim == 0)
|
|
2797 {
|
|
2798 this->result_ = build_constructor (build_ctype (ta), NULL);
|
|
2799 return;
|
|
2800 }
|
|
2801
|
|
2802 /* Build an expression that assigns all expressions in KEYS
|
|
2803 to a constructor. */
|
|
2804 vec<constructor_elt, va_gc> *kelts = NULL;
|
|
2805 vec_safe_reserve (kelts, e->keys->dim);
|
|
2806 for (size_t i = 0; i < e->keys->dim; i++)
|
|
2807 {
|
|
2808 Expression *key = (*e->keys)[i];
|
|
2809 tree t = build_expr (key);
|
|
2810 CONSTRUCTOR_APPEND_ELT (kelts, size_int (i),
|
|
2811 convert_expr (t, key->type, ta->index));
|
|
2812 }
|
|
2813 tree tkeys = make_array_type (ta->index, e->keys->dim);
|
|
2814 tree akeys = build_constructor (tkeys, kelts);
|
|
2815
|
|
2816 /* Do the same with all expressions in VALUES. */
|
|
2817 vec<constructor_elt, va_gc> *velts = NULL;
|
|
2818 vec_safe_reserve (velts, e->values->dim);
|
|
2819 for (size_t i = 0; i < e->values->dim; i++)
|
|
2820 {
|
|
2821 Expression *value = (*e->values)[i];
|
|
2822 tree t = build_expr (value);
|
|
2823 CONSTRUCTOR_APPEND_ELT (velts, size_int (i),
|
|
2824 convert_expr (t, value->type, ta->next));
|
|
2825 }
|
|
2826 tree tvals = make_array_type (ta->next, e->values->dim);
|
|
2827 tree avals = build_constructor (tvals, velts);
|
|
2828
|
|
2829 /* Generate: _d_assocarrayliteralTX (ti, keys, vals); */
|
|
2830 tree keys = d_array_value (build_ctype (ta->index->arrayOf ()),
|
|
2831 size_int (e->keys->dim), build_address (akeys));
|
|
2832 tree vals = d_array_value (build_ctype (ta->next->arrayOf ()),
|
|
2833 size_int (e->values->dim),
|
|
2834 build_address (avals));
|
|
2835
|
|
2836 tree mem = build_libcall (LIBCALL_ASSOCARRAYLITERALTX, Type::tvoidptr, 3,
|
|
2837 build_typeinfo (e->loc, ta), keys, vals);
|
|
2838
|
|
2839 /* Return an associative array pointed to by MEM. */
|
|
2840 tree aatype = build_ctype (ta);
|
|
2841 vec<constructor_elt, va_gc> *ce = NULL;
|
|
2842 CONSTRUCTOR_APPEND_ELT (ce, TYPE_FIELDS (aatype), mem);
|
|
2843
|
|
2844 this->result_ = build_nop (build_ctype (e->type),
|
|
2845 build_constructor (aatype, ce));
|
|
2846 }
|
|
2847
|
|
2848 /* Build a struct literal. */
|
|
2849
|
|
2850 void visit (StructLiteralExp *e)
|
|
2851 {
|
|
2852 /* Handle empty struct literals. */
|
|
2853 if (e->elements == NULL || e->sd->fields.dim == 0)
|
|
2854 {
|
|
2855 this->result_ = build_constructor (build_ctype (e->type), NULL);
|
|
2856 return;
|
|
2857 }
|
|
2858
|
|
2859 /* Building sinit trees are delayed until after frontend semantic
|
|
2860 processing has complete. Build the static initializer now. */
|
|
2861 if (e->useStaticInit && !this->constp_)
|
|
2862 {
|
|
2863 this->result_ = aggregate_initializer_decl (e->sd);
|
|
2864 return;
|
|
2865 }
|
|
2866
|
|
2867 /* Build a constructor that assigns the expressions in ELEMENTS
|
|
2868 at each field index that has been filled in. */
|
|
2869 vec<constructor_elt, va_gc> *ve = NULL;
|
|
2870 tree saved_elems = NULL_TREE;
|
|
2871
|
|
2872 /* CTFE may fill the hidden pointer by NullExp. */
|
|
2873 gcc_assert (e->elements->dim <= e->sd->fields.dim);
|
|
2874
|
|
2875 Type *tb = e->type->toBasetype ();
|
|
2876 gcc_assert (tb->ty == Tstruct);
|
|
2877
|
|
2878 for (size_t i = 0; i < e->elements->dim; i++)
|
|
2879 {
|
|
2880 Expression *exp = (*e->elements)[i];
|
|
2881 if (!exp)
|
|
2882 continue;
|
|
2883
|
|
2884 VarDeclaration *field = e->sd->fields[i];
|
|
2885 Type *type = exp->type->toBasetype ();
|
|
2886 Type *ftype = field->type->toBasetype ();
|
|
2887 tree value = NULL_TREE;
|
|
2888
|
|
2889 if (ftype->ty == Tsarray && !same_type_p (type, ftype))
|
|
2890 {
|
|
2891 /* Initialize a static array with a single element. */
|
|
2892 tree elem = build_expr (exp, this->constp_);
|
|
2893 elem = d_save_expr (elem);
|
|
2894
|
|
2895 if (initializer_zerop (elem))
|
|
2896 value = build_constructor (build_ctype (ftype), NULL);
|
|
2897 else
|
|
2898 value = build_array_from_val (ftype, elem);
|
|
2899 }
|
|
2900 else
|
|
2901 {
|
|
2902 value = convert_expr (build_expr (exp, this->constp_),
|
|
2903 exp->type, field->type);
|
|
2904 }
|
|
2905
|
|
2906 /* Split construction of values out of the constructor. */
|
|
2907 tree init = stabilize_expr (&value);
|
|
2908 if (init != NULL_TREE)
|
|
2909 saved_elems = compound_expr (saved_elems, init);
|
|
2910
|
|
2911 CONSTRUCTOR_APPEND_ELT (ve, get_symbol_decl (field), value);
|
|
2912 }
|
|
2913
|
|
2914 /* Maybe setup hidden pointer to outer scope context. */
|
|
2915 if (e->sd->isNested () && e->elements->dim != e->sd->fields.dim
|
|
2916 && this->constp_ == false)
|
|
2917 {
|
|
2918 tree field = get_symbol_decl (e->sd->vthis);
|
|
2919 tree value = build_vthis (e->sd);
|
|
2920 CONSTRUCTOR_APPEND_ELT (ve, field, value);
|
|
2921 gcc_assert (e->useStaticInit == false);
|
|
2922 }
|
|
2923
|
|
2924 /* Build a constructor in the correct shape of the aggregate type. */
|
|
2925 tree ctor = build_struct_literal (build_ctype (e->type), ve);
|
|
2926
|
|
2927 /* Nothing more to do for constant literals. */
|
|
2928 if (this->constp_)
|
|
2929 {
|
|
2930 /* If the struct literal is a valid for static data. */
|
|
2931 if (TREE_CONSTANT (ctor)
|
|
2932 && initializer_constant_valid_p (ctor, TREE_TYPE (ctor)))
|
|
2933 TREE_STATIC (ctor) = 1;
|
|
2934
|
|
2935 this->result_ = compound_expr (saved_elems, ctor);
|
|
2936 return;
|
|
2937 }
|
|
2938
|
|
2939 if (e->sym != NULL)
|
|
2940 {
|
|
2941 tree var = build_deref (e->sym);
|
|
2942 ctor = compound_expr (modify_expr (var, ctor), var);
|
|
2943 this->result_ = compound_expr (saved_elems, ctor);
|
|
2944 }
|
|
2945 else if (e->sd->isUnionDeclaration ())
|
|
2946 {
|
|
2947 /* For unions, use memset to fill holes in the object. */
|
|
2948 tree var = build_local_temp (TREE_TYPE (ctor));
|
|
2949 tree tmemset = builtin_decl_explicit (BUILT_IN_MEMSET);
|
|
2950 tree init = build_call_expr (tmemset, 3, build_address (var),
|
|
2951 size_zero_node,
|
|
2952 size_int (e->sd->structsize));
|
|
2953
|
|
2954 init = compound_expr (init, saved_elems);
|
|
2955 init = compound_expr (init, modify_expr (var, ctor));
|
|
2956 this->result_ = compound_expr (init, var);
|
|
2957 }
|
|
2958 else
|
|
2959 this->result_ = compound_expr (saved_elems, ctor);
|
|
2960 }
|
|
2961
|
|
2962 /* Build a null literal. */
|
|
2963
|
|
2964 void visit (NullExp *e)
|
|
2965 {
|
|
2966 this->result_ = build_typeof_null_value (e->type);
|
|
2967 }
|
|
2968
|
|
2969 /* Build a vector literal. */
|
|
2970
|
|
2971 void visit (VectorExp *e)
|
|
2972 {
|
|
2973 tree type = build_ctype (e->type);
|
|
2974 tree etype = TREE_TYPE (type);
|
|
2975
|
|
2976 /* First handle array literal expressions. */
|
|
2977 if (e->e1->op == TOKarrayliteral)
|
|
2978 {
|
|
2979 ArrayLiteralExp *ale = ((ArrayLiteralExp *) e->e1);
|
|
2980 vec<constructor_elt, va_gc> *elms = NULL;
|
|
2981 bool constant_p = true;
|
|
2982
|
|
2983 vec_safe_reserve (elms, ale->elements->dim);
|
|
2984 for (size_t i = 0; i < ale->elements->dim; i++)
|
|
2985 {
|
|
2986 Expression *expr = ale->getElement (i);
|
|
2987 tree value = d_convert (etype, build_expr (expr, this->constp_));
|
|
2988 if (!CONSTANT_CLASS_P (value))
|
|
2989 constant_p = false;
|
|
2990
|
|
2991 CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
|
|
2992 }
|
|
2993
|
|
2994 /* Build a VECTOR_CST from a constant vector constructor. */
|
|
2995 if (constant_p)
|
|
2996 this->result_ = build_vector_from_ctor (type, elms);
|
|
2997 else
|
|
2998 this->result_ = build_constructor (type, elms);
|
|
2999 }
|
|
3000 else
|
|
3001 {
|
|
3002 /* Build constructor from single value. */
|
|
3003 tree val = d_convert (etype, build_expr (e->e1, this->constp_));
|
|
3004 this->result_ = build_vector_from_val (type, val);
|
|
3005 }
|
|
3006 }
|
|
3007
|
|
3008 /* Build a static array representation of a vector expression. */
|
|
3009
|
|
3010 void visit (VectorArrayExp *e)
|
|
3011 {
|
|
3012 this->result_ = convert_expr (build_expr (e->e1, this->constp_),
|
|
3013 e->e1->type, e->type);
|
|
3014 }
|
|
3015
|
|
3016 /* Build a static class literal, return its reference. */
|
|
3017
|
|
3018 void visit (ClassReferenceExp *e)
|
|
3019 {
|
|
3020 /* The result of build_new_class_expr is a RECORD_TYPE, we want
|
|
3021 the reference. */
|
|
3022 tree var = build_address (build_new_class_expr (e));
|
|
3023
|
|
3024 /* If the type of this literal is an interface, the we must add the
|
|
3025 interface offset to symbol. */
|
|
3026 if (this->constp_)
|
|
3027 {
|
|
3028 TypeClass *tc = (TypeClass *) e->type;
|
|
3029 InterfaceDeclaration *to = tc->sym->isInterfaceDeclaration ();
|
|
3030
|
|
3031 if (to != NULL)
|
|
3032 {
|
|
3033 ClassDeclaration *from = e->originalClass ();
|
|
3034 int offset = 0;
|
|
3035
|
|
3036 gcc_assert (to->isBaseOf (from, &offset) != 0);
|
|
3037
|
|
3038 if (offset != 0)
|
|
3039 var = build_offset (var, size_int (offset));
|
|
3040 }
|
|
3041 }
|
|
3042
|
|
3043 this->result_ = var;
|
|
3044 }
|
|
3045
|
|
3046 /* These expressions are mainly just a placeholders in the frontend.
|
|
3047 We shouldn't see them here. */
|
|
3048
|
|
3049 void visit (ScopeExp *e)
|
|
3050 {
|
|
3051 error_at (make_location_t (e->loc), "%qs is not an expression",
|
|
3052 e->toChars ());
|
|
3053 this->result_ = error_mark_node;
|
|
3054 }
|
|
3055
|
|
3056 void visit (TypeExp *e)
|
|
3057 {
|
|
3058 error_at (make_location_t (e->loc), "type %qs is not an expression",
|
|
3059 e->toChars ());
|
|
3060 this->result_ = error_mark_node;
|
|
3061 }
|
|
3062 };
|
|
3063
|
|
3064
|
|
3065 /* Main entry point for ExprVisitor interface to generate code for
|
|
3066 the Expression AST class E. If CONST_P is true, then E is a
|
|
3067 constant expression. */
|
|
3068
|
|
3069 tree
|
|
3070 build_expr (Expression *e, bool const_p)
|
|
3071 {
|
|
3072 ExprVisitor v = ExprVisitor (const_p);
|
|
3073 location_t saved_location = input_location;
|
|
3074
|
|
3075 input_location = make_location_t (e->loc);
|
|
3076 e->accept (&v);
|
|
3077 tree expr = v.result ();
|
|
3078 input_location = saved_location;
|
|
3079
|
|
3080 /* Check if initializer expression is valid constant. */
|
|
3081 if (const_p && !initializer_constant_valid_p (expr, TREE_TYPE (expr)))
|
|
3082 {
|
|
3083 error_at (make_location_t (e->loc), "non-constant expression %qs",
|
|
3084 e->toChars ());
|
|
3085 return error_mark_node;
|
|
3086 }
|
|
3087
|
|
3088 return expr;
|
|
3089 }
|
|
3090
|
|
3091 /* Same as build_expr, but also calls destructors on any temporaries. */
|
|
3092
|
|
3093 tree
|
|
3094 build_expr_dtor (Expression *e)
|
|
3095 {
|
|
3096 /* Codegen can be improved by determining if no exceptions can be thrown
|
|
3097 between the ctor and dtor, and eliminating the ctor and dtor. */
|
|
3098 size_t saved_vars = vec_safe_length (d_function_chain->vars_in_scope);
|
|
3099 tree result = build_expr (e);
|
|
3100
|
|
3101 if (saved_vars != vec_safe_length (d_function_chain->vars_in_scope))
|
|
3102 {
|
|
3103 result = fold_build_cleanup_point_expr (TREE_TYPE (result), result);
|
|
3104 vec_safe_truncate (d_function_chain->vars_in_scope, saved_vars);
|
|
3105 }
|
|
3106
|
|
3107 return result;
|
|
3108 }
|
|
3109
|
|
3110 /* Same as build_expr_dtor, but handles the result of E as a return value. */
|
|
3111
|
|
3112 tree
|
|
3113 build_return_dtor (Expression *e, Type *type, TypeFunction *tf)
|
|
3114 {
|
|
3115 size_t saved_vars = vec_safe_length (d_function_chain->vars_in_scope);
|
|
3116 tree result = build_expr (e);
|
|
3117
|
|
3118 /* Convert for initializing the DECL_RESULT. */
|
|
3119 result = convert_expr (result, e->type, type);
|
|
3120
|
|
3121 /* If we are returning a reference, take the address. */
|
|
3122 if (tf->isref)
|
|
3123 result = build_address (result);
|
|
3124
|
|
3125 /* The decl to store the return expression. */
|
|
3126 tree decl = DECL_RESULT (cfun->decl);
|
|
3127
|
|
3128 /* Split comma expressions, so that the result is returned directly. */
|
|
3129 tree expr = stabilize_expr (&result);
|
|
3130 result = build_assign (INIT_EXPR, decl, result);
|
|
3131 result = compound_expr (expr, return_expr (result));
|
|
3132
|
|
3133 /* May nest the return expression inside the try/finally expression. */
|
|
3134 if (saved_vars != vec_safe_length (d_function_chain->vars_in_scope))
|
|
3135 {
|
|
3136 result = fold_build_cleanup_point_expr (TREE_TYPE (result), result);
|
|
3137 vec_safe_truncate (d_function_chain->vars_in_scope, saved_vars);
|
|
3138 }
|
|
3139
|
|
3140 return result;
|
|
3141 }
|
|
3142
|