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