1
2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
4 * written by Walter Bright
5 * http://www.digitalmars.com
6 * Distributed under the Boost Software License, Version 1.0.
7 * http://www.boost.org/LICENSE_1_0.txt
8 * https://github.com/D-Programming-Language/dmd/blob/master/src/ctfeexpr.c
9 */
10
11 #include "root/dsystem.h" // mem{cpy|set}()
12 #include "root/rmem.h"
13
14 #include "mars.h"
15 #include "expression.h"
16 #include "declaration.h"
17 #include "aggregate.h"
18 // for AssocArray
19 #include "id.h"
20 #include "utf.h"
21 #include "template.h"
22 #include "ctfe.h"
23
24 int RealEquals(real_t x1, real_t x2);
25
26 /************** ClassReferenceExp ********************************************/
27
ClassReferenceExp(Loc loc,StructLiteralExp * lit,Type * type)28 ClassReferenceExp::ClassReferenceExp(Loc loc, StructLiteralExp *lit, Type *type)
29 : Expression(loc, TOKclassreference, sizeof(ClassReferenceExp))
30 {
31 assert(lit && lit->sd && lit->sd->isClassDeclaration());
32 this->value = lit;
33 this->type = type;
34 }
35
originalClass()36 ClassDeclaration *ClassReferenceExp::originalClass()
37 {
38 return value->sd->isClassDeclaration();
39 }
40
41 // Return index of the field, or -1 if not found
getFieldIndex(Type * fieldtype,unsigned fieldoffset)42 int ClassReferenceExp::getFieldIndex(Type *fieldtype, unsigned fieldoffset)
43 {
44 ClassDeclaration *cd = originalClass();
45 unsigned fieldsSoFar = 0;
46 for (size_t j = 0; j < value->elements->dim; j++)
47 {
48 while (j - fieldsSoFar >= cd->fields.dim)
49 {
50 fieldsSoFar += cd->fields.dim;
51 cd = cd->baseClass;
52 }
53 VarDeclaration *v2 = cd->fields[j - fieldsSoFar];
54 if (fieldoffset == v2->offset &&
55 fieldtype->size() == v2->type->size())
56 {
57 return (int)(value->elements->dim - fieldsSoFar - cd->fields.dim + (j-fieldsSoFar));
58 }
59 }
60 return -1;
61 }
62
63 // Return index of the field, or -1 if not found
64 // Same as getFieldIndex, but checks for a direct match with the VarDeclaration
findFieldIndexByName(VarDeclaration * v)65 int ClassReferenceExp::findFieldIndexByName(VarDeclaration *v)
66 {
67 ClassDeclaration *cd = originalClass();
68 size_t fieldsSoFar = 0;
69 for (size_t j = 0; j < value->elements->dim; j++)
70 {
71 while (j - fieldsSoFar >= cd->fields.dim)
72 {
73 fieldsSoFar += cd->fields.dim;
74 cd = cd->baseClass;
75 }
76 VarDeclaration *v2 = cd->fields[j - fieldsSoFar];
77 if (v == v2)
78 {
79 return (int)(value->elements->dim - fieldsSoFar - cd->fields.dim + (j-fieldsSoFar));
80 }
81 }
82 return -1;
83 }
84
85 /************** VoidInitExp ********************************************/
86
VoidInitExp(VarDeclaration * var,Type *)87 VoidInitExp::VoidInitExp(VarDeclaration *var, Type *)
88 : Expression(var->loc, TOKvoid, sizeof(VoidInitExp))
89 {
90 this->var = var;
91 this->type = var->type;
92 }
93
toChars()94 const char *VoidInitExp::toChars()
95 {
96 return "void";
97 }
98
99 // Return index of the field, or -1 if not found
100 // Same as getFieldIndex, but checks for a direct match with the VarDeclaration
findFieldIndexByName(StructDeclaration * sd,VarDeclaration * v)101 int findFieldIndexByName(StructDeclaration *sd, VarDeclaration *v)
102 {
103 for (size_t i = 0; i < sd->fields.dim; ++i)
104 {
105 if (sd->fields[i] == v)
106 return (int)i;
107 }
108 return -1;
109 }
110
111 /************** ThrownExceptionExp ********************************************/
112
ThrownExceptionExp(Loc loc,ClassReferenceExp * victim)113 ThrownExceptionExp::ThrownExceptionExp(Loc loc, ClassReferenceExp *victim) : Expression(loc, TOKthrownexception, sizeof(ThrownExceptionExp))
114 {
115 this->thrown = victim;
116 this->type = victim->type;
117 }
118
toChars()119 const char *ThrownExceptionExp::toChars()
120 {
121 return "CTFE ThrownException";
122 }
123
124 // Generate an error message when this exception is not caught
generateUncaughtError()125 void ThrownExceptionExp::generateUncaughtError()
126 {
127 UnionExp ue;
128 Expression *e = resolveSlice((*thrown->value->elements)[0], &ue);
129 StringExp *se = e->toStringExp();
130 thrown->error("uncaught CTFE exception %s(%s)", thrown->type->toChars(), se ? se->toChars() : e->toChars());
131
132 /* Also give the line where the throw statement was. We won't have it
133 * in the case where the ThrowStatement is generated internally
134 * (eg, in ScopeStatement)
135 */
136 if (loc.filename && !loc.equals(thrown->loc))
137 errorSupplemental(loc, "thrown from here");
138 }
139
140 // True if 'e' is CTFEExp::cantexp, or an exception
exceptionOrCantInterpret(Expression * e)141 bool exceptionOrCantInterpret(Expression *e)
142 {
143 return e && (e->op == TOKcantexp || e->op == TOKthrownexception);
144 }
145
146 /********************** CTFEExp ******************************************/
147
148 CTFEExp *CTFEExp::cantexp;
149 CTFEExp *CTFEExp::voidexp;
150 CTFEExp *CTFEExp::breakexp;
151 CTFEExp *CTFEExp::continueexp;
152 CTFEExp *CTFEExp::gotoexp;
153
CTFEExp(TOK tok)154 CTFEExp::CTFEExp(TOK tok)
155 : Expression(Loc(), tok, sizeof(CTFEExp))
156 {
157 type = Type::tvoid;
158 }
159
toChars()160 const char *CTFEExp::toChars()
161 {
162 switch (op)
163 {
164 case TOKcantexp: return "<cant>";
165 case TOKvoidexp: return "<void>";
166 case TOKbreak: return "<break>";
167 case TOKcontinue: return "<continue>";
168 case TOKgoto: return "<goto>";
169 default: assert(0); return NULL;
170 }
171 }
172
copy()173 Expression *UnionExp::copy()
174 {
175 Expression *e = exp();
176 //if (e->size > sizeof(u)) printf("%s\n", Token::toChars(e->op));
177 assert(e->size <= sizeof(u));
178 if (e->op == TOKcantexp) return CTFEExp::cantexp;
179 if (e->op == TOKvoidexp) return CTFEExp::voidexp;
180 if (e->op == TOKbreak) return CTFEExp::breakexp;
181 if (e->op == TOKcontinue) return CTFEExp::continueexp;
182 if (e->op == TOKgoto) return CTFEExp::gotoexp;
183 return e->copy();
184 }
185
186 /************** Aggregate literals (AA/string/array/struct) ******************/
187
188 // Given expr, which evaluates to an array/AA/string literal,
189 // return true if it needs to be copied
needToCopyLiteral(Expression * expr)190 bool needToCopyLiteral(Expression *expr)
191 {
192 for (;;)
193 {
194 switch (expr->op)
195 {
196 case TOKarrayliteral:
197 return ((ArrayLiteralExp *)expr)->ownedByCtfe == OWNEDcode;
198 case TOKassocarrayliteral:
199 return ((AssocArrayLiteralExp *)expr)->ownedByCtfe == OWNEDcode;
200 case TOKstructliteral:
201 return ((StructLiteralExp *)expr)->ownedByCtfe == OWNEDcode;
202 case TOKstring:
203 case TOKthis:
204 case TOKvar:
205 return false;
206 case TOKassign:
207 return false;
208 case TOKindex:
209 case TOKdotvar:
210 case TOKslice:
211 case TOKcast:
212 expr = ((UnaExp *)expr)->e1;
213 continue;
214 case TOKcat:
215 return needToCopyLiteral(((BinExp *)expr)->e1) ||
216 needToCopyLiteral(((BinExp *)expr)->e2);
217 case TOKcatass:
218 expr = ((BinExp *)expr)->e2;
219 continue;
220 default:
221 return false;
222 }
223 }
224 }
225
226 Expressions *copyLiteralArray(Expressions *oldelems, Expression *basis = NULL)
227 {
228 if (!oldelems)
229 return oldelems;
230 CtfeStatus::numArrayAllocs++;
231 Expressions *newelems = new Expressions();
232 newelems->setDim(oldelems->dim);
233 for (size_t i = 0; i < oldelems->dim; i++)
234 {
235 Expression *el = (*oldelems)[i];
236 if (!el)
237 el = basis;
238 (*newelems)[i] = copyLiteral(el).copy();
239 }
240 return newelems;
241 }
242
243 // Make a copy of the ArrayLiteral, AALiteral, String, or StructLiteral.
244 // This value will be used for in-place modification.
copyLiteral(Expression * e)245 UnionExp copyLiteral(Expression *e)
246 {
247 UnionExp ue;
248 if (e->op == TOKstring) // syntaxCopy doesn't make a copy for StringExp!
249 {
250 StringExp *se = (StringExp *)e;
251 utf8_t *s = (utf8_t *)mem.xcalloc(se->len + 1, se->sz);
252 memcpy(s, se->string, se->len * se->sz);
253 new(&ue) StringExp(se->loc, s, se->len);
254 StringExp *se2 = (StringExp *)ue.exp();
255 se2->committed = se->committed;
256 se2->postfix = se->postfix;
257 se2->type = se->type;
258 se2->sz = se->sz;
259 se2->ownedByCtfe = OWNEDctfe;
260 return ue;
261 }
262 if (e->op == TOKarrayliteral)
263 {
264 ArrayLiteralExp *ale = (ArrayLiteralExp *)e;
265 Expressions *elements = copyLiteralArray(ale->elements, ale->basis);
266
267 new(&ue) ArrayLiteralExp(e->loc, e->type, elements);
268
269 ArrayLiteralExp *r = (ArrayLiteralExp *)ue.exp();
270 r->ownedByCtfe = OWNEDctfe;
271 return ue;
272 }
273 if (e->op == TOKassocarrayliteral)
274 {
275 AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e;
276 new(&ue) AssocArrayLiteralExp(e->loc, copyLiteralArray(aae->keys), copyLiteralArray(aae->values));
277 AssocArrayLiteralExp *r = (AssocArrayLiteralExp *)ue.exp();
278 r->type = e->type;
279 r->ownedByCtfe = OWNEDctfe;
280 return ue;
281 }
282 if (e->op == TOKstructliteral)
283 {
284 /* syntaxCopy doesn't work for struct literals, because of a nasty special
285 * case: block assignment is permitted inside struct literals, eg,
286 * an int[4] array can be initialized with a single int.
287 */
288 StructLiteralExp *sle = (StructLiteralExp *)e;
289 Expressions *oldelems = sle->elements;
290 Expressions * newelems = new Expressions();
291 newelems->setDim(oldelems->dim);
292 for (size_t i = 0; i < newelems->dim; i++)
293 {
294 // We need the struct definition to detect block assignment
295 VarDeclaration *v = sle->sd->fields[i];
296 Expression *m = (*oldelems)[i];
297
298 // If it is a void assignment, use the default initializer
299 if (!m)
300 m = voidInitLiteral(v->type, v).copy();
301
302 if (v->type->ty == Tarray || v->type->ty == Taarray)
303 {
304 // Don't have to copy array references
305 }
306 else
307 {
308 // Buzilla 15681: Copy the source element always.
309 m = copyLiteral(m).copy();
310
311 // Block assignment from inside struct literals
312 if (v->type->ty != m->type->ty && v->type->ty == Tsarray)
313 {
314 TypeSArray *tsa = (TypeSArray *)v->type;
315 size_t len = (size_t)tsa->dim->toInteger();
316 UnionExp uex;
317 m = createBlockDuplicatedArrayLiteral(&uex, e->loc, v->type, m, len);
318 if (m == uex.exp())
319 m = uex.copy();
320 }
321 }
322 (*newelems)[i] = m;
323 }
324 new(&ue) StructLiteralExp(e->loc, sle->sd, newelems, sle->stype);
325 StructLiteralExp *r = (StructLiteralExp *)ue.exp();
326 r->type = e->type;
327 r->ownedByCtfe = OWNEDctfe;
328 r->origin = ((StructLiteralExp *)e)->origin;
329 return ue;
330 }
331 if (e->op == TOKfunction || e->op == TOKdelegate ||
332 e->op == TOKsymoff || e->op == TOKnull ||
333 e->op == TOKvar || e->op == TOKdotvar ||
334 e->op == TOKint64 || e->op == TOKfloat64 ||
335 e->op == TOKchar || e->op == TOKcomplex80 ||
336 e->op == TOKvoid || e->op == TOKvector ||
337 e->op == TOKtypeid)
338 {
339 // Simple value types
340 // Keep e1 for DelegateExp and DotVarExp
341 new(&ue) UnionExp(e);
342 Expression *r = ue.exp();
343 r->type = e->type;
344 return ue;
345 }
346 if (e->op == TOKslice)
347 {
348 SliceExp *se = (SliceExp *)e;
349 if (se->type->toBasetype()->ty == Tsarray)
350 {
351 // same with resolveSlice()
352 if (se->e1->op == TOKnull)
353 {
354 new(&ue) NullExp(se->loc, se->type);
355 return ue;
356 }
357 ue = Slice(se->type, se->e1, se->lwr, se->upr);
358 assert(ue.exp()->op == TOKarrayliteral);
359 ArrayLiteralExp *r = (ArrayLiteralExp *)ue.exp();
360 r->elements = copyLiteralArray(r->elements);
361 r->ownedByCtfe = OWNEDctfe;
362 return ue;
363 }
364 else
365 {
366 // Array slices only do a shallow copy
367 new(&ue) SliceExp(e->loc, se->e1, se->lwr, se->upr);
368 Expression *r = ue.exp();
369 r->type = e->type;
370 return ue;
371 }
372 }
373 if (isPointer(e->type))
374 {
375 // For pointers, we only do a shallow copy.
376 if (e->op == TOKaddress)
377 new(&ue) AddrExp(e->loc, ((AddrExp *)e)->e1);
378 else if (e->op == TOKindex)
379 new(&ue) IndexExp(e->loc, ((IndexExp *)e)->e1, ((IndexExp *)e)->e2);
380 else if (e->op == TOKdotvar)
381 {
382 new(&ue) DotVarExp(e->loc, ((DotVarExp *)e)->e1,
383 ((DotVarExp *)e)->var, ((DotVarExp *)e)->hasOverloads);
384 }
385 else
386 assert(0);
387 Expression *r = ue.exp();
388 r->type = e->type;
389 return ue;
390 }
391 if (e->op == TOKclassreference)
392 {
393 new(&ue) ClassReferenceExp(e->loc, ((ClassReferenceExp *)e)->value, e->type);
394 return ue;
395 }
396 if (e->op == TOKerror)
397 {
398 new(&ue) UnionExp(e);
399 return ue;
400 }
401 e->error("CTFE internal error: literal %s", e->toChars());
402 assert(0);
403 return ue;
404 }
405
406 /* Deal with type painting.
407 * Type painting is a major nuisance: we can't just set
408 * e->type = type, because that would change the original literal.
409 * But, we can't simply copy the literal either, because that would change
410 * the values of any pointers.
411 */
paintTypeOntoLiteral(Type * type,Expression * lit)412 Expression *paintTypeOntoLiteral(Type *type, Expression *lit)
413 {
414 if (lit->type->equals(type))
415 return lit;
416 return paintTypeOntoLiteralCopy(type, lit).copy();
417 }
418
paintTypeOntoLiteral(UnionExp * pue,Type * type,Expression * lit)419 Expression *paintTypeOntoLiteral(UnionExp *pue, Type *type, Expression *lit)
420 {
421 if (lit->type->equals(type))
422 return lit;
423 *pue = paintTypeOntoLiteralCopy(type, lit);
424 return pue->exp();
425 }
426
paintTypeOntoLiteralCopy(Type * type,Expression * lit)427 UnionExp paintTypeOntoLiteralCopy(Type *type, Expression *lit)
428 {
429 UnionExp ue;
430
431 if (lit->type->equals(type))
432 {
433 new(&ue) UnionExp(lit);
434 return ue;
435 }
436
437 // If it is a cast to inout, retain the original type of the referenced part.
438 if (type->hasWild() && type->hasPointers())
439 {
440 new(&ue) UnionExp(lit);
441 ue.exp()->type = type;
442 return ue;
443 }
444
445 if (lit->op == TOKslice)
446 {
447 SliceExp *se = (SliceExp *)lit;
448 new(&ue) SliceExp(lit->loc, se->e1, se->lwr, se->upr);
449 }
450 else if (lit->op == TOKindex)
451 {
452 IndexExp *ie = (IndexExp *)lit;
453 new(&ue) IndexExp(lit->loc, ie->e1, ie->e2);
454 }
455 else if (lit->op == TOKarrayliteral)
456 {
457 new(&ue) SliceExp(lit->loc, lit,
458 new IntegerExp(Loc(), 0, Type::tsize_t), ArrayLength(Type::tsize_t, lit).copy());
459 }
460 else if (lit->op == TOKstring)
461 {
462 // For strings, we need to introduce another level of indirection
463 new(&ue) SliceExp(lit->loc, lit,
464 new IntegerExp(Loc(), 0, Type::tsize_t), ArrayLength(Type::tsize_t, lit).copy());
465 }
466 else if (lit->op == TOKassocarrayliteral)
467 {
468 AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)lit;
469 // TODO: we should be creating a reference to this AAExp, not
470 // just a ref to the keys and values.
471 OwnedBy wasOwned = aae->ownedByCtfe;
472 new(&ue) AssocArrayLiteralExp(lit->loc, aae->keys, aae->values);
473 aae = (AssocArrayLiteralExp *)ue.exp();
474 aae->ownedByCtfe = wasOwned;
475 }
476 else
477 {
478 // Can't type paint from struct to struct*; this needs another
479 // level of indirection
480 if (lit->op == TOKstructliteral && isPointer(type))
481 lit->error("CTFE internal error: painting %s", type->toChars());
482 ue = copyLiteral(lit);
483 }
484 ue.exp()->type = type;
485 return ue;
486 }
487
488 /*************************************
489 * If e is a SliceExp, constant fold it.
490 * Params:
491 * e = expression to resolve
492 * pue = if not null, store resulting expression here
493 * Returns:
494 * resulting expression
495 */
resolveSlice(Expression * e,UnionExp * pue)496 Expression *resolveSlice(Expression *e, UnionExp *pue)
497 {
498 if (e->op != TOKslice)
499 return e;
500 SliceExp *se = (SliceExp *)e;
501 if (se->e1->op == TOKnull)
502 return se->e1;
503 if (pue)
504 {
505 *pue = Slice(e->type, se->e1, se->lwr, se->upr);
506 return pue->exp();
507 }
508 else
509 return Slice(e->type, se->e1, se->lwr, se->upr).copy();
510 }
511
512 /* Determine the array length, without interpreting it.
513 * e must be an array literal, or a slice
514 * It's very wasteful to resolve the slice when we only
515 * need the length.
516 */
resolveArrayLength(Expression * e)517 uinteger_t resolveArrayLength(Expression *e)
518 {
519 if (e->op == TOKvector)
520 return ((VectorExp *)e)->dim;
521
522 if (e->op == TOKnull)
523 return 0;
524 if (e->op == TOKslice)
525 {
526 uinteger_t ilo = ((SliceExp *)e)->lwr->toInteger();
527 uinteger_t iup = ((SliceExp *)e)->upr->toInteger();
528 return iup - ilo;
529 }
530 if (e->op == TOKstring)
531 {
532 return ((StringExp *)e)->len;
533 }
534 if (e->op == TOKarrayliteral)
535 {
536 ArrayLiteralExp *ale = (ArrayLiteralExp *)e;
537 return ale->elements ? ale->elements->dim : 0;
538 }
539 if (e->op == TOKassocarrayliteral)
540 {
541 AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e;
542 return ale->keys->dim;
543 }
544 assert(0);
545 return 0;
546 }
547
548 /******************************
549 * Helper for NewExp
550 * Create an array literal consisting of 'elem' duplicated 'dim' times.
551 * Params:
552 * pue = where to store result
553 * loc = source location where the interpretation occurs
554 * type = target type of the result
555 * elem = the source of array element, it will be owned by the result
556 * dim = element number of the result
557 * Returns:
558 * Constructed ArrayLiteralExp
559 */
createBlockDuplicatedArrayLiteral(UnionExp * pue,Loc loc,Type * type,Expression * elem,size_t dim)560 ArrayLiteralExp *createBlockDuplicatedArrayLiteral(UnionExp *pue, Loc loc, Type *type,
561 Expression *elem, size_t dim)
562 {
563 if (type->ty == Tsarray && type->nextOf()->ty == Tsarray && elem->type->ty != Tsarray)
564 {
565 // If it is a multidimensional array literal, do it recursively
566 TypeSArray *tsa = (TypeSArray *)type->nextOf();
567 size_t len = (size_t)tsa->dim->toInteger();
568 UnionExp ue;
569 elem = createBlockDuplicatedArrayLiteral(&ue, loc, type->nextOf(), elem, len);
570 if (elem == ue.exp())
571 elem = ue.copy();
572 }
573
574 // Buzilla 15681
575 Type *tb = elem->type->toBasetype();
576 const bool mustCopy = tb->ty == Tstruct || tb->ty == Tsarray;
577
578 Expressions *elements = new Expressions();
579 elements->setDim(dim);
580 for (size_t i = 0; i < dim; i++)
581 {
582 (*elements)[i] = mustCopy ? copyLiteral(elem).copy() : elem;
583 }
584 new(pue) ArrayLiteralExp(loc, type, elements);
585 ArrayLiteralExp *ale = (ArrayLiteralExp *)pue->exp();
586 ale->ownedByCtfe = OWNEDctfe;
587 return ale;
588 }
589
590 /******************************
591 * Helper for NewExp
592 * Create a string literal consisting of 'value' duplicated 'dim' times.
593 */
createBlockDuplicatedStringLiteral(UnionExp * pue,Loc loc,Type * type,unsigned value,size_t dim,unsigned char sz)594 StringExp *createBlockDuplicatedStringLiteral(UnionExp *pue, Loc loc, Type *type,
595 unsigned value, size_t dim, unsigned char sz)
596 {
597 utf8_t *s = (utf8_t *)mem.xcalloc(dim + 1, sz);
598 for (size_t elemi = 0; elemi < dim; ++elemi)
599 {
600 switch (sz)
601 {
602 case 1: s[elemi] = (utf8_t)value; break;
603 case 2: ((unsigned short *)s)[elemi] = (unsigned short)value; break;
604 case 4: ((unsigned *)s)[elemi] = value; break;
605 default: assert(0);
606 }
607 }
608 new(pue) StringExp(loc, s, dim);
609 StringExp *se = (StringExp *)pue->exp();
610 se->type = type;
611 se->sz = sz;
612 se->committed = true;
613 se->ownedByCtfe = OWNEDctfe;
614 return se;
615 }
616
617 // Return true if t is an AA
isAssocArray(Type * t)618 bool isAssocArray(Type *t)
619 {
620 t = t->toBasetype();
621 if (t->ty == Taarray)
622 return true;
623 return false;
624 }
625
626 // Given a template AA type, extract the corresponding built-in AA type
toBuiltinAAType(Type * t)627 TypeAArray *toBuiltinAAType(Type *t)
628 {
629 t = t->toBasetype();
630 if (t->ty == Taarray)
631 return (TypeAArray *)t;
632 assert(0);
633 return NULL;
634 }
635
636 /************** TypeInfo operations ************************************/
637
638 // Return true if type is TypeInfo_Class
isTypeInfo_Class(Type * type)639 bool isTypeInfo_Class(Type *type)
640 {
641 return type->ty == Tclass &&
642 (Type::dtypeinfo == ((TypeClass *)type)->sym ||
643 Type::dtypeinfo->isBaseOf(((TypeClass *)type)->sym, NULL));
644 }
645
646 /************** Pointer operations ************************************/
647
648 // Return true if t is a pointer (not a function pointer)
isPointer(Type * t)649 bool isPointer(Type *t)
650 {
651 Type * tb = t->toBasetype();
652 return tb->ty == Tpointer && tb->nextOf()->ty != Tfunction;
653 }
654
655 // For CTFE only. Returns true if 'e' is true or a non-null pointer.
isTrueBool(Expression * e)656 bool isTrueBool(Expression *e)
657 {
658 return e->isBool(true) ||
659 ((e->type->ty == Tpointer || e->type->ty == Tclass) && e->op != TOKnull);
660 }
661
662 /* Is it safe to convert from srcPointee* to destPointee* ?
663 * srcPointee is the genuine type (never void).
664 * destPointee may be void.
665 */
isSafePointerCast(Type * srcPointee,Type * destPointee)666 bool isSafePointerCast(Type *srcPointee, Type *destPointee)
667 {
668 // It's safe to cast S** to D** if it's OK to cast S* to D*
669 while (srcPointee->ty == Tpointer && destPointee->ty == Tpointer)
670 {
671 srcPointee = srcPointee->nextOf();
672 destPointee = destPointee->nextOf();
673 }
674
675 // It's OK if both are the same (modulo const)
676 if (srcPointee->constConv(destPointee))
677 return true;
678
679 // It's OK if function pointers differ only in safe/pure/nothrow
680 if (srcPointee->ty == Tfunction && destPointee->ty == Tfunction)
681 return srcPointee->covariant(destPointee) == 1;
682
683 // it's OK to cast to void*
684 if (destPointee->ty == Tvoid)
685 return true;
686
687 // It's OK to cast from V[K] to void*
688 if (srcPointee->ty == Taarray && destPointee == Type::tvoidptr)
689 return true;
690
691 // It's OK if they are the same size (static array of) integers, eg:
692 // int* --> uint*
693 // int[5][] --> uint[5][]
694 if (srcPointee->ty == Tsarray && destPointee->ty == Tsarray)
695 {
696 if (srcPointee->size() != destPointee->size())
697 return false;
698 srcPointee = srcPointee->baseElemOf();
699 destPointee = destPointee->baseElemOf();
700 }
701 return srcPointee->isintegral() &&
702 destPointee->isintegral() &&
703 srcPointee->size() == destPointee->size();
704 }
705
getAggregateFromPointer(Expression * e,dinteger_t * ofs)706 Expression *getAggregateFromPointer(Expression *e, dinteger_t *ofs)
707 {
708 *ofs = 0;
709 if (e->op == TOKaddress)
710 e = ((AddrExp *)e)->e1;
711 if (e->op == TOKsymoff)
712 *ofs = ((SymOffExp *)e)->offset;
713 if (e->op == TOKdotvar)
714 {
715 Expression *ex = ((DotVarExp *)e)->e1;
716 VarDeclaration *v = ((DotVarExp *)e)->var->isVarDeclaration();
717 assert(v);
718 StructLiteralExp *se = ex->op == TOKclassreference ? ((ClassReferenceExp *)ex)->value : (StructLiteralExp *)ex;
719 // We can't use getField, because it makes a copy
720 unsigned i;
721 if (ex->op == TOKclassreference)
722 i = ((ClassReferenceExp *)ex)->getFieldIndex(e->type, v->offset);
723 else
724 i = se->getFieldIndex(e->type, v->offset);
725 e = (*se->elements)[i];
726 }
727 if (e->op == TOKindex)
728 {
729 IndexExp *ie = (IndexExp *)e;
730 // Note that each AA element is part of its own memory block
731 if ((ie->e1->type->ty == Tarray ||
732 ie->e1->type->ty == Tsarray ||
733 ie->e1->op == TOKstring ||
734 ie->e1->op == TOKarrayliteral) &&
735 ie->e2->op == TOKint64)
736 {
737 *ofs = ie->e2->toInteger();
738 return ie->e1;
739 }
740 }
741 if (e->op == TOKslice && e->type->toBasetype()->ty == Tsarray)
742 {
743 SliceExp *se = (SliceExp *)e;
744 if ((se->e1->type->ty == Tarray ||
745 se->e1->type->ty == Tsarray ||
746 se->e1->op == TOKstring ||
747 se->e1->op == TOKarrayliteral) &&
748 se->lwr->op == TOKint64)
749 {
750 *ofs = se->lwr->toInteger();
751 return se->e1;
752 }
753 }
754 return e;
755 }
756
757 /** Return true if agg1 and agg2 are pointers to the same memory block
758 */
pointToSameMemoryBlock(Expression * agg1,Expression * agg2)759 bool pointToSameMemoryBlock(Expression *agg1, Expression *agg2)
760 {
761 if (agg1 == agg2)
762 return true;
763
764 // For integers cast to pointers, we regard them as non-comparable
765 // unless they are identical. (This may be overly strict).
766 if (agg1->op == TOKint64 && agg2->op == TOKint64 &&
767 agg1->toInteger() == agg2->toInteger())
768 {
769 return true;
770 }
771
772 // Note that type painting can occur with VarExp, so we
773 // must compare the variables being pointed to.
774 if (agg1->op == TOKvar && agg2->op == TOKvar &&
775 ((VarExp *)agg1)->var == ((VarExp *)agg2)->var)
776 {
777 return true;
778 }
779 if (agg1->op == TOKsymoff && agg2->op == TOKsymoff &&
780 ((SymOffExp *)agg1)->var == ((SymOffExp *)agg2)->var)
781 {
782 return true;
783 }
784
785 return false;
786 }
787
788 // return e1 - e2 as an integer, or error if not possible
pointerDifference(Loc loc,Type * type,Expression * e1,Expression * e2)789 UnionExp pointerDifference(Loc loc, Type *type, Expression *e1, Expression *e2)
790 {
791 UnionExp ue;
792 dinteger_t ofs1, ofs2;
793 Expression *agg1 = getAggregateFromPointer(e1, &ofs1);
794 Expression *agg2 = getAggregateFromPointer(e2, &ofs2);
795 if (agg1 == agg2)
796 {
797 Type *pointee = ((TypePointer *)agg1->type)->next;
798 dinteger_t sz = pointee->size();
799 new(&ue) IntegerExp(loc, (ofs1 - ofs2) * sz, type);
800 }
801 else if (agg1->op == TOKstring && agg2->op == TOKstring)
802 {
803 if (((StringExp *)agg1)->string == ((StringExp *)agg2)->string)
804 {
805 Type *pointee = ((TypePointer *)agg1->type)->next;
806 dinteger_t sz = pointee->size();
807 new(&ue) IntegerExp(loc, (ofs1 - ofs2) * sz, type);
808 }
809 }
810 else if (agg1->op == TOKsymoff && agg2->op == TOKsymoff &&
811 ((SymOffExp *)agg1)->var == ((SymOffExp *)agg2)->var)
812 {
813 new(&ue) IntegerExp(loc, ofs1 - ofs2, type);
814 }
815 else
816 {
817 error(loc, "%s - %s cannot be interpreted at compile time: cannot subtract "
818 "pointers to two different memory blocks",
819 e1->toChars(), e2->toChars());
820 new(&ue) CTFEExp(TOKcantexp);
821 }
822 return ue;
823 }
824
825 // Return eptr op e2, where eptr is a pointer, e2 is an integer,
826 // and op is TOKadd or TOKmin
pointerArithmetic(Loc loc,TOK op,Type * type,Expression * eptr,Expression * e2)827 UnionExp pointerArithmetic(Loc loc, TOK op, Type *type,
828 Expression *eptr, Expression *e2)
829 {
830 UnionExp ue;
831
832 if (eptr->type->nextOf()->ty == Tvoid)
833 {
834 error(loc, "cannot perform arithmetic on void* pointers at compile time");
835 Lcant:
836 new(&ue) CTFEExp(TOKcantexp);
837 return ue;
838 }
839
840 dinteger_t ofs1;
841 if (eptr->op == TOKaddress)
842 eptr = ((AddrExp *)eptr)->e1;
843 Expression *agg1 = getAggregateFromPointer(eptr, &ofs1);
844 if (agg1->op == TOKsymoff)
845 {
846 if (((SymOffExp *)agg1)->var->type->ty != Tsarray)
847 {
848 error(loc, "cannot perform pointer arithmetic on arrays of unknown length at compile time");
849 goto Lcant;
850 }
851 }
852 else if (agg1->op != TOKstring && agg1->op != TOKarrayliteral)
853 {
854 error(loc, "cannot perform pointer arithmetic on non-arrays at compile time");
855 goto Lcant;
856 }
857 dinteger_t ofs2 = e2->toInteger();
858
859 Type *pointee = ((TypeNext *)agg1->type->toBasetype())->next;
860 dinteger_t sz = pointee->size();
861
862 sinteger_t indx;
863 dinteger_t len;
864 if (agg1->op == TOKsymoff)
865 {
866 indx = ofs1 / sz;
867 len = ((TypeSArray *)((SymOffExp *)agg1)->var->type)->dim->toInteger();
868 }
869 else
870 {
871 Expression *dollar = ArrayLength(Type::tsize_t, agg1).copy();
872 assert(!CTFEExp::isCantExp(dollar));
873 indx = ofs1;
874 len = dollar->toInteger();
875 }
876 if (op == TOKadd || op == TOKaddass || op == TOKplusplus)
877 indx += ofs2 / sz;
878 else if (op == TOKmin || op == TOKminass || op == TOKminusminus)
879 indx -= ofs2 / sz;
880 else
881 {
882 error(loc, "CTFE internal error: bad pointer operation");
883 goto Lcant;
884 }
885
886 if (indx < 0 || len < (dinteger_t)indx)
887 {
888 error(loc, "cannot assign pointer to index %lld inside memory block [0..%lld]", (ulonglong)indx, (ulonglong)len);
889 goto Lcant;
890 }
891
892 if (agg1->op == TOKsymoff)
893 {
894 new(&ue) SymOffExp(loc, ((SymOffExp *)agg1)->var, indx * sz);
895 SymOffExp *se = (SymOffExp *)ue.exp();
896 se->type = type;
897 return ue;
898 }
899
900 if (agg1->op != TOKarrayliteral && agg1->op != TOKstring)
901 {
902 error(loc, "CTFE internal error: pointer arithmetic %s", agg1->toChars());
903 goto Lcant;
904 }
905
906 if (eptr->type->toBasetype()->ty == Tsarray)
907 {
908 dinteger_t dim = ((TypeSArray *)eptr->type->toBasetype())->dim->toInteger();
909
910 // Create a CTFE pointer &agg1[indx .. indx+dim]
911 SliceExp *se = new SliceExp(loc, agg1,
912 new IntegerExp(loc, indx, Type::tsize_t),
913 new IntegerExp(loc, indx + dim, Type::tsize_t));
914 se->type = type->toBasetype()->nextOf();
915 new(&ue) AddrExp(loc, se);
916 ue.exp()->type = type;
917 return ue;
918 }
919
920 // Create a CTFE pointer &agg1[indx]
921 IntegerExp *ofs = new IntegerExp(loc, indx, Type::tsize_t);
922 Expression *ie = new IndexExp(loc, agg1, ofs);
923 ie->type = type->toBasetype()->nextOf(); // Bugzilla 13992
924 new(&ue) AddrExp(loc, ie);
925 ue.exp()->type = type;
926 return ue;
927 }
928
929 // Return 1 if true, 0 if false
930 // -1 if comparison is illegal because they point to non-comparable memory blocks
comparePointers(TOK op,Expression * agg1,dinteger_t ofs1,Expression * agg2,dinteger_t ofs2)931 int comparePointers(TOK op, Expression *agg1, dinteger_t ofs1, Expression *agg2, dinteger_t ofs2)
932 {
933 if (pointToSameMemoryBlock(agg1, agg2))
934 {
935 int n;
936 switch (op)
937 {
938 case TOKlt: n = (ofs1 < ofs2); break;
939 case TOKle: n = (ofs1 <= ofs2); break;
940 case TOKgt: n = (ofs1 > ofs2); break;
941 case TOKge: n = (ofs1 >= ofs2); break;
942 case TOKidentity:
943 case TOKequal: n = (ofs1 == ofs2); break;
944 case TOKnotidentity:
945 case TOKnotequal: n = (ofs1 != ofs2); break;
946 default:
947 assert(0);
948 }
949 return n;
950 }
951 bool null1 = (agg1->op == TOKnull);
952 bool null2 = (agg2->op == TOKnull);
953
954 int cmp;
955 if (null1 || null2)
956 {
957 switch (op)
958 {
959 case TOKlt: cmp = null1 && !null2; break;
960 case TOKgt: cmp = !null1 && null2; break;
961 case TOKle: cmp = null1; break;
962 case TOKge: cmp = null2; break;
963 case TOKidentity:
964 case TOKequal:
965 case TOKnotidentity: // 'cmp' gets inverted below
966 case TOKnotequal:
967 cmp = (null1 == null2);
968 break;
969 default:
970 assert(0);
971 }
972 }
973 else
974 {
975 switch (op)
976 {
977 case TOKidentity:
978 case TOKequal:
979 case TOKnotidentity: // 'cmp' gets inverted below
980 case TOKnotequal:
981 cmp = 0;
982 break;
983 default:
984 return -1; // memory blocks are different
985 }
986 }
987 if (op == TOKnotidentity || op == TOKnotequal)
988 cmp ^= 1;
989 return cmp;
990 }
991
992 // True if conversion from type 'from' to 'to' involves a reinterpret_cast
993 // floating point -> integer or integer -> floating point
isFloatIntPaint(Type * to,Type * from)994 bool isFloatIntPaint(Type *to, Type *from)
995 {
996 return from->size() == to->size() &&
997 ((from->isintegral() && to->isfloating()) ||
998 (from->isfloating() && to->isintegral()));
999 }
1000
1001 // Reinterpret float/int value 'fromVal' as a float/integer of type 'to'.
paintFloatInt(UnionExp * pue,Expression * fromVal,Type * to)1002 Expression *paintFloatInt(UnionExp *pue, Expression *fromVal, Type *to)
1003 {
1004 if (exceptionOrCantInterpret(fromVal))
1005 return fromVal;
1006
1007 assert(to->size() == 4 || to->size() == 8);
1008 return Compiler::paintAsType(pue, fromVal, to);
1009 }
1010
1011 /******** Constant folding, with support for CTFE ***************************/
1012
1013 /// Return true if non-pointer expression e can be compared
1014 /// with >,is, ==, etc, using ctfeCmp, ctfeEqual, ctfeIdentity
isCtfeComparable(Expression * e)1015 bool isCtfeComparable(Expression *e)
1016 {
1017 if (e->op == TOKslice)
1018 e = ((SliceExp *)e)->e1;
1019
1020 if (e->isConst() != 1)
1021 {
1022 if (e->op == TOKnull ||
1023 e->op == TOKstring ||
1024 e->op == TOKfunction ||
1025 e->op == TOKdelegate ||
1026 e->op == TOKarrayliteral ||
1027 e->op == TOKstructliteral ||
1028 e->op == TOKassocarrayliteral ||
1029 e->op == TOKclassreference)
1030 {
1031 return true;
1032 }
1033 // Bugzilla 14123: TypeInfo object is comparable in CTFE
1034 if (e->op == TOKtypeid)
1035 return true;
1036
1037 return false;
1038 }
1039 return true;
1040 }
1041
1042 /// Map TOK comparison ops
1043 template <typename N>
numCmp(TOK op,N n1,N n2)1044 static bool numCmp(TOK op, N n1, N n2)
1045 {
1046 switch (op)
1047 {
1048 case TOKlt:
1049 return n1 < n2;
1050 case TOKle:
1051 return n1 <= n2;
1052 case TOKgt:
1053 return n1 > n2;
1054 case TOKge:
1055 return n1 >= n2;
1056
1057 default:
1058 assert(0);
1059 }
1060 }
1061
1062 /// Returns cmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1
specificCmp(TOK op,int rawCmp)1063 int specificCmp(TOK op, int rawCmp)
1064 {
1065 return numCmp<int>(op, rawCmp, 0);
1066 }
1067
1068 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
intUnsignedCmp(TOK op,dinteger_t n1,dinteger_t n2)1069 int intUnsignedCmp(TOK op, dinteger_t n1, dinteger_t n2)
1070 {
1071 return numCmp<dinteger_t>(op, n1, n2);
1072 }
1073
1074 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
intSignedCmp(TOK op,sinteger_t n1,sinteger_t n2)1075 int intSignedCmp(TOK op, sinteger_t n1, sinteger_t n2)
1076 {
1077 return numCmp<sinteger_t>(op, n1, n2);
1078 }
1079
1080 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
realCmp(TOK op,real_t r1,real_t r2)1081 int realCmp(TOK op, real_t r1, real_t r2)
1082 {
1083 // Don't rely on compiler, handle NAN arguments separately
1084 if (CTFloat::isNaN(r1) || CTFloat::isNaN(r2)) // if unordered
1085 {
1086 switch (op)
1087 {
1088 case TOKlt:
1089 case TOKle:
1090 case TOKgt:
1091 case TOKge:
1092 return 0;
1093
1094 default:
1095 assert(0);
1096 }
1097 }
1098 else
1099 {
1100 return numCmp<real_t>(op, r1, r2);
1101 }
1102 }
1103
1104 int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2);
1105
1106 /* Conceptually the same as memcmp(e1, e2).
1107 * e1 and e2 may be strings, arrayliterals, or slices.
1108 * For string types, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2.
1109 * For all other types, return 0 if e1 == e2, !=0 if e1 != e2.
1110 */
ctfeCmpArrays(Loc loc,Expression * e1,Expression * e2,uinteger_t len)1111 int ctfeCmpArrays(Loc loc, Expression *e1, Expression *e2, uinteger_t len)
1112 {
1113 // Resolve slices, if necessary
1114 uinteger_t lo1 = 0;
1115 uinteger_t lo2 = 0;
1116
1117 Expression *x = e1;
1118 if (x->op == TOKslice)
1119 {
1120 lo1 = ((SliceExp *)x)->lwr->toInteger();
1121 x = ((SliceExp *)x)->e1;
1122 }
1123 StringExp *se1 = (x->op == TOKstring) ? (StringExp *)x : NULL;
1124 ArrayLiteralExp *ae1 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : NULL;
1125
1126 x = e2;
1127 if (x->op == TOKslice)
1128 {
1129 lo2 = ((SliceExp *)x)->lwr->toInteger();
1130 x = ((SliceExp *)x)->e1;
1131 }
1132 StringExp *se2 = (x->op == TOKstring) ? (StringExp *)x : NULL;
1133 ArrayLiteralExp *ae2 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : NULL;
1134
1135 // Now both must be either TOKarrayliteral or TOKstring
1136 if (se1 && se2)
1137 return sliceCmpStringWithString(se1, se2, (size_t)lo1, (size_t)lo2, (size_t)len);
1138 if (se1 && ae2)
1139 return sliceCmpStringWithArray(se1, ae2, (size_t)lo1, (size_t)lo2, (size_t)len);
1140 if (se2 && ae1)
1141 return -sliceCmpStringWithArray(se2, ae1, (size_t)lo2, (size_t)lo1, (size_t)len);
1142
1143 assert (ae1 && ae2);
1144 // Comparing two array literals. This case is potentially recursive.
1145 // If they aren't strings, we just need an equality check rather than
1146 // a full cmp.
1147 bool needCmp = ae1->type->nextOf()->isintegral();
1148 for (size_t i = 0; i < (size_t)len; i++)
1149 {
1150 Expression *ee1 = (*ae1->elements)[(size_t)(lo1 + i)];
1151 Expression *ee2 = (*ae2->elements)[(size_t)(lo2 + i)];
1152 if (needCmp)
1153 {
1154 sinteger_t c = ee1->toInteger() - ee2->toInteger();
1155 if (c > 0)
1156 return 1;
1157 if (c < 0)
1158 return -1;
1159 }
1160 else
1161 {
1162 if (ctfeRawCmp(loc, ee1, ee2))
1163 return 1;
1164 }
1165 }
1166 return 0;
1167 }
1168
1169 /* Given a delegate expression e, return .funcptr.
1170 * If e is NullExp, return NULL.
1171 */
funcptrOf(Expression * e)1172 FuncDeclaration *funcptrOf(Expression *e)
1173 {
1174 assert(e->type->ty == Tdelegate);
1175
1176 if (e->op == TOKdelegate)
1177 return ((DelegateExp *)e)->func;
1178 if (e->op == TOKfunction)
1179 return ((FuncExp *)e)->fd;
1180 assert(e->op == TOKnull);
1181 return NULL;
1182 }
1183
isArray(Expression * e)1184 bool isArray(Expression *e)
1185 {
1186 return e->op == TOKarrayliteral || e->op == TOKstring ||
1187 e->op == TOKslice || e->op == TOKnull;
1188 }
1189
1190 /* For strings, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2.
1191 * For all other types, return 0 if e1 == e2, !=0 if e1 != e2.
1192 */
ctfeRawCmp(Loc loc,Expression * e1,Expression * e2)1193 int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2)
1194 {
1195 if (e1->op == TOKclassreference || e2->op == TOKclassreference)
1196 {
1197 if (e1->op == TOKclassreference && e2->op == TOKclassreference &&
1198 ((ClassReferenceExp *)e1)->value == ((ClassReferenceExp *)e2)->value)
1199 return 0;
1200 return 1;
1201 }
1202 if (e1->op == TOKtypeid && e2->op == TOKtypeid)
1203 {
1204 // printf("e1: %s\n", e1->toChars());
1205 // printf("e2: %s\n", e2->toChars());
1206 Type *t1 = isType(((TypeidExp *)e1)->obj);
1207 Type *t2 = isType(((TypeidExp *)e2)->obj);
1208 assert(t1);
1209 assert(t2);
1210 return t1 != t2;
1211 }
1212
1213 // null == null, regardless of type
1214
1215 if (e1->op == TOKnull && e2->op == TOKnull)
1216 return 0;
1217
1218 if (e1->type->ty == Tpointer && e2->type->ty == Tpointer)
1219 {
1220 // Can only be an equality test.
1221
1222 dinteger_t ofs1, ofs2;
1223 Expression *agg1 = getAggregateFromPointer(e1, &ofs1);
1224 Expression *agg2 = getAggregateFromPointer(e2, &ofs2);
1225 if ((agg1 == agg2) || (agg1->op == TOKvar && agg2->op == TOKvar &&
1226 ((VarExp *)agg1)->var == ((VarExp *)agg2)->var))
1227 {
1228 if (ofs1 == ofs2)
1229 return 0;
1230 }
1231 return 1;
1232 }
1233 if (e1->type->ty == Tdelegate && e2->type->ty == Tdelegate)
1234 {
1235 // If .funcptr isn't the same, they are not equal
1236
1237 if (funcptrOf(e1) != funcptrOf(e2))
1238 return 1;
1239
1240 // If both are delegate literals, assume they have the
1241 // same closure pointer. TODO: We don't support closures yet!
1242 if (e1->op == TOKfunction && e2->op == TOKfunction)
1243 return 0;
1244 assert(e1->op == TOKdelegate && e2->op == TOKdelegate);
1245
1246 // Same .funcptr. Do they have the same .ptr?
1247 Expression * ptr1 = ((DelegateExp *)e1)->e1;
1248 Expression * ptr2 = ((DelegateExp *)e2)->e1;
1249
1250 dinteger_t ofs1, ofs2;
1251 Expression *agg1 = getAggregateFromPointer(ptr1, &ofs1);
1252 Expression *agg2 = getAggregateFromPointer(ptr2, &ofs2);
1253 // If they are TOKvar, it means they are FuncDeclarations
1254 if ((agg1 == agg2 && ofs1 == ofs2) ||
1255 (agg1->op == TOKvar && agg2->op == TOKvar &&
1256 ((VarExp *)agg1)->var == ((VarExp *)agg2)->var))
1257 {
1258 return 0;
1259 }
1260 return 1;
1261 }
1262 if (isArray(e1) && isArray(e2))
1263 {
1264 uinteger_t len1 = resolveArrayLength(e1);
1265 uinteger_t len2 = resolveArrayLength(e2);
1266 // workaround for dmc optimizer bug calculating wrong len for
1267 // uinteger_t len = (len1 < len2 ? len1 : len2);
1268 // if (len == 0) ...
1269 if (len1 > 0 && len2 > 0)
1270 {
1271 uinteger_t len = (len1 < len2 ? len1 : len2);
1272 int res = ctfeCmpArrays(loc, e1, e2, len);
1273 if (res != 0)
1274 return res;
1275 }
1276 return (int)(len1 - len2);
1277 }
1278 if (e1->type->isintegral())
1279 {
1280 return e1->toInteger() != e2->toInteger();
1281 }
1282 real_t r1;
1283 real_t r2;
1284 if (e1->type->isreal())
1285 {
1286 r1 = e1->toReal();
1287 r2 = e2->toReal();
1288 goto L1;
1289 }
1290 else if (e1->type->isimaginary())
1291 {
1292 r1 = e1->toImaginary();
1293 r2 = e2->toImaginary();
1294 L1:
1295 if (CTFloat::isNaN(r1) || CTFloat::isNaN(r2)) // if unordered
1296 {
1297 return 1;
1298 }
1299 else
1300 {
1301 return (r1 != r2);
1302 }
1303 }
1304 else if (e1->type->iscomplex())
1305 {
1306 return e1->toComplex() != e2->toComplex();
1307 }
1308
1309 if (e1->op == TOKstructliteral && e2->op == TOKstructliteral)
1310 {
1311 StructLiteralExp *es1 = (StructLiteralExp *)e1;
1312 StructLiteralExp *es2 = (StructLiteralExp *)e2;
1313 // For structs, we only need to return 0 or 1 (< and > aren't legal).
1314
1315 if (es1->sd != es2->sd)
1316 return 1;
1317 else if ((!es1->elements || !es1->elements->dim) &&
1318 (!es2->elements || !es2->elements->dim))
1319 return 0; // both arrays are empty
1320 else if (!es1->elements || !es2->elements)
1321 return 1;
1322 else if (es1->elements->dim != es2->elements->dim)
1323 return 1;
1324 else
1325 {
1326 for (size_t i = 0; i < es1->elements->dim; i++)
1327 {
1328 Expression *ee1 = (*es1->elements)[i];
1329 Expression *ee2 = (*es2->elements)[i];
1330
1331 if (ee1 == ee2)
1332 continue;
1333 if (!ee1 || !ee2)
1334 return 1;
1335 int cmp = ctfeRawCmp(loc, ee1, ee2);
1336 if (cmp)
1337 return 1;
1338 }
1339 return 0; // All elements are equal
1340 }
1341 }
1342 if (e1->op == TOKassocarrayliteral && e2->op == TOKassocarrayliteral)
1343 {
1344 AssocArrayLiteralExp *es1 = (AssocArrayLiteralExp *)e1;
1345 AssocArrayLiteralExp *es2 = (AssocArrayLiteralExp *)e2;
1346
1347 size_t dim = es1->keys->dim;
1348 if (es2->keys->dim != dim)
1349 return 1;
1350
1351 bool *used = (bool *)mem.xmalloc(sizeof(bool) * dim);
1352 memset(used, 0, sizeof(bool) * dim);
1353
1354 for (size_t i = 0; i < dim; ++i)
1355 {
1356 Expression *k1 = (*es1->keys)[i];
1357 Expression *v1 = (*es1->values)[i];
1358 Expression *v2 = NULL;
1359 for (size_t j = 0; j < dim; ++j)
1360 {
1361 if (used[j])
1362 continue;
1363 Expression *k2 = (*es2->keys)[j];
1364
1365 if (ctfeRawCmp(loc, k1, k2))
1366 continue;
1367 used[j] = true;
1368 v2 = (*es2->values)[j];
1369 break;
1370 }
1371 if (!v2 || ctfeRawCmp(loc, v1, v2))
1372 {
1373 mem.xfree(used);
1374 return 1;
1375 }
1376 }
1377 mem.xfree(used);
1378 return 0;
1379 }
1380 error(loc, "CTFE internal error: bad compare of `%s` and `%s`", e1->toChars(), e2->toChars());
1381 assert(0);
1382 return 0;
1383 }
1384
1385 /// Evaluate ==, !=. Resolves slices before comparing. Returns 0 or 1
ctfeEqual(Loc loc,TOK op,Expression * e1,Expression * e2)1386 int ctfeEqual(Loc loc, TOK op, Expression *e1, Expression *e2)
1387 {
1388 int cmp = !ctfeRawCmp(loc, e1, e2);
1389 if (op == TOKnotequal)
1390 cmp ^= 1;
1391 return cmp;
1392 }
1393
1394 /// Evaluate is, !is. Resolves slices before comparing. Returns 0 or 1
ctfeIdentity(Loc loc,TOK op,Expression * e1,Expression * e2)1395 int ctfeIdentity(Loc loc, TOK op, Expression *e1, Expression *e2)
1396 {
1397 //printf("ctfeIdentity op = '%s', e1 = %s %s, e2 = %s %s\n", Token::toChars(op),
1398 // Token::toChars(e1->op), e1->toChars(), Token::toChars(e2->op), e1->toChars());
1399 int cmp;
1400 if (e1->op == TOKnull)
1401 {
1402 cmp = (e2->op == TOKnull);
1403 }
1404 else if (e2->op == TOKnull)
1405 {
1406 cmp = 0;
1407 }
1408 else if (e1->op == TOKsymoff && e2->op == TOKsymoff)
1409 {
1410 SymOffExp *es1 = (SymOffExp *)e1;
1411 SymOffExp *es2 = (SymOffExp *)e2;
1412 cmp = (es1->var == es2->var && es1->offset == es2->offset);
1413 }
1414 else if (e1->type->isreal())
1415 cmp = RealEquals(e1->toReal(), e2->toReal());
1416 else if (e1->type->isimaginary())
1417 cmp = RealEquals(e1->toImaginary(), e2->toImaginary());
1418 else if (e1->type->iscomplex())
1419 {
1420 complex_t v1 = e1->toComplex();
1421 complex_t v2 = e2->toComplex();
1422 cmp = RealEquals(creall(v1), creall(v2)) &&
1423 RealEquals(cimagl(v1), cimagl(v1));
1424 }
1425 else
1426 cmp = !ctfeRawCmp(loc, e1, e2);
1427
1428 if (op == TOKnotidentity || op == TOKnotequal)
1429 cmp ^= 1;
1430 return cmp;
1431 }
1432
1433 /// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1
ctfeCmp(Loc loc,TOK op,Expression * e1,Expression * e2)1434 int ctfeCmp(Loc loc, TOK op, Expression *e1, Expression *e2)
1435 {
1436 Type *t1 = e1->type->toBasetype();
1437 Type *t2 = e2->type->toBasetype();
1438
1439 if (t1->isString() && t2->isString())
1440 return specificCmp(op, ctfeRawCmp(loc, e1, e2));
1441 else if (t1->isreal())
1442 return realCmp(op, e1->toReal(), e2->toReal());
1443 else if (t1->isimaginary())
1444 return realCmp(op, e1->toImaginary(), e2->toImaginary());
1445 else if (t1->isunsigned() || t2->isunsigned())
1446 return intUnsignedCmp(op, e1->toInteger(), e2->toInteger());
1447 else
1448 return intSignedCmp(op, e1->toInteger(), e2->toInteger());
1449 }
1450
ctfeCat(Loc loc,Type * type,Expression * e1,Expression * e2)1451 UnionExp ctfeCat(Loc loc, Type *type, Expression *e1, Expression *e2)
1452 {
1453 Type *t1 = e1->type->toBasetype();
1454 Type *t2 = e2->type->toBasetype();
1455 UnionExp ue;
1456 if (e2->op == TOKstring && e1->op == TOKarrayliteral &&
1457 t1->nextOf()->isintegral())
1458 {
1459 // [chars] ~ string => string (only valid for CTFE)
1460 StringExp *es1 = (StringExp *)e2;
1461 ArrayLiteralExp *es2 = (ArrayLiteralExp *)e1;
1462 size_t len = es1->len + es2->elements->dim;
1463 unsigned char sz = es1->sz;
1464
1465 void *s = mem.xmalloc((len + 1) * sz);
1466 memcpy((char *)s + sz * es2->elements->dim, es1->string, es1->len * sz);
1467 for (size_t i = 0; i < es2->elements->dim; i++)
1468 {
1469 Expression *es2e = (*es2->elements)[i];
1470 if (es2e->op != TOKint64)
1471 {
1472 new(&ue) CTFEExp(TOKcantexp);
1473 return ue;
1474 }
1475 dinteger_t v = es2e->toInteger();
1476 Port::valcpy((utf8_t *)s + i * sz, v, sz);
1477 }
1478
1479 // Add terminating 0
1480 memset((utf8_t *)s + len * sz, 0, sz);
1481
1482 new(&ue) StringExp(loc, s, len);
1483 StringExp *es = (StringExp *)ue.exp();
1484 es->sz = sz;
1485 es->committed = 0;
1486 es->type = type;
1487 return ue;
1488 }
1489 if (e1->op == TOKstring && e2->op == TOKarrayliteral &&
1490 t2->nextOf()->isintegral())
1491 {
1492 // string ~ [chars] => string (only valid for CTFE)
1493 // Concatenate the strings
1494 StringExp *es1 = (StringExp *)e1;
1495 ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
1496 size_t len = es1->len + es2->elements->dim;
1497 unsigned char sz = es1->sz;
1498
1499 void *s = mem.xmalloc((len + 1) * sz);
1500 memcpy(s, es1->string, es1->len * sz);
1501 for (size_t i = 0; i < es2->elements->dim; i++)
1502 {
1503 Expression *es2e = (*es2->elements)[i];
1504 if (es2e->op != TOKint64)
1505 {
1506 new(&ue) CTFEExp(TOKcantexp);
1507 return ue;
1508 }
1509 dinteger_t v = es2e->toInteger();
1510 Port::valcpy((utf8_t *)s + (es1->len + i) * sz, v, sz);
1511 }
1512
1513 // Add terminating 0
1514 memset((utf8_t *)s + len * sz, 0, sz);
1515
1516 new(&ue) StringExp(loc, s, len);
1517 StringExp *es = (StringExp *)ue.exp();
1518 es->sz = sz;
1519 es->committed = 0; //es1->committed;
1520 es->type = type;
1521 return ue;
1522 }
1523 if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral &&
1524 t1->nextOf()->equals(t2->nextOf()))
1525 {
1526 // [ e1 ] ~ [ e2 ] ---> [ e1, e2 ]
1527 ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
1528 ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
1529
1530 new(&ue) ArrayLiteralExp(es1->loc, type, copyLiteralArray(es1->elements));
1531 es1 = (ArrayLiteralExp *)ue.exp();
1532 es1->elements->insert(es1->elements->dim, copyLiteralArray(es2->elements));
1533 return ue;
1534 }
1535 if (e1->op == TOKarrayliteral && e2->op == TOKnull &&
1536 t1->nextOf()->equals(t2->nextOf()))
1537 {
1538 // [ e1 ] ~ null ----> [ e1 ].dup
1539 ue = paintTypeOntoLiteralCopy(type, copyLiteral(e1).copy());
1540 return ue;
1541 }
1542 if (e1->op == TOKnull && e2->op == TOKarrayliteral &&
1543 t1->nextOf()->equals(t2->nextOf()))
1544 {
1545 // null ~ [ e2 ] ----> [ e2 ].dup
1546 ue = paintTypeOntoLiteralCopy(type, copyLiteral(e2).copy());
1547 return ue;
1548 }
1549 ue = Cat(type, e1, e2);
1550 return ue;
1551 }
1552
1553 /* Given an AA literal 'ae', and a key 'e2':
1554 * Return ae[e2] if present, or NULL if not found.
1555 */
findKeyInAA(Loc loc,AssocArrayLiteralExp * ae,Expression * e2)1556 Expression *findKeyInAA(Loc loc, AssocArrayLiteralExp *ae, Expression *e2)
1557 {
1558 /* Search the keys backwards, in case there are duplicate keys
1559 */
1560 for (size_t i = ae->keys->dim; i;)
1561 {
1562 i--;
1563 Expression *ekey = (*ae->keys)[i];
1564 int eq = ctfeEqual(loc, TOKequal, ekey, e2);
1565 if (eq)
1566 {
1567 return (*ae->values)[i];
1568 }
1569 }
1570 return NULL;
1571 }
1572
1573 /* Same as for constfold.Index, except that it only works for static arrays,
1574 * dynamic arrays, and strings. We know that e1 is an
1575 * interpreted CTFE expression, so it cannot have side-effects.
1576 */
ctfeIndex(Loc loc,Type * type,Expression * e1,uinteger_t indx)1577 Expression *ctfeIndex(Loc loc, Type *type, Expression *e1, uinteger_t indx)
1578 {
1579 //printf("ctfeIndex(e1 = %s)\n", e1->toChars());
1580 assert(e1->type);
1581 if (e1->op == TOKstring)
1582 {
1583 StringExp *es1 = (StringExp *)e1;
1584 if (indx >= es1->len)
1585 {
1586 error(loc, "string index %llu is out of bounds [0 .. %llu]", (ulonglong)indx, (ulonglong)es1->len);
1587 return CTFEExp::cantexp;
1588 }
1589 return new IntegerExp(loc, es1->charAt(indx), type);
1590 }
1591 assert(e1->op == TOKarrayliteral);
1592 {
1593 ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
1594 if (indx >= ale->elements->dim)
1595 {
1596 error(loc, "array index %llu is out of bounds %s[0 .. %llu]", (ulonglong)indx, e1->toChars(), (ulonglong)ale->elements->dim);
1597 return CTFEExp::cantexp;
1598 }
1599 Expression *e = (*ale->elements)[(size_t)indx];
1600 return paintTypeOntoLiteral(type, e);
1601 }
1602 }
1603
ctfeCast(UnionExp * pue,Loc loc,Type * type,Type * to,Expression * e)1604 Expression *ctfeCast(UnionExp *pue, Loc loc, Type *type, Type *to, Expression *e)
1605 {
1606 if (e->op == TOKnull)
1607 return paintTypeOntoLiteral(pue, to, e);
1608
1609 if (e->op == TOKclassreference)
1610 {
1611 // Disallow reinterpreting class casts. Do this by ensuring that
1612 // the original class can implicitly convert to the target class
1613 ClassDeclaration *originalClass = ((ClassReferenceExp *)e)->originalClass();
1614 if (originalClass->type->implicitConvTo(to->mutableOf()))
1615 return paintTypeOntoLiteral(pue, to, e);
1616 else
1617 {
1618 new(pue) NullExp(loc, to);
1619 return pue->exp();
1620 }
1621 }
1622
1623 // Allow TypeInfo type painting
1624 if (isTypeInfo_Class(e->type) && e->type->implicitConvTo(to))
1625 return paintTypeOntoLiteral(pue, to, e);
1626
1627 // Allow casting away const for struct literals
1628 if (e->op == TOKstructliteral &&
1629 e->type->toBasetype()->castMod(0) == to->toBasetype()->castMod(0))
1630 return paintTypeOntoLiteral(pue, to, e);
1631
1632 Expression *r;
1633 if (e->type->equals(type) && type->equals(to))
1634 {
1635 // necessary not to change e's address for pointer comparisons
1636 r = e;
1637 }
1638 else if (to->toBasetype()->ty == Tarray &&
1639 type->toBasetype()->ty == Tarray &&
1640 to->toBasetype()->nextOf()->size() == type->toBasetype()->nextOf()->size())
1641 {
1642 // Bugzilla 12495: Array reinterpret casts: eg. string to immutable(ubyte)[]
1643 return paintTypeOntoLiteral(pue, to, e);
1644 }
1645 else
1646 {
1647 *pue = Cast(loc, type, to, e);
1648 r = pue->exp();
1649 }
1650
1651 if (CTFEExp::isCantExp(r))
1652 error(loc, "cannot cast %s to %s at compile time", e->toChars(), to->toChars());
1653
1654 if (e->op == TOKarrayliteral)
1655 ((ArrayLiteralExp *)e)->ownedByCtfe = OWNEDctfe;
1656
1657 if (e->op == TOKstring)
1658 ((StringExp *)e)->ownedByCtfe = OWNEDctfe;
1659
1660 return r;
1661 }
1662
1663 /******** Assignment helper functions ***************************/
1664
1665 /* Set dest = src, where both dest and src are container value literals
1666 * (ie, struct literals, or static arrays (can be an array literal or a string))
1667 * Assignment is recursively in-place.
1668 * Purpose: any reference to a member of 'dest' will remain valid after the
1669 * assignment.
1670 */
assignInPlace(Expression * dest,Expression * src)1671 void assignInPlace(Expression *dest, Expression *src)
1672 {
1673 assert(dest->op == TOKstructliteral ||
1674 dest->op == TOKarrayliteral ||
1675 dest->op == TOKstring);
1676 Expressions *oldelems;
1677 Expressions *newelems;
1678 if (dest->op == TOKstructliteral)
1679 {
1680 assert(dest->op == src->op);
1681 oldelems = ((StructLiteralExp *)dest)->elements;
1682 newelems = ((StructLiteralExp *)src)->elements;
1683 if (((StructLiteralExp *)dest)->sd->isNested() && oldelems->dim == newelems->dim - 1)
1684 oldelems->push(NULL);
1685 }
1686 else if (dest->op == TOKarrayliteral && src->op==TOKarrayliteral)
1687 {
1688 oldelems = ((ArrayLiteralExp *)dest)->elements;
1689 newelems = ((ArrayLiteralExp *)src)->elements;
1690 }
1691 else if (dest->op == TOKstring && src->op == TOKstring)
1692 {
1693 sliceAssignStringFromString((StringExp *)dest, (StringExp *)src, 0);
1694 return;
1695 }
1696 else if (dest->op == TOKarrayliteral && src->op == TOKstring)
1697 {
1698 sliceAssignArrayLiteralFromString((ArrayLiteralExp *)dest, (StringExp *)src, 0);
1699 return;
1700 }
1701 else if (src->op == TOKarrayliteral && dest->op == TOKstring)
1702 {
1703 sliceAssignStringFromArrayLiteral((StringExp *)dest, (ArrayLiteralExp *)src, 0);
1704 return;
1705 }
1706 else
1707 assert(0);
1708
1709 assert(oldelems->dim == newelems->dim);
1710
1711 for (size_t i= 0; i < oldelems->dim; ++i)
1712 {
1713 Expression *e = (*newelems)[i];
1714 Expression *o = (*oldelems)[i];
1715 if (e->op == TOKstructliteral)
1716 {
1717 assert(o->op == e->op);
1718 assignInPlace(o, e);
1719 }
1720 else if (e->type->ty == Tsarray && e->op != TOKvoid &&
1721 o->type->ty == Tsarray)
1722 {
1723 assignInPlace(o, e);
1724 }
1725 else
1726 {
1727 (*oldelems)[i] = (*newelems)[i];
1728 }
1729 }
1730 }
1731
1732 // Duplicate the elements array, then set field 'indexToChange' = newelem.
changeOneElement(Expressions * oldelems,size_t indexToChange,Expression * newelem)1733 Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, Expression *newelem)
1734 {
1735 Expressions *expsx = new Expressions();
1736 ++CtfeStatus::numArrayAllocs;
1737 expsx->setDim(oldelems->dim);
1738 for (size_t j = 0; j < expsx->dim; j++)
1739 {
1740 if (j == indexToChange)
1741 (*expsx)[j] = newelem;
1742 else
1743 (*expsx)[j] = (*oldelems)[j];
1744 }
1745 return expsx;
1746 }
1747
1748 // Given an AA literal aae, set aae[index] = newval and return newval.
assignAssocArrayElement(Loc loc,AssocArrayLiteralExp * aae,Expression * index,Expression * newval)1749 Expression *assignAssocArrayElement(Loc loc, AssocArrayLiteralExp *aae,
1750 Expression *index, Expression *newval)
1751 {
1752 /* Create new associative array literal reflecting updated key/value
1753 */
1754 Expressions *keysx = aae->keys;
1755 Expressions *valuesx = aae->values;
1756 int updated = 0;
1757 for (size_t j = valuesx->dim; j; )
1758 {
1759 j--;
1760 Expression *ekey = (*aae->keys)[j];
1761 int eq = ctfeEqual(loc, TOKequal, ekey, index);
1762 if (eq)
1763 {
1764 (*valuesx)[j] = newval;
1765 updated = 1;
1766 }
1767 }
1768 if (!updated)
1769 {
1770 // Append index/newval to keysx[]/valuesx[]
1771 valuesx->push(newval);
1772 keysx->push(index);
1773 }
1774 return newval;
1775 }
1776
1777 /// Given array literal oldval of type ArrayLiteralExp or StringExp, of length
1778 /// oldlen, change its length to newlen. If the newlen is longer than oldlen,
1779 /// all new elements will be set to the default initializer for the element type.
changeArrayLiteralLength(Loc loc,TypeArray * arrayType,Expression * oldval,size_t oldlen,size_t newlen)1780 UnionExp changeArrayLiteralLength(Loc loc, TypeArray *arrayType,
1781 Expression *oldval, size_t oldlen, size_t newlen)
1782 {
1783 UnionExp ue;
1784 Type *elemType = arrayType->next;
1785 assert(elemType);
1786 Expression *defaultElem = elemType->defaultInitLiteral(loc);
1787 Expressions *elements = new Expressions();
1788 elements->setDim(newlen);
1789
1790 // Resolve slices
1791 size_t indxlo = 0;
1792 if (oldval->op == TOKslice)
1793 {
1794 indxlo = (size_t)((SliceExp *)oldval)->lwr->toInteger();
1795 oldval = ((SliceExp *)oldval)->e1;
1796 }
1797 size_t copylen = oldlen < newlen ? oldlen : newlen;
1798 if (oldval->op == TOKstring)
1799 {
1800 StringExp *oldse = (StringExp *)oldval;
1801 void *s = mem.xcalloc(newlen + 1, oldse->sz);
1802 memcpy(s, oldse->string, copylen * oldse->sz);
1803 unsigned defaultValue = (unsigned)(defaultElem->toInteger());
1804 for (size_t elemi = copylen; elemi < newlen; ++elemi)
1805 {
1806 switch (oldse->sz)
1807 {
1808 case 1: (( utf8_t *)s)[(size_t)(indxlo + elemi)] = ( utf8_t)defaultValue; break;
1809 case 2: ((utf16_t *)s)[(size_t)(indxlo + elemi)] = (utf16_t)defaultValue; break;
1810 case 4: ((utf32_t *)s)[(size_t)(indxlo + elemi)] = (utf32_t)defaultValue; break;
1811 default: assert(0);
1812 }
1813 }
1814 new(&ue) StringExp(loc, s, newlen);
1815 StringExp *se = (StringExp *)ue.exp();
1816 se->type = arrayType;
1817 se->sz = oldse->sz;
1818 se->committed = oldse->committed;
1819 se->ownedByCtfe = OWNEDctfe;
1820 }
1821 else
1822 {
1823 if (oldlen != 0)
1824 {
1825 assert(oldval->op == TOKarrayliteral);
1826 ArrayLiteralExp *ae = (ArrayLiteralExp *)oldval;
1827 for (size_t i = 0; i < copylen; i++)
1828 (*elements)[i] = (*ae->elements)[indxlo + i];
1829 }
1830 if (elemType->ty == Tstruct || elemType->ty == Tsarray)
1831 {
1832 /* If it is an aggregate literal representing a value type,
1833 * we need to create a unique copy for each element
1834 */
1835 for (size_t i = copylen; i < newlen; i++)
1836 (*elements)[i] = copyLiteral(defaultElem).copy();
1837 }
1838 else
1839 {
1840 for (size_t i = copylen; i < newlen; i++)
1841 (*elements)[i] = defaultElem;
1842 }
1843 new(&ue) ArrayLiteralExp(loc, arrayType, elements);
1844 ArrayLiteralExp *aae = (ArrayLiteralExp *)ue.exp();
1845 aae->ownedByCtfe = OWNEDctfe;
1846 }
1847 return ue;
1848 }
1849
1850 /*************************** CTFE Sanity Checks ***************************/
1851
isCtfeValueValid(Expression * newval)1852 bool isCtfeValueValid(Expression *newval)
1853 {
1854 Type *tb = newval->type->toBasetype();
1855
1856 if (newval->op == TOKint64 ||
1857 newval->op == TOKfloat64 ||
1858 newval->op == TOKchar ||
1859 newval->op == TOKcomplex80)
1860 {
1861 return tb->isscalar();
1862 }
1863 if (newval->op == TOKnull)
1864 {
1865 return tb->ty == Tnull ||
1866 tb->ty == Tpointer ||
1867 tb->ty == Tarray ||
1868 tb->ty == Taarray ||
1869 tb->ty == Tclass ||
1870 tb->ty == Tdelegate;
1871 }
1872
1873 if (newval->op == TOKstring)
1874 return true; // CTFE would directly use the StringExp in AST.
1875 if (newval->op == TOKarrayliteral)
1876 return true; //((ArrayLiteralExp *)newval)->ownedByCtfe;
1877 if (newval->op == TOKassocarrayliteral)
1878 return true; //((AssocArrayLiteralExp *)newval)->ownedByCtfe;
1879 if (newval->op == TOKstructliteral)
1880 return true; //((StructLiteralExp *)newval)->ownedByCtfe;
1881 if (newval->op == TOKclassreference)
1882 return true;
1883
1884 if (newval->op == TOKvector)
1885 return true; // vector literal
1886
1887 if (newval->op == TOKfunction)
1888 return true; // function literal or delegate literal
1889 if (newval->op == TOKdelegate)
1890 {
1891 // &struct.func or &clasinst.func
1892 // &nestedfunc
1893 Expression *ethis = ((DelegateExp *)newval)->e1;
1894 return (ethis->op == TOKstructliteral ||
1895 ethis->op == TOKclassreference ||
1896 (ethis->op == TOKvar && ((VarExp *)ethis)->var == ((DelegateExp *)newval)->func));
1897 }
1898 if (newval->op == TOKsymoff)
1899 {
1900 // function pointer, or pointer to static variable
1901 Declaration *d = ((SymOffExp *)newval)->var;
1902 return d->isFuncDeclaration() || d->isDataseg();
1903 }
1904 if (newval->op == TOKtypeid)
1905 {
1906 // always valid
1907 return true;
1908 }
1909 if (newval->op == TOKaddress)
1910 {
1911 // e1 should be a CTFE reference
1912 Expression *e1 = ((AddrExp *)newval)->e1;
1913 return tb->ty == Tpointer &&
1914 (((e1->op == TOKstructliteral || e1->op == TOKarrayliteral) && isCtfeValueValid(e1)) ||
1915 (e1->op == TOKvar) ||
1916 (e1->op == TOKdotvar && isCtfeReferenceValid(e1)) ||
1917 (e1->op == TOKindex && isCtfeReferenceValid(e1)) ||
1918 (e1->op == TOKslice && e1->type->toBasetype()->ty == Tsarray));
1919 }
1920 if (newval->op == TOKslice)
1921 {
1922 // e1 should be an array aggregate
1923 SliceExp *se = (SliceExp *)newval;
1924 assert(se->lwr && se->lwr->op == TOKint64);
1925 assert(se->upr && se->upr->op == TOKint64);
1926 return (tb->ty == Tarray ||
1927 tb->ty == Tsarray) &&
1928 (se->e1->op == TOKstring ||
1929 se->e1->op == TOKarrayliteral);
1930 }
1931
1932 if (newval->op == TOKvoid)
1933 return true; // uninitialized value
1934
1935 newval->error("CTFE internal error: illegal CTFE value %s", newval->toChars());
1936 return false;
1937 }
1938
isCtfeReferenceValid(Expression * newval)1939 bool isCtfeReferenceValid(Expression *newval)
1940 {
1941 if (newval->op == TOKthis)
1942 return true;
1943 if (newval->op == TOKvar)
1944 {
1945 VarDeclaration *v = ((VarExp *)newval)->var->isVarDeclaration();
1946 assert(v);
1947 // Must not be a reference to a reference
1948 return true;
1949 }
1950 if (newval->op == TOKindex)
1951 {
1952 Expression *eagg = ((IndexExp *)newval)->e1;
1953 return eagg->op == TOKstring ||
1954 eagg->op == TOKarrayliteral ||
1955 eagg->op == TOKassocarrayliteral;
1956 }
1957 if (newval->op == TOKdotvar)
1958 {
1959 Expression *eagg = ((DotVarExp *)newval)->e1;
1960 return (eagg->op == TOKstructliteral || eagg->op == TOKclassreference) &&
1961 isCtfeValueValid(eagg);
1962 }
1963
1964 // Internally a ref variable may directly point a stack memory.
1965 // e.g. ref int v = 1;
1966 return isCtfeValueValid(newval);
1967 }
1968
1969 // Used for debugging only
showCtfeExpr(Expression * e,int level)1970 void showCtfeExpr(Expression *e, int level)
1971 {
1972 for (int i = level; i > 0; --i) printf(" ");
1973 Expressions *elements = NULL;
1974 // We need the struct definition to detect block assignment
1975 StructDeclaration *sd = NULL;
1976 ClassDeclaration *cd = NULL;
1977 if (e->op == TOKstructliteral)
1978 {
1979 elements = ((StructLiteralExp *)e)->elements;
1980 sd = ((StructLiteralExp *)e)->sd;
1981 printf("STRUCT type = %s %p:\n", e->type->toChars(),
1982 e);
1983 }
1984 else if (e->op == TOKclassreference)
1985 {
1986 elements = ((ClassReferenceExp *)e)->value->elements;
1987 cd = ((ClassReferenceExp *)e)->originalClass();
1988 printf("CLASS type = %s %p:\n", e->type->toChars(),
1989 ((ClassReferenceExp *)e)->value);
1990 }
1991 else if (e->op == TOKarrayliteral)
1992 {
1993 elements = ((ArrayLiteralExp *)e)->elements;
1994 printf("ARRAY LITERAL type=%s %p:\n", e->type->toChars(),
1995 e);
1996 }
1997 else if (e->op == TOKassocarrayliteral)
1998 {
1999 printf("AA LITERAL type=%s %p:\n", e->type->toChars(),
2000 e);
2001 }
2002 else if (e->op == TOKstring)
2003 {
2004 printf("STRING %s %p\n", e->toChars(),
2005 ((StringExp *)e)->string);
2006 }
2007 else if (e->op == TOKslice)
2008 {
2009 printf("SLICE %p: %s\n", e, e->toChars());
2010 showCtfeExpr(((SliceExp *)e)->e1, level + 1);
2011 }
2012 else if (e->op == TOKvar)
2013 {
2014 printf("VAR %p %s\n", e, e->toChars());
2015 VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration();
2016 if (v && getValue(v))
2017 showCtfeExpr(getValue(v), level + 1);
2018 }
2019 else if (e->op == TOKaddress)
2020 {
2021 // This is potentially recursive. We mustn't try to print the thing we're pointing to.
2022 printf("POINTER %p to %p: %s\n", e, ((AddrExp *)e)->e1, e->toChars());
2023 }
2024 else
2025 printf("VALUE %p: %s\n", e, e->toChars());
2026
2027 if (elements)
2028 {
2029 size_t fieldsSoFar = 0;
2030 for (size_t i = 0; i < elements->dim; i++)
2031 {
2032 Expression *z = NULL;
2033 VarDeclaration *v = NULL;
2034 if (i > 15)
2035 {
2036 printf("...(total %d elements)\n", (int)elements->dim);
2037 return;
2038 }
2039 if (sd)
2040 {
2041 v = sd->fields[i];
2042 z = (*elements)[i];
2043 }
2044 else if (cd)
2045 {
2046 while (i - fieldsSoFar >= cd->fields.dim)
2047 {
2048 fieldsSoFar += cd->fields.dim;
2049 cd = cd->baseClass;
2050 for (int j = level; j > 0; --j) printf(" ");
2051 printf(" BASE CLASS: %s\n", cd->toChars());
2052 }
2053 v = cd->fields[i - fieldsSoFar];
2054 assert((elements->dim + i) >= (fieldsSoFar + cd->fields.dim));
2055 size_t indx = (elements->dim - fieldsSoFar)- cd->fields.dim + i;
2056 assert(indx < elements->dim);
2057 z = (*elements)[indx];
2058 }
2059 if (!z)
2060 {
2061 for (int j = level; j > 0; --j) printf(" ");
2062 printf(" void\n");
2063 continue;
2064 }
2065
2066 if (v)
2067 {
2068 // If it is a void assignment, use the default initializer
2069 if ((v->type->ty != z->type->ty) && v->type->ty == Tsarray)
2070 {
2071 for (int j = level; --j; ) printf(" ");
2072 printf(" field: block initalized static array\n");
2073 continue;
2074 }
2075 }
2076 showCtfeExpr(z, level + 1);
2077 }
2078 }
2079 }
2080
2081 /*************************** Void initialization ***************************/
2082
voidInitLiteral(Type * t,VarDeclaration * var)2083 UnionExp voidInitLiteral(Type *t, VarDeclaration *var)
2084 {
2085 UnionExp ue;
2086 if (t->ty == Tsarray)
2087 {
2088 TypeSArray *tsa = (TypeSArray *)t;
2089 Expression *elem = voidInitLiteral(tsa->next, var).copy();
2090
2091 // For aggregate value types (structs, static arrays) we must
2092 // create an a separate copy for each element.
2093 bool mustCopy = (elem->op == TOKarrayliteral || elem->op == TOKstructliteral);
2094
2095 Expressions *elements = new Expressions();
2096 size_t d = (size_t)tsa->dim->toInteger();
2097 elements->setDim(d);
2098 for (size_t i = 0; i < d; i++)
2099 {
2100 if (mustCopy && i > 0)
2101 elem = copyLiteral(elem).copy();
2102 (*elements)[i] = elem;
2103 }
2104 new(&ue) ArrayLiteralExp(var->loc, tsa, elements);
2105 ArrayLiteralExp *ae = (ArrayLiteralExp *)ue.exp();
2106 ae->ownedByCtfe = OWNEDctfe;
2107 }
2108 else if (t->ty == Tstruct)
2109 {
2110 TypeStruct *ts = (TypeStruct *)t;
2111 Expressions *exps = new Expressions();
2112 exps->setDim(ts->sym->fields.dim);
2113 for (size_t i = 0; i < ts->sym->fields.dim; i++)
2114 {
2115 (*exps)[i] = voidInitLiteral(ts->sym->fields[i]->type, ts->sym->fields[i]).copy();
2116 }
2117 new(&ue) StructLiteralExp(var->loc, ts->sym, exps);
2118 StructLiteralExp *se = (StructLiteralExp *)ue.exp();
2119 se->type = ts;
2120 se->ownedByCtfe = OWNEDctfe;
2121 }
2122 else
2123 new(&ue) VoidInitExp(var, t);
2124 return ue;
2125 }
2126