1 /**
2  * The entry point for CTFE.
3  *
4  * Specification: ($LINK2 https://dlang.org/spec/function.html#interpretation, Compile Time Function Execution (CTFE))
5  *
6  * Copyright:   Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
7  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
8  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dinterpret.d, _dinterpret.d)
10  * Documentation:  https://dlang.org/phobos/dmd_dinterpret.html
11  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dinterpret.d
12  */
13 
14 module dmd.dinterpret;
15 
16 import core.stdc.stdio;
17 import core.stdc.stdlib;
18 import core.stdc.string;
19 import dmd.arraytypes;
20 import dmd.astenums;
21 import dmd.attrib;
22 import dmd.builtin;
23 import dmd.constfold;
24 import dmd.ctfeexpr;
25 import dmd.dcast;
26 import dmd.dclass;
27 import dmd.declaration;
28 import dmd.dstruct;
29 import dmd.dsymbol;
30 import dmd.dsymbolsem;
31 import dmd.dtemplate;
32 import dmd.errors;
33 import dmd.expression;
34 import dmd.expressionsem;
35 import dmd.func;
36 import dmd.globals;
37 import dmd.hdrgen;
38 import dmd.id;
39 import dmd.identifier;
40 import dmd.init;
41 import dmd.initsem;
42 import dmd.location;
43 import dmd.mtype;
44 import dmd.root.rmem;
45 import dmd.root.array;
46 import dmd.root.ctfloat;
47 import dmd.root.region;
48 import dmd.rootobject;
49 import dmd.root.utf;
50 import dmd.statement;
51 import dmd.tokens;
52 import dmd.visitor;
53 
54 /*************************************
55  * Entry point for CTFE.
56  * A compile-time result is required. Give an error if not possible.
57  *
58  * `e` must be semantically valid expression. In other words, it should not
59  * contain any `ErrorExp`s in it. But, CTFE interpretation will cross over
60  * functions and may invoke a function that contains `ErrorStatement` in its body.
61  * If that, the "CTFE failed because of previous errors" error is raised.
62  */
63 extern(C++) public Expression ctfeInterpret(Expression e)
64 {
65     switch (e.op)
66     {
67         case EXP.int64:
68         case EXP.float64:
69         case EXP.complex80:
70         case EXP.null_:
71         case EXP.void_:
72         case EXP.string_:
73         case EXP.this_:
74         case EXP.super_:
75         case EXP.type:
76         case EXP.typeid_:
77         case EXP.template_:              // non-eponymous template/instance
78         case EXP.scope_:                 // ditto
79         case EXP.dotTemplateDeclaration: // ditto, e.e1 doesn't matter here
80         case EXP.dotTemplateInstance:    // ditto
81         case EXP.dot:                    // ditto
82              if (e.type.ty == Terror)
83                 return ErrorExp.get();
84             goto case EXP.error;
85 
86         case EXP.error:
87             return e;
88 
89         default:
90             break;
91     }
92 
93     assert(e.type); // https://issues.dlang.org/show_bug.cgi?id=14642
94     //assert(e.type.ty != Terror);    // FIXME
95     if (e.type.ty == Terror)
96         return ErrorExp.get();
97 
98     auto rgnpos = ctfeGlobals.region.savePos();
99 
100     Expression result = interpret(e, null);
101 
102     // Report an error if the expression contained a `ThrowException` and
103     // hence generated an uncaught exception
104     if (auto tee = result.isThrownExceptionExp())
105     {
106         tee.generateUncaughtError();
107         result = CTFEExp.cantexp;
108     }
109     else
110         result = copyRegionExp(result);
111 
112     if (!CTFEExp.isCantExp(result))
113         result = scrubReturnValue(e.loc, result);
114     if (CTFEExp.isCantExp(result))
115         result = ErrorExp.get();
116 
117     ctfeGlobals.region.release(rgnpos);
118 
119     return result;
120 }
121 
122 /* Run CTFE on the expression, but allow the expression to be a TypeExp
123  *  or a tuple containing a TypeExp. (This is required by pragma(msg)).
124  */
125 public Expression ctfeInterpretForPragmaMsg(Expression e)
126 {
127     if (e.op == EXP.error || e.op == EXP.type)
128         return e;
129 
130     // It's also OK for it to be a function declaration (happens only with
131     // __traits(getOverloads))
132     if (auto ve = e.isVarExp())
133         if (ve.var.isFuncDeclaration())
134         {
135             return e;
136         }
137 
138     auto tup = e.isTupleExp();
139     if (!tup)
140         return e.ctfeInterpret();
141 
142     // Tuples need to be treated separately, since they are
143     // allowed to contain a TypeExp in this case.
144 
145     Expressions* expsx = null;
146     foreach (i, g; *tup.exps)
147     {
148         auto h = ctfeInterpretForPragmaMsg(g);
149         if (h != g)
150         {
151             if (!expsx)
152             {
153                 expsx = tup.exps.copy();
154             }
155             (*expsx)[i] = h;
156         }
157     }
158     if (expsx)
159     {
160         auto te = new TupleExp(e.loc, expsx);
161         expandTuples(te.exps);
162         te.type = new TypeTuple(te.exps);
163         return te;
164     }
165     return e;
166 }
167 
168 public Expression getValue(VarDeclaration vd)
169 {
170     return ctfeGlobals.stack.getValue(vd);
171 }
172 
173 /*************************************************
174  * Allocate an Expression in the ctfe region.
175  * Params:
176  *      T = type of Expression to allocate
177  *      args = arguments to Expression's constructor
178  * Returns:
179  *      allocated Expression
180  */
181 T ctfeEmplaceExp(T : Expression, Args...)(Args args)
182 {
183     if (mem.isGCEnabled)
184         return new T(args);
185     auto p = ctfeGlobals.region.malloc(__traits(classInstanceSize, T));
186     emplaceExp!T(p, args);
187     return cast(T)p;
188 }
189 
190 // CTFE diagnostic information
191 public extern (C++) void printCtfePerformanceStats()
192 {
193     debug (SHOWPERFORMANCE)
194     {
195         printf("        ---- CTFE Performance ----\n");
196         printf("max call depth = %d\tmax stack = %d\n", ctfeGlobals.maxCallDepth, ctfeGlobals.stack.maxStackUsage());
197         printf("array allocs = %d\tassignments = %d\n\n", ctfeGlobals.numArrayAllocs, ctfeGlobals.numAssignments);
198     }
199 }
200 
201 /**************************
202  */
203 
204 void incArrayAllocs()
205 {
206     ++ctfeGlobals.numArrayAllocs;
207 }
208 
209 /* ================================================ Implementation ======================================= */
210 
211 private:
212 
213 /***************
214  * Collect together globals used by CTFE
215  */
216 struct CtfeGlobals
217 {
218     Region region;
219 
220     CtfeStack stack;
221 
222     int callDepth = 0;        // current number of recursive calls
223 
224     // When printing a stack trace, suppress this number of calls
225     int stackTraceCallsToSuppress = 0;
226 
227     int maxCallDepth = 0;     // highest number of recursive calls
228     int numArrayAllocs = 0;   // Number of allocated arrays
229     int numAssignments = 0;   // total number of assignments executed
230 }
231 
232 __gshared CtfeGlobals ctfeGlobals;
233 
234 enum CTFEGoal : int
235 {
236     RValue,     /// Must return an Rvalue (== CTFE value)
237     LValue,     /// Must return an Lvalue (== CTFE reference)
238     Nothing,    /// The return value is not required
239 }
240 
241 //debug = LOG;
242 //debug = LOGASSIGN;
243 //debug = LOGCOMPILE;
244 //debug = SHOWPERFORMANCE;
245 
246 // Maximum allowable recursive function calls in CTFE
247 enum CTFE_RECURSION_LIMIT = 1000;
248 
249 /**
250  The values of all CTFE variables
251  */
252 struct CtfeStack
253 {
254 private:
255     /* The stack. Every declaration we encounter is pushed here,
256      * together with the VarDeclaration, and the previous
257      * stack address of that variable, so that we can restore it
258      * when we leave the stack frame.
259      * Note that when a function is forward referenced, the interpreter must
260      * run semantic3, and that may start CTFE again with a NULL istate. Thus
261      * the stack might not be empty when CTFE begins.
262      *
263      * Ctfe Stack addresses are just 0-based integers, but we save
264      * them as 'void *' because Array can only do pointers.
265      */
266     Expressions values;         // values on the stack
267     VarDeclarations vars;       // corresponding variables
268     Array!(void*) savedId;      // id of the previous state of that var
269 
270     Array!(void*) frames;       // all previous frame pointers
271     Expressions savedThis;      // all previous values of localThis
272 
273     /* Global constants get saved here after evaluation, so we never
274      * have to redo them. This saves a lot of time and memory.
275      */
276     Expressions globalValues;   // values of global constants
277 
278     size_t framepointer;        // current frame pointer
279     size_t maxStackPointer;     // most stack we've ever used
280     Expression localThis;       // value of 'this', or NULL if none
281 
282 public:
283     size_t stackPointer() @safe
284     {
285         return values.length;
286     }
287 
288     // The current value of 'this', or NULL if none
289     Expression getThis() @safe
290     {
291         return localThis;
292     }
293 
294     // Largest number of stack positions we've used
295     size_t maxStackUsage() @safe
296     {
297         return maxStackPointer;
298     }
299 
300     // Start a new stack frame, using the provided 'this'.
301     void startFrame(Expression thisexp)
302     {
303         frames.push(cast(void*)cast(size_t)framepointer);
304         savedThis.push(localThis);
305         framepointer = stackPointer();
306         localThis = thisexp;
307     }
308 
309     void endFrame()
310     {
311         size_t oldframe = cast(size_t)frames[frames.length - 1];
312         localThis = savedThis[savedThis.length - 1];
313         popAll(framepointer);
314         framepointer = oldframe;
315         frames.setDim(frames.length - 1);
316         savedThis.setDim(savedThis.length - 1);
317     }
318 
319     bool isInCurrentFrame(VarDeclaration v)
320     {
321         if (v.isDataseg() && !v.isCTFE())
322             return false; // It's a global
323         return v.ctfeAdrOnStack >= framepointer;
324     }
325 
326     Expression getValue(VarDeclaration v)
327     {
328         //printf("getValue() %s\n", v.toChars());
329         if ((v.isDataseg() || v.storage_class & STC.manifest) && !v.isCTFE())
330         {
331             assert(v.ctfeAdrOnStack < globalValues.length);
332             return globalValues[v.ctfeAdrOnStack];
333         }
334         assert(v.ctfeAdrOnStack < stackPointer());
335         return values[v.ctfeAdrOnStack];
336     }
337 
338     void setValue(VarDeclaration v, Expression e)
339     {
340         //printf("setValue() %s : %s\n", v.toChars(), e.toChars());
341         assert(!v.isDataseg() || v.isCTFE());
342         assert(v.ctfeAdrOnStack < stackPointer());
343         values[v.ctfeAdrOnStack] = e;
344     }
345 
346     void push(VarDeclaration v)
347     {
348         //printf("push() %s\n", v.toChars());
349         assert(!v.isDataseg() || v.isCTFE());
350         if (v.ctfeAdrOnStack != VarDeclaration.AdrOnStackNone && v.ctfeAdrOnStack >= framepointer)
351         {
352             // Already exists in this frame, reuse it.
353             values[v.ctfeAdrOnStack] = null;
354             return;
355         }
356         savedId.push(cast(void*)cast(size_t)v.ctfeAdrOnStack);
357         v.ctfeAdrOnStack = cast(uint)values.length;
358         vars.push(v);
359         values.push(null);
360     }
361 
362     void pop(VarDeclaration v)
363     {
364         assert(!v.isDataseg() || v.isCTFE());
365         assert(!v.isReference());
366         const oldid = v.ctfeAdrOnStack;
367         v.ctfeAdrOnStack = cast(uint)cast(size_t)savedId[oldid];
368         if (v.ctfeAdrOnStack == values.length - 1)
369         {
370             values.pop();
371             vars.pop();
372             savedId.pop();
373         }
374     }
375 
376     void popAll(size_t stackpointer)
377     {
378         if (stackPointer() > maxStackPointer)
379             maxStackPointer = stackPointer();
380         assert(values.length >= stackpointer);
381         for (size_t i = stackpointer; i < values.length; ++i)
382         {
383             VarDeclaration v = vars[i];
384             v.ctfeAdrOnStack = cast(uint)cast(size_t)savedId[i];
385         }
386         values.setDim(stackpointer);
387         vars.setDim(stackpointer);
388         savedId.setDim(stackpointer);
389     }
390 
391     void saveGlobalConstant(VarDeclaration v, Expression e)
392     {
393         assert(v._init && (v.isConst() || v.isImmutable() || v.storage_class & STC.manifest) && !v.isCTFE());
394         v.ctfeAdrOnStack = cast(uint)globalValues.length;
395         globalValues.push(copyRegionExp(e));
396     }
397 }
398 
399 private struct InterState
400 {
401     InterState* caller;     // calling function's InterState
402     FuncDeclaration fd;     // function being interpreted
403     Statement start;        // if !=NULL, start execution at this statement
404 
405     /* target of CTFEExp result; also
406      * target of labelled CTFEExp or
407      * CTFEExp. (null if no label).
408      */
409     Statement gotoTarget;
410 }
411 
412 /*************************************
413  * Attempt to interpret a function given the arguments.
414  * Params:
415  *      pue       = storage for result
416  *      fd        = function being called
417  *      istate    = state for calling function (NULL if none)
418  *      arguments = function arguments
419  *      thisarg   = 'this', if a needThis() function, NULL if not.
420  *
421  * Returns:
422  * result expression if successful, EXP.cantExpression if not,
423  * or CTFEExp if function returned void.
424  */
425 private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterState* istate, Expressions* arguments, Expression thisarg)
426 {
427     debug (LOG)
428     {
429         printf("\n********\n%s FuncDeclaration::interpret(istate = %p) %s\n", fd.loc.toChars(), istate, fd.toChars());
430     }
431 
432     void fdError(const(char)* msg)
433     {
434         error(fd.loc, "%s `%s` %s", fd.kind, fd.toPrettyChars, msg);
435     }
436 
437     assert(pue);
438     if (fd.semanticRun == PASS.semantic3)
439     {
440         fdError("circular dependency. Functions cannot be interpreted while being compiled");
441         return CTFEExp.cantexp;
442     }
443     if (!fd.functionSemantic3())
444         return CTFEExp.cantexp;
445     if (fd.semanticRun < PASS.semantic3done)
446     {
447         fdError("circular dependency. Functions cannot be interpreted while being compiled");
448         return CTFEExp.cantexp;
449     }
450 
451     auto tf = fd.type.toBasetype().isTypeFunction();
452     if (tf.parameterList.varargs != VarArg.none && arguments &&
453         ((fd.parameters && arguments.length != fd.parameters.length) || (!fd.parameters && arguments.length)))
454     {
455         fdError("C-style variadic functions are not yet implemented in CTFE");
456         return CTFEExp.cantexp;
457     }
458 
459     // Nested functions always inherit the 'this' pointer from the parent,
460     // except for delegates. (Note that the 'this' pointer may be null).
461     // Func literals report isNested() even if they are in global scope,
462     // so we need to check that the parent is a function.
463     if (fd.isNested() && fd.toParentLocal().isFuncDeclaration() && !thisarg && istate)
464         thisarg = ctfeGlobals.stack.getThis();
465 
466     if (fd.needThis() && !thisarg)
467     {
468         // error, no this. Prevent segfault.
469         // Here should be unreachable by the strict 'this' check in front-end.
470         error(fd.loc, "%s `%s` need `this` to access member `%s`", fd.kind, fd.toPrettyChars, fd.toChars());
471         return CTFEExp.cantexp;
472     }
473 
474     // Place to hold all the arguments to the function while
475     // we are evaluating them.
476     size_t dim = arguments ? arguments.length : 0;
477     assert((fd.parameters ? fd.parameters.length : 0) == dim);
478 
479     /* Evaluate all the arguments to the function,
480      * store the results in eargs[]
481      */
482     Expressions eargs = Expressions(dim);
483     for (size_t i = 0; i < dim; i++)
484     {
485         Expression earg = (*arguments)[i];
486         Parameter fparam = tf.parameterList[i];
487 
488         if (fparam.isReference())
489         {
490             if (!istate && (fparam.storageClass & STC.out_))
491             {
492                 // initializing an out parameter involves writing to it.
493                 error(earg.loc, "global `%s` cannot be passed as an `out` parameter at compile time", earg.toChars());
494                 return CTFEExp.cantexp;
495             }
496             // Convert all reference arguments into lvalue references
497             earg = interpretRegion(earg, istate, CTFEGoal.LValue);
498             if (CTFEExp.isCantExp(earg))
499                 return earg;
500         }
501         else if (fparam.isLazy())
502         {
503         }
504         else
505         {
506             /* Value parameters
507              */
508             Type ta = fparam.type.toBasetype();
509             if (ta.ty == Tsarray)
510                 if (auto eaddr = earg.isAddrExp())
511                 {
512                     /* Static arrays are passed by a simple pointer.
513                      * Skip past this to get at the actual arg.
514                      */
515                     earg = eaddr.e1;
516                 }
517 
518             earg = interpretRegion(earg, istate);
519             if (CTFEExp.isCantExp(earg))
520                 return earg;
521 
522             /* Struct literals are passed by value, but we don't need to
523              * copy them if they are passed as const
524              */
525             if (earg.op == EXP.structLiteral && !(fparam.storageClass & (STC.const_ | STC.immutable_)))
526                 earg = copyLiteral(earg).copy();
527         }
528         if (auto tee = earg.isThrownExceptionExp())
529         {
530             if (istate)
531                 return tee;
532             tee.generateUncaughtError();
533             return CTFEExp.cantexp;
534         }
535         eargs[i] = earg;
536     }
537 
538     // Now that we've evaluated all the arguments, we can start the frame
539     // (this is the moment when the 'call' actually takes place).
540     InterState istatex;
541     istatex.caller = istate;
542     istatex.fd = fd;
543 
544     if (fd.hasDualContext())
545     {
546         Expression arg0 = thisarg;
547         if (arg0 && arg0.type.ty == Tstruct)
548         {
549             Type t = arg0.type.pointerTo();
550             arg0 = ctfeEmplaceExp!AddrExp(arg0.loc, arg0);
551             arg0.type = t;
552         }
553         auto elements = new Expressions(2);
554         (*elements)[0] = arg0;
555         (*elements)[1] = ctfeGlobals.stack.getThis();
556         Type t2 = Type.tvoidptr.sarrayOf(2);
557         const loc = thisarg ? thisarg.loc : fd.loc;
558         thisarg = ctfeEmplaceExp!ArrayLiteralExp(loc, t2, elements);
559         thisarg = ctfeEmplaceExp!AddrExp(loc, thisarg);
560         thisarg.type = t2.pointerTo();
561     }
562 
563     ctfeGlobals.stack.startFrame(thisarg);
564     if (fd.vthis && thisarg)
565     {
566         ctfeGlobals.stack.push(fd.vthis);
567         setValue(fd.vthis, thisarg);
568     }
569 
570     for (size_t i = 0; i < dim; i++)
571     {
572         Expression earg = eargs[i];
573         Parameter fparam = tf.parameterList[i];
574         VarDeclaration v = (*fd.parameters)[i];
575         debug (LOG)
576         {
577             printf("arg[%zu] = %s\n", i, earg.toChars());
578         }
579         ctfeGlobals.stack.push(v);
580 
581         if (fparam.isReference() && earg.op == EXP.variable &&
582             earg.isVarExp().var.toParent2() == fd)
583         {
584             VarDeclaration vx = earg.isVarExp().var.isVarDeclaration();
585             if (!vx)
586             {
587                 error(fd.loc, "%s `%s` cannot interpret `%s` as a `ref` parameter", fd.kind, fd.toPrettyChars, earg.toChars());
588                 return CTFEExp.cantexp;
589             }
590 
591             /* vx is a variable that is declared in fd.
592              * It means that fd is recursively called. e.g.
593              *
594              *  void fd(int n, ref int v = dummy) {
595              *      int vx;
596              *      if (n == 1) fd(2, vx);
597              *  }
598              *  fd(1);
599              *
600              * The old value of vx on the stack in fd(1)
601              * should be saved at the start of fd(2, vx) call.
602              */
603             const oldadr = vx.ctfeAdrOnStack;
604 
605             ctfeGlobals.stack.push(vx);
606             assert(!hasValue(vx)); // vx is made uninitialized
607 
608             // https://issues.dlang.org/show_bug.cgi?id=14299
609             // v.ctfeAdrOnStack should be saved already
610             // in the stack before the overwrite.
611             v.ctfeAdrOnStack = oldadr;
612             assert(hasValue(v)); // ref parameter v should refer existing value.
613         }
614         else
615         {
616             // Value parameters and non-trivial references
617             setValueWithoutChecking(v, earg);
618         }
619         debug (LOG)
620         {
621             printf("interpreted arg[%zu] = %s\n", i, earg.toChars());
622             showCtfeExpr(earg);
623         }
624         debug (LOGASSIGN)
625         {
626             printf("interpreted arg[%zu] = %s\n", i, earg.toChars());
627             showCtfeExpr(earg);
628         }
629     }
630 
631     if (fd.vresult)
632         ctfeGlobals.stack.push(fd.vresult);
633 
634     // Enter the function
635     ++ctfeGlobals.callDepth;
636     if (ctfeGlobals.callDepth > ctfeGlobals.maxCallDepth)
637         ctfeGlobals.maxCallDepth = ctfeGlobals.callDepth;
638 
639     Expression e = null;
640     while (1)
641     {
642         if (ctfeGlobals.callDepth > CTFE_RECURSION_LIMIT)
643         {
644             fdError("CTFE recursion limit exceeded");
645             e = CTFEExp.cantexp;
646             break;
647         }
648         e = interpretStatement(pue, fd.fbody, &istatex);
649         if (CTFEExp.isCantExp(e))
650         {
651             debug (LOG)
652             {
653                 printf("function body failed to interpret\n");
654             }
655         }
656 
657         if (istatex.start)
658         {
659             error(fd.loc, "%s `%s` CTFE internal error: failed to resume at statement `%s`", fd.kind, fd.toPrettyChars, istatex.start.toChars());
660             return CTFEExp.cantexp;
661         }
662 
663         /* This is how we deal with a recursive statement AST
664          * that has arbitrary goto statements in it.
665          * Bubble up a 'result' which is the target of the goto
666          * statement, then go recursively down the AST looking
667          * for that statement, then execute starting there.
668          */
669         if (CTFEExp.isGotoExp(e))
670         {
671             istatex.start = istatex.gotoTarget; // set starting statement
672             istatex.gotoTarget = null;
673         }
674         else
675         {
676             assert(!e || (e.op != EXP.continue_ && e.op != EXP.break_));
677             break;
678         }
679     }
680     // If fell off the end of a void function, return void
681     if (!e)
682     {
683         if (tf.next.ty == Tvoid)
684             e = CTFEExp.voidexp;
685         else
686         {
687             /* missing a return statement can happen with C functions
688              * https://issues.dlang.org/show_bug.cgi?id=23056
689              */
690             fdError("no return value from function");
691             e = CTFEExp.cantexp;
692         }
693     }
694 
695     if (tf.isref && e.op == EXP.variable && e.isVarExp().var == fd.vthis)
696         e = thisarg;
697     if (tf.isref && fd.hasDualContext() && e.op == EXP.index)
698     {
699         auto ie = e.isIndexExp();
700         auto pe = ie.e1.isPtrExp();
701         auto ve = !pe ?  null : pe.e1.isVarExp();
702         if (ve && ve.var == fd.vthis)
703         {
704             auto ne = ie.e2.isIntegerExp();
705             assert(ne);
706             auto ale = thisarg.isAddrExp().e1.isArrayLiteralExp();
707             e = (*ale.elements)[cast(size_t)ne.getInteger()];
708             if (auto ae = e.isAddrExp())
709             {
710                 e = ae.e1;
711             }
712         }
713     }
714 
715     // Leave the function
716     --ctfeGlobals.callDepth;
717 
718     ctfeGlobals.stack.endFrame();
719 
720     // If it generated an uncaught exception, report error.
721     if (!istate && e.isThrownExceptionExp())
722     {
723         if (e == pue.exp())
724             e = pue.copy();
725         e.isThrownExceptionExp().generateUncaughtError();
726         e = CTFEExp.cantexp;
727     }
728 
729     return e;
730 }
731 
732 /// used to collect coverage information in ctfe
733 void incUsageCtfe(InterState* istate, const ref Loc loc)
734 {
735     if (global.params.ctfe_cov && istate)
736     {
737         auto line = loc.linnum;
738         auto mod = istate.fd.getModule();
739 
740         ++mod.ctfe_cov[line];
741     }
742 }
743 
744 /***********************************
745  * Interpret the statement.
746  * Params:
747  *    s = Statement to interpret
748  *    istate = context
749  * Returns:
750  *      NULL    continue to next statement
751  *      EXP.cantExpression      cannot interpret statement at compile time
752  *      !NULL   expression from return statement, or thrown exception
753  */
754 
755 Expression interpretStatement(Statement s, InterState* istate)
756 {
757     UnionExp ue = void;
758     auto result = interpretStatement(&ue, s, istate);
759     if (result == ue.exp())
760         result = ue.copy();
761     return result;
762 }
763 
764 ///
765 Expression interpretStatement(UnionExp* pue, Statement s, InterState* istate)
766 {
767     Expression result;
768 
769     // If e is EXP.throw_exception or EXP.cantExpression,
770     // set it to 'result' and returns true.
771     bool exceptionOrCant(Expression e)
772     {
773         if (exceptionOrCantInterpret(e))
774         {
775             // Make sure e is not pointing to a stack temporary
776             result = (e.op == EXP.cantExpression) ? CTFEExp.cantexp : e;
777             return true;
778         }
779         return false;
780     }
781 
782     /******************************** Statement ***************************/
783 
784     void visitDefaultCase(Statement s)
785     {
786         debug (LOG)
787         {
788             printf("%s Statement::interpret() %s\n", s.loc.toChars(), s.toChars());
789         }
790         if (istate.start)
791         {
792             if (istate.start != s)
793                 return;
794             istate.start = null;
795         }
796 
797         error(s.loc, "statement `%s` cannot be interpreted at compile time", s.toChars());
798         result = CTFEExp.cantexp;
799     }
800 
801     void visitExp(ExpStatement s)
802     {
803         debug (LOG)
804         {
805             printf("%s ExpStatement::interpret(%s)\n", s.loc.toChars(), s.exp ? s.exp.toChars() : "");
806         }
807         if (istate.start)
808         {
809             if (istate.start != s)
810                 return;
811             istate.start = null;
812         }
813         if (s.exp && s.exp.hasCode)
814             incUsageCtfe(istate, s.loc);
815 
816         Expression e = interpret(pue, s.exp, istate, CTFEGoal.Nothing);
817         if (exceptionOrCant(e))
818             return;
819     }
820 
821     void visitDtorExp(DtorExpStatement s)
822     {
823         visitExp(s);
824     }
825 
826     void visitCompound(CompoundStatement s)
827     {
828         debug (LOG)
829         {
830             printf("%s CompoundStatement::interpret()\n", s.loc.toChars());
831         }
832         if (istate.start == s)
833             istate.start = null;
834 
835         const dim = s.statements ? s.statements.length : 0;
836         foreach (i; 0 .. dim)
837         {
838             Statement sx = (*s.statements)[i];
839             result = interpretStatement(pue, sx, istate);
840             if (result)
841                 break;
842         }
843         debug (LOG)
844         {
845             printf("%s -CompoundStatement::interpret() %p\n", s.loc.toChars(), result);
846         }
847     }
848 
849     void visitCompoundAsm(CompoundAsmStatement s)
850     {
851         visitCompound(s);
852     }
853 
854     void visitUnrolledLoop(UnrolledLoopStatement s)
855     {
856         debug (LOG)
857         {
858             printf("%s UnrolledLoopStatement::interpret()\n", s.loc.toChars());
859         }
860         if (istate.start == s)
861             istate.start = null;
862 
863         const dim = s.statements ? s.statements.length : 0;
864         foreach (i; 0 .. dim)
865         {
866             Statement sx = (*s.statements)[i];
867             Expression e = interpretStatement(pue, sx, istate);
868             if (!e) // succeeds to interpret, or goto target was not found
869                 continue;
870             if (exceptionOrCant(e))
871                 return;
872             if (e.op == EXP.break_)
873             {
874                 if (istate.gotoTarget && istate.gotoTarget != s)
875                 {
876                     result = e; // break at a higher level
877                     return;
878                 }
879                 istate.gotoTarget = null;
880                 result = null;
881                 return;
882             }
883             if (e.op == EXP.continue_)
884             {
885                 if (istate.gotoTarget && istate.gotoTarget != s)
886                 {
887                     result = e; // continue at a higher level
888                     return;
889                 }
890                 istate.gotoTarget = null;
891                 continue;
892             }
893 
894             // expression from return statement, or thrown exception
895             result = e;
896             break;
897         }
898     }
899 
900     void visitIf(IfStatement s)
901     {
902         debug (LOG)
903         {
904             printf("%s IfStatement::interpret(%s)\n", s.loc.toChars(), s.condition.toChars());
905         }
906         incUsageCtfe(istate, s.loc);
907         if (istate.start == s)
908             istate.start = null;
909         if (istate.start)
910         {
911             Expression e = null;
912             e = interpretStatement(s.ifbody, istate);
913             if (!e && istate.start)
914                 e = interpretStatement(s.elsebody, istate);
915             result = e;
916             return;
917         }
918 
919         UnionExp ue = void;
920         Expression e = interpret(&ue, s.condition, istate);
921         assert(e);
922         if (exceptionOrCant(e))
923             return;
924 
925         if (isTrueBool(e))
926             result = interpretStatement(pue, s.ifbody, istate);
927         else if (e.toBool().hasValue(false))
928             result = interpretStatement(pue, s.elsebody, istate);
929         else
930         {
931             // no error, or assert(0)?
932             result = CTFEExp.cantexp;
933         }
934     }
935 
936     void visitScope(ScopeStatement s)
937     {
938         debug (LOG)
939         {
940             printf("%s ScopeStatement::interpret()\n", s.loc.toChars());
941         }
942         if (istate.start == s)
943             istate.start = null;
944 
945         result = interpretStatement(pue, s.statement, istate);
946     }
947 
948     void visitReturn(ReturnStatement s)
949     {
950         debug (LOG)
951         {
952             printf("%s ReturnStatement::interpret(%s)\n", s.loc.toChars(), s.exp ? s.exp.toChars() : "");
953         }
954         if (istate.start)
955         {
956             if (istate.start != s)
957                 return;
958             istate.start = null;
959         }
960 
961         if (!s.exp)
962         {
963             result = CTFEExp.voidexp;
964             return;
965         }
966 
967         incUsageCtfe(istate, s.loc);
968         assert(istate && istate.fd && istate.fd.type && istate.fd.type.ty == Tfunction);
969         TypeFunction tf = cast(TypeFunction)istate.fd.type;
970 
971         /* If the function returns a ref AND it's been called from an assignment,
972          * we need to return an lvalue. Otherwise, just do an (rvalue) interpret.
973          */
974         if (tf.isref)
975         {
976             result = interpret(pue, s.exp, istate, CTFEGoal.LValue);
977             return;
978         }
979         if (tf.next && tf.next.ty == Tdelegate && istate.fd.closureVars.length > 0)
980         {
981             // To support this, we need to copy all the closure vars
982             // into the delegate literal.
983             error(s.loc, "closures are not yet supported in CTFE");
984             result = CTFEExp.cantexp;
985             return;
986         }
987 
988         // We need to treat pointers specially, because EXP.symbolOffset can be used to
989         // return a value OR a pointer
990         Expression e = interpret(pue, s.exp, istate);
991         if (exceptionOrCant(e))
992             return;
993 
994         /**
995          * Interpret `return a ~= b` (i.e. `return _d_arrayappendT{,Trace}(a, b)`) as:
996          *     a ~= b;
997          *     return a;
998          * This is needed because `a ~= b` has to be interpreted as an lvalue, in order to avoid
999          * assigning a larger array into a smaller one, such as:
1000          *    `a = [1, 2], a ~= [3]` => `[1, 2] ~= [3]` => `[1, 2] = [1, 2, 3]`
1001          */
1002         if (isRuntimeHook(s.exp, Id._d_arrayappendT) || isRuntimeHook(s.exp, Id._d_arrayappendTTrace))
1003         {
1004             auto rs = new ReturnStatement(s.loc, e);
1005             visitReturn(rs);
1006             return;
1007         }
1008 
1009         // Disallow returning pointers to stack-allocated variables (bug 7876)
1010         if (!stopPointersEscaping(s.loc, e))
1011         {
1012             result = CTFEExp.cantexp;
1013             return;
1014         }
1015 
1016         if (needToCopyLiteral(e))
1017             e = copyLiteral(e).copy();
1018         debug (LOGASSIGN)
1019         {
1020             printf("RETURN %s\n", s.loc.toChars());
1021             showCtfeExpr(e);
1022         }
1023         result = e;
1024     }
1025 
1026     void visitBreak(BreakStatement s)
1027     {
1028         debug (LOG)
1029         {
1030             printf("%s BreakStatement::interpret()\n", s.loc.toChars());
1031         }
1032         incUsageCtfe(istate, s.loc);
1033         if (istate.start)
1034         {
1035             if (istate.start != s)
1036                 return;
1037             istate.start = null;
1038         }
1039 
1040         istate.gotoTarget = findGotoTarget(istate, s.ident);
1041         result = CTFEExp.breakexp;
1042     }
1043 
1044     void visitContinue(ContinueStatement s)
1045     {
1046         debug (LOG)
1047         {
1048             printf("%s ContinueStatement::interpret()\n", s.loc.toChars());
1049         }
1050         incUsageCtfe(istate, s.loc);
1051         if (istate.start)
1052         {
1053             if (istate.start != s)
1054                 return;
1055             istate.start = null;
1056         }
1057 
1058         istate.gotoTarget = findGotoTarget(istate, s.ident);
1059         result = CTFEExp.continueexp;
1060     }
1061 
1062     void visitWhile(WhileStatement s)
1063     {
1064         debug (LOG)
1065         {
1066             printf("WhileStatement::interpret()\n");
1067         }
1068         assert(0); // rewritten to ForStatement
1069     }
1070 
1071     void visitDo(DoStatement s)
1072     {
1073         debug (LOG)
1074         {
1075             printf("%s DoStatement::interpret()\n", s.loc.toChars());
1076         }
1077         if (istate.start == s)
1078             istate.start = null;
1079 
1080         while (1)
1081         {
1082             Expression e = interpretStatement(s._body, istate);
1083             if (!e && istate.start) // goto target was not found
1084                 return;
1085             assert(!istate.start);
1086 
1087             if (exceptionOrCant(e))
1088                 return;
1089             if (e && e.op == EXP.break_)
1090             {
1091                 if (istate.gotoTarget && istate.gotoTarget != s)
1092                 {
1093                     result = e; // break at a higher level
1094                     return;
1095                 }
1096                 istate.gotoTarget = null;
1097                 break;
1098             }
1099             if (e && e.op == EXP.continue_)
1100             {
1101                 if (istate.gotoTarget && istate.gotoTarget != s)
1102                 {
1103                     result = e; // continue at a higher level
1104                     return;
1105                 }
1106                 istate.gotoTarget = null;
1107                 e = null;
1108             }
1109             if (e)
1110             {
1111                 result = e; // bubbled up from ReturnStatement
1112                 return;
1113             }
1114 
1115             UnionExp ue = void;
1116             incUsageCtfe(istate, s.condition.loc);
1117             e = interpret(&ue, s.condition, istate);
1118             if (exceptionOrCant(e))
1119                 return;
1120             if (!e.isConst())
1121             {
1122                 result = CTFEExp.cantexp;
1123                 return;
1124             }
1125             if (e.toBool().hasValue(false))
1126                 break;
1127             assert(isTrueBool(e));
1128         }
1129         assert(result is null);
1130     }
1131 
1132     void visitFor(ForStatement s)
1133     {
1134         debug (LOG)
1135         {
1136             printf("%s ForStatement::interpret()\n", s.loc.toChars());
1137         }
1138         if (istate.start == s)
1139             istate.start = null;
1140 
1141         UnionExp ueinit = void;
1142         Expression ei = interpretStatement(&ueinit, s._init, istate);
1143         if (exceptionOrCant(ei))
1144             return;
1145         assert(!ei); // s.init never returns from function, or jumps out from it
1146 
1147         while (1)
1148         {
1149             if (s.condition && !istate.start)
1150             {
1151                 UnionExp ue = void;
1152                 incUsageCtfe(istate, s.condition.loc);
1153                 Expression e = interpret(&ue, s.condition, istate);
1154                 if (exceptionOrCant(e))
1155                     return;
1156                 if (e.toBool().hasValue(false))
1157                     break;
1158                 assert(isTrueBool(e));
1159             }
1160 
1161             Expression e = interpretStatement(pue, s._body, istate);
1162             if (!e && istate.start) // goto target was not found
1163                 return;
1164             assert(!istate.start);
1165 
1166             if (exceptionOrCant(e))
1167                 return;
1168             if (e && e.op == EXP.break_)
1169             {
1170                 if (istate.gotoTarget && istate.gotoTarget != s)
1171                 {
1172                     result = e; // break at a higher level
1173                     return;
1174                 }
1175                 istate.gotoTarget = null;
1176                 break;
1177             }
1178             if (e && e.op == EXP.continue_)
1179             {
1180                 if (istate.gotoTarget && istate.gotoTarget != s)
1181                 {
1182                     result = e; // continue at a higher level
1183                     return;
1184                 }
1185                 istate.gotoTarget = null;
1186                 e = null;
1187             }
1188             if (e)
1189             {
1190                 result = e; // bubbled up from ReturnStatement
1191                 return;
1192             }
1193 
1194             UnionExp uei = void;
1195             if (s.increment)
1196                 incUsageCtfe(istate, s.increment.loc);
1197             e = interpret(&uei, s.increment, istate, CTFEGoal.Nothing);
1198             if (exceptionOrCant(e))
1199                 return;
1200         }
1201         assert(result is null);
1202     }
1203 
1204     void visitForeach(ForeachStatement s)
1205     {
1206         assert(0); // rewritten to ForStatement
1207     }
1208 
1209     void visitForeachRange(ForeachRangeStatement s)
1210     {
1211         assert(0); // rewritten to ForStatement
1212     }
1213 
1214     void visitSwitch(SwitchStatement s)
1215     {
1216         debug (LOG)
1217         {
1218             printf("%s SwitchStatement::interpret()\n", s.loc.toChars());
1219         }
1220         incUsageCtfe(istate, s.loc);
1221         if (istate.start == s)
1222             istate.start = null;
1223         if (istate.start)
1224         {
1225             Expression e = interpretStatement(s._body, istate);
1226             if (istate.start) // goto target was not found
1227                 return;
1228             if (exceptionOrCant(e))
1229                 return;
1230             if (e && e.op == EXP.break_)
1231             {
1232                 if (istate.gotoTarget && istate.gotoTarget != s)
1233                 {
1234                     result = e; // break at a higher level
1235                     return;
1236                 }
1237                 istate.gotoTarget = null;
1238                 e = null;
1239             }
1240             result = e;
1241             return;
1242         }
1243 
1244         UnionExp uecond = void;
1245         Expression econdition = interpret(&uecond, s.condition, istate);
1246         if (exceptionOrCant(econdition))
1247             return;
1248 
1249         Statement scase = null;
1250         if (s.cases)
1251             foreach (cs; *s.cases)
1252             {
1253                 UnionExp uecase = void;
1254                 Expression ecase = interpret(&uecase, cs.exp, istate);
1255                 if (exceptionOrCant(ecase))
1256                     return;
1257                 if (ctfeEqual(cs.exp.loc, EXP.equal, econdition, ecase))
1258                 {
1259                     scase = cs;
1260                     break;
1261                 }
1262             }
1263         if (!scase)
1264         {
1265             if (!s.hasDefault)
1266                 error(s.loc, "no `default` or `case` for `%s` in `switch` statement", econdition.toChars());
1267             scase = s.sdefault;
1268         }
1269 
1270         assert(scase);
1271 
1272         /* Jump to scase
1273          */
1274         istate.start = scase;
1275         Expression e = interpretStatement(pue, s._body, istate);
1276         assert(!istate.start); // jump must not fail
1277         if (e && e.op == EXP.break_)
1278         {
1279             if (istate.gotoTarget && istate.gotoTarget != s)
1280             {
1281                 result = e; // break at a higher level
1282                 return;
1283             }
1284             istate.gotoTarget = null;
1285             e = null;
1286         }
1287         result = e;
1288     }
1289 
1290     void visitCase(CaseStatement s)
1291     {
1292         debug (LOG)
1293         {
1294             printf("%s CaseStatement::interpret(%s) this = %p\n", s.loc.toChars(), s.exp.toChars(), s);
1295         }
1296         incUsageCtfe(istate, s.loc);
1297         if (istate.start == s)
1298             istate.start = null;
1299 
1300         result = interpretStatement(pue, s.statement, istate);
1301     }
1302 
1303     void visitDefault(DefaultStatement s)
1304     {
1305         debug (LOG)
1306         {
1307             printf("%s DefaultStatement::interpret()\n", s.loc.toChars());
1308         }
1309         incUsageCtfe(istate, s.loc);
1310         if (istate.start == s)
1311             istate.start = null;
1312 
1313         result = interpretStatement(pue, s.statement, istate);
1314     }
1315 
1316     void visitGoto(GotoStatement s)
1317     {
1318         debug (LOG)
1319         {
1320             printf("%s GotoStatement::interpret()\n", s.loc.toChars());
1321         }
1322         if (istate.start)
1323         {
1324             if (istate.start != s)
1325                 return;
1326             istate.start = null;
1327         }
1328         incUsageCtfe(istate, s.loc);
1329 
1330         assert(s.label && s.label.statement);
1331         istate.gotoTarget = s.label.statement;
1332         result = CTFEExp.gotoexp;
1333     }
1334 
1335     void visitGotoCase(GotoCaseStatement s)
1336     {
1337         debug (LOG)
1338         {
1339             printf("%s GotoCaseStatement::interpret()\n", s.loc.toChars());
1340         }
1341         if (istate.start)
1342         {
1343             if (istate.start != s)
1344                 return;
1345             istate.start = null;
1346         }
1347         incUsageCtfe(istate, s.loc);
1348 
1349         assert(s.cs);
1350         istate.gotoTarget = s.cs;
1351         result = CTFEExp.gotoexp;
1352     }
1353 
1354     void visitGotoDefault(GotoDefaultStatement s)
1355     {
1356         debug (LOG)
1357         {
1358             printf("%s GotoDefaultStatement::interpret()\n", s.loc.toChars());
1359         }
1360         if (istate.start)
1361         {
1362             if (istate.start != s)
1363                 return;
1364             istate.start = null;
1365         }
1366         incUsageCtfe(istate, s.loc);
1367 
1368         assert(s.sw && s.sw.sdefault);
1369         istate.gotoTarget = s.sw.sdefault;
1370         result = CTFEExp.gotoexp;
1371     }
1372 
1373     void visitLabel(LabelStatement s)
1374     {
1375         debug (LOG)
1376         {
1377             printf("%s LabelStatement::interpret()\n", s.loc.toChars());
1378         }
1379         if (istate.start == s)
1380             istate.start = null;
1381 
1382         result = interpretStatement(pue, s.statement, istate);
1383     }
1384 
1385     void visitTryCatch(TryCatchStatement s)
1386     {
1387         debug (LOG)
1388         {
1389             printf("%s TryCatchStatement::interpret()\n", s.loc.toChars());
1390         }
1391         if (istate.start == s)
1392             istate.start = null;
1393         if (istate.start)
1394         {
1395             Expression e = null;
1396             e = interpretStatement(pue, s._body, istate);
1397             foreach (ca; *s.catches)
1398             {
1399                 if (e || !istate.start) // goto target was found
1400                     break;
1401                 e = interpretStatement(pue, ca.handler, istate);
1402             }
1403             result = e;
1404             return;
1405         }
1406 
1407         Expression e = interpretStatement(s._body, istate);
1408 
1409         // An exception was thrown
1410         if (e && e.isThrownExceptionExp())
1411         {
1412             ThrownExceptionExp ex = e.isThrownExceptionExp();
1413             Type extype = ex.thrown.originalClass().type;
1414 
1415             // Search for an appropriate catch clause.
1416             foreach (ca; *s.catches)
1417             {
1418                 Type catype = ca.type;
1419                 if (!catype.equals(extype) && !catype.isBaseOf(extype, null))
1420                     continue;
1421 
1422                 // Execute the handler
1423                 if (ca.var)
1424                 {
1425                     ctfeGlobals.stack.push(ca.var);
1426                     setValue(ca.var, ex.thrown);
1427                 }
1428                 e = interpretStatement(ca.handler, istate);
1429                 while (CTFEExp.isGotoExp(e))
1430                 {
1431                     /* This is an optimization that relies on the locality of the jump target.
1432                      * If the label is in the same catch handler, the following scan
1433                      * would find it quickly and can reduce jump cost.
1434                      * Otherwise, the catch block may be unnnecessary scanned again
1435                      * so it would make CTFE speed slower.
1436                      */
1437                     InterState istatex = *istate;
1438                     istatex.start = istate.gotoTarget; // set starting statement
1439                     istatex.gotoTarget = null;
1440                     Expression eh = interpretStatement(ca.handler, &istatex);
1441                     if (istatex.start)
1442                     {
1443                         // The goto target is outside the current scope.
1444                         break;
1445                     }
1446                     // The goto target was within the body.
1447                     if (CTFEExp.isCantExp(eh))
1448                     {
1449                         e = eh;
1450                         break;
1451                     }
1452                     *istate = istatex;
1453                     e = eh;
1454                 }
1455                 break;
1456             }
1457         }
1458         result = e;
1459     }
1460 
1461     void visitTryFinally(TryFinallyStatement s)
1462     {
1463         debug (LOG)
1464         {
1465             printf("%s TryFinallyStatement::interpret()\n", s.loc.toChars());
1466         }
1467         if (istate.start == s)
1468             istate.start = null;
1469         if (istate.start)
1470         {
1471             Expression e = null;
1472             e = interpretStatement(pue, s._body, istate);
1473             // Jump into/out from finalbody is disabled in semantic analysis.
1474             // and jump inside will be handled by the ScopeStatement == finalbody.
1475             result = e;
1476             return;
1477         }
1478 
1479         Expression ex = interpretStatement(s._body, istate);
1480         if (CTFEExp.isCantExp(ex))
1481         {
1482             result = ex;
1483             return;
1484         }
1485         while (CTFEExp.isGotoExp(ex))
1486         {
1487             // If the goto target is within the body, we must not interpret the finally statement,
1488             // because that will call destructors for objects within the scope, which we should not do.
1489             InterState istatex = *istate;
1490             istatex.start = istate.gotoTarget; // set starting statement
1491             istatex.gotoTarget = null;
1492             Expression bex = interpretStatement(s._body, &istatex);
1493             if (istatex.start)
1494             {
1495                 // The goto target is outside the current scope.
1496                 break;
1497             }
1498             // The goto target was within the body.
1499             if (CTFEExp.isCantExp(bex))
1500             {
1501                 result = bex;
1502                 return;
1503             }
1504             *istate = istatex;
1505             ex = bex;
1506         }
1507 
1508         Expression ey = interpretStatement(s.finalbody, istate);
1509         if (CTFEExp.isCantExp(ey))
1510         {
1511             result = ey;
1512             return;
1513         }
1514         if (ey && ey.isThrownExceptionExp())
1515         {
1516             // Check for collided exceptions
1517             if (ex && ex.isThrownExceptionExp())
1518                 ex = chainExceptions(ex.isThrownExceptionExp(), ey.isThrownExceptionExp());
1519             else
1520                 ex = ey;
1521         }
1522         result = ex;
1523     }
1524 
1525     void visitThrow(ThrowStatement s)
1526     {
1527         debug (LOG)
1528         {
1529             printf("%s ThrowStatement::interpret()\n", s.loc.toChars());
1530         }
1531         if (istate.start)
1532         {
1533             if (istate.start != s)
1534                 return;
1535             istate.start = null;
1536         }
1537 
1538         interpretThrow(result, s.exp, s.loc, istate);
1539     }
1540 
1541     void visitScopeGuard(ScopeGuardStatement s)
1542     {
1543         assert(0);
1544     }
1545 
1546     void visitWith(WithStatement s)
1547     {
1548         debug (LOG)
1549         {
1550             printf("%s WithStatement::interpret()\n", s.loc.toChars());
1551         }
1552         if (istate.start == s)
1553             istate.start = null;
1554         if (istate.start)
1555         {
1556             result = s._body ? interpretStatement(s._body, istate) : null;
1557             return;
1558         }
1559 
1560         // If it is with(Enum) {...}, just execute the body.
1561         if (s.exp.op == EXP.scope_ || s.exp.op == EXP.type)
1562         {
1563             result = interpretStatement(pue, s._body, istate);
1564             return;
1565         }
1566 
1567         incUsageCtfe(istate, s.loc);
1568 
1569         Expression e = interpret(s.exp, istate);
1570         if (exceptionOrCant(e))
1571             return;
1572 
1573         if (s.wthis.type.ty == Tpointer && s.exp.type.ty != Tpointer)
1574         {
1575             e = ctfeEmplaceExp!AddrExp(s.loc, e, s.wthis.type);
1576         }
1577         ctfeGlobals.stack.push(s.wthis);
1578         setValue(s.wthis, e);
1579         e = interpretStatement(s._body, istate);
1580         while (CTFEExp.isGotoExp(e))
1581         {
1582             /* This is an optimization that relies on the locality of the jump target.
1583              * If the label is in the same WithStatement, the following scan
1584              * would find it quickly and can reduce jump cost.
1585              * Otherwise, the statement body may be unnnecessary scanned again
1586              * so it would make CTFE speed slower.
1587              */
1588             InterState istatex = *istate;
1589             istatex.start = istate.gotoTarget; // set starting statement
1590             istatex.gotoTarget = null;
1591             Expression ex = interpretStatement(s._body, &istatex);
1592             if (istatex.start)
1593             {
1594                 // The goto target is outside the current scope.
1595                 break;
1596             }
1597             // The goto target was within the body.
1598             if (CTFEExp.isCantExp(ex))
1599             {
1600                 e = ex;
1601                 break;
1602             }
1603             *istate = istatex;
1604             e = ex;
1605         }
1606         ctfeGlobals.stack.pop(s.wthis);
1607         result = e;
1608     }
1609 
1610     void visitAsm(AsmStatement s)
1611     {
1612         debug (LOG)
1613         {
1614             printf("%s AsmStatement::interpret()\n", s.loc.toChars());
1615         }
1616         if (istate.start)
1617         {
1618             if (istate.start != s)
1619                 return;
1620             istate.start = null;
1621         }
1622         error(s.loc, "`asm` statements cannot be interpreted at compile time");
1623         result = CTFEExp.cantexp;
1624     }
1625 
1626     void visitInlineAsm(InlineAsmStatement s)
1627     {
1628         visitAsm(s);
1629     }
1630 
1631     void visitGccAsm(GccAsmStatement s)
1632     {
1633         visitAsm(s);
1634     }
1635 
1636     void visitImport(ImportStatement s)
1637     {
1638         debug (LOG)
1639         {
1640             printf("ImportStatement::interpret()\n");
1641         }
1642         if (istate.start)
1643         {
1644             if (istate.start != s)
1645                 return;
1646             istate.start = null;
1647         }
1648     }
1649 
1650     if (!s)
1651         return null;
1652 
1653     mixin VisitStatement!void visit;
1654     visit.VisitStatement(s);
1655     return result;
1656 }
1657 
1658 ///
1659 
1660 private extern (C++) final class Interpreter : Visitor
1661 {
1662     alias visit = Visitor.visit;
1663 public:
1664     InterState* istate;
1665     CTFEGoal goal;
1666     Expression result;
1667     UnionExp* pue;              // storage for `result`
1668 
1669     extern (D) this(UnionExp* pue, InterState* istate, CTFEGoal goal) scope @safe
1670     {
1671         this.pue = pue;
1672         this.istate = istate;
1673         this.goal = goal;
1674     }
1675 
1676     // If e is EXP.throw_exception or EXP.cantExpression,
1677     // set it to 'result' and returns true.
1678     bool exceptionOrCant(Expression e)
1679     {
1680         if (exceptionOrCantInterpret(e))
1681         {
1682             // Make sure e is not pointing to a stack temporary
1683             result = (e.op == EXP.cantExpression) ? CTFEExp.cantexp : e;
1684             return true;
1685         }
1686         return false;
1687     }
1688 
1689     /******************************** Expression ***************************/
1690 
1691     override void visit(Expression e)
1692     {
1693         debug (LOG)
1694         {
1695             printf("%s Expression::interpret() '%s' %s\n", e.loc.toChars(), EXPtoString(e.op).ptr, e.toChars());
1696             printf("type = %s\n", e.type.toChars());
1697             showCtfeExpr(e);
1698         }
1699         error(e.loc, "cannot interpret `%s` at compile time", e.toChars());
1700         result = CTFEExp.cantexp;
1701     }
1702 
1703     override void visit(TypeExp e)
1704     {
1705         debug (LOG)
1706         {
1707             printf("%s TypeExp.interpret() %s\n", e.loc.toChars(), e.toChars());
1708         }
1709         result = e;
1710     }
1711 
1712     override void visit(ThisExp e)
1713     {
1714         debug (LOG)
1715         {
1716             printf("%s ThisExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1717         }
1718         if (goal == CTFEGoal.LValue)
1719         {
1720             // We might end up here with istate being zero
1721             // https://issues.dlang.org/show_bug.cgi?id=16382
1722             if (istate && istate.fd.vthis)
1723             {
1724                 result = ctfeEmplaceExp!VarExp(e.loc, istate.fd.vthis);
1725                 if (istate.fd.hasDualContext())
1726                 {
1727                     result = ctfeEmplaceExp!PtrExp(e.loc, result);
1728                     result.type = Type.tvoidptr.sarrayOf(2);
1729                     result = ctfeEmplaceExp!IndexExp(e.loc, result, IntegerExp.literal!0);
1730                 }
1731                 result.type = e.type;
1732             }
1733             else
1734                 result = e;
1735             return;
1736         }
1737 
1738         result = ctfeGlobals.stack.getThis();
1739         if (result)
1740         {
1741             if (istate && istate.fd.hasDualContext())
1742             {
1743                 assert(result.op == EXP.address);
1744                 result = result.isAddrExp().e1;
1745                 assert(result.op == EXP.arrayLiteral);
1746                 result = (*result.isArrayLiteralExp().elements)[0];
1747                 if (e.type.ty == Tstruct)
1748                 {
1749                     result = result.isAddrExp().e1;
1750                 }
1751                 return;
1752             }
1753             assert(result.op == EXP.structLiteral || result.op == EXP.classReference || result.op == EXP.type);
1754             return;
1755         }
1756         error(e.loc, "value of `this` is not known at compile time");
1757         result = CTFEExp.cantexp;
1758     }
1759 
1760     override void visit(NullExp e)
1761     {
1762         result = e;
1763     }
1764 
1765     override void visit(IntegerExp e)
1766     {
1767         debug (LOG)
1768         {
1769             printf("%s IntegerExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1770         }
1771         result = e;
1772     }
1773 
1774     override void visit(RealExp e)
1775     {
1776         debug (LOG)
1777         {
1778             printf("%s RealExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1779         }
1780         result = e;
1781     }
1782 
1783     override void visit(ComplexExp e)
1784     {
1785         result = e;
1786     }
1787 
1788     override void visit(StringExp e)
1789     {
1790         debug (LOG)
1791         {
1792             printf("%s StringExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1793         }
1794         if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted the string
1795         {
1796             result = e;
1797             return;
1798         }
1799 
1800         if (e.type.ty != Tsarray ||
1801             (cast(TypeNext)e.type).next.mod & (MODFlags.const_ | MODFlags.immutable_))
1802         {
1803             // If it's immutable, we don't need to dup it. Attempts to modify
1804             // string literals are prevented in BinExp::interpretAssignCommon.
1805             result = e;
1806         }
1807         else
1808         {
1809             // https://issues.dlang.org/show_bug.cgi?id=20811
1810             // Create a copy of mutable string literals, so that any change in
1811             // value via an index or slice will not survive CTFE.
1812             *pue = copyLiteral(e);
1813             result = pue.exp();
1814         }
1815     }
1816 
1817     override void visit(FuncExp e)
1818     {
1819         debug (LOG)
1820         {
1821             printf("%s FuncExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1822         }
1823         result = e;
1824     }
1825 
1826     override void visit(SymOffExp e)
1827     {
1828         debug (LOG)
1829         {
1830             printf("%s SymOffExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1831         }
1832         if (e.var.isFuncDeclaration() && e.offset == 0)
1833         {
1834             result = e;
1835             return;
1836         }
1837         if (isTypeInfo_Class(e.type) && e.offset == 0)
1838         {
1839             result = e;
1840             return;
1841         }
1842         if (e.type.ty != Tpointer)
1843         {
1844             // Probably impossible
1845             error(e.loc, "cannot interpret `%s` at compile time", e.toChars());
1846             result = CTFEExp.cantexp;
1847             return;
1848         }
1849         Type pointee = (cast(TypePointer)e.type).next;
1850         if (e.var.isThreadlocal())
1851         {
1852             error(e.loc, "cannot take address of thread-local variable %s at compile time", e.var.toChars());
1853             result = CTFEExp.cantexp;
1854             return;
1855         }
1856         // Check for taking an address of a shared variable.
1857         // If the shared variable is an array, the offset might not be zero.
1858         Type fromType = null;
1859         if (e.var.type.ty == Tarray || e.var.type.ty == Tsarray)
1860         {
1861             fromType = (cast(TypeArray)e.var.type).next;
1862         }
1863         if (e.var.isDataseg() && ((e.offset == 0 && isSafePointerCast(e.var.type, pointee)) ||
1864                                   (fromType && isSafePointerCast(fromType, pointee)) ||
1865                                   (e.var.isCsymbol() && e.offset + pointee.size() <= e.var.type.size())))
1866         {
1867             result = e;
1868             return;
1869         }
1870 
1871         Expression val = getVarExp(e.loc, istate, e.var, goal);
1872         if (exceptionOrCant(val))
1873             return;
1874         if (val.type.ty == Tarray || val.type.ty == Tsarray)
1875         {
1876             // Check for unsupported type painting operations
1877             Type elemtype = (cast(TypeArray)val.type).next;
1878             const elemsize = elemtype.size();
1879 
1880             // It's OK to cast from fixed length to fixed length array, eg &int[n] to int[d]*.
1881             if (val.type.ty == Tsarray && pointee.ty == Tsarray && elemsize == pointee.nextOf().size())
1882             {
1883                 size_t d = cast(size_t)(cast(TypeSArray)pointee).dim.toInteger();
1884                 Expression elwr = ctfeEmplaceExp!IntegerExp(e.loc, e.offset / elemsize, Type.tsize_t);
1885                 Expression eupr = ctfeEmplaceExp!IntegerExp(e.loc, e.offset / elemsize + d, Type.tsize_t);
1886 
1887                 // Create a CTFE pointer &val[ofs..ofs+d]
1888                 auto se = ctfeEmplaceExp!SliceExp(e.loc, val, elwr, eupr);
1889                 se.type = pointee;
1890                 emplaceExp!(AddrExp)(pue, e.loc, se, e.type);
1891                 result = pue.exp();
1892                 return;
1893             }
1894 
1895             if (!isSafePointerCast(elemtype, pointee))
1896             {
1897                 // It's also OK to cast from &string to string*.
1898                 if (e.offset == 0 && isSafePointerCast(e.var.type, pointee))
1899                 {
1900                     // Create a CTFE pointer &var
1901                     auto ve = ctfeEmplaceExp!VarExp(e.loc, e.var);
1902                     ve.type = elemtype;
1903                     emplaceExp!(AddrExp)(pue, e.loc, ve, e.type);
1904                     result = pue.exp();
1905                     return;
1906                 }
1907                 error(e.loc, "reinterpreting cast from `%s` to `%s` is not supported in CTFE", val.type.toChars(), e.type.toChars());
1908                 result = CTFEExp.cantexp;
1909                 return;
1910             }
1911 
1912             const dinteger_t sz = pointee.size();
1913             dinteger_t indx = e.offset / sz;
1914             assert(sz * indx == e.offset);
1915             Expression aggregate = null;
1916             if (val.op == EXP.arrayLiteral || val.op == EXP.string_)
1917             {
1918                 aggregate = val;
1919             }
1920             else if (auto se = val.isSliceExp())
1921             {
1922                 aggregate = se.e1;
1923                 UnionExp uelwr = void;
1924                 Expression lwr = interpret(&uelwr, se.lwr, istate);
1925                 indx += lwr.toInteger();
1926             }
1927             if (aggregate)
1928             {
1929                 // Create a CTFE pointer &aggregate[ofs]
1930                 auto ofs = ctfeEmplaceExp!IntegerExp(e.loc, indx, Type.tsize_t);
1931                 auto ei = ctfeEmplaceExp!IndexExp(e.loc, aggregate, ofs);
1932                 ei.type = elemtype;
1933                 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
1934                 result = pue.exp();
1935                 return;
1936             }
1937         }
1938         else if (e.offset == 0 && isSafePointerCast(e.var.type, pointee))
1939         {
1940             // Create a CTFE pointer &var
1941             auto ve = ctfeEmplaceExp!VarExp(e.loc, e.var);
1942             ve.type = e.var.type;
1943             emplaceExp!(AddrExp)(pue, e.loc, ve, e.type);
1944             result = pue.exp();
1945             return;
1946         }
1947 
1948         error(e.loc, "cannot convert `&%s` to `%s` at compile time", e.var.type.toChars(), e.type.toChars());
1949         result = CTFEExp.cantexp;
1950     }
1951 
1952     override void visit(AddrExp e)
1953     {
1954         debug (LOG)
1955         {
1956             printf("%s AddrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1957         }
1958         if (auto ve = e.e1.isVarExp())
1959         {
1960             Declaration decl = ve.var;
1961 
1962             // We cannot take the address of an imported symbol at compile time
1963             if (decl.isImportedSymbol()) {
1964                 error(e.loc, "cannot take address of imported symbol `%s` at compile time", decl.toChars());
1965                 result = CTFEExp.cantexp;
1966                 return;
1967             }
1968 
1969             if (decl.isDataseg()) {
1970                 // Normally this is already done by optimize()
1971                 // Do it here in case optimize(WANTvalue) wasn't run before CTFE
1972                 emplaceExp!(SymOffExp)(pue, e.loc, e.e1.isVarExp().var, 0);
1973                 result = pue.exp();
1974                 result.type = e.type;
1975                 return;
1976             }
1977         }
1978         auto er = interpret(e.e1, istate, CTFEGoal.LValue);
1979         if (auto ve = er.isVarExp())
1980             if (istate && ve.var == istate.fd.vthis)
1981                 er = interpret(er, istate);
1982 
1983         if (exceptionOrCant(er))
1984             return;
1985 
1986         // Return a simplified address expression
1987         emplaceExp!(AddrExp)(pue, e.loc, er, e.type);
1988         result = pue.exp();
1989     }
1990 
1991     override void visit(DelegateExp e)
1992     {
1993         debug (LOG)
1994         {
1995             printf("%s DelegateExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1996         }
1997         // TODO: Really we should create a CTFE-only delegate expression
1998         // of a pointer and a funcptr.
1999 
2000         // If it is &nestedfunc, just return it
2001         // TODO: We should save the context pointer
2002         if (auto ve1 = e.e1.isVarExp())
2003             if (ve1.var == e.func)
2004             {
2005                 result = e;
2006                 return;
2007             }
2008 
2009         auto er = interpret(pue, e.e1, istate);
2010         if (exceptionOrCant(er))
2011             return;
2012         if (er == e.e1)
2013         {
2014             // If it has already been CTFE'd, just return it
2015             result = e;
2016         }
2017         else
2018         {
2019             er = (er == pue.exp()) ? pue.copy() : er;
2020             emplaceExp!(DelegateExp)(pue, e.loc, er, e.func, false);
2021             result = pue.exp();
2022             result.type = e.type;
2023         }
2024     }
2025 
2026     static Expression getVarExp(const ref Loc loc, InterState* istate, Declaration d, CTFEGoal goal)
2027     {
2028         Expression e = CTFEExp.cantexp;
2029         if (VarDeclaration v = d.isVarDeclaration())
2030         {
2031             /* Magic variable __ctfe always returns true when interpreting
2032              */
2033             if (v.ident == Id.ctfe)
2034                 return IntegerExp.createBool(true);
2035 
2036             if (!v.originalType && v.semanticRun < PASS.semanticdone) // semantic() not yet run
2037             {
2038                 v.dsymbolSemantic(null);
2039                 if (v.type.ty == Terror)
2040                     return CTFEExp.cantexp;
2041             }
2042 
2043             if ((v.isConst() || v.isImmutable() || v.storage_class & STC.manifest) && !hasValue(v) && v._init && !v.isCTFE())
2044             {
2045                 if (v.inuse)
2046                 {
2047                     error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
2048                     return CTFEExp.cantexp;
2049                 }
2050                 if (v._scope)
2051                 {
2052                     v.inuse++;
2053                     v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret); // might not be run on aggregate members
2054                     v.inuse--;
2055                 }
2056                 e = v._init.initializerToExpression(v.type);
2057                 if (!e)
2058                     return CTFEExp.cantexp;
2059                 assert(e.type);
2060 
2061                 // There's a terrible hack in `dmd.dsymbolsem` that special case
2062                 // a struct with all zeros to an `ExpInitializer(BlitExp(IntegerExp(0)))`
2063                 // There's matching code for it in e2ir (toElem's visitAssignExp),
2064                 // so we need the same hack here.
2065                 // This does not trigger for global as they get a normal initializer.
2066                 if (auto ts = e.type.isTypeStruct())
2067                     if (auto ae = e.isBlitExp())
2068                         if (ae.e2.op == EXP.int64)
2069                             e = ts.defaultInitLiteral(loc);
2070 
2071                 if (e.op == EXP.construct || e.op == EXP.blit)
2072                 {
2073                     AssignExp ae = cast(AssignExp)e;
2074                     e = ae.e2;
2075                 }
2076 
2077                 if (e.op == EXP.error)
2078                 {
2079                     // FIXME: Ultimately all errors should be detected in prior semantic analysis stage.
2080                 }
2081                 else if (v.isDataseg() || (v.storage_class & STC.manifest))
2082                 {
2083                     /* https://issues.dlang.org/show_bug.cgi?id=14304
2084                      * e is a value that is not yet owned by CTFE.
2085                      * Mark as "cached", and use it directly during interpretation.
2086                      */
2087                     e = scrubCacheValue(e);
2088                     ctfeGlobals.stack.saveGlobalConstant(v, e);
2089                 }
2090                 else
2091                 {
2092                     v.inuse++;
2093                     e = interpret(e, istate);
2094                     v.inuse--;
2095                     if (CTFEExp.isCantExp(e) && !global.gag && !ctfeGlobals.stackTraceCallsToSuppress)
2096                         errorSupplemental(loc, "while evaluating %s.init", v.toChars());
2097                     if (exceptionOrCantInterpret(e))
2098                         return e;
2099                 }
2100             }
2101             else if (v.isCTFE() && !hasValue(v))
2102             {
2103                 if (v._init && v.type.size() != 0)
2104                 {
2105                     if (v._init.isVoidInitializer())
2106                     {
2107                         // var should have been initialized when it was created
2108                         error(loc, "CTFE internal error: trying to access uninitialized var");
2109                         assert(0);
2110                     }
2111                     e = v._init.initializerToExpression();
2112                 }
2113                 else
2114                     // Zero-length arrays don't have an initializer
2115                     e = v.type.defaultInitLiteral(e.loc);
2116 
2117                 e = interpret(e, istate);
2118             }
2119             else if (!(v.isDataseg() || v.storage_class & STC.manifest) && !v.isCTFE() && !istate)
2120             {
2121                 error(loc, "variable `%s` cannot be read at compile time", v.toChars());
2122                 return CTFEExp.cantexp;
2123             }
2124             else
2125             {
2126                 e = hasValue(v) ? getValue(v) : null;
2127                 if (!e)
2128                 {
2129                     // Zero-length arrays don't have an initializer
2130                     if (v.type.size() == 0)
2131                         e = v.type.defaultInitLiteral(loc);
2132                     else if (!v.isCTFE() && v.isDataseg())
2133                     {
2134                         error(loc, "static variable `%s` cannot be read at compile time", v.toChars());
2135                         return CTFEExp.cantexp;
2136                     }
2137                     else
2138                     {
2139                         assert(!(v._init && v._init.isVoidInitializer()));
2140                         // CTFE initiated from inside a function
2141                         error(loc, "variable `%s` cannot be read at compile time", v.toChars());
2142                         return CTFEExp.cantexp;
2143                     }
2144                 }
2145                 if (auto vie = e.isVoidInitExp())
2146                 {
2147                     error(loc, "cannot read uninitialized variable `%s` in ctfe", v.toPrettyChars());
2148                     errorSupplemental(vie.var.loc, "`%s` was uninitialized and used before set", vie.var.toChars());
2149                     return CTFEExp.cantexp;
2150                 }
2151                 if (goal != CTFEGoal.LValue && v.isReference())
2152                     e = interpret(e, istate, goal);
2153             }
2154             if (!e)
2155                 e = CTFEExp.cantexp;
2156         }
2157         else if (SymbolDeclaration s = d.isSymbolDeclaration())
2158         {
2159             // exclude void[]-typed `__traits(initSymbol)`
2160             if (auto ta = s.type.toBasetype().isTypeDArray())
2161             {
2162                 assert(ta.next.ty == Tvoid);
2163                 error(loc, "cannot determine the address of the initializer symbol during CTFE");
2164                 return CTFEExp.cantexp;
2165             }
2166 
2167             // Struct static initializers, for example
2168             e = s.dsym.type.defaultInitLiteral(loc);
2169             if (e.op == EXP.error)
2170                 error(loc, "CTFE failed because of previous errors in `%s.init`", s.toChars());
2171             e = e.expressionSemantic(null);
2172             if (e.op == EXP.error)
2173                 e = CTFEExp.cantexp;
2174             else // Convert NULL to CTFEExp
2175                 e = interpret(e, istate, goal);
2176         }
2177         else
2178             error(loc, "cannot interpret declaration `%s` at compile time", d.toChars());
2179         return e;
2180     }
2181 
2182     override void visit(VarExp e)
2183     {
2184         debug (LOG)
2185         {
2186             printf("%s VarExp::interpret() `%s`, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
2187         }
2188         if (e.var.isFuncDeclaration())
2189         {
2190             result = e;
2191             return;
2192         }
2193 
2194         if (goal == CTFEGoal.LValue)
2195         {
2196             if (auto v = e.var.isVarDeclaration())
2197             {
2198                 if (!hasValue(v))
2199                 {
2200                     // Compile-time known non-CTFE variable from an outer context
2201                     // e.g. global or from a ref argument
2202                     if (v.isConst() || v.isImmutable())
2203                     {
2204                         result = getVarExp(e.loc, istate, v, goal);
2205                         return;
2206                     }
2207 
2208                     if (!v.isCTFE() && v.isDataseg())
2209                         error(e.loc, "static variable `%s` cannot be read at compile time", v.toChars());
2210                     else // CTFE initiated from inside a function
2211                         error(e.loc, "variable `%s` cannot be read at compile time", v.toChars());
2212                     result = CTFEExp.cantexp;
2213                     return;
2214                 }
2215 
2216                 if (v.storage_class & (STC.out_ | STC.ref_))
2217                 {
2218                     // Strip off the nest of ref variables
2219                     Expression ev = getValue(v);
2220                     if (ev.op == EXP.variable ||
2221                         ev.op == EXP.index ||
2222                         (ev.op == EXP.slice && ev.type.toBasetype().ty == Tsarray) ||
2223                         ev.op == EXP.dotVariable)
2224                     {
2225                         result = interpret(pue, ev, istate, goal);
2226                         return;
2227                     }
2228                 }
2229             }
2230             result = e;
2231             return;
2232         }
2233         result = getVarExp(e.loc, istate, e.var, goal);
2234         if (exceptionOrCant(result))
2235             return;
2236 
2237         // Visit the default initializer for noreturn variables
2238         // (Custom initializers would abort the current function call and exit above)
2239         if (result.type.ty == Tnoreturn)
2240         {
2241             result.accept(this);
2242             return;
2243         }
2244 
2245         if ((e.var.storage_class & (STC.ref_ | STC.out_)) == 0 && e.type.baseElemOf().ty != Tstruct)
2246         {
2247             /* Ultimately, STC.ref_|STC.out_ check should be enough to see the
2248              * necessity of type repainting. But currently front-end paints
2249              * non-ref struct variables by the const type.
2250              *
2251              *  auto foo(ref const S cs);
2252              *  S s;
2253              *  foo(s); // VarExp('s') will have const(S)
2254              */
2255             // A VarExp may include an implicit cast. It must be done explicitly.
2256             result = paintTypeOntoLiteral(pue, e.type, result);
2257         }
2258     }
2259 
2260     override void visit(DeclarationExp e)
2261     {
2262         debug (LOG)
2263         {
2264             printf("%s DeclarationExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2265         }
2266         Dsymbol s = e.declaration;
2267         while (s.isAttribDeclaration())
2268         {
2269             auto ad = cast(AttribDeclaration)s;
2270             assert(ad.decl && ad.decl.length == 1); // Currently, only one allowed when parsing
2271             s = (*ad.decl)[0];
2272         }
2273         if (VarDeclaration v = s.isVarDeclaration())
2274         {
2275             if (TupleDeclaration td = v.toAlias().isTupleDeclaration())
2276             {
2277                 result = null;
2278 
2279                 // Reserve stack space for all tuple members
2280                 td.foreachVar((s)
2281                 {
2282                     VarDeclaration v2 = s.isVarDeclaration();
2283                     assert(v2);
2284                     if (v2.isDataseg() && !v2.isCTFE())
2285                         return 0;
2286 
2287                     ctfeGlobals.stack.push(v2);
2288                     if (v2._init)
2289                     {
2290                         Expression einit;
2291                         if (ExpInitializer ie = v2._init.isExpInitializer())
2292                         {
2293                             einit = interpretRegion(ie.exp, istate, goal);
2294                             if (exceptionOrCant(einit))
2295                                 return 1;
2296                         }
2297                         else if (v2._init.isVoidInitializer())
2298                         {
2299                             einit = voidInitLiteral(v2.type, v2).copy();
2300                         }
2301                         else
2302                         {
2303                             error(e.loc, "declaration `%s` is not yet implemented in CTFE", e.toChars());
2304                             result = CTFEExp.cantexp;
2305                             return 1;
2306                         }
2307                         setValue(v2, einit);
2308                     }
2309                     return 0;
2310                 });
2311                 return;
2312             }
2313             if (v.isStatic())
2314             {
2315                 // Just ignore static variables which aren't read or written yet
2316                 result = null;
2317                 return;
2318             }
2319             if (!(v.isDataseg() || v.storage_class & STC.manifest) || v.isCTFE())
2320                 ctfeGlobals.stack.push(v);
2321             if (v._init)
2322             {
2323                 if (ExpInitializer ie = v._init.isExpInitializer())
2324                 {
2325                     result = interpretRegion(ie.exp, istate, goal);
2326                     return;
2327                 }
2328                 else if (v._init.isVoidInitializer())
2329                 {
2330                     result = voidInitLiteral(v.type, v).copy();
2331                     // There is no AssignExp for void initializers,
2332                     // so set it here.
2333                     setValue(v, result);
2334                     return;
2335                 }
2336                 else if (v._init.isArrayInitializer())
2337                 {
2338                     result = v._init.initializerToExpression(v.type);
2339                     if (result !is null)
2340                         return;
2341                 }
2342                 error(e.loc, "declaration `%s` is not yet implemented in CTFE", e.toChars());
2343                 result = CTFEExp.cantexp;
2344             }
2345             else if (v.type.size() == 0)
2346             {
2347                 // Zero-length arrays don't need an initializer
2348                 result = v.type.defaultInitLiteral(e.loc);
2349             }
2350             else
2351             {
2352                 error(e.loc, "variable `%s` cannot be modified at compile time", v.toChars());
2353                 result = CTFEExp.cantexp;
2354             }
2355             return;
2356         }
2357         if (s.isTemplateMixin() || s.isTupleDeclaration())
2358         {
2359             // These can be made to work, too lazy now
2360             error(e.loc, "declaration `%s` is not yet implemented in CTFE", e.toChars());
2361             result = CTFEExp.cantexp;
2362             return;
2363         }
2364 
2365         // Others should not contain executable code, so are trivial to evaluate
2366         result = null;
2367         debug (LOG)
2368         {
2369             printf("-DeclarationExp::interpret(%s): %p\n", e.toChars(), result);
2370         }
2371     }
2372 
2373     override void visit(TypeidExp e)
2374     {
2375         debug (LOG)
2376         {
2377             printf("%s TypeidExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2378         }
2379         if (Type t = isType(e.obj))
2380         {
2381             result = e;
2382             return;
2383         }
2384         if (Expression ex = isExpression(e.obj))
2385         {
2386             result = interpret(pue, ex, istate);
2387             if (exceptionOrCant(ex))
2388                 return;
2389 
2390             if (result.op == EXP.null_)
2391             {
2392                 error(e.loc, "null pointer dereference evaluating typeid. `%s` is `null`", ex.toChars());
2393                 result = CTFEExp.cantexp;
2394                 return;
2395             }
2396             if (result.op != EXP.classReference)
2397             {
2398                 error(e.loc, "CTFE internal error: determining classinfo");
2399                 result = CTFEExp.cantexp;
2400                 return;
2401             }
2402 
2403             ClassDeclaration cd = result.isClassReferenceExp().originalClass();
2404             assert(cd);
2405 
2406             emplaceExp!(TypeidExp)(pue, e.loc, cd.type);
2407             result = pue.exp();
2408             result.type = e.type;
2409             return;
2410         }
2411         visit(cast(Expression)e);
2412     }
2413 
2414     override void visit(TupleExp e)
2415     {
2416         debug (LOG)
2417         {
2418             printf("%s TupleExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2419         }
2420         if (exceptionOrCant(interpretRegion(e.e0, istate, CTFEGoal.Nothing)))
2421             return;
2422 
2423         auto expsx = e.exps;
2424         foreach (i, exp; *expsx)
2425         {
2426             Expression ex = interpretRegion(exp, istate);
2427             if (exceptionOrCant(ex))
2428                 return;
2429 
2430             // A tuple of assignments can contain void (Bug 5676).
2431             if (goal == CTFEGoal.Nothing)
2432                 continue;
2433             if (ex.op == EXP.voidExpression)
2434             {
2435                 error(e.loc, "CTFE internal error: void element `%s` in sequence", exp.toChars());
2436                 assert(0);
2437             }
2438 
2439             /* If any changes, do Copy On Write
2440              */
2441             if (ex !is exp)
2442             {
2443                 expsx = copyArrayOnWrite(expsx, e.exps);
2444                 (*expsx)[i] = copyRegionExp(ex);
2445             }
2446         }
2447 
2448         if (expsx !is e.exps)
2449         {
2450             expandTuples(expsx);
2451             emplaceExp!(TupleExp)(pue, e.loc, expsx);
2452             result = pue.exp();
2453             result.type = new TypeTuple(expsx);
2454         }
2455         else
2456             result = e;
2457     }
2458 
2459     override void visit(ArrayLiteralExp e)
2460     {
2461         debug (LOG)
2462         {
2463             printf("%s ArrayLiteralExp::interpret() %s, %s\n", e.loc.toChars(), e.type.toChars(), e.toChars());
2464         }
2465         if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
2466         {
2467             result = e;
2468             return;
2469         }
2470 
2471         Type tb = e.type.toBasetype();
2472         Type tn = tb.nextOf().toBasetype();
2473         bool wantCopy = (tn.ty == Tsarray || tn.ty == Tstruct);
2474 
2475         auto basis = interpretRegion(e.basis, istate);
2476         if (exceptionOrCant(basis))
2477             return;
2478 
2479         auto expsx = e.elements;
2480         size_t dim = expsx ? expsx.length : 0;
2481 
2482         for (size_t i = 0; i < dim; i++)
2483         {
2484             Expression exp = (*expsx)[i];
2485             Expression ex;
2486             if (!exp)
2487             {
2488                 ex = copyLiteral(basis).copy();
2489             }
2490             else
2491             {
2492                 // segfault bug 6250
2493                 assert(exp.op != EXP.index || exp.isIndexExp().e1 != e);
2494 
2495                 ex = interpretRegion(exp, istate);
2496                 if (exceptionOrCant(ex))
2497                     return;
2498 
2499                 /* Each elements should have distinct CTFE memory.
2500                  *  int[1] z = 7;
2501                  *  int[1][] pieces = [z,z];    // here
2502                  */
2503                 if (wantCopy)
2504                     ex = copyLiteral(ex).copy();
2505             }
2506 
2507             /* If any changes, do Copy On Write
2508              */
2509             if (ex !is exp)
2510             {
2511                 expsx = copyArrayOnWrite(expsx, e.elements);
2512                 (*expsx)[i] = ex;
2513             }
2514         }
2515 
2516         if (expsx !is e.elements)
2517         {
2518             // todo: all tuple expansions should go in semantic phase.
2519             expandTuples(expsx);
2520             if (expsx.length != dim)
2521             {
2522                 error(e.loc, "CTFE internal error: invalid array literal");
2523                 result = CTFEExp.cantexp;
2524                 return;
2525             }
2526             emplaceExp!(ArrayLiteralExp)(pue, e.loc, e.type, basis, expsx);
2527             auto ale = pue.exp().isArrayLiteralExp();
2528             ale.ownedByCtfe = OwnedBy.ctfe;
2529             result = ale;
2530         }
2531         else if ((cast(TypeNext)e.type).next.mod & (MODFlags.const_ | MODFlags.immutable_))
2532         {
2533             // If it's immutable, we don't need to dup it
2534             result = e;
2535         }
2536         else
2537         {
2538             *pue = copyLiteral(e);
2539             result = pue.exp();
2540         }
2541     }
2542 
2543     override void visit(AssocArrayLiteralExp e)
2544     {
2545         debug (LOG)
2546         {
2547             printf("%s AssocArrayLiteralExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2548         }
2549         if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
2550         {
2551             result = e;
2552             return;
2553         }
2554 
2555         auto keysx = e.keys;
2556         auto valuesx = e.values;
2557         foreach (i, ekey; *keysx)
2558         {
2559             auto evalue = (*valuesx)[i];
2560 
2561             auto ek = interpretRegion(ekey, istate);
2562             if (exceptionOrCant(ek))
2563                 return;
2564             auto ev = interpretRegion(evalue, istate);
2565             if (exceptionOrCant(ev))
2566                 return;
2567 
2568             /* If any changes, do Copy On Write
2569              */
2570             if (ek !is ekey ||
2571                 ev !is evalue)
2572             {
2573                 keysx = copyArrayOnWrite(keysx, e.keys);
2574                 valuesx = copyArrayOnWrite(valuesx, e.values);
2575                 (*keysx)[i] = ek;
2576                 (*valuesx)[i] = ev;
2577             }
2578         }
2579         if (keysx !is e.keys)
2580             expandTuples(keysx);
2581         if (valuesx !is e.values)
2582             expandTuples(valuesx);
2583         if (keysx.length != valuesx.length)
2584         {
2585             error(e.loc, "CTFE internal error: invalid AA");
2586             result = CTFEExp.cantexp;
2587             return;
2588         }
2589 
2590         /* Remove duplicate keys
2591          */
2592         for (size_t i = 1; i < keysx.length; i++)
2593         {
2594             auto ekey = (*keysx)[i - 1];
2595             for (size_t j = i; j < keysx.length; j++)
2596             {
2597                 auto ekey2 = (*keysx)[j];
2598                 if (!ctfeEqual(e.loc, EXP.equal, ekey, ekey2))
2599                     continue;
2600 
2601                 // Remove ekey
2602                 keysx = copyArrayOnWrite(keysx, e.keys);
2603                 valuesx = copyArrayOnWrite(valuesx, e.values);
2604                 keysx.remove(i - 1);
2605                 valuesx.remove(i - 1);
2606 
2607                 i -= 1; // redo the i'th iteration
2608                 break;
2609             }
2610         }
2611 
2612         if (keysx !is e.keys ||
2613             valuesx !is e.values)
2614         {
2615             assert(keysx !is e.keys &&
2616                    valuesx !is e.values);
2617             auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
2618             aae.type = e.type;
2619             aae.ownedByCtfe = OwnedBy.ctfe;
2620             result = aae;
2621         }
2622         else
2623         {
2624             *pue = copyLiteral(e);
2625             result = pue.exp();
2626         }
2627     }
2628 
2629     override void visit(StructLiteralExp e)
2630     {
2631         debug (LOG)
2632         {
2633             printf("%s StructLiteralExp::interpret() %s ownedByCtfe = %d\n", e.loc.toChars(), e.toChars(), e.ownedByCtfe);
2634         }
2635         if (e.ownedByCtfe >= OwnedBy.ctfe)
2636         {
2637             result = e;
2638             return;
2639         }
2640 
2641         size_t dim = e.elements ? e.elements.length : 0;
2642         auto expsx = e.elements;
2643 
2644         if (dim != e.sd.fields.length)
2645         {
2646             // guaranteed by AggregateDeclaration.fill and TypeStruct.defaultInitLiteral
2647             const nvthis = e.sd.fields.length - e.sd.nonHiddenFields();
2648             assert(e.sd.fields.length - dim == nvthis);
2649 
2650             /* If a nested struct has no initialized hidden pointer,
2651              * set it to null to match the runtime behaviour.
2652              */
2653             foreach (const i; 0 .. nvthis)
2654             {
2655                 auto ne = ctfeEmplaceExp!NullExp(e.loc);
2656                 auto vthis = i == 0 ? e.sd.vthis : e.sd.vthis2;
2657                 ne.type = vthis.type;
2658 
2659                 expsx = copyArrayOnWrite(expsx, e.elements);
2660                 expsx.push(ne);
2661                 ++dim;
2662             }
2663         }
2664         assert(dim == e.sd.fields.length);
2665 
2666         foreach (i; 0 .. dim)
2667         {
2668             auto v = e.sd.fields[i];
2669             Expression exp = (*expsx)[i];
2670             Expression ex;
2671             if (!exp)
2672             {
2673                 ex = voidInitLiteral(v.type, v).copy();
2674             }
2675             else
2676             {
2677                 ex = interpretRegion(exp, istate);
2678                 if (exceptionOrCant(ex))
2679                     return;
2680                 if ((v.type.ty != ex.type.ty) && v.type.ty == Tsarray)
2681                 {
2682                     // Block assignment from inside struct literals
2683                     auto tsa = cast(TypeSArray)v.type;
2684                     auto len = cast(size_t)tsa.dim.toInteger();
2685                     UnionExp ue = void;
2686                     ex = createBlockDuplicatedArrayLiteral(&ue, ex.loc, v.type, ex, len);
2687                     if (ex == ue.exp())
2688                         ex = ue.copy();
2689                 }
2690             }
2691 
2692             /* If any changes, do Copy On Write
2693              */
2694             if (ex !is exp)
2695             {
2696                 expsx = copyArrayOnWrite(expsx, e.elements);
2697                 (*expsx)[i] = ex;
2698             }
2699         }
2700 
2701         if (expsx !is e.elements)
2702         {
2703             expandTuples(expsx);
2704             if (expsx.length != e.sd.fields.length)
2705             {
2706                 error(e.loc, "CTFE internal error: invalid struct literal");
2707                 result = CTFEExp.cantexp;
2708                 return;
2709             }
2710             emplaceExp!(StructLiteralExp)(pue, e.loc, e.sd, expsx);
2711             auto sle = pue.exp().isStructLiteralExp();
2712             sle.type = e.type;
2713             sle.ownedByCtfe = OwnedBy.ctfe;
2714             sle.origin = e.origin;
2715             result = sle;
2716         }
2717         else
2718         {
2719             *pue = copyLiteral(e);
2720             result = pue.exp();
2721         }
2722     }
2723 
2724     // Create an array literal of type 'newtype' with dimensions given by
2725     // 'arguments'[argnum..$]
2726     static Expression recursivelyCreateArrayLiteral(UnionExp* pue, const ref Loc loc, Type newtype, InterState* istate, Expressions* arguments, int argnum)
2727     {
2728         Expression lenExpr = interpret(pue, (*arguments)[argnum], istate);
2729         if (exceptionOrCantInterpret(lenExpr))
2730             return lenExpr;
2731         size_t len = cast(size_t)lenExpr.toInteger();
2732         Type elemType = (cast(TypeArray)newtype).next;
2733         if (elemType.ty == Tarray && argnum < arguments.length - 1)
2734         {
2735             Expression elem = recursivelyCreateArrayLiteral(pue, loc, elemType, istate, arguments, argnum + 1);
2736             if (exceptionOrCantInterpret(elem))
2737                 return elem;
2738 
2739             auto elements = new Expressions(len);
2740             foreach (ref element; *elements)
2741                 element = copyLiteral(elem).copy();
2742             emplaceExp!(ArrayLiteralExp)(pue, loc, newtype, elements);
2743             auto ae = pue.exp().isArrayLiteralExp();
2744             ae.ownedByCtfe = OwnedBy.ctfe;
2745             return ae;
2746         }
2747         assert(argnum == arguments.length - 1);
2748         if (elemType.ty.isSomeChar)
2749         {
2750             const ch = cast(dchar)elemType.defaultInitLiteral(loc).toInteger();
2751             const sz = cast(ubyte)elemType.size();
2752             return createBlockDuplicatedStringLiteral(pue, loc, newtype, ch, len, sz);
2753         }
2754         else
2755         {
2756             auto el = interpret(elemType.defaultInitLiteral(loc), istate);
2757             return createBlockDuplicatedArrayLiteral(pue, loc, newtype, el, len);
2758         }
2759     }
2760 
2761     override void visit(NewExp e)
2762     {
2763         debug (LOG)
2764         {
2765             printf("%s NewExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2766         }
2767 
2768         Expression epre = interpret(pue, e.argprefix, istate, CTFEGoal.Nothing);
2769         if (exceptionOrCant(epre))
2770             return;
2771 
2772         if (e.newtype.ty == Tarray && e.arguments)
2773         {
2774             result = recursivelyCreateArrayLiteral(pue, e.loc, e.newtype, istate, e.arguments, 0);
2775             return;
2776         }
2777         if (auto ts = e.newtype.toBasetype().isTypeStruct())
2778         {
2779             if (e.member)
2780             {
2781                 Expression se = e.newtype.defaultInitLiteral(e.loc);
2782                 se = interpret(se, istate);
2783                 if (exceptionOrCant(se))
2784                     return;
2785                 result = interpretFunction(pue, e.member, istate, e.arguments, se);
2786 
2787                 // Repaint as same as CallExp::interpret() does.
2788                 result.loc = e.loc;
2789             }
2790             else
2791             {
2792                 StructDeclaration sd = ts.sym;
2793                 auto exps = new Expressions();
2794                 exps.reserve(sd.fields.length);
2795                 if (e.arguments)
2796                 {
2797                     exps.setDim(e.arguments.length);
2798                     foreach (i, ex; *e.arguments)
2799                     {
2800                         ex = interpretRegion(ex, istate);
2801                         if (exceptionOrCant(ex))
2802                             return;
2803                         (*exps)[i] = ex;
2804                     }
2805                 }
2806                 sd.fill(e.loc, *exps, false);
2807 
2808                 auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, sd, exps, e.newtype);
2809                 se.origin = se;
2810                 se.type = e.newtype;
2811                 se.ownedByCtfe = OwnedBy.ctfe;
2812                 result = interpret(pue, se, istate);
2813             }
2814             if (exceptionOrCant(result))
2815                 return;
2816             Expression ev = (result == pue.exp()) ? pue.copy() : result;
2817             emplaceExp!(AddrExp)(pue, e.loc, ev, e.type);
2818             result = pue.exp();
2819             return;
2820         }
2821         if (auto tc = e.newtype.toBasetype().isTypeClass())
2822         {
2823             ClassDeclaration cd = tc.sym;
2824             size_t totalFieldCount = 0;
2825             for (ClassDeclaration c = cd; c; c = c.baseClass)
2826                 totalFieldCount += c.fields.length;
2827             auto elems = new Expressions(totalFieldCount);
2828             size_t fieldsSoFar = totalFieldCount;
2829             for (ClassDeclaration c = cd; c; c = c.baseClass)
2830             {
2831                 fieldsSoFar -= c.fields.length;
2832                 foreach (i, v; c.fields)
2833                 {
2834                     if (v.inuse)
2835                     {
2836                         error(e.loc, "circular reference to `%s`", v.toPrettyChars());
2837                         result = CTFEExp.cantexp;
2838                         return;
2839                     }
2840                     Expression m;
2841                     if (v._init)
2842                     {
2843                         if (v._init.isVoidInitializer())
2844                             m = voidInitLiteral(v.type, v).copy();
2845                         else
2846                             m = v.getConstInitializer(true);
2847                     }
2848                     else if (v.type.isTypeNoreturn())
2849                     {
2850                         // Noreturn field with default initializer
2851                         (*elems)[fieldsSoFar + i] = null;
2852                         continue;
2853                     }
2854                     else
2855                         m = v.type.defaultInitLiteral(e.loc);
2856                     if (exceptionOrCant(m))
2857                         return;
2858                     (*elems)[fieldsSoFar + i] = copyLiteral(m).copy();
2859                 }
2860             }
2861             // Hack: we store a ClassDeclaration instead of a StructDeclaration.
2862             // We probably won't get away with this.
2863 //            auto se = new StructLiteralExp(e.loc, cast(StructDeclaration)cd, elems, e.newtype);
2864             auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, cast(StructDeclaration)cd, elems, e.newtype);
2865             se.origin = se;
2866             se.ownedByCtfe = OwnedBy.ctfe;
2867             Expression eref = ctfeEmplaceExp!ClassReferenceExp(e.loc, se, e.type);
2868             if (e.member)
2869             {
2870                 // Call constructor
2871                 if (!e.member.fbody)
2872                 {
2873                     Expression ctorfail = evaluateIfBuiltin(pue, istate, e.loc, e.member, e.arguments, eref);
2874                     if (ctorfail)
2875                     {
2876                         if (exceptionOrCant(ctorfail))
2877                             return;
2878                         result = eref;
2879                         return;
2880                     }
2881                     auto m = e.member;
2882                     error(m.loc, "%s `%s` `%s` cannot be constructed at compile time, because the constructor has no available source code",
2883                         m.kind, m.toPrettyChars, e.newtype.toChars());
2884                     result = CTFEExp.cantexp;
2885                     return;
2886                 }
2887                 UnionExp ue = void;
2888                 Expression ctorfail = interpretFunction(&ue, e.member, istate, e.arguments, eref);
2889                 if (exceptionOrCant(ctorfail))
2890                     return;
2891 
2892                 /* https://issues.dlang.org/show_bug.cgi?id=14465
2893                  * Repaint the loc, because a super() call
2894                  * in the constructor modifies the loc of ClassReferenceExp
2895                  * in CallExp::interpret().
2896                  */
2897                 eref.loc = e.loc;
2898             }
2899             result = eref;
2900             return;
2901         }
2902         if (e.newtype.toBasetype().isscalar())
2903         {
2904             Expression newval;
2905             if (e.arguments && e.arguments.length)
2906                 newval = (*e.arguments)[0];
2907             else
2908                 newval = e.newtype.defaultInitLiteral(e.loc);
2909             newval = interpretRegion(newval, istate);
2910             if (exceptionOrCant(newval))
2911                 return;
2912 
2913             // Create a CTFE pointer &[newval][0]
2914             auto elements = new Expressions(1);
2915             (*elements)[0] = newval;
2916             auto ae = ctfeEmplaceExp!ArrayLiteralExp(e.loc, e.newtype.arrayOf(), elements);
2917             ae.ownedByCtfe = OwnedBy.ctfe;
2918 
2919             auto ei = ctfeEmplaceExp!IndexExp(e.loc, ae, ctfeEmplaceExp!IntegerExp(Loc.initial, 0, Type.tsize_t));
2920             ei.type = e.newtype;
2921             emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
2922             result = pue.exp();
2923             return;
2924         }
2925         error(e.loc, "cannot interpret `%s` at compile time", e.toChars());
2926         result = CTFEExp.cantexp;
2927     }
2928 
2929     override void visit(UnaExp e)
2930     {
2931         debug (LOG)
2932         {
2933             printf("%s UnaExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2934         }
2935         UnionExp ue = void;
2936         Expression e1 = interpret(&ue, e.e1, istate);
2937         if (exceptionOrCant(e1))
2938             return;
2939         switch (e.op)
2940         {
2941         case EXP.negate:
2942             *pue = Neg(e.type, e1);
2943             break;
2944 
2945         case EXP.tilde:
2946             *pue = Com(e.type, e1);
2947             break;
2948 
2949         case EXP.not:
2950             *pue = Not(e.type, e1);
2951             break;
2952 
2953         default:
2954             assert(0);
2955         }
2956         result = (*pue).exp();
2957     }
2958 
2959     override void visit(DotTypeExp e)
2960     {
2961         debug (LOG)
2962         {
2963             printf("%s DotTypeExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2964         }
2965         UnionExp ue = void;
2966         Expression e1 = interpret(&ue, e.e1, istate);
2967         if (exceptionOrCant(e1))
2968             return;
2969         if (e1 == e.e1)
2970             result = e; // optimize: reuse this CTFE reference
2971         else
2972         {
2973             auto edt = e.copy().isDotTypeExp();
2974             edt.e1 = (e1 == ue.exp()) ? e1.copy() : e1; // don't return pointer to ue
2975             result = edt;
2976         }
2977     }
2978 
2979     private alias fp_t = extern (D) UnionExp function(const ref Loc loc, Type, Expression, Expression);
2980     private alias fp2_t = extern (D) bool function(const ref Loc loc, EXP, Expression, Expression);
2981 
2982     extern (D) private void interpretCommon(BinExp e, fp_t fp)
2983     {
2984         debug (LOG)
2985         {
2986             printf("%s BinExp::interpretCommon() %s\n", e.loc.toChars(), e.toChars());
2987         }
2988         if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer && e.op == EXP.min)
2989         {
2990             UnionExp ue1 = void;
2991             Expression e1 = interpret(&ue1, e.e1, istate);
2992             if (exceptionOrCant(e1))
2993                 return;
2994             UnionExp ue2 = void;
2995             Expression e2 = interpret(&ue2, e.e2, istate);
2996             if (exceptionOrCant(e2))
2997                 return;
2998             result = pointerDifference(pue, e.loc, e.type, e1, e2);
2999             return;
3000         }
3001         if (e.e1.type.ty == Tpointer && e.e2.type.isintegral())
3002         {
3003             UnionExp ue1 = void;
3004             Expression e1 = interpret(&ue1, e.e1, istate);
3005             if (exceptionOrCant(e1))
3006                 return;
3007             UnionExp ue2 = void;
3008             Expression e2 = interpret(&ue2, e.e2, istate);
3009             if (exceptionOrCant(e2))
3010                 return;
3011             result = pointerArithmetic(pue, e.loc, e.op, e.type, e1, e2);
3012             return;
3013         }
3014         if (e.e2.type.ty == Tpointer && e.e1.type.isintegral() && e.op == EXP.add)
3015         {
3016             UnionExp ue1 = void;
3017             Expression e1 = interpret(&ue1, e.e1, istate);
3018             if (exceptionOrCant(e1))
3019                 return;
3020             UnionExp ue2 = void;
3021             Expression e2 = interpret(&ue2, e.e2, istate);
3022             if (exceptionOrCant(e2))
3023                 return;
3024             result = pointerArithmetic(pue, e.loc, e.op, e.type, e2, e1);
3025             return;
3026         }
3027         if (e.e1.type.ty == Tpointer || e.e2.type.ty == Tpointer)
3028         {
3029             error(e.loc, "pointer expression `%s` cannot be interpreted at compile time", e.toChars());
3030             result = CTFEExp.cantexp;
3031             return;
3032         }
3033 
3034         bool evalOperand(UnionExp* pue, Expression ex, out Expression er)
3035         {
3036             er = interpret(pue, ex, istate);
3037             if (exceptionOrCant(er))
3038                 return false;
3039             return true;
3040         }
3041 
3042         UnionExp ue1 = void;
3043         Expression e1;
3044         if (!evalOperand(&ue1, e.e1, e1))
3045             return;
3046 
3047         UnionExp ue2 = void;
3048         Expression e2;
3049         if (!evalOperand(&ue2, e.e2, e2))
3050             return;
3051 
3052         if (e.op == EXP.rightShift || e.op == EXP.leftShift || e.op == EXP.unsignedRightShift)
3053         {
3054             const sinteger_t i2 = e2.toInteger();
3055             const uinteger_t sz = e1.type.size() * 8;
3056             if (i2 < 0 || i2 >= sz)
3057             {
3058                 error(e.loc, "shift by %lld is outside the range 0..%llu", i2, cast(ulong)sz - 1);
3059                 result = CTFEExp.cantexp;
3060                 return;
3061             }
3062         }
3063 
3064         /******************************************
3065          * Perform the operation fp on operands e1 and e2.
3066          */
3067         UnionExp evaluate(Loc loc, Type type, Expression e1, Expression e2)
3068         {
3069             UnionExp ue = void;
3070             auto ae1 = e1.isArrayLiteralExp();
3071             auto ae2 = e2.isArrayLiteralExp();
3072             if (ae1 || ae2)
3073             {
3074                 /* Cases:
3075                  * 1. T[] op T[]
3076                  * 2. T op T[]
3077                  * 3. T[] op T
3078                  */
3079                 if (ae1 && e2.implicitConvTo(e1.type.toBasetype().nextOf())) // case 3
3080                     ae2 = null;
3081                 else if (ae2 && e1.implicitConvTo(e2.type.toBasetype().nextOf())) // case 2
3082                     ae1 = null;
3083                 // else case 1
3084 
3085                 auto aex = ae1 ? ae1 : ae2;
3086                 if (!aex.elements)
3087                 {
3088                     emplaceExp!ArrayLiteralExp(&ue, loc, type, cast(Expressions*) null);
3089                     return ue;
3090                 }
3091                 const length = aex.elements.length;
3092                 Expressions* elements = new Expressions(length);
3093 
3094                 emplaceExp!ArrayLiteralExp(&ue, loc, type, elements);
3095                 foreach (i; 0 .. length)
3096                 {
3097                     Expression e1x = ae1 ? ae1[i] : e1;
3098                     Expression e2x = ae2 ? ae2[i] : e2;
3099                     UnionExp uex = evaluate(loc, e1x.type, e1x, e2x);
3100                     // This can be made more efficient by making use of ue.basis
3101                     (*elements)[i] = uex.copy();
3102                 }
3103                 return ue;
3104             }
3105 
3106             if (e1.isConst() != 1)
3107             {
3108                 // The following should really be an assert()
3109                 error(e1.loc, "CTFE internal error: non-constant value `%s`", e1.toChars());
3110                 emplaceExp!CTFEExp(&ue, EXP.cantExpression);
3111                 return ue;
3112             }
3113             if (e2.isConst() != 1)
3114             {
3115                 error(e2.loc, "CTFE internal error: non-constant value `%s`", e2.toChars());
3116                 emplaceExp!CTFEExp(&ue, EXP.cantExpression);
3117                 return ue;
3118             }
3119 
3120             return (*fp)(loc, type, e1, e2);
3121         }
3122 
3123         *pue = evaluate(e.loc, e.type, e1, e2);
3124         result = (*pue).exp();
3125         if (CTFEExp.isCantExp(result))
3126             error(e.loc, "`%s` cannot be interpreted at compile time", e.toChars());
3127     }
3128 
3129     extern (D) private void interpretCompareCommon(BinExp e, fp2_t fp)
3130     {
3131         debug (LOG)
3132         {
3133             printf("%s BinExp::interpretCompareCommon() %s\n", e.loc.toChars(), e.toChars());
3134         }
3135         UnionExp ue1 = void;
3136         UnionExp ue2 = void;
3137         if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer)
3138         {
3139             Expression e1 = interpret(&ue1, e.e1, istate);
3140             if (exceptionOrCant(e1))
3141                 return;
3142             Expression e2 = interpret(&ue2, e.e2, istate);
3143             if (exceptionOrCant(e2))
3144                 return;
3145             //printf("e1 = %s %s, e2 = %s %s\n", e1.type.toChars(), e1.toChars(), e2.type.toChars(), e2.toChars());
3146             dinteger_t ofs1, ofs2;
3147             Expression agg1 = getAggregateFromPointer(e1, &ofs1);
3148             Expression agg2 = getAggregateFromPointer(e2, &ofs2);
3149             //printf("agg1 = %p %s, agg2 = %p %s\n", agg1, agg1.toChars(), agg2, agg2.toChars());
3150             const cmp = comparePointers(e.op, agg1, ofs1, agg2, ofs2);
3151             if (cmp == -1)
3152             {
3153                 char dir = (e.op == EXP.greaterThan || e.op == EXP.greaterOrEqual) ? '<' : '>';
3154                 error(e.loc, "the ordering of pointers to unrelated memory blocks is indeterminate in CTFE. To check if they point to the same memory block, use both `>` and `<` inside `&&` or `||`, eg `%s && %s %c= %s + 1`", e.toChars(), e.e1.toChars(), dir, e.e2.toChars());
3155                 result = CTFEExp.cantexp;
3156                 return;
3157             }
3158             if (e.type.equals(Type.tbool))
3159                 result = IntegerExp.createBool(cmp != 0);
3160             else
3161             {
3162                 emplaceExp!(IntegerExp)(pue, e.loc, cmp, e.type);
3163                 result = (*pue).exp();
3164             }
3165             return;
3166         }
3167         Expression e1 = interpret(&ue1, e.e1, istate);
3168         if (exceptionOrCant(e1))
3169             return;
3170         if (!isCtfeComparable(e1))
3171         {
3172             error(e.loc, "cannot compare `%s` at compile time", e1.toChars());
3173             result = CTFEExp.cantexp;
3174             return;
3175         }
3176         Expression e2 = interpret(&ue2, e.e2, istate);
3177         if (exceptionOrCant(e2))
3178             return;
3179         if (!isCtfeComparable(e2))
3180         {
3181             error(e.loc, "cannot compare `%s` at compile time", e2.toChars());
3182             result = CTFEExp.cantexp;
3183             return;
3184         }
3185         const cmp = (*fp)(e.loc, e.op, e1, e2);
3186         if (e.type.equals(Type.tbool))
3187             result = IntegerExp.createBool(cmp);
3188         else
3189         {
3190             emplaceExp!(IntegerExp)(pue, e.loc, cmp, e.type);
3191             result = (*pue).exp();
3192         }
3193     }
3194 
3195     override void visit(BinExp e)
3196     {
3197         switch (e.op)
3198         {
3199         case EXP.add:
3200             interpretCommon(e, &Add);
3201             return;
3202 
3203         case EXP.min:
3204             interpretCommon(e, &Min);
3205             return;
3206 
3207         case EXP.mul:
3208             interpretCommon(e, &Mul);
3209             return;
3210 
3211         case EXP.div:
3212             interpretCommon(e, &Div);
3213             return;
3214 
3215         case EXP.mod:
3216             interpretCommon(e, &Mod);
3217             return;
3218 
3219         case EXP.leftShift:
3220             interpretCommon(e, &Shl);
3221             return;
3222 
3223         case EXP.rightShift:
3224             interpretCommon(e, &Shr);
3225             return;
3226 
3227         case EXP.unsignedRightShift:
3228             interpretCommon(e, &Ushr);
3229             return;
3230 
3231         case EXP.and:
3232             interpretCommon(e, &And);
3233             return;
3234 
3235         case EXP.or:
3236             interpretCommon(e, &Or);
3237             return;
3238 
3239         case EXP.xor:
3240             interpretCommon(e, &Xor);
3241             return;
3242 
3243         case EXP.pow:
3244             interpretCommon(e, &Pow);
3245             return;
3246 
3247         case EXP.equal:
3248         case EXP.notEqual:
3249             interpretCompareCommon(e, &ctfeEqual);
3250             return;
3251 
3252         case EXP.identity:
3253         case EXP.notIdentity:
3254             interpretCompareCommon(e, &ctfeIdentity);
3255             return;
3256 
3257         case EXP.lessThan:
3258         case EXP.lessOrEqual:
3259         case EXP.greaterThan:
3260         case EXP.greaterOrEqual:
3261             interpretCompareCommon(e, &ctfeCmp);
3262             return;
3263 
3264         default:
3265             printf("be = '%s' %s at [%s]\n", EXPtoString(e.op).ptr, e.toChars(), e.loc.toChars());
3266             assert(0);
3267         }
3268     }
3269 
3270     /* Helper functions for BinExp::interpretAssignCommon
3271      */
3272     // Returns the variable which is eventually modified, or NULL if an rvalue.
3273     // thisval is the current value of 'this'.
3274     static VarDeclaration findParentVar(Expression e) @safe
3275     {
3276         for (;;)
3277         {
3278             if (auto ve = e.isVarExp())
3279             {
3280                 VarDeclaration v = ve.var.isVarDeclaration();
3281                 assert(v);
3282                 return v;
3283             }
3284             if (auto ie = e.isIndexExp())
3285                 e = ie.e1;
3286             else if (auto dve = e.isDotVarExp())
3287                 e = dve.e1;
3288             else if (auto dtie = e.isDotTemplateInstanceExp())
3289                 e = dtie.e1;
3290             else if (auto se = e.isSliceExp())
3291                 e = se.e1;
3292             else
3293                 return null;
3294         }
3295     }
3296 
3297     extern (D) private void interpretAssignCommon(BinExp e, fp_t fp, int post = 0)
3298     {
3299         debug (LOG)
3300         {
3301             printf("%s BinExp::interpretAssignCommon() %s\n", e.loc.toChars(), e.toChars());
3302         }
3303         result = CTFEExp.cantexp;
3304 
3305         Expression e1 = e.e1;
3306         if (!istate)
3307         {
3308             error(e.loc, "value of `%s` is not known at compile time", e1.toChars());
3309             return;
3310         }
3311 
3312         ++ctfeGlobals.numAssignments;
3313 
3314         /* Before we begin, we need to know if this is a reference assignment
3315          * (dynamic array, AA, or class) or a value assignment.
3316          * Determining this for slice assignments are tricky: we need to know
3317          * if it is a block assignment (a[] = e) rather than a direct slice
3318          * assignment (a[] = b[]). Note that initializers of multi-dimensional
3319          * static arrays can have 2D block assignments (eg, int[7][7] x = 6;).
3320          * So we need to recurse to determine if it is a block assignment.
3321          */
3322         bool isBlockAssignment = false;
3323         if (e1.op == EXP.slice)
3324         {
3325             // a[] = e can have const e. So we compare the naked types.
3326             Type tdst = e1.type.toBasetype();
3327             Type tsrc = e.e2.type.toBasetype();
3328             while (tdst.ty == Tsarray || tdst.ty == Tarray)
3329             {
3330                 tdst = (cast(TypeArray)tdst).next.toBasetype();
3331                 if (tsrc.equivalent(tdst))
3332                 {
3333                     isBlockAssignment = true;
3334                     break;
3335                 }
3336             }
3337         }
3338 
3339         // ---------------------------------------
3340         //      Deal with reference assignment
3341         // ---------------------------------------
3342         // If it is a construction of a ref variable, it is a ref assignment
3343         if ((e.op == EXP.construct || e.op == EXP.blit) &&
3344             ((cast(AssignExp)e).memset == MemorySet.referenceInit))
3345         {
3346             assert(!fp);
3347 
3348             Expression newval = interpretRegion(e.e2, istate, CTFEGoal.LValue);
3349             if (exceptionOrCant(newval))
3350                 return;
3351 
3352             VarDeclaration v = e1.isVarExp().var.isVarDeclaration();
3353             setValue(v, newval);
3354 
3355             // Get the value to return. Note that 'newval' is an Lvalue,
3356             // so if we need an Rvalue, we have to interpret again.
3357             if (goal == CTFEGoal.RValue)
3358                 result = interpretRegion(newval, istate);
3359             else
3360                 result = e1; // VarExp is a CTFE reference
3361             return;
3362         }
3363 
3364         if (fp)
3365         {
3366             while (e1.op == EXP.cast_)
3367             {
3368                 CastExp ce = e1.isCastExp();
3369                 e1 = ce.e1;
3370             }
3371         }
3372 
3373         // ---------------------------------------
3374         //      Interpret left hand side
3375         // ---------------------------------------
3376         AssocArrayLiteralExp existingAA = null;
3377         Expression lastIndex = null;
3378         Expression oldval = null;
3379         if (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
3380         {
3381             // ---------------------------------------
3382             //      Deal with AA index assignment
3383             // ---------------------------------------
3384             /* This needs special treatment if the AA doesn't exist yet.
3385              * There are two special cases:
3386              * (1) If the AA is itself an index of another AA, we may need to create
3387              *     multiple nested AA literals before we can insert the new value.
3388              * (2) If the ultimate AA is null, no insertion happens at all. Instead,
3389              *     we create nested AA literals, and change it into a assignment.
3390              */
3391             IndexExp ie = e1.isIndexExp();
3392             int depth = 0; // how many nested AA indices are there?
3393             while (ie.e1.op == EXP.index && ie.e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
3394             {
3395                 assert(ie.modifiable);
3396                 ie = ie.e1.isIndexExp();
3397                 ++depth;
3398             }
3399 
3400             // Get the AA value to be modified.
3401             Expression aggregate = interpretRegion(ie.e1, istate);
3402             if (exceptionOrCant(aggregate))
3403                 return;
3404             if ((existingAA = aggregate.isAssocArrayLiteralExp()) !is null)
3405             {
3406                 // Normal case, ultimate parent AA already exists
3407                 // We need to walk from the deepest index up, checking that an AA literal
3408                 // already exists on each level.
3409                 lastIndex = interpretRegion(e1.isIndexExp().e2, istate);
3410                 lastIndex = resolveSlice(lastIndex); // only happens with AA assignment
3411                 if (exceptionOrCant(lastIndex))
3412                     return;
3413 
3414                 while (depth > 0)
3415                 {
3416                     // Walk the syntax tree to find the indexExp at this depth
3417                     IndexExp xe = e1.isIndexExp();
3418                     foreach (d; 0 .. depth)
3419                         xe = xe.e1.isIndexExp();
3420 
3421                     Expression ekey = interpretRegion(xe.e2, istate);
3422                     if (exceptionOrCant(ekey))
3423                         return;
3424                     UnionExp ekeyTmp = void;
3425                     ekey = resolveSlice(ekey, &ekeyTmp); // only happens with AA assignment
3426 
3427                     // Look up this index in it up in the existing AA, to get the next level of AA.
3428                     AssocArrayLiteralExp newAA = cast(AssocArrayLiteralExp)findKeyInAA(e.loc, existingAA, ekey);
3429                     if (exceptionOrCant(newAA))
3430                         return;
3431                     if (!newAA)
3432                     {
3433                         // Doesn't exist yet, create an empty AA...
3434                         auto keysx = new Expressions();
3435                         auto valuesx = new Expressions();
3436                         newAA = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
3437                         newAA.type = xe.type;
3438                         newAA.ownedByCtfe = OwnedBy.ctfe;
3439                         //... and insert it into the existing AA.
3440                         existingAA.keys.push(ekey);
3441                         existingAA.values.push(newAA);
3442                     }
3443                     existingAA = newAA;
3444                     --depth;
3445                 }
3446 
3447                 if (fp)
3448                 {
3449                     oldval = findKeyInAA(e.loc, existingAA, lastIndex);
3450                     if (!oldval)
3451                         oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
3452                 }
3453             }
3454             else
3455             {
3456                 /* The AA is currently null. 'aggregate' is actually a reference to
3457                  * whatever contains it. It could be anything: var, dotvarexp, ...
3458                  * We rewrite the assignment from:
3459                  *     aa[i][j] op= newval;
3460                  * into:
3461                  *     aa = [i:[j:T.init]];
3462                  *     aa[j] op= newval;
3463                  */
3464                 oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
3465 
3466                 Expression newaae = oldval;
3467                 while (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
3468                 {
3469                     Expression ekey = interpretRegion(e1.isIndexExp().e2, istate);
3470                     if (exceptionOrCant(ekey))
3471                         return;
3472                     ekey = resolveSlice(ekey); // only happens with AA assignment
3473 
3474                     auto keysx = new Expressions();
3475                     auto valuesx = new Expressions();
3476                     keysx.push(ekey);
3477                     valuesx.push(newaae);
3478 
3479                     auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
3480                     aae.type = e1.isIndexExp().e1.type;
3481                     aae.ownedByCtfe = OwnedBy.ctfe;
3482                     if (!existingAA)
3483                     {
3484                         existingAA = aae;
3485                         lastIndex = ekey;
3486                     }
3487                     newaae = aae;
3488                     e1 = e1.isIndexExp().e1;
3489                 }
3490 
3491                 // We must set to aggregate with newaae
3492                 e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
3493                 if (exceptionOrCant(e1))
3494                     return;
3495                 e1 = assignToLvalue(e, e1, newaae);
3496                 if (exceptionOrCant(e1))
3497                     return;
3498             }
3499             assert(existingAA && lastIndex);
3500             e1 = null; // stomp
3501         }
3502         else if (e1.op == EXP.arrayLength)
3503         {
3504             oldval = interpretRegion(e1, istate);
3505             if (exceptionOrCant(oldval))
3506                 return;
3507         }
3508         else if (e.op == EXP.construct || e.op == EXP.blit)
3509         {
3510             // Unless we have a simple var assignment, we're
3511             // only modifying part of the variable. So we need to make sure
3512             // that the parent variable exists.
3513             VarDeclaration ultimateVar = findParentVar(e1);
3514             if (auto ve = e1.isVarExp())
3515             {
3516                 VarDeclaration v = ve.var.isVarDeclaration();
3517                 assert(v);
3518                 if (v.storage_class & STC.out_)
3519                     goto L1;
3520             }
3521             else if (ultimateVar && !getValue(ultimateVar))
3522             {
3523                 Expression ex = interpretRegion(ultimateVar.type.defaultInitLiteral(e.loc), istate);
3524                 if (exceptionOrCant(ex))
3525                     return;
3526                 setValue(ultimateVar, ex);
3527             }
3528             else
3529                 goto L1;
3530         }
3531         else
3532         {
3533         L1:
3534             e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
3535             if (exceptionOrCant(e1))
3536                 return;
3537 
3538             if (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
3539             {
3540                 IndexExp ie = e1.isIndexExp();
3541                 assert(ie.e1.op == EXP.assocArrayLiteral);
3542                 existingAA = ie.e1.isAssocArrayLiteralExp();
3543                 lastIndex = ie.e2;
3544             }
3545         }
3546 
3547         // ---------------------------------------
3548         //      Interpret right hand side
3549         // ---------------------------------------
3550         Expression newval = interpretRegion(e.e2, istate);
3551         if (exceptionOrCant(newval))
3552             return;
3553         if (e.op == EXP.blit && newval.op == EXP.int64)
3554         {
3555             Type tbn = e.type.baseElemOf();
3556             if (tbn.ty == Tstruct)
3557             {
3558                 /* Look for special case of struct being initialized with 0.
3559                  */
3560                 newval = e.type.defaultInitLiteral(e.loc);
3561                 if (newval.op == EXP.error)
3562                 {
3563                     result = CTFEExp.cantexp;
3564                     return;
3565                 }
3566                 newval = interpretRegion(newval, istate); // copy and set ownedByCtfe flag
3567                 if (exceptionOrCant(newval))
3568                     return;
3569             }
3570         }
3571 
3572         // ----------------------------------------------------
3573         //  Deal with read-modify-write assignments.
3574         //  Set 'newval' to the final assignment value
3575         //  Also determine the return value (except for slice
3576         //  assignments, which are more complicated)
3577         // ----------------------------------------------------
3578         if (fp)
3579         {
3580             if (!oldval)
3581             {
3582                 // Load the left hand side after interpreting the right hand side.
3583                 oldval = interpretRegion(e1, istate);
3584                 if (exceptionOrCant(oldval))
3585                     return;
3586             }
3587 
3588             if (e.e1.type.ty != Tpointer)
3589             {
3590                 // ~= can create new values (see bug 6052)
3591                 if (e.op == EXP.concatenateAssign || e.op == EXP.concatenateElemAssign || e.op == EXP.concatenateDcharAssign)
3592                 {
3593                     // We need to dup it and repaint the type. For a dynamic array
3594                     // we can skip duplication, because it gets copied later anyway.
3595                     if (newval.type.ty != Tarray)
3596                     {
3597                         newval = copyLiteral(newval).copy();
3598                         newval.type = e.e2.type; // repaint type
3599                     }
3600                     else
3601                     {
3602                         newval = paintTypeOntoLiteral(e.e2.type, newval);
3603                         newval = resolveSlice(newval);
3604                     }
3605                 }
3606                 oldval = resolveSlice(oldval);
3607 
3608                 newval = (*fp)(e.loc, e.type, oldval, newval).copy();
3609             }
3610             else if (e.e2.type.isintegral() &&
3611                      (e.op == EXP.addAssign ||
3612                       e.op == EXP.minAssign ||
3613                       e.op == EXP.plusPlus ||
3614                       e.op == EXP.minusMinus))
3615             {
3616                 newval = pointerArithmetic(pue, e.loc, e.op, e.type, oldval, newval).copy();
3617                 if (newval == pue.exp())
3618                     newval = pue.copy();
3619             }
3620             else
3621             {
3622                 error(e.loc, "pointer expression `%s` cannot be interpreted at compile time", e.toChars());
3623                 result = CTFEExp.cantexp;
3624                 return;
3625             }
3626             if (exceptionOrCant(newval))
3627             {
3628                 if (CTFEExp.isCantExp(newval))
3629                     error(e.loc, "cannot interpret `%s` at compile time", e.toChars());
3630                 return;
3631             }
3632         }
3633 
3634         if (existingAA)
3635         {
3636             if (existingAA.ownedByCtfe != OwnedBy.ctfe)
3637             {
3638                 error(e.loc, "cannot modify read-only constant `%s`", existingAA.toChars());
3639                 result = CTFEExp.cantexp;
3640                 return;
3641             }
3642 
3643             //printf("\t+L%d existingAA = %s, lastIndex = %s, oldval = %s, newval = %s\n",
3644             //    __LINE__, existingAA.toChars(), lastIndex.toChars(), oldval ? oldval.toChars() : NULL, newval.toChars());
3645             assignAssocArrayElement(e.loc, existingAA, lastIndex, newval);
3646 
3647             // Determine the return value
3648             result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
3649             return;
3650         }
3651         if (e1.op == EXP.arrayLength)
3652         {
3653             /* Change the assignment from:
3654              *  arr.length = n;
3655              * into:
3656              *  arr = new_length_array; (result is n)
3657              */
3658 
3659             // Determine the return value
3660             result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
3661             if (exceptionOrCant(result))
3662                 return;
3663 
3664             if (result == pue.exp())
3665                 result = pue.copy();
3666 
3667             size_t oldlen = cast(size_t)oldval.toInteger();
3668             size_t newlen = cast(size_t)newval.toInteger();
3669             if (oldlen == newlen) // no change required -- we're done!
3670                 return;
3671 
3672             // We have changed it into a reference assignment
3673             // Note that returnValue is still the new length.
3674             e1 = e1.isArrayLengthExp().e1;
3675             Type t = e1.type.toBasetype();
3676             if (t.ty != Tarray)
3677             {
3678                 error(e.loc, "`%s` is not yet supported at compile time", e.toChars());
3679                 result = CTFEExp.cantexp;
3680                 return;
3681             }
3682             e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
3683             if (exceptionOrCant(e1))
3684                 return;
3685 
3686             if (oldlen != 0) // Get the old array literal.
3687                 oldval = interpretRegion(e1, istate);
3688             UnionExp utmp = void;
3689             oldval = resolveSlice(oldval, &utmp);
3690 
3691             newval = changeArrayLiteralLength(pue, e.loc, cast(TypeArray)t, oldval, oldlen, newlen);
3692             if (newval == pue.exp())
3693                 newval = pue.copy();
3694 
3695             e1 = assignToLvalue(e, e1, newval);
3696             if (exceptionOrCant(e1))
3697                 return;
3698 
3699             return;
3700         }
3701 
3702         if (!isBlockAssignment)
3703         {
3704             newval = ctfeCast(pue, e.loc, e.type, e.type, newval);
3705             if (exceptionOrCant(newval))
3706                 return;
3707             if (newval == pue.exp())
3708                 newval = pue.copy();
3709 
3710             // Determine the return value
3711             if (goal == CTFEGoal.LValue) // https://issues.dlang.org/show_bug.cgi?id=14371
3712                 result = e1;
3713             else
3714             {
3715                 result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
3716                 if (result == pue.exp())
3717                     result = pue.copy();
3718             }
3719             if (exceptionOrCant(result))
3720                 return;
3721         }
3722         if (exceptionOrCant(newval))
3723             return;
3724 
3725         debug (LOGASSIGN)
3726         {
3727             printf("ASSIGN: %s=%s\n", e1.toChars(), newval.toChars());
3728             showCtfeExpr(newval);
3729         }
3730 
3731         /* Block assignment or element-wise assignment.
3732          */
3733         if (e1.op == EXP.slice ||
3734             e1.op == EXP.vector ||
3735             e1.op == EXP.arrayLiteral ||
3736             e1.op == EXP.string_ ||
3737             e1.op == EXP.null_ && e1.type.toBasetype().ty == Tarray)
3738         {
3739             // Note that slice assignments don't support things like ++, so
3740             // we don't need to remember 'returnValue'.
3741             result = interpretAssignToSlice(pue, e, e1, newval, isBlockAssignment);
3742             if (exceptionOrCant(result))
3743                 return;
3744             if (auto se = e.e1.isSliceExp())
3745             {
3746                 Expression e1x = interpretRegion(se.e1, istate, CTFEGoal.LValue);
3747                 if (auto dve = e1x.isDotVarExp())
3748                 {
3749                     auto ex = dve.e1;
3750                     auto sle = ex.op == EXP.structLiteral ? ex.isStructLiteralExp()
3751                              : ex.op == EXP.classReference ? ex.isClassReferenceExp().value
3752                              : null;
3753                     auto v = dve.var.isVarDeclaration();
3754                     if (!sle || !v)
3755                     {
3756                         error(e.loc, "CTFE internal error: dotvar slice assignment");
3757                         result = CTFEExp.cantexp;
3758                         return;
3759                     }
3760                     stompOverlappedFields(sle, v);
3761                 }
3762             }
3763             return;
3764         }
3765         assert(result);
3766 
3767         /* Assignment to a CTFE reference.
3768          */
3769         if (Expression ex = assignToLvalue(e, e1, newval))
3770             result = ex;
3771 
3772         return;
3773     }
3774 
3775     /* Set all sibling fields which overlap with v to VoidExp.
3776      */
3777     private void stompOverlappedFields(StructLiteralExp sle, VarDeclaration v)
3778     {
3779         if (!v.overlapped)
3780             return;
3781         foreach (size_t i, v2; sle.sd.fields)
3782         {
3783             if (v is v2 || !v.isOverlappedWith(v2))
3784                 continue;
3785             auto e = (*sle.elements)[i];
3786             if (e.op != EXP.void_)
3787                 (*sle.elements)[i] = voidInitLiteral(e.type, v).copy();
3788         }
3789     }
3790 
3791     private Expression assignToLvalue(BinExp e, Expression e1, Expression newval)
3792     {
3793         //printf("assignToLvalue() e: %s e1: %s newval: %s\n", e.toChars(), e1.toChars(), newval.toChars());
3794         VarDeclaration vd = null;
3795         Expression* payload = null; // dead-store to prevent spurious warning
3796         Expression oldval;
3797 
3798         if (auto ve = e1.isVarExp())
3799         {
3800             vd = ve.var.isVarDeclaration();
3801             oldval = getValue(vd);
3802         }
3803         else if (auto dve = e1.isDotVarExp())
3804         {
3805             /* Assignment to member variable of the form:
3806              *  e.v = newval
3807              */
3808             auto ex = dve.e1;
3809             auto sle = ex.op == EXP.structLiteral ? ex.isStructLiteralExp()
3810                      : ex.op == EXP.classReference ? ex.isClassReferenceExp().value
3811                      : null;
3812             auto v = e1.isDotVarExp().var.isVarDeclaration();
3813             if (!sle || !v)
3814             {
3815                 error(e.loc, "CTFE internal error: dotvar assignment");
3816                 return CTFEExp.cantexp;
3817             }
3818             if (sle.ownedByCtfe != OwnedBy.ctfe)
3819             {
3820                 error(e.loc, "cannot modify read-only constant `%s`", sle.toChars());
3821                 return CTFEExp.cantexp;
3822             }
3823 
3824             int fieldi = ex.op == EXP.structLiteral ? findFieldIndexByName(sle.sd, v)
3825                        : ex.isClassReferenceExp().findFieldIndexByName(v);
3826             if (fieldi == -1)
3827             {
3828                 error(e.loc, "CTFE internal error: cannot find field `%s` in `%s`", v.toChars(), ex.toChars());
3829                 return CTFEExp.cantexp;
3830             }
3831             assert(0 <= fieldi && fieldi < sle.elements.length);
3832 
3833             // If it's a union, set all other members of this union to void
3834             stompOverlappedFields(sle, v);
3835 
3836             payload = &(*sle.elements)[fieldi];
3837             oldval = *payload;
3838             if (auto ival = newval.isIntegerExp())
3839             {
3840                 if (auto bf = v.isBitFieldDeclaration())
3841                 {
3842                     sinteger_t value = ival.toInteger();
3843                     if (bf.type.isunsigned())
3844                         value &= (1L << bf.fieldWidth) - 1; // zero extra bits
3845                     else
3846                     {   // sign extend extra bits
3847                         value = value << (64 - bf.fieldWidth);
3848                         value = value >> (64 - bf.fieldWidth);
3849                     }
3850                     ival.setInteger(value);
3851                 }
3852             }
3853         }
3854         else if (auto ie = e1.isIndexExp())
3855         {
3856             assert(ie.e1.type.toBasetype().ty != Taarray);
3857 
3858             Expression aggregate;
3859             uinteger_t indexToModify;
3860             if (!resolveIndexing(ie, istate, &aggregate, &indexToModify, true))
3861             {
3862                 return CTFEExp.cantexp;
3863             }
3864             size_t index = cast(size_t)indexToModify;
3865 
3866             if (auto existingSE = aggregate.isStringExp())
3867             {
3868                 if (existingSE.ownedByCtfe != OwnedBy.ctfe)
3869                 {
3870                     error(e.loc, "cannot modify read-only string literal `%s`", ie.e1.toChars());
3871                     return CTFEExp.cantexp;
3872                 }
3873                 existingSE.setCodeUnit(index, cast(dchar)newval.toInteger());
3874                 return null;
3875             }
3876             if (aggregate.op != EXP.arrayLiteral)
3877             {
3878                 error(e.loc, "index assignment `%s` is not yet supported in CTFE ", e.toChars());
3879                 return CTFEExp.cantexp;
3880             }
3881 
3882             ArrayLiteralExp existingAE = aggregate.isArrayLiteralExp();
3883             if (existingAE.ownedByCtfe != OwnedBy.ctfe)
3884             {
3885                 error(e.loc, "cannot modify read-only constant `%s`", existingAE.toChars());
3886                 return CTFEExp.cantexp;
3887             }
3888 
3889             payload = &(*existingAE.elements)[index];
3890             oldval = *payload;
3891         }
3892         else
3893         {
3894             error(e.loc, "`%s` cannot be evaluated at compile time", e.toChars());
3895             return CTFEExp.cantexp;
3896         }
3897 
3898         Type t1b = e1.type.toBasetype();
3899         bool wantCopy = t1b.baseElemOf().ty == Tstruct;
3900 
3901         if (auto ve = newval.isVectorExp())
3902         {
3903             // Ensure ve is an array literal, and not a broadcast
3904             if (ve.e1.op == EXP.int64 || ve.e1.op == EXP.float64) // if broadcast
3905             {
3906                 UnionExp ue = void;
3907                 Expression ex = interpretVectorToArray(&ue, ve);
3908                 ve.e1 = (ex == ue.exp()) ? ue.copy() : ex;
3909             }
3910         }
3911 
3912         if (newval.op == EXP.structLiteral && oldval)
3913         {
3914             assert(oldval.op == EXP.structLiteral || oldval.op == EXP.arrayLiteral || oldval.op == EXP.string_);
3915             newval = copyLiteral(newval).copy();
3916             assignInPlace(oldval, newval);
3917         }
3918         else if (wantCopy && (e.op == EXP.assign || e.op == EXP.loweredAssignExp))
3919         {
3920             // Currently postblit/destructor calls on static array are done
3921             // in the druntime internal functions so they don't appear in AST.
3922             // Therefore interpreter should handle them specially.
3923 
3924             assert(oldval);
3925             version (all) // todo: instead we can directly access to each elements of the slice
3926             {
3927                 newval = resolveSlice(newval);
3928                 if (CTFEExp.isCantExp(newval))
3929                 {
3930                     error(e.loc, "CTFE internal error: assignment `%s`", e.toChars());
3931                     return CTFEExp.cantexp;
3932                 }
3933             }
3934             assert(oldval.op == EXP.arrayLiteral);
3935             assert(newval.op == EXP.arrayLiteral);
3936 
3937             Expressions* oldelems = oldval.isArrayLiteralExp().elements;
3938             Expressions* newelems = newval.isArrayLiteralExp().elements;
3939             assert(oldelems.length == newelems.length);
3940 
3941             Type elemtype = oldval.type.nextOf();
3942             foreach (i, ref oldelem; *oldelems)
3943             {
3944                 Expression newelem = paintTypeOntoLiteral(elemtype, (*newelems)[i]);
3945                 // https://issues.dlang.org/show_bug.cgi?id=9245
3946                 if (e.e2.isLvalue())
3947                 {
3948                     if (Expression ex = evaluatePostblit(istate, newelem))
3949                         return ex;
3950                 }
3951                 // https://issues.dlang.org/show_bug.cgi?id=13661
3952                 if (Expression ex = evaluateDtor(istate, oldelem))
3953                     return ex;
3954                 oldelem = newelem;
3955             }
3956         }
3957         else
3958         {
3959             // e1 has its own payload, so we have to create a new literal.
3960             if (wantCopy)
3961                 newval = copyLiteral(newval).copy();
3962 
3963             if (t1b.ty == Tsarray && e.op == EXP.construct && e.e2.isLvalue())
3964             {
3965                 // https://issues.dlang.org/show_bug.cgi?id=9245
3966                 if (Expression ex = evaluatePostblit(istate, newval))
3967                     return ex;
3968             }
3969 
3970             oldval = newval;
3971         }
3972 
3973         if (vd)
3974             setValue(vd, oldval);
3975         else
3976             *payload = oldval;
3977 
3978         // Blit assignment should return the newly created value.
3979         if (e.op == EXP.blit)
3980             return oldval;
3981 
3982         return null;
3983     }
3984 
3985     /*************
3986      * Deal with assignments of the form:
3987      *  dest[] = newval
3988      *  dest[low..upp] = newval
3989      * where newval has already been interpreted
3990      *
3991      * This could be a slice assignment or a block assignment, and
3992      * dest could be either an array literal, or a string.
3993      *
3994      * Returns EXP.cantExpression on failure. If there are no errors,
3995      * it returns aggregate[low..upp], except that as an optimisation,
3996      * if goal == CTFEGoal.Nothing, it will return NULL
3997      */
3998     private Expression interpretAssignToSlice(UnionExp* pue, BinExp e, Expression e1, Expression newval, bool isBlockAssignment)
3999     {
4000         //printf("interpretAssignToSlice(e: %s e1: %s newval: %s\n", e.toChars(), e1.toChars(), newval.toChars());
4001 
4002         dinteger_t lowerbound;
4003         dinteger_t upperbound;
4004         dinteger_t firstIndex;
4005 
4006         Expression aggregate;
4007 
4008         if (auto se = e1.isSliceExp())
4009         {
4010             // ------------------------------
4011             //   aggregate[] = newval
4012             //   aggregate[low..upp] = newval
4013             // ------------------------------
4014             aggregate = interpretRegion(se.e1, istate);
4015             lowerbound = se.lwr ? se.lwr.toInteger() : 0;
4016             upperbound = se.upr ? se.upr.toInteger() : resolveArrayLength(aggregate);
4017 
4018             // Slice of a slice --> change the bounds
4019             if (auto oldse = aggregate.isSliceExp())
4020             {
4021                 aggregate = oldse.e1;
4022                 firstIndex = lowerbound + oldse.lwr.toInteger();
4023             }
4024             else
4025                 firstIndex = lowerbound;
4026         }
4027         else
4028         {
4029             if (auto ale = e1.isArrayLiteralExp())
4030             {
4031                 lowerbound = 0;
4032                 upperbound = ale.elements.length;
4033             }
4034             else if (auto se = e1.isStringExp())
4035             {
4036                 lowerbound = 0;
4037                 upperbound = se.len;
4038             }
4039             else if (e1.op == EXP.null_)
4040             {
4041                 lowerbound = 0;
4042                 upperbound = 0;
4043             }
4044             else if (VectorExp ve = e1.isVectorExp())
4045             {
4046                 // ve is not handled but a proper error message is returned
4047                 // this is to prevent https://issues.dlang.org/show_bug.cgi?id=20042
4048                 lowerbound = 0;
4049                 upperbound = ve.dim;
4050             }
4051             else
4052                 assert(0);
4053 
4054             aggregate = e1;
4055             firstIndex = lowerbound;
4056         }
4057         if (upperbound == lowerbound)
4058             return newval;
4059 
4060         // For slice assignment, we check that the lengths match.
4061         if (!isBlockAssignment && e1.type.ty != Tpointer)
4062         {
4063             const srclen = resolveArrayLength(newval);
4064             if (srclen != (upperbound - lowerbound))
4065             {
4066                 error(e.loc, "array length mismatch assigning `[0..%llu]` to `[%llu..%llu]`",
4067                     ulong(srclen), ulong(lowerbound), ulong(upperbound));
4068                 return CTFEExp.cantexp;
4069             }
4070         }
4071 
4072         if (auto existingSE = aggregate.isStringExp())
4073         {
4074             if (existingSE.ownedByCtfe != OwnedBy.ctfe)
4075             {
4076                 error(e.loc, "cannot modify read-only string literal `%s`", existingSE.toChars());
4077                 return CTFEExp.cantexp;
4078             }
4079 
4080             if (auto se = newval.isSliceExp())
4081             {
4082                 auto aggr2 = se.e1;
4083                 const srclower = se.lwr.toInteger();
4084                 const srcupper = se.upr.toInteger();
4085 
4086                 if (aggregate == aggr2 &&
4087                     lowerbound < srcupper && srclower < upperbound)
4088                 {
4089                     error(e.loc, "overlapping slice assignment `[%llu..%llu] = [%llu..%llu]`",
4090                         ulong(lowerbound), ulong(upperbound), ulong(srclower), ulong(srcupper));
4091                     return CTFEExp.cantexp;
4092                 }
4093                 version (all) // todo: instead we can directly access to each elements of the slice
4094                 {
4095                     Expression orignewval = newval;
4096                     newval = resolveSlice(newval);
4097                     if (CTFEExp.isCantExp(newval))
4098                     {
4099                         error(e.loc, "CTFE internal error: slice `%s`", orignewval.toChars());
4100                         return CTFEExp.cantexp;
4101                     }
4102                 }
4103                 assert(newval.op != EXP.slice);
4104             }
4105             if (auto se = newval.isStringExp())
4106             {
4107                 sliceAssignStringFromString(existingSE, se, cast(size_t)firstIndex);
4108                 return newval;
4109             }
4110             if (auto ale = newval.isArrayLiteralExp())
4111             {
4112                 /* Mixed slice: it was initialized as a string literal.
4113                  * Now a slice of it is being set with an array literal.
4114                  */
4115                 sliceAssignStringFromArrayLiteral(existingSE, ale, cast(size_t)firstIndex);
4116                 return newval;
4117             }
4118 
4119             // String literal block slice assign
4120             const value = cast(dchar)newval.toInteger();
4121             foreach (i; 0 .. upperbound - lowerbound)
4122             {
4123                 existingSE.setCodeUnit(cast(size_t)(i + firstIndex), value);
4124             }
4125             if (goal == CTFEGoal.Nothing)
4126                 return null; // avoid creating an unused literal
4127             auto retslice = ctfeEmplaceExp!SliceExp(e.loc, existingSE,
4128                         ctfeEmplaceExp!IntegerExp(e.loc, firstIndex, Type.tsize_t),
4129                         ctfeEmplaceExp!IntegerExp(e.loc, firstIndex + upperbound - lowerbound, Type.tsize_t));
4130             retslice.type = e.type;
4131             return interpret(pue, retslice, istate);
4132         }
4133         if (auto existingAE = aggregate.isArrayLiteralExp())
4134         {
4135             if (existingAE.ownedByCtfe != OwnedBy.ctfe)
4136             {
4137                 error(e.loc, "cannot modify read-only constant `%s`", existingAE.toChars());
4138                 return CTFEExp.cantexp;
4139             }
4140 
4141             if (newval.op == EXP.slice && !isBlockAssignment)
4142             {
4143                 auto se = newval.isSliceExp();
4144                 auto aggr2 = se.e1;
4145                 const srclower = se.lwr.toInteger();
4146                 const srcupper = se.upr.toInteger();
4147                 const wantCopy = (newval.type.toBasetype().nextOf().baseElemOf().ty == Tstruct);
4148 
4149                 //printf("oldval = %p %s[%d..%u]\nnewval = %p %s[%llu..%llu] wantCopy = %d\n",
4150                 //    aggregate, aggregate.toChars(), lowerbound, upperbound,
4151                 //    aggr2, aggr2.toChars(), srclower, srcupper, wantCopy);
4152                 if (wantCopy)
4153                 {
4154                     // Currently overlapping for struct array is allowed.
4155                     // The order of elements processing depends on the overlapping.
4156                     // https://issues.dlang.org/show_bug.cgi?id=14024
4157                     assert(aggr2.op == EXP.arrayLiteral);
4158                     Expressions* oldelems = existingAE.elements;
4159                     Expressions* newelems = aggr2.isArrayLiteralExp().elements;
4160 
4161                     Type elemtype = aggregate.type.nextOf();
4162                     bool needsPostblit = e.e2.isLvalue();
4163 
4164                     if (aggregate == aggr2 && srclower < lowerbound && lowerbound < srcupper)
4165                     {
4166                         // reverse order
4167                         for (auto i = upperbound - lowerbound; 0 < i--;)
4168                         {
4169                             Expression oldelem = (*oldelems)[cast(size_t)(i + firstIndex)];
4170                             Expression newelem = (*newelems)[cast(size_t)(i + srclower)];
4171                             newelem = copyLiteral(newelem).copy();
4172                             newelem.type = elemtype;
4173                             if (needsPostblit)
4174                             {
4175                                 if (Expression x = evaluatePostblit(istate, newelem))
4176                                     return x;
4177                             }
4178                             if (Expression x = evaluateDtor(istate, oldelem))
4179                                 return x;
4180                             (*oldelems)[cast(size_t)(lowerbound + i)] = newelem;
4181                         }
4182                     }
4183                     else
4184                     {
4185                         // normal order
4186                         for (auto i = 0; i < upperbound - lowerbound; i++)
4187                         {
4188                             Expression oldelem = (*oldelems)[cast(size_t)(i + firstIndex)];
4189                             Expression newelem = (*newelems)[cast(size_t)(i + srclower)];
4190                             newelem = copyLiteral(newelem).copy();
4191                             newelem.type = elemtype;
4192                             if (needsPostblit)
4193                             {
4194                                 if (Expression x = evaluatePostblit(istate, newelem))
4195                                     return x;
4196                             }
4197                             if (Expression x = evaluateDtor(istate, oldelem))
4198                                 return x;
4199                             (*oldelems)[cast(size_t)(lowerbound + i)] = newelem;
4200                         }
4201                     }
4202 
4203                     //assert(0);
4204                     return newval; // oldval?
4205                 }
4206                 if (aggregate == aggr2 &&
4207                     lowerbound < srcupper && srclower < upperbound)
4208                 {
4209                     error(e.loc, "overlapping slice assignment `[%llu..%llu] = [%llu..%llu]`",
4210                         ulong(lowerbound), ulong(upperbound), ulong(srclower), ulong(srcupper));
4211                     return CTFEExp.cantexp;
4212                 }
4213                 version (all) // todo: instead we can directly access to each elements of the slice
4214                 {
4215                     Expression orignewval = newval;
4216                     newval = resolveSlice(newval);
4217                     if (CTFEExp.isCantExp(newval))
4218                     {
4219                         error(e.loc, "CTFE internal error: slice `%s`", orignewval.toChars());
4220                         return CTFEExp.cantexp;
4221                     }
4222                 }
4223                 // no overlapping
4224                 //length?
4225                 assert(newval.op != EXP.slice);
4226             }
4227             if (newval.op == EXP.string_ && !isBlockAssignment)
4228             {
4229                 /* Mixed slice: it was initialized as an array literal of chars/integers.
4230                  * Now a slice of it is being set with a string.
4231                  */
4232                 sliceAssignArrayLiteralFromString(existingAE, newval.isStringExp(), cast(size_t)firstIndex);
4233                 return newval;
4234             }
4235             if (newval.op == EXP.arrayLiteral && !isBlockAssignment)
4236             {
4237                 Expressions* oldelems = existingAE.elements;
4238                 Expressions* newelems = newval.isArrayLiteralExp().elements;
4239                 Type elemtype = existingAE.type.nextOf();
4240                 bool needsPostblit = e.op != EXP.blit && e.e2.isLvalue();
4241                 foreach (j, newelem; *newelems)
4242                 {
4243                     newelem = paintTypeOntoLiteral(elemtype, newelem);
4244                     if (needsPostblit)
4245                     {
4246                         Expression x = evaluatePostblit(istate, newelem);
4247                         if (exceptionOrCantInterpret(x))
4248                             return x;
4249                     }
4250                     (*oldelems)[cast(size_t)(j + firstIndex)] = newelem;
4251                 }
4252                 return newval;
4253             }
4254 
4255             /* Block assignment, initialization of static arrays
4256              *   x[] = newval
4257              *  x may be a multidimensional static array. (Note that this
4258              *  only happens with array literals, never with strings).
4259              */
4260             struct RecursiveBlock
4261             {
4262                 InterState* istate;
4263                 Expression newval;
4264                 bool refCopy;
4265                 bool needsPostblit;
4266                 bool needsDtor;
4267 
4268                 Expression assignTo(ArrayLiteralExp ae)
4269                 {
4270                     return assignTo(ae, 0, ae.elements.length);
4271                 }
4272 
4273                 Expression assignTo(ArrayLiteralExp ae, size_t lwr, size_t upr)
4274                 {
4275                     Expressions* w = ae.elements;
4276                     assert(ae.type.ty == Tsarray || ae.type.ty == Tarray || ae.type.ty == Tpointer);
4277                     bool directblk = (cast(TypeNext)ae.type).next.equivalent(newval.type);
4278                     for (size_t k = lwr; k < upr; k++)
4279                     {
4280                         if (!directblk && (*w)[k].op == EXP.arrayLiteral)
4281                         {
4282                             // Multidimensional array block assign
4283                             if (Expression ex = assignTo((*w)[k].isArrayLiteralExp()))
4284                                 return ex;
4285                         }
4286                         else if (refCopy)
4287                         {
4288                             (*w)[k] = newval;
4289                         }
4290                         else if (!needsPostblit && !needsDtor)
4291                         {
4292                             assignInPlace((*w)[k], newval);
4293                         }
4294                         else
4295                         {
4296                             Expression oldelem = (*w)[k];
4297                             Expression tmpelem = needsDtor ? copyLiteral(oldelem).copy() : null;
4298                             assignInPlace(oldelem, newval);
4299                             if (needsPostblit)
4300                             {
4301                                 if (Expression ex = evaluatePostblit(istate, oldelem))
4302                                     return ex;
4303                             }
4304                             if (needsDtor)
4305                             {
4306                                 // https://issues.dlang.org/show_bug.cgi?id=14860
4307                                 if (Expression ex = evaluateDtor(istate, tmpelem))
4308                                     return ex;
4309                             }
4310                         }
4311                     }
4312                     return null;
4313                 }
4314             }
4315 
4316             Type tn = newval.type.toBasetype();
4317             bool wantRef = (tn.ty == Tarray || isAssocArray(tn) || tn.ty == Tclass);
4318             bool cow = newval.op != EXP.structLiteral && newval.op != EXP.arrayLiteral && newval.op != EXP.string_;
4319             Type tb = tn.baseElemOf();
4320             StructDeclaration sd = (tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null);
4321 
4322             RecursiveBlock rb;
4323             rb.istate = istate;
4324             rb.newval = newval;
4325             rb.refCopy = wantRef || cow;
4326             rb.needsPostblit = sd && sd.postblit && e.op != EXP.blit && e.e2.isLvalue();
4327             rb.needsDtor = sd && sd.dtor && (e.op == EXP.assign || e.op == EXP.loweredAssignExp);
4328             if (Expression ex = rb.assignTo(existingAE, cast(size_t)lowerbound, cast(size_t)upperbound))
4329                 return ex;
4330 
4331             if (goal == CTFEGoal.Nothing)
4332                 return null; // avoid creating an unused literal
4333             auto retslice = ctfeEmplaceExp!SliceExp(e.loc, existingAE,
4334                 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex, Type.tsize_t),
4335                 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex + upperbound - lowerbound, Type.tsize_t));
4336             retslice.type = e.type;
4337             return interpret(pue, retslice, istate);
4338         }
4339 
4340         error(e.loc, "slice operation `%s = %s` cannot be evaluated at compile time", e1.toChars(), newval.toChars());
4341         return CTFEExp.cantexp;
4342     }
4343 
4344     override void visit(AssignExp e)
4345     {
4346         interpretAssignCommon(e, null);
4347     }
4348 
4349     override void visit(BinAssignExp e)
4350     {
4351         switch (e.op)
4352         {
4353         case EXP.addAssign:
4354             interpretAssignCommon(e, &Add);
4355             return;
4356 
4357         case EXP.minAssign:
4358             interpretAssignCommon(e, &Min);
4359             return;
4360 
4361         case EXP.concatenateAssign:
4362         case EXP.concatenateElemAssign:
4363         case EXP.concatenateDcharAssign:
4364             interpretAssignCommon(e, &ctfeCat);
4365             return;
4366 
4367         case EXP.mulAssign:
4368             interpretAssignCommon(e, &Mul);
4369             return;
4370 
4371         case EXP.divAssign:
4372             interpretAssignCommon(e, &Div);
4373             return;
4374 
4375         case EXP.modAssign:
4376             interpretAssignCommon(e, &Mod);
4377             return;
4378 
4379         case EXP.leftShiftAssign:
4380             interpretAssignCommon(e, &Shl);
4381             return;
4382 
4383         case EXP.rightShiftAssign:
4384             interpretAssignCommon(e, &Shr);
4385             return;
4386 
4387         case EXP.unsignedRightShiftAssign:
4388             interpretAssignCommon(e, &Ushr);
4389             return;
4390 
4391         case EXP.andAssign:
4392             interpretAssignCommon(e, &And);
4393             return;
4394 
4395         case EXP.orAssign:
4396             interpretAssignCommon(e, &Or);
4397             return;
4398 
4399         case EXP.xorAssign:
4400             interpretAssignCommon(e, &Xor);
4401             return;
4402 
4403         case EXP.powAssign:
4404             interpretAssignCommon(e, &Pow);
4405             return;
4406 
4407         default:
4408             assert(0);
4409         }
4410     }
4411 
4412     override void visit(PostExp e)
4413     {
4414         debug (LOG)
4415         {
4416             printf("%s PostExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4417         }
4418         if (e.op == EXP.plusPlus)
4419             interpretAssignCommon(e, &Add, 1);
4420         else
4421             interpretAssignCommon(e, &Min, 1);
4422         debug (LOG)
4423         {
4424             if (CTFEExp.isCantExp(result))
4425                 printf("PostExp::interpret() CANT\n");
4426         }
4427     }
4428 
4429     /* Return 1 if e is a p1 > p2 or p1 >= p2 pointer comparison;
4430      *       -1 if e is a p1 < p2 or p1 <= p2 pointer comparison;
4431      *        0 otherwise
4432      */
4433     static int isPointerCmpExp(Expression e, Expression* p1, Expression* p2)
4434     {
4435         int ret = 1;
4436         while (e.op == EXP.not)
4437         {
4438             ret *= -1;
4439             e = e.isNotExp().e1;
4440         }
4441         switch (e.op)
4442         {
4443         case EXP.lessThan:
4444         case EXP.lessOrEqual:
4445             ret *= -1;
4446             goto case; /+ fall through +/
4447         case EXP.greaterThan:
4448         case EXP.greaterOrEqual:
4449             *p1 = e.isBinExp().e1;
4450             *p2 = e.isBinExp().e2;
4451             if (!(isPointer((*p1).type) && isPointer((*p2).type)))
4452                 ret = 0;
4453             break;
4454 
4455         default:
4456             ret = 0;
4457             break;
4458         }
4459         return ret;
4460     }
4461 
4462     /** If this is a four pointer relation, evaluate it, else return NULL.
4463      *
4464      *  This is an expression of the form (p1 > q1 && p2 < q2) or (p1 < q1 || p2 > q2)
4465      *  where p1, p2 are expressions yielding pointers to memory block p,
4466      *  and q1, q2 are expressions yielding pointers to memory block q.
4467      *  This expression is valid even if p and q are independent memory
4468      *  blocks and are therefore not normally comparable; the && form returns true
4469      *  if [p1..p2] lies inside [q1..q2], and false otherwise; the || form returns
4470      *  true if [p1..p2] lies outside [q1..q2], and false otherwise.
4471      *
4472      *  Within the expression, any ordering of p1, p2, q1, q2 is permissible;
4473      *  the comparison operators can be any of >, <, <=, >=, provided that
4474      *  both directions (p > q and p < q) are checked. Additionally the
4475      *  relational sub-expressions can be negated, eg
4476      *  (!(q1 < p1) && p2 <= q2) is valid.
4477      */
4478     private void interpretFourPointerRelation(UnionExp* pue, BinExp e)
4479     {
4480         assert(e.op == EXP.andAnd || e.op == EXP.orOr);
4481 
4482         /*  It can only be an isInside expression, if both e1 and e2 are
4483          *  directional pointer comparisons.
4484          *  Note that this check can be made statically; it does not depends on
4485          *  any runtime values. This allows a JIT implementation to compile a
4486          *  special AndAndPossiblyInside, keeping the normal AndAnd case efficient.
4487          */
4488 
4489         // Save the pointer expressions and the comparison directions,
4490         // so we can use them later.
4491         Expression p1 = null;
4492         Expression p2 = null;
4493         Expression p3 = null;
4494         Expression p4 = null;
4495         int dir1 = isPointerCmpExp(e.e1, &p1, &p2);
4496         int dir2 = isPointerCmpExp(e.e2, &p3, &p4);
4497         if (dir1 == 0 || dir2 == 0)
4498         {
4499             result = null;
4500             return;
4501         }
4502 
4503         //printf("FourPointerRelation %s\n", toChars());
4504 
4505         UnionExp ue1 = void;
4506         UnionExp ue2 = void;
4507         UnionExp ue3 = void;
4508         UnionExp ue4 = void;
4509 
4510         // Evaluate the first two pointers
4511         p1 = interpret(&ue1, p1, istate);
4512         if (exceptionOrCant(p1))
4513             return;
4514         p2 = interpret(&ue2, p2, istate);
4515         if (exceptionOrCant(p2))
4516             return;
4517         dinteger_t ofs1, ofs2;
4518         Expression agg1 = getAggregateFromPointer(p1, &ofs1);
4519         Expression agg2 = getAggregateFromPointer(p2, &ofs2);
4520 
4521         if (!pointToSameMemoryBlock(agg1, agg2) && agg1.op != EXP.null_ && agg2.op != EXP.null_)
4522         {
4523             // Here it is either CANT_INTERPRET,
4524             // or an IsInside comparison returning false.
4525             p3 = interpret(&ue3, p3, istate);
4526             if (CTFEExp.isCantExp(p3))
4527                 return;
4528             // Note that it is NOT legal for it to throw an exception!
4529             Expression except = null;
4530             if (exceptionOrCantInterpret(p3))
4531                 except = p3;
4532             else
4533             {
4534                 p4 = interpret(&ue4, p4, istate);
4535                 if (CTFEExp.isCantExp(p4))
4536                 {
4537                     result = p4;
4538                     return;
4539                 }
4540                 if (exceptionOrCantInterpret(p4))
4541                     except = p4;
4542             }
4543             if (except)
4544             {
4545                 error(e.loc, "comparison `%s` of pointers to unrelated memory blocks remains indeterminate at compile time because exception `%s` was thrown while evaluating `%s`", e.e1.toChars(), except.toChars(), e.e2.toChars());
4546                 result = CTFEExp.cantexp;
4547                 return;
4548             }
4549             dinteger_t ofs3, ofs4;
4550             Expression agg3 = getAggregateFromPointer(p3, &ofs3);
4551             Expression agg4 = getAggregateFromPointer(p4, &ofs4);
4552             // The valid cases are:
4553             // p1 > p2 && p3 > p4  (same direction, also for < && <)
4554             // p1 > p2 && p3 < p4  (different direction, also < && >)
4555             // Changing any > into >= doesn't affect the result
4556             if ((dir1 == dir2 && pointToSameMemoryBlock(agg1, agg4) && pointToSameMemoryBlock(agg2, agg3)) ||
4557                 (dir1 != dir2 && pointToSameMemoryBlock(agg1, agg3) && pointToSameMemoryBlock(agg2, agg4)))
4558             {
4559                 // it's a legal two-sided comparison
4560                 emplaceExp!(IntegerExp)(pue, e.loc, (e.op == EXP.andAnd) ? 0 : 1, e.type);
4561                 result = pue.exp();
4562                 return;
4563             }
4564             // It's an invalid four-pointer comparison. Either the second
4565             // comparison is in the same direction as the first, or else
4566             // more than two memory blocks are involved (either two independent
4567             // invalid comparisons are present, or else agg3 == agg4).
4568             error(e.loc, "comparison `%s` of pointers to unrelated memory blocks is indeterminate at compile time, even when combined with `%s`.", e.e1.toChars(), e.e2.toChars());
4569             result = CTFEExp.cantexp;
4570             return;
4571         }
4572         // The first pointer expression didn't need special treatment, so we
4573         // we need to interpret the entire expression exactly as a normal && or ||.
4574         // This is easy because we haven't evaluated e2 at all yet, and we already
4575         // know it will return a bool.
4576         // But we mustn't evaluate the pointer expressions in e1 again, in case
4577         // they have side-effects.
4578         bool nott = false;
4579         Expression ex = e.e1;
4580         while (1)
4581         {
4582             if (auto ne = ex.isNotExp())
4583             {
4584                 nott = !nott;
4585                 ex = ne.e1;
4586             }
4587             else
4588                 break;
4589         }
4590 
4591         /** Negate relational operator, eg >= becomes <
4592          * Params:
4593          *      op = comparison operator to negate
4594          * Returns:
4595          *      negate operator
4596          */
4597         static EXP negateRelation(EXP op) pure
4598         {
4599             switch (op)
4600             {
4601                 case EXP.greaterOrEqual:  op = EXP.lessThan;       break;
4602                 case EXP.greaterThan:     op = EXP.lessOrEqual;    break;
4603                 case EXP.lessOrEqual:     op = EXP.greaterThan;    break;
4604                 case EXP.lessThan:        op = EXP.greaterOrEqual; break;
4605                 default:                  assert(0);
4606             }
4607             return op;
4608         }
4609 
4610         const EXP cmpop = nott ? negateRelation(ex.op) : ex.op;
4611         const cmp = comparePointers(cmpop, agg1, ofs1, agg2, ofs2);
4612         // We already know this is a valid comparison.
4613         assert(cmp >= 0);
4614         if (e.op == EXP.andAnd && cmp == 1 || e.op == EXP.orOr && cmp == 0)
4615         {
4616             result = interpret(pue, e.e2, istate);
4617             return;
4618         }
4619         emplaceExp!(IntegerExp)(pue, e.loc, (e.op == EXP.andAnd) ? 0 : 1, e.type);
4620         result = pue.exp();
4621     }
4622 
4623     override void visit(LogicalExp e)
4624     {
4625         debug (LOG)
4626         {
4627             printf("%s LogicalExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4628         }
4629         // Check for an insidePointer expression, evaluate it if so
4630         interpretFourPointerRelation(pue, e);
4631         if (result)
4632             return;
4633 
4634         UnionExp ue1 = void;
4635         result = interpret(&ue1, e.e1, istate);
4636         if (exceptionOrCant(result))
4637             return;
4638 
4639         bool res;
4640         const andand = e.op == EXP.andAnd;
4641         if (andand ? result.toBool().hasValue(false) : isTrueBool(result))
4642             res = !andand;
4643         else if (andand ? isTrueBool(result) : result.toBool().hasValue(false))
4644         {
4645             UnionExp ue2 = void;
4646             result = interpret(&ue2, e.e2, istate);
4647             if (exceptionOrCant(result))
4648                 return;
4649             if (result.op == EXP.voidExpression)
4650             {
4651                 assert(e.type.ty == Tvoid);
4652                 result = null;
4653                 return;
4654             }
4655             if (result.toBool().hasValue(false))
4656                 res = false;
4657             else if (isTrueBool(result))
4658                 res = true;
4659             else
4660             {
4661                 error(e.loc, "`%s` does not evaluate to a `bool`", result.toChars());
4662                 result = CTFEExp.cantexp;
4663                 return;
4664             }
4665         }
4666         else
4667         {
4668             error(e.loc, "`%s` cannot be interpreted as a `bool`", result.toChars());
4669             result = CTFEExp.cantexp;
4670             return;
4671         }
4672         incUsageCtfe(istate, e.e2.loc);
4673 
4674         if (goal != CTFEGoal.Nothing)
4675         {
4676             if (e.type.equals(Type.tbool))
4677                 result = IntegerExp.createBool(res);
4678             else
4679             {
4680                 emplaceExp!(IntegerExp)(pue, e.loc, res, e.type);
4681                 result = pue.exp();
4682             }
4683         }
4684     }
4685 
4686 
4687     // Print a stack trace, starting from callingExp which called fd.
4688     // To shorten the stack trace, try to detect recursion.
4689     private void showCtfeBackTrace(CallExp callingExp, FuncDeclaration fd)
4690     {
4691         if (ctfeGlobals.stackTraceCallsToSuppress > 0)
4692         {
4693             --ctfeGlobals.stackTraceCallsToSuppress;
4694             return;
4695         }
4696         errorSupplemental(callingExp.loc, "called from here: `%s`", callingExp.toChars());
4697         // Quit if it's not worth trying to compress the stack trace
4698         if (ctfeGlobals.callDepth < 6 || global.params.v.verbose)
4699             return;
4700         // Recursion happens if the current function already exists in the call stack.
4701         int numToSuppress = 0;
4702         int recurseCount = 0;
4703         int depthSoFar = 0;
4704         InterState* lastRecurse = istate;
4705         for (InterState* cur = istate; cur; cur = cur.caller)
4706         {
4707             if (cur.fd == fd)
4708             {
4709                 ++recurseCount;
4710                 numToSuppress = depthSoFar;
4711                 lastRecurse = cur;
4712             }
4713             ++depthSoFar;
4714         }
4715         // We need at least three calls to the same function, to make compression worthwhile
4716         if (recurseCount < 2)
4717             return;
4718         // We found a useful recursion.  Print all the calls involved in the recursion
4719         errorSupplemental(fd.loc, "%d recursive calls to function `%s`", recurseCount, fd.toChars());
4720         for (InterState* cur = istate; cur.fd != fd; cur = cur.caller)
4721         {
4722             errorSupplemental(cur.fd.loc, "recursively called from function `%s`", cur.fd.toChars());
4723         }
4724         // We probably didn't enter the recursion in this function.
4725         // Go deeper to find the real beginning.
4726         InterState* cur = istate;
4727         while (lastRecurse.caller && cur.fd == lastRecurse.caller.fd)
4728         {
4729             cur = cur.caller;
4730             lastRecurse = lastRecurse.caller;
4731             ++numToSuppress;
4732         }
4733         ctfeGlobals.stackTraceCallsToSuppress = numToSuppress;
4734     }
4735 
4736     override void visit(CallExp e)
4737     {
4738         debug (LOG)
4739         {
4740             printf("%s CallExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4741         }
4742         Expression pthis = null;
4743         FuncDeclaration fd = null;
4744 
4745         Expression ecall = interpretRegion(e.e1, istate);
4746         if (exceptionOrCant(ecall))
4747             return;
4748 
4749         if (auto dve = ecall.isDotVarExp())
4750         {
4751             // Calling a member function
4752             pthis = dve.e1;
4753             fd = dve.var.isFuncDeclaration();
4754             assert(fd);
4755 
4756             if (auto dte = pthis.isDotTypeExp())
4757                 pthis = dte.e1;
4758         }
4759         else if (auto ve = ecall.isVarExp())
4760         {
4761             fd = ve.var.isFuncDeclaration();
4762             assert(fd);
4763 
4764             // If `_d_HookTraceImpl` is found, resolve the underlying hook and replace `e` and `fd` with it.
4765             removeHookTraceImpl(e, fd);
4766 
4767             if (fd.ident == Id.__ArrayPostblit || fd.ident == Id.__ArrayDtor)
4768             {
4769                 assert(e.arguments.length == 1);
4770                 Expression ea = (*e.arguments)[0];
4771                 // printf("1 ea = %s %s\n", ea.type.toChars(), ea.toChars());
4772                 if (auto se = ea.isSliceExp())
4773                     ea = se.e1;
4774                 if (auto ce = ea.isCastExp())
4775                     ea = ce.e1;
4776 
4777                 // printf("2 ea = %s, %s %s\n", ea.type.toChars(), EXPtoString(ea.op).ptr, ea.toChars());
4778                 if (ea.op == EXP.variable || ea.op == EXP.symbolOffset)
4779                     result = getVarExp(e.loc, istate, (cast(SymbolExp)ea).var, CTFEGoal.RValue);
4780                 else if (auto ae = ea.isAddrExp())
4781                     result = interpretRegion(ae.e1, istate);
4782 
4783                 // https://issues.dlang.org/show_bug.cgi?id=18871
4784                 // https://issues.dlang.org/show_bug.cgi?id=18819
4785                 else if (auto ale = ea.isArrayLiteralExp())
4786                     result = interpretRegion(ale, istate);
4787 
4788                 else
4789                     assert(0);
4790                 if (CTFEExp.isCantExp(result))
4791                     return;
4792 
4793                 if (fd.ident == Id.__ArrayPostblit)
4794                     result = evaluatePostblit(istate, result);
4795                 else
4796                     result = evaluateDtor(istate, result);
4797                 if (!result)
4798                     result = CTFEExp.voidexp;
4799                 return;
4800             }
4801             else if (isArrayConstruction(fd.ident))
4802             {
4803                 // In expressionsem.d, `T[x] ea = eb;` was lowered to:
4804                 // `_d_array{,set}ctor(ea[], eb[]);`.
4805                 // The following code will rewrite it back to `ea = eb` and
4806                 // then interpret that expression.
4807 
4808                 if (fd.ident == Id._d_arrayctor)
4809                     assert(e.arguments.length == 3);
4810                 else
4811                     assert(e.arguments.length == 2);
4812 
4813                 Expression ea = (*e.arguments)[0];
4814                 if (ea.isCastExp)
4815                     ea = ea.isCastExp.e1;
4816 
4817                 Expression eb = (*e.arguments)[1];
4818                 if (eb.isCastExp() && fd.ident == Id._d_arrayctor)
4819                     eb = eb.isCastExp.e1;
4820 
4821                 ConstructExp ce = new ConstructExp(e.loc, ea, eb);
4822                 ce.type = ea.type;
4823 
4824                 ce.type = ea.type;
4825                 result = interpret(ce, istate);
4826 
4827                 return;
4828             }
4829             else if (fd.ident == Id._d_arrayappendT || fd.ident == Id._d_arrayappendTTrace)
4830             {
4831                 // In expressionsem.d `ea ~= eb` was lowered to `_d_arrayappendT{,Trace}({file, line, funcname}, ea, eb);`.
4832                 // The following code will rewrite it back to `ea ~= eb` and then interpret that expression.
4833                 Expression lhs, rhs;
4834 
4835                 if (fd.ident == Id._d_arrayappendT)
4836                 {
4837                     assert(e.arguments.length == 2);
4838                     lhs = (*e.arguments)[0];
4839                     rhs = (*e.arguments)[1];
4840                 }
4841                 else
4842                 {
4843                     assert(e.arguments.length == 5);
4844                     lhs = (*e.arguments)[3];
4845                     rhs = (*e.arguments)[4];
4846                 }
4847 
4848                 auto cae = new CatAssignExp(e.loc, lhs, rhs);
4849                 cae.type = e.type;
4850 
4851                 result = interpretRegion(cae, istate, CTFEGoal.LValue);
4852                 return;
4853             }
4854             else if (fd.ident == Id._d_arrayappendcTX)
4855                 assert(0, "CTFE cannot interpret _d_arrayappendcTX!");
4856         }
4857         else if (auto soe = ecall.isSymOffExp())
4858         {
4859             fd = soe.var.isFuncDeclaration();
4860             assert(fd && soe.offset == 0);
4861         }
4862         else if (auto de = ecall.isDelegateExp())
4863         {
4864             // Calling a delegate
4865             fd = de.func;
4866             pthis = de.e1;
4867 
4868             // Special handling for: &nestedfunc --> DelegateExp(VarExp(nestedfunc), nestedfunc)
4869             if (auto ve = pthis.isVarExp())
4870                 if (ve.var == fd)
4871                     pthis = null; // context is not necessary for CTFE
4872         }
4873         else if (auto fe = ecall.isFuncExp())
4874         {
4875             // Calling a delegate literal
4876             fd = fe.fd;
4877         }
4878         else
4879         {
4880             // delegate.funcptr()
4881             // others
4882             error(e.loc, "cannot call `%s` at compile time", e.toChars());
4883             result = CTFEExp.cantexp;
4884             return;
4885         }
4886         if (!fd)
4887         {
4888             error(e.loc, "CTFE internal error: cannot evaluate `%s` at compile time", e.toChars());
4889             result = CTFEExp.cantexp;
4890             return;
4891         }
4892         if (pthis)
4893         {
4894             // Member function call
4895 
4896             // Currently this is satisfied because closure is not yet supported.
4897             assert(!fd.isNested() || fd.needThis());
4898 
4899             if (pthis.op == EXP.typeid_)
4900             {
4901                 error(pthis.loc, "static variable `%s` cannot be read at compile time", pthis.toChars());
4902                 result = CTFEExp.cantexp;
4903                 return;
4904             }
4905             assert(pthis);
4906 
4907             if (pthis.op == EXP.null_)
4908             {
4909                 assert(pthis.type.toBasetype().ty == Tclass);
4910                 error(e.loc, "function call through null class reference `%s`", pthis.toChars());
4911                 result = CTFEExp.cantexp;
4912                 return;
4913             }
4914 
4915             assert(pthis.op == EXP.structLiteral || pthis.op == EXP.classReference || pthis.op == EXP.type);
4916 
4917             if (fd.isVirtual() && !e.directcall)
4918             {
4919                 // Make a virtual function call.
4920                 // Get the function from the vtable of the original class
4921                 ClassDeclaration cd = pthis.isClassReferenceExp().originalClass();
4922 
4923                 // We can't just use the vtable index to look it up, because
4924                 // vtables for interfaces don't get populated until the glue layer.
4925                 fd = cd.findFunc(fd.ident, fd.type.isTypeFunction());
4926                 assert(fd);
4927             }
4928         }
4929 
4930         if (fd && fd.semanticRun >= PASS.semantic3done && fd.hasSemantic3Errors())
4931         {
4932             error(e.loc, "CTFE failed because of previous errors in `%s`", fd.toChars());
4933             result = CTFEExp.cantexp;
4934             return;
4935         }
4936 
4937         // Check for built-in functions
4938         result = evaluateIfBuiltin(pue, istate, e.loc, fd, e.arguments, pthis);
4939         if (result)
4940             return;
4941 
4942         if (!fd.fbody)
4943         {
4944             error(e.loc, "`%s` cannot be interpreted at compile time, because it has no available source code", fd.toChars());
4945             result = CTFEExp.showcontext;
4946             return;
4947         }
4948 
4949         result = interpretFunction(pue, fd, istate, e.arguments, pthis);
4950         if (result.op == EXP.voidExpression)
4951             return;
4952         if (!exceptionOrCantInterpret(result))
4953         {
4954             if (goal != CTFEGoal.LValue) // Peel off CTFE reference if it's unnecessary
4955             {
4956                 if (result == pue.exp())
4957                     result = pue.copy();
4958                 result = interpret(pue, result, istate);
4959             }
4960         }
4961         if (!exceptionOrCantInterpret(result))
4962         {
4963             result = paintTypeOntoLiteral(pue, e.type, result);
4964             result.loc = e.loc;
4965         }
4966         else if (CTFEExp.isCantExp(result) && !global.gag)
4967             showCtfeBackTrace(e, fd); // Print a stack trace.
4968     }
4969 
4970     override void visit(CommaExp e)
4971     {
4972         /****************************************
4973          * Find the first non-comma expression.
4974          * Params:
4975          *      e = Expressions connected by commas
4976          * Returns:
4977          *      left-most non-comma expression
4978          */
4979         static inout(Expression) firstComma(inout Expression e)
4980         {
4981             Expression ex = cast()e;
4982             while (ex.op == EXP.comma)
4983                 ex = (cast(CommaExp)ex).e1;
4984             return cast(inout)ex;
4985 
4986         }
4987 
4988         debug (LOG)
4989         {
4990             printf("%s CommaExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4991         }
4992 
4993         bool isNewThrowableHook()
4994         {
4995             auto de = e.e1.isDeclarationExp();
4996             if (de is null)
4997                 return false;
4998 
4999             auto vd = de.declaration.isVarDeclaration();
5000             if (vd is null)
5001                 return false;
5002 
5003             auto ei = vd._init.isExpInitializer();
5004             if (ei is null)
5005                 return false;
5006 
5007             auto ce = ei.exp.isConstructExp();
5008             if (ce is null)
5009                 return false;
5010 
5011             return isRuntimeHook(ce.e2, Id._d_newThrowable) !is null;
5012         }
5013 
5014         if (auto ce = isRuntimeHook(e.e1, Id._d_arrayappendcTX))
5015         {
5016             // In expressionsem.d `arr ~= elem` was lowered to
5017             // `_d_arrayappendcTX(arr, elem), arr[arr.length - 1] = elem, elem;`.
5018             // The following code will rewrite it back to `arr ~= elem`
5019             // and then interpret that expression.
5020             assert(ce.arguments.length == 2);
5021 
5022             auto arr = (*ce.arguments)[0];
5023             auto elem = e.e2.isConstructExp().e2;
5024             assert(elem);
5025 
5026             auto cae = new CatAssignExp(e.loc, arr, elem);
5027             cae.type = arr.type;
5028 
5029             result = interpret(cae, istate);
5030             return;
5031         }
5032         else if (isNewThrowableHook())
5033         {
5034             // In expressionsem.d `throw new Exception(args)` was lowered to
5035             // `throw (tmp = _d_newThrowable!Exception(), tmp.ctor(args), tmp)`.
5036             // The following code will rewrite it back to `throw new Exception(args)`
5037             // and then interpret this expression instead.
5038             auto ce = e.e2.isCallExp();
5039             assert(ce);
5040 
5041             auto ne = new NewExp(e.loc, null, e.type, ce.arguments);
5042             ne.type = e.e1.type;
5043 
5044             result = interpret(ne, istate);
5045             return;
5046         }
5047 
5048         // If it creates a variable, and there's no context for
5049         // the variable to be created in, we need to create one now.
5050         InterState istateComma;
5051         if (!istate && firstComma(e.e1).op == EXP.declaration)
5052         {
5053             ctfeGlobals.stack.startFrame(null);
5054             istate = &istateComma;
5055         }
5056 
5057         void endTempStackFrame()
5058         {
5059             // If we created a temporary stack frame, end it now.
5060             if (istate == &istateComma)
5061                 ctfeGlobals.stack.endFrame();
5062         }
5063 
5064         result = CTFEExp.cantexp;
5065 
5066         // If the comma returns a temporary variable, it needs to be an lvalue
5067         // (this is particularly important for struct constructors)
5068         if (e.e1.op == EXP.declaration &&
5069             e.e2.op == EXP.variable &&
5070             e.e1.isDeclarationExp().declaration == e.e2.isVarExp().var &&
5071             e.e2.isVarExp().var.storage_class & STC.ctfe)
5072         {
5073             VarExp ve = e.e2.isVarExp();
5074             VarDeclaration v = ve.var.isVarDeclaration();
5075             ctfeGlobals.stack.push(v);
5076             if (!v._init && !getValue(v))
5077             {
5078                 setValue(v, copyLiteral(v.type.defaultInitLiteral(e.loc)).copy());
5079             }
5080             if (!getValue(v))
5081             {
5082                 Expression newval = v._init.initializerToExpression();
5083                 // Bug 4027. Copy constructors are a weird case where the
5084                 // initializer is a void function (the variable is modified
5085                 // through a reference parameter instead).
5086                 newval = interpretRegion(newval, istate);
5087                 if (exceptionOrCant(newval))
5088                     return endTempStackFrame();
5089                 if (newval.op != EXP.voidExpression)
5090                 {
5091                     // v isn't necessarily null.
5092                     setValueWithoutChecking(v, copyLiteral(newval).copy());
5093                 }
5094             }
5095         }
5096         else
5097         {
5098             UnionExp ue = void;
5099             auto e1 = interpret(&ue, e.e1, istate, CTFEGoal.Nothing);
5100             if (exceptionOrCant(e1))
5101                 return endTempStackFrame();
5102         }
5103         result = interpret(pue, e.e2, istate, goal);
5104         return endTempStackFrame();
5105     }
5106 
5107     override void visit(CondExp e)
5108     {
5109         debug (LOG)
5110         {
5111             printf("%s CondExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5112         }
5113         UnionExp uecond = void;
5114         Expression econd;
5115         econd = interpret(&uecond, e.econd, istate);
5116         if (exceptionOrCant(econd))
5117             return;
5118 
5119         if (isPointer(e.econd.type))
5120         {
5121             if (econd.op != EXP.null_)
5122             {
5123                 econd = IntegerExp.createBool(true);
5124             }
5125         }
5126 
5127         if (isTrueBool(econd))
5128         {
5129             result = interpret(pue, e.e1, istate, goal);
5130             incUsageCtfe(istate, e.e1.loc);
5131         }
5132         else if (econd.toBool().hasValue(false))
5133         {
5134             result = interpret(pue, e.e2, istate, goal);
5135             incUsageCtfe(istate, e.e2.loc);
5136         }
5137         else
5138         {
5139             error(e.loc, "`%s` does not evaluate to boolean result at compile time", e.econd.toChars());
5140             result = CTFEExp.cantexp;
5141         }
5142     }
5143 
5144     override void visit(ArrayLengthExp e)
5145     {
5146         debug (LOG)
5147         {
5148             printf("%s ArrayLengthExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5149         }
5150         UnionExp ue1;
5151         Expression e1 = interpret(&ue1, e.e1, istate);
5152         assert(e1);
5153         if (exceptionOrCant(e1))
5154             return;
5155         if (e1.op != EXP.string_ && e1.op != EXP.arrayLiteral && e1.op != EXP.slice && e1.op != EXP.null_)
5156         {
5157             error(e.loc, "`%s` cannot be evaluated at compile time", e.toChars());
5158             result = CTFEExp.cantexp;
5159             return;
5160         }
5161         emplaceExp!(IntegerExp)(pue, e.loc, resolveArrayLength(e1), e.type);
5162         result = pue.exp();
5163     }
5164 
5165     /**
5166      * Interpret the vector expression as an array literal.
5167      * Params:
5168      *    pue = non-null pointer to temporary storage that can be used to store the return value
5169      *    e = Expression to interpret
5170      * Returns:
5171      *    resulting array literal or 'e' if unable to interpret
5172      */
5173     static Expression interpretVectorToArray(UnionExp* pue, VectorExp e)
5174     {
5175         if (auto ale = e.e1.isArrayLiteralExp())
5176             return ale;         // it's already an array literal
5177         if (e.e1.op == EXP.int64 || e.e1.op == EXP.float64)
5178         {
5179             // Convert literal __vector(int) -> __vector([array])
5180             auto elements = new Expressions(e.dim);
5181             foreach (ref element; *elements)
5182                 element = copyLiteral(e.e1).copy();
5183             auto type = (e.type.ty == Tvector) ? e.type.isTypeVector().basetype : e.type.isTypeSArray();
5184             assert(type);
5185             emplaceExp!(ArrayLiteralExp)(pue, e.loc, type, elements);
5186             auto ale = pue.exp().isArrayLiteralExp();
5187             ale.ownedByCtfe = OwnedBy.ctfe;
5188             return ale;
5189         }
5190         return e;
5191     }
5192 
5193     override void visit(VectorExp e)
5194     {
5195         debug (LOG)
5196         {
5197             printf("%s VectorExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5198         }
5199         if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
5200         {
5201             result = e;
5202             return;
5203         }
5204         Expression e1 = interpret(pue, e.e1, istate);
5205         assert(e1);
5206         if (exceptionOrCant(e1))
5207             return;
5208         if (e1.op != EXP.arrayLiteral && e1.op != EXP.int64 && e1.op != EXP.float64)
5209         {
5210             error(e.loc, "`%s` cannot be evaluated at compile time", e.toChars());
5211             result = CTFEExp.cantexp;
5212             return;
5213         }
5214         if (e1 == pue.exp())
5215             e1 = pue.copy();
5216         emplaceExp!(VectorExp)(pue, e.loc, e1, e.to);
5217         auto ve = pue.exp().isVectorExp();
5218         ve.type = e.type;
5219         ve.dim = e.dim;
5220         ve.ownedByCtfe = OwnedBy.ctfe;
5221         result = ve;
5222     }
5223 
5224     override void visit(VectorArrayExp e)
5225     {
5226         debug (LOG)
5227         {
5228             printf("%s VectorArrayExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5229         }
5230         Expression e1 = interpret(pue, e.e1, istate);
5231         assert(e1);
5232         if (exceptionOrCant(e1))
5233             return;
5234         if (auto ve = e1.isVectorExp())
5235         {
5236             result = interpretVectorToArray(pue, ve);
5237             if (result.op != EXP.vector)
5238                 return;
5239         }
5240         error(e.loc, "`%s` cannot be evaluated at compile time", e.toChars());
5241         result = CTFEExp.cantexp;
5242     }
5243 
5244     override void visit(DelegatePtrExp e)
5245     {
5246         debug (LOG)
5247         {
5248             printf("%s DelegatePtrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5249         }
5250         Expression e1 = interpret(pue, e.e1, istate);
5251         assert(e1);
5252         if (exceptionOrCant(e1))
5253             return;
5254         error(e.loc, "`%s` cannot be evaluated at compile time", e.toChars());
5255         result = CTFEExp.cantexp;
5256     }
5257 
5258     override void visit(DelegateFuncptrExp e)
5259     {
5260         debug (LOG)
5261         {
5262             printf("%s DelegateFuncptrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5263         }
5264         Expression e1 = interpret(pue, e.e1, istate);
5265         assert(e1);
5266         if (exceptionOrCant(e1))
5267             return;
5268         error(e.loc, "`%s` cannot be evaluated at compile time", e.toChars());
5269         result = CTFEExp.cantexp;
5270     }
5271 
5272     static bool resolveIndexing(IndexExp e, InterState* istate, Expression* pagg, uinteger_t* pidx, bool modify)
5273     {
5274         assert(e.e1.type.toBasetype().ty != Taarray);
5275 
5276         if (e.e1.type.toBasetype().ty == Tpointer)
5277         {
5278             // Indexing a pointer. Note that there is no $ in this case.
5279             Expression e1 = interpretRegion(e.e1, istate);
5280             if (exceptionOrCantInterpret(e1))
5281                 return false;
5282 
5283             Expression e2 = interpretRegion(e.e2, istate);
5284             if (exceptionOrCantInterpret(e2))
5285                 return false;
5286             sinteger_t indx = e2.toInteger();
5287 
5288             dinteger_t ofs;
5289             Expression agg = getAggregateFromPointer(e1, &ofs);
5290 
5291             if (agg.op == EXP.null_)
5292             {
5293                 error(e.loc, "cannot index through null pointer `%s`", e.e1.toChars());
5294                 return false;
5295             }
5296             if (agg.op == EXP.int64)
5297             {
5298                 error(e.loc, "cannot index through invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars());
5299                 return false;
5300             }
5301             // Pointer to a non-array variable
5302             if (agg.op == EXP.symbolOffset)
5303             {
5304                 error(e.loc, "mutable variable `%s` cannot be %s at compile time, even through a pointer", cast(char*)(modify ? "modified" : "read"), agg.isSymOffExp().var.toChars());
5305                 return false;
5306             }
5307 
5308             if (agg.op == EXP.arrayLiteral || agg.op == EXP.string_)
5309             {
5310                 dinteger_t len = resolveArrayLength(agg);
5311                 if (ofs + indx >= len)
5312                 {
5313                     error(e.loc, "pointer index `[%lld]` exceeds allocated memory block `[0..%lld]`", ofs + indx, len);
5314                     return false;
5315                 }
5316             }
5317             else
5318             {
5319                 if (ofs + indx != 0)
5320                 {
5321                     error(e.loc, "pointer index `[%lld]` lies outside memory block `[0..1]`", ofs + indx);
5322                     return false;
5323                 }
5324             }
5325             *pagg = agg;
5326             *pidx = ofs + indx;
5327             return true;
5328         }
5329 
5330         Expression e1 = interpretRegion(e.e1, istate);
5331         if (exceptionOrCantInterpret(e1))
5332             return false;
5333         if (e1.op == EXP.null_)
5334         {
5335             error(e.loc, "cannot index null array `%s`", e.e1.toChars());
5336             return false;
5337         }
5338         if (auto ve = e1.isVectorExp())
5339         {
5340             UnionExp ue = void;
5341             e1 = interpretVectorToArray(&ue, ve);
5342             e1 = (e1 == ue.exp()) ? ue.copy() : e1;
5343         }
5344 
5345         // Set the $ variable, and find the array literal to modify
5346         dinteger_t len;
5347         if (e1.op == EXP.variable && e1.type.toBasetype().ty == Tsarray)
5348             len = e1.type.toBasetype().isTypeSArray().dim.toInteger();
5349         else
5350         {
5351             if (e1.op != EXP.arrayLiteral && e1.op != EXP.string_ && e1.op != EXP.slice && e1.op != EXP.vector)
5352             {
5353                 error(e.loc, "cannot determine length of `%s` at compile time", e.e1.toChars());
5354                 return false;
5355             }
5356             len = resolveArrayLength(e1);
5357         }
5358 
5359         if (e.lengthVar)
5360         {
5361             Expression dollarExp = ctfeEmplaceExp!IntegerExp(e.loc, len, Type.tsize_t);
5362             ctfeGlobals.stack.push(e.lengthVar);
5363             setValue(e.lengthVar, dollarExp);
5364         }
5365         Expression e2 = interpretRegion(e.e2, istate);
5366         if (e.lengthVar)
5367             ctfeGlobals.stack.pop(e.lengthVar); // $ is defined only inside []
5368         if (exceptionOrCantInterpret(e2))
5369             return false;
5370         if (e2.op != EXP.int64)
5371         {
5372             error(e.loc, "CTFE internal error: non-integral index `[%s]`", e.e2.toChars());
5373             return false;
5374         }
5375 
5376         if (auto se = e1.isSliceExp())
5377         {
5378             // Simplify index of slice: agg[lwr..upr][indx] --> agg[indx']
5379             uinteger_t index = e2.toInteger();
5380             uinteger_t ilwr = se.lwr.toInteger();
5381             uinteger_t iupr = se.upr.toInteger();
5382 
5383             if (index > iupr - ilwr)
5384             {
5385                 error(e.loc, "index %llu exceeds array length %llu", index, iupr - ilwr);
5386                 return false;
5387             }
5388             *pagg = e1.isSliceExp().e1;
5389             *pidx = index + ilwr;
5390         }
5391         else
5392         {
5393             *pagg = e1;
5394             *pidx = e2.toInteger();
5395             if (len <= *pidx)
5396             {
5397                 error(e.loc, "array index %lld is out of bounds `[0..%lld]`", *pidx, len);
5398                 return false;
5399             }
5400         }
5401         return true;
5402     }
5403 
5404     override void visit(IndexExp e)
5405     {
5406         debug (LOG)
5407         {
5408             printf("%s IndexExp::interpret() %s, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
5409         }
5410         if (e.e1.type.toBasetype().ty == Tpointer)
5411         {
5412             Expression agg;
5413             uinteger_t indexToAccess;
5414             if (!resolveIndexing(e, istate, &agg, &indexToAccess, false))
5415             {
5416                 result = CTFEExp.cantexp;
5417                 return;
5418             }
5419             if (agg.op == EXP.arrayLiteral || agg.op == EXP.string_)
5420             {
5421                 if (goal == CTFEGoal.LValue)
5422                 {
5423                     // if we need a reference, IndexExp shouldn't be interpreting
5424                     // the expression to a value, it should stay as a reference
5425                     emplaceExp!(IndexExp)(pue, e.loc, agg, ctfeEmplaceExp!IntegerExp(e.e2.loc, indexToAccess, e.e2.type));
5426                     result = pue.exp();
5427                     result.type = e.type;
5428                     return;
5429                 }
5430                 result = ctfeIndex(pue, e.loc, e.type, agg, indexToAccess);
5431                 return;
5432             }
5433             else
5434             {
5435                 assert(indexToAccess == 0);
5436                 result = interpretRegion(agg, istate, goal);
5437                 if (exceptionOrCant(result))
5438                     return;
5439                 result = paintTypeOntoLiteral(pue, e.type, result);
5440                 return;
5441             }
5442         }
5443 
5444         if (e.e1.type.toBasetype().ty == Taarray)
5445         {
5446             Expression e1 = interpretRegion(e.e1, istate);
5447             if (exceptionOrCant(e1))
5448                 return;
5449             if (e1.op == EXP.null_)
5450             {
5451                 if (goal == CTFEGoal.LValue && e1.type.ty == Taarray && e.modifiable)
5452                 {
5453                     assert(0); // does not reach here?
5454                 }
5455                 error(e.loc, "cannot index null array `%s`", e.e1.toChars());
5456                 result = CTFEExp.cantexp;
5457                 return;
5458             }
5459             Expression e2 = interpretRegion(e.e2, istate);
5460             if (exceptionOrCant(e2))
5461                 return;
5462 
5463             if (goal == CTFEGoal.LValue)
5464             {
5465                 // Pointer or reference of a scalar type
5466                 if (e1 == e.e1 && e2 == e.e2)
5467                     result = e;
5468                 else
5469                 {
5470                     emplaceExp!(IndexExp)(pue, e.loc, e1, e2);
5471                     result = pue.exp();
5472                     result.type = e.type;
5473                 }
5474                 return;
5475             }
5476 
5477             assert(e1.op == EXP.assocArrayLiteral);
5478             UnionExp e2tmp = void;
5479             e2 = resolveSlice(e2, &e2tmp);
5480             result = findKeyInAA(e.loc, e1.isAssocArrayLiteralExp(), e2);
5481             if (!result)
5482             {
5483                 error(e.loc, "key `%s` not found in associative array `%s`", e2.toChars(), e.e1.toChars());
5484                 result = CTFEExp.cantexp;
5485             }
5486             return;
5487         }
5488 
5489         Expression agg;
5490         uinteger_t indexToAccess;
5491         if (!resolveIndexing(e, istate, &agg, &indexToAccess, false))
5492         {
5493             result = CTFEExp.cantexp;
5494             return;
5495         }
5496 
5497         if (goal == CTFEGoal.LValue)
5498         {
5499             Expression e2 = ctfeEmplaceExp!IntegerExp(e.e2.loc, indexToAccess, Type.tsize_t);
5500             emplaceExp!(IndexExp)(pue, e.loc, agg, e2);
5501             result = pue.exp();
5502             result.type = e.type;
5503             return;
5504         }
5505 
5506         result = ctfeIndex(pue, e.loc, e.type, agg, indexToAccess);
5507         if (exceptionOrCant(result))
5508             return;
5509         if (result.op == EXP.void_)
5510         {
5511             error(e.loc, "`%s` is used before initialized", e.toChars());
5512             errorSupplemental(result.loc, "originally uninitialized here");
5513             result = CTFEExp.cantexp;
5514             return;
5515         }
5516         if (result == pue.exp())
5517             result = result.copy();
5518     }
5519 
5520     override void visit(SliceExp e)
5521     {
5522         debug (LOG)
5523         {
5524             printf("%s SliceExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5525         }
5526         if (e.e1.type.toBasetype().ty == Tpointer)
5527         {
5528             // Slicing a pointer. Note that there is no $ in this case.
5529             Expression e1 = interpretRegion(e.e1, istate);
5530             if (exceptionOrCant(e1))
5531                 return;
5532             if (e1.op == EXP.int64)
5533             {
5534                 error(e.loc, "cannot slice invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars());
5535                 result = CTFEExp.cantexp;
5536                 return;
5537             }
5538 
5539             /* Evaluate lower and upper bounds of slice
5540              */
5541             Expression lwr = interpretRegion(e.lwr, istate);
5542             if (exceptionOrCant(lwr))
5543                 return;
5544             Expression upr = interpretRegion(e.upr, istate);
5545             if (exceptionOrCant(upr))
5546                 return;
5547             uinteger_t ilwr = lwr.toInteger();
5548             uinteger_t iupr = upr.toInteger();
5549 
5550             dinteger_t ofs;
5551             Expression agg = getAggregateFromPointer(e1, &ofs);
5552             ilwr += ofs;
5553             iupr += ofs;
5554             if (agg.op == EXP.null_)
5555             {
5556                 if (iupr == ilwr)
5557                 {
5558                     result = ctfeEmplaceExp!NullExp(e.loc);
5559                     result.type = e.type;
5560                     return;
5561                 }
5562                 error(e.loc, "cannot slice null pointer `%s`", e.e1.toChars());
5563                 result = CTFEExp.cantexp;
5564                 return;
5565             }
5566             if (agg.op == EXP.symbolOffset)
5567             {
5568                 error(e.loc, "slicing pointers to static variables is not supported in CTFE");
5569                 result = CTFEExp.cantexp;
5570                 return;
5571             }
5572             if (agg.op != EXP.arrayLiteral && agg.op != EXP.string_)
5573             {
5574                 error(e.loc, "pointer `%s` cannot be sliced at compile time (it does not point to an array)", e.e1.toChars());
5575                 result = CTFEExp.cantexp;
5576                 return;
5577             }
5578             assert(agg.op == EXP.arrayLiteral || agg.op == EXP.string_);
5579             dinteger_t len = ArrayLength(Type.tsize_t, agg).exp().toInteger();
5580             //Type *pointee = ((TypePointer *)agg.type)->next;
5581             if (sliceBoundsCheck(0, len, ilwr, iupr))
5582             {
5583                 error(e.loc, "pointer slice `[%lld..%lld]` exceeds allocated memory block `[0..%lld]`", ilwr, iupr, len);
5584                 result = CTFEExp.cantexp;
5585                 return;
5586             }
5587             if (ofs != 0)
5588             {
5589                 lwr = ctfeEmplaceExp!IntegerExp(e.loc, ilwr, lwr.type);
5590                 upr = ctfeEmplaceExp!IntegerExp(e.loc, iupr, upr.type);
5591             }
5592             emplaceExp!(SliceExp)(pue, e.loc, agg, lwr, upr);
5593             result = pue.exp();
5594             result.type = e.type;
5595             return;
5596         }
5597 
5598         CTFEGoal goal1 = CTFEGoal.RValue;
5599         if (goal == CTFEGoal.LValue)
5600         {
5601             if (e.e1.type.toBasetype().ty == Tsarray)
5602                 if (auto ve = e.e1.isVarExp())
5603                     if (auto vd = ve.var.isVarDeclaration())
5604                         if (vd.storage_class & STC.ref_)
5605                             goal1 = CTFEGoal.LValue;
5606         }
5607         Expression e1 = interpret(e.e1, istate, goal1);
5608         if (exceptionOrCant(e1))
5609             return;
5610 
5611         if (!e.lwr)
5612         {
5613             result = paintTypeOntoLiteral(pue, e.type, e1);
5614             return;
5615         }
5616         if (auto ve = e1.isVectorExp())
5617         {
5618             e1 = interpretVectorToArray(pue, ve);
5619             e1 = (e1 == pue.exp()) ? pue.copy() : e1;
5620         }
5621 
5622         /* Set dollar to the length of the array
5623          */
5624         uinteger_t dollar;
5625         if ((e1.op == EXP.variable || e1.op == EXP.dotVariable) && e1.type.toBasetype().ty == Tsarray)
5626             dollar = e1.type.toBasetype().isTypeSArray().dim.toInteger();
5627         else
5628         {
5629             if (e1.op != EXP.arrayLiteral && e1.op != EXP.string_ && e1.op != EXP.null_ && e1.op != EXP.slice && e1.op != EXP.vector)
5630             {
5631                 error(e.loc, "cannot determine length of `%s` at compile time", e1.toChars());
5632                 result = CTFEExp.cantexp;
5633                 return;
5634             }
5635             dollar = resolveArrayLength(e1);
5636         }
5637 
5638         /* Set the $ variable
5639          */
5640         if (e.lengthVar)
5641         {
5642             auto dollarExp = ctfeEmplaceExp!IntegerExp(e.loc, dollar, Type.tsize_t);
5643             ctfeGlobals.stack.push(e.lengthVar);
5644             setValue(e.lengthVar, dollarExp);
5645         }
5646 
5647         /* Evaluate lower and upper bounds of slice
5648          */
5649         Expression lwr = interpretRegion(e.lwr, istate);
5650         if (exceptionOrCant(lwr))
5651         {
5652             if (e.lengthVar)
5653                 ctfeGlobals.stack.pop(e.lengthVar);
5654             return;
5655         }
5656         Expression upr = interpretRegion(e.upr, istate);
5657         if (exceptionOrCant(upr))
5658         {
5659             if (e.lengthVar)
5660                 ctfeGlobals.stack.pop(e.lengthVar);
5661             return;
5662         }
5663         if (e.lengthVar)
5664             ctfeGlobals.stack.pop(e.lengthVar); // $ is defined only inside [L..U]
5665 
5666         uinteger_t ilwr = lwr.toInteger();
5667         uinteger_t iupr = upr.toInteger();
5668         if (e1.op == EXP.null_)
5669         {
5670             if (ilwr == 0 && iupr == 0)
5671             {
5672                 result = e1;
5673                 return;
5674             }
5675             error(e1.loc, "slice `[%llu..%llu]` is out of bounds", ilwr, iupr);
5676             result = CTFEExp.cantexp;
5677             return;
5678         }
5679         if (auto se = e1.isSliceExp())
5680         {
5681             // Simplify slice of slice:
5682             //  aggregate[lo1..up1][lwr..upr] ---> aggregate[lwr'..upr']
5683             uinteger_t lo1 = se.lwr.toInteger();
5684             uinteger_t up1 = se.upr.toInteger();
5685             if (sliceBoundsCheck(0, up1 - lo1, ilwr, iupr))
5686             {
5687                 error(e.loc, "slice `[%llu..%llu]` exceeds array bounds `[0..%llu]`", ilwr, iupr, up1 - lo1);
5688                 result = CTFEExp.cantexp;
5689                 return;
5690             }
5691             ilwr += lo1;
5692             iupr += lo1;
5693             emplaceExp!(SliceExp)(pue, e.loc, se.e1,
5694                 ctfeEmplaceExp!IntegerExp(e.loc, ilwr, lwr.type),
5695                 ctfeEmplaceExp!IntegerExp(e.loc, iupr, upr.type));
5696             result = pue.exp();
5697             result.type = e.type;
5698             return;
5699         }
5700         if (e1.op == EXP.arrayLiteral || e1.op == EXP.string_)
5701         {
5702             if (sliceBoundsCheck(0, dollar, ilwr, iupr))
5703             {
5704                 error(e.loc, "slice `[%lld..%lld]` exceeds array bounds `[0..%lld]`", ilwr, iupr, dollar);
5705                 result = CTFEExp.cantexp;
5706                 return;
5707             }
5708         }
5709         emplaceExp!(SliceExp)(pue, e.loc, e1, lwr, upr);
5710         result = pue.exp();
5711         result.type = e.type;
5712     }
5713 
5714     override void visit(InExp e)
5715     {
5716         debug (LOG)
5717         {
5718             printf("%s InExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5719         }
5720         Expression e1 = interpretRegion(e.e1, istate);
5721         if (exceptionOrCant(e1))
5722             return;
5723         Expression e2 = interpretRegion(e.e2, istate);
5724         if (exceptionOrCant(e2))
5725             return;
5726         if (e2.op == EXP.null_)
5727         {
5728             emplaceExp!(NullExp)(pue, e.loc, e.type);
5729             result = pue.exp();
5730             return;
5731         }
5732         if (e2.op != EXP.assocArrayLiteral)
5733         {
5734             error(e.loc, "`%s` cannot be interpreted at compile time", e.toChars());
5735             result = CTFEExp.cantexp;
5736             return;
5737         }
5738 
5739         e1 = resolveSlice(e1);
5740         result = findKeyInAA(e.loc, e2.isAssocArrayLiteralExp(), e1);
5741         if (exceptionOrCant(result))
5742             return;
5743         if (!result)
5744         {
5745             emplaceExp!(NullExp)(pue, e.loc, e.type);
5746             result = pue.exp();
5747         }
5748         else
5749         {
5750             // Create a CTFE pointer &aa[index]
5751             result = ctfeEmplaceExp!IndexExp(e.loc, e2, e1);
5752             result.type = e.type.nextOf();
5753             emplaceExp!(AddrExp)(pue, e.loc, result, e.type);
5754             result = pue.exp();
5755         }
5756     }
5757 
5758     override void visit(CatExp e)
5759     {
5760         debug (LOG)
5761         {
5762             printf("%s CatExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5763         }
5764 
5765         UnionExp ue1 = void;
5766         Expression e1 = interpret(&ue1, e.e1, istate);
5767         if (exceptionOrCant(e1))
5768             return;
5769 
5770         UnionExp ue2 = void;
5771         Expression e2 = interpret(&ue2, e.e2, istate);
5772         if (exceptionOrCant(e2))
5773             return;
5774 
5775         UnionExp e1tmp = void;
5776         e1 = resolveSlice(e1, &e1tmp);
5777 
5778         UnionExp e2tmp = void;
5779         e2 = resolveSlice(e2, &e2tmp);
5780 
5781         /* e1 and e2 can't go on the stack because of x~[y] and [x]~y will
5782          * result in [x,y] and then x or y is on the stack.
5783          * But if they are both strings, we can, because it isn't the x~[y] case.
5784          */
5785         if (!(e1.op == EXP.string_ && e2.op == EXP.string_))
5786         {
5787             if (e1 == ue1.exp())
5788                 e1 = ue1.copy();
5789             if (e2 == ue2.exp())
5790                 e2 = ue2.copy();
5791         }
5792 
5793         Expression prepareCatOperand(Expression exp)
5794         {
5795             /* Convert `elem ~ array` to `[elem] ~ array` if `elem` is itself an
5796              * array. This is needed because interpreting the `CatExp` calls
5797              * `Cat()`, which cannot handle concatenations between different
5798              * types, except for strings and chars.
5799              */
5800             auto tb = e.type.toBasetype();
5801             auto tbNext = tb.nextOf();
5802             auto expTb = exp.type.toBasetype();
5803 
5804             if (exp.type.implicitConvTo(tbNext) >= MATCH.convert &&
5805                 (tb.ty == Tarray || tb.ty == Tsarray) &&
5806                 (expTb.ty == Tarray || expTb.ty == Tsarray))
5807                 return new ArrayLiteralExp(exp.loc, e.type, exp);
5808             return exp;
5809         }
5810 
5811         *pue = ctfeCat(e.loc, e.type, prepareCatOperand(e1), prepareCatOperand(e2));
5812         result = pue.exp();
5813 
5814         if (CTFEExp.isCantExp(result))
5815         {
5816             error(e.loc, "`%s` cannot be interpreted at compile time", e.toChars());
5817             return;
5818         }
5819         // We know we still own it, because we interpreted both e1 and e2
5820         if (auto ale = result.isArrayLiteralExp())
5821         {
5822             ale.ownedByCtfe = OwnedBy.ctfe;
5823 
5824             // https://issues.dlang.org/show_bug.cgi?id=14686
5825             foreach (elem; *ale.elements)
5826             {
5827                 Expression ex = evaluatePostblit(istate, elem);
5828                 if (exceptionOrCant(ex))
5829                     return;
5830             }
5831         }
5832         else if (auto se = result.isStringExp())
5833             se.ownedByCtfe = OwnedBy.ctfe;
5834     }
5835 
5836     override void visit(DeleteExp e)
5837     {
5838         debug (LOG)
5839         {
5840             printf("%s DeleteExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5841         }
5842         result = interpretRegion(e.e1, istate);
5843         if (exceptionOrCant(result))
5844             return;
5845 
5846         if (result.op == EXP.null_)
5847         {
5848             result = CTFEExp.voidexp;
5849             return;
5850         }
5851 
5852         auto tb = e.e1.type.toBasetype();
5853         switch (tb.ty)
5854         {
5855         case Tclass:
5856             if (result.op != EXP.classReference)
5857             {
5858                 error(e.loc, "`delete` on invalid class reference `%s`", result.toChars());
5859                 result = CTFEExp.cantexp;
5860                 return;
5861             }
5862 
5863             auto cre = result.isClassReferenceExp();
5864             auto cd = cre.originalClass();
5865 
5866             // Find dtor(s) in inheritance chain
5867             do
5868             {
5869                 if (cd.dtor)
5870                 {
5871                     result = interpretFunction(pue, cd.dtor, istate, null, cre);
5872                     if (exceptionOrCant(result))
5873                         return;
5874 
5875                     // Dtors of Non-extern(D) classes use implicit chaining (like structs)
5876                     import dmd.aggregate : ClassKind;
5877                     if (cd.classKind != ClassKind.d)
5878                         break;
5879                 }
5880 
5881                 // Emulate manual chaining as done in rt_finalize2
5882                 cd = cd.baseClass;
5883 
5884             } while (cd); // Stop after Object
5885 
5886             break;
5887 
5888         default:
5889             assert(0);
5890         }
5891         result = CTFEExp.voidexp;
5892     }
5893 
5894     override void visit(CastExp e)
5895     {
5896         debug (LOG)
5897         {
5898             printf("%s CastExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5899         }
5900         Expression e1 = interpretRegion(e.e1, istate, goal);
5901         if (exceptionOrCant(e1))
5902             return;
5903         // If the expression has been cast to void, do nothing.
5904         if (e.to.ty == Tvoid)
5905         {
5906             result = CTFEExp.voidexp;
5907             return;
5908         }
5909         if (e.to.ty == Tpointer && e1.op != EXP.null_)
5910         {
5911             Type pointee = (cast(TypePointer)e.type).next;
5912             // Implement special cases of normally-unsafe casts
5913             if (e1.op == EXP.int64)
5914             {
5915                 // Happens with Windows HANDLEs, for example.
5916                 result = paintTypeOntoLiteral(pue, e.to, e1);
5917                 return;
5918             }
5919 
5920             bool castToSarrayPointer = false;
5921             bool castBackFromVoid = false;
5922             if (e1.type.ty == Tarray || e1.type.ty == Tsarray || e1.type.ty == Tpointer)
5923             {
5924                 // Check for unsupported type painting operations
5925                 // For slices, we need the type being sliced,
5926                 // since it may have already been type painted
5927                 Type elemtype = e1.type.nextOf();
5928                 if (auto se = e1.isSliceExp())
5929                     elemtype = se.e1.type.nextOf();
5930 
5931                 // Allow casts from X* to void *, and X** to void** for any X.
5932                 // But don't allow cast from X* to void**.
5933                 // So, we strip all matching * from source and target to find X.
5934                 // Allow casts to X* from void* only if the 'void' was originally an X;
5935                 // we check this later on.
5936                 Type ultimatePointee = pointee;
5937                 Type ultimateSrc = elemtype;
5938                 while (ultimatePointee.ty == Tpointer && ultimateSrc.ty == Tpointer)
5939                 {
5940                     ultimatePointee = ultimatePointee.nextOf();
5941                     ultimateSrc = ultimateSrc.nextOf();
5942                 }
5943                 if (ultimatePointee.ty == Tsarray && ultimatePointee.nextOf().equivalent(ultimateSrc))
5944                 {
5945                     castToSarrayPointer = true;
5946                 }
5947                 else if (ultimatePointee.ty != Tvoid && ultimateSrc.ty != Tvoid && !isSafePointerCast(elemtype, pointee))
5948                 {
5949                     error(e.loc, "reinterpreting cast from `%s*` to `%s*` is not supported in CTFE", elemtype.toChars(), pointee.toChars());
5950                     result = CTFEExp.cantexp;
5951                     return;
5952                 }
5953                 if (ultimateSrc.ty == Tvoid)
5954                     castBackFromVoid = true;
5955             }
5956 
5957             if (auto se = e1.isSliceExp())
5958             {
5959                 if (se.e1.op == EXP.null_)
5960                 {
5961                     result = paintTypeOntoLiteral(pue, e.type, se.e1);
5962                     return;
5963                 }
5964                 // Create a CTFE pointer &aggregate[1..2]
5965                 auto ei = ctfeEmplaceExp!IndexExp(e.loc, se.e1, se.lwr);
5966                 ei.type = e.type.nextOf();
5967                 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
5968                 result = pue.exp();
5969                 return;
5970             }
5971             if (e1.op == EXP.arrayLiteral || e1.op == EXP.string_)
5972             {
5973                 // Create a CTFE pointer &[1,2,3][0] or &"abc"[0]
5974                 auto ei = ctfeEmplaceExp!IndexExp(e.loc, e1, ctfeEmplaceExp!IntegerExp(e.loc, 0, Type.tsize_t));
5975                 ei.type = e.type.nextOf();
5976                 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
5977                 result = pue.exp();
5978                 return;
5979             }
5980             if (e1.op == EXP.index && !e1.isIndexExp().e1.type.equals(e1.type))
5981             {
5982                 // type painting operation
5983                 IndexExp ie = e1.isIndexExp();
5984                 if (castBackFromVoid)
5985                 {
5986                     // get the original type. For strings, it's just the type...
5987                     Type origType = ie.e1.type.nextOf();
5988                     // ..but for arrays of type void*, it's the type of the element
5989                     if (ie.e1.op == EXP.arrayLiteral && ie.e2.op == EXP.int64)
5990                     {
5991                         ArrayLiteralExp ale = ie.e1.isArrayLiteralExp();
5992                         const indx = cast(size_t)ie.e2.toInteger();
5993                         if (indx < ale.elements.length)
5994                         {
5995                             if (Expression xx = (*ale.elements)[indx])
5996                             {
5997                                 if (auto iex = xx.isIndexExp())
5998                                     origType = iex.e1.type.nextOf();
5999                                 else if (auto ae = xx.isAddrExp())
6000                                     origType = ae.e1.type;
6001                                 else if (auto ve = xx.isVarExp())
6002                                     origType = ve.var.type;
6003                             }
6004                         }
6005                     }
6006                     if (!isSafePointerCast(origType, pointee))
6007                     {
6008                         error(e.loc, "using `void*` to reinterpret cast from `%s*` to `%s*` is not supported in CTFE", origType.toChars(), pointee.toChars());
6009                         result = CTFEExp.cantexp;
6010                         return;
6011                     }
6012                 }
6013                 emplaceExp!(IndexExp)(pue, e1.loc, ie.e1, ie.e2);
6014                 result = pue.exp();
6015                 result.type = e.type;
6016                 return;
6017             }
6018 
6019             if (auto ae = e1.isAddrExp())
6020             {
6021                 Type origType = ae.e1.type;
6022                 if (isSafePointerCast(origType, pointee))
6023                 {
6024                     emplaceExp!(AddrExp)(pue, e.loc, ae.e1, e.type);
6025                     result = pue.exp();
6026                     return;
6027                 }
6028 
6029                 if (castToSarrayPointer && pointee.toBasetype().ty == Tsarray && ae.e1.op == EXP.index)
6030                 {
6031                     // &val[idx]
6032                     dinteger_t dim = (cast(TypeSArray)pointee.toBasetype()).dim.toInteger();
6033                     IndexExp ie = ae.e1.isIndexExp();
6034                     Expression lwr = ie.e2;
6035                     Expression upr = ctfeEmplaceExp!IntegerExp(ie.e2.loc, ie.e2.toInteger() + dim, Type.tsize_t);
6036 
6037                     // Create a CTFE pointer &val[idx..idx+dim]
6038                     auto er = ctfeEmplaceExp!SliceExp(e.loc, ie.e1, lwr, upr);
6039                     er.type = pointee;
6040                     emplaceExp!(AddrExp)(pue, e.loc, er, e.type);
6041                     result = pue.exp();
6042                     return;
6043                 }
6044             }
6045 
6046             if (e1.op == EXP.variable || e1.op == EXP.symbolOffset)
6047             {
6048                 // type painting operation
6049                 Type origType = (cast(SymbolExp)e1).var.type;
6050                 if (castBackFromVoid && !isSafePointerCast(origType, pointee))
6051                 {
6052                     error(e.loc, "using `void*` to reinterpret cast from `%s*` to `%s*` is not supported in CTFE", origType.toChars(), pointee.toChars());
6053                     result = CTFEExp.cantexp;
6054                     return;
6055                 }
6056                 if (auto ve = e1.isVarExp())
6057                     emplaceExp!(VarExp)(pue, e.loc, ve.var);
6058                 else
6059                     emplaceExp!(SymOffExp)(pue, e.loc, e1.isSymOffExp().var, e1.isSymOffExp().offset);
6060                 result = pue.exp();
6061                 result.type = e.to;
6062                 return;
6063             }
6064 
6065             // Check if we have a null pointer (eg, inside a struct)
6066             e1 = interpretRegion(e1, istate);
6067             if (e1.op != EXP.null_)
6068             {
6069                 error(e.loc, "pointer cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars());
6070                 result = CTFEExp.cantexp;
6071                 return;
6072             }
6073         }
6074         if (e.to.ty == Tsarray && e.e1.type.ty == Tvector)
6075         {
6076             // Special handling for: cast(float[4])__vector([w, x, y, z])
6077             e1 = interpretRegion(e.e1, istate);
6078             if (exceptionOrCant(e1))
6079                 return;
6080             assert(e1.op == EXP.vector);
6081             e1 = interpretVectorToArray(pue, e1.isVectorExp());
6082         }
6083         if (e.to.ty == Tarray && e1.op == EXP.slice)
6084         {
6085             // Note that the slice may be void[], so when checking for dangerous
6086             // casts, we need to use the original type, which is se.e1.
6087             SliceExp se = e1.isSliceExp();
6088             if (!isSafePointerCast(se.e1.type.nextOf(), e.to.nextOf()))
6089             {
6090                 error(e.loc, "array cast from `%s` to `%s` is not supported at compile time", se.e1.type.toChars(), e.to.toChars());
6091                 result = CTFEExp.cantexp;
6092                 return;
6093             }
6094             emplaceExp!(SliceExp)(pue, e1.loc, se.e1, se.lwr, se.upr);
6095             result = pue.exp();
6096             result.type = e.to;
6097             return;
6098         }
6099         // Disallow array type painting, except for conversions between built-in
6100         // types of identical size.
6101         if ((e.to.ty == Tsarray || e.to.ty == Tarray) && (e1.type.ty == Tsarray || e1.type.ty == Tarray) && !isSafePointerCast(e1.type.nextOf(), e.to.nextOf()))
6102         {
6103             error(e.loc, "array cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars());
6104             result = CTFEExp.cantexp;
6105             return;
6106         }
6107         if (e.to.ty == Tsarray)
6108             e1 = resolveSlice(e1);
6109 
6110         auto tobt = e.to.toBasetype();
6111         if (tobt.ty == Tbool && e1.type.ty == Tpointer)
6112         {
6113             emplaceExp!(IntegerExp)(pue, e.loc, e1.op != EXP.null_, e.to);
6114             result = pue.exp();
6115             return;
6116         }
6117         else if (tobt.isTypeBasic() && e1.op == EXP.null_)
6118         {
6119             if (tobt.isintegral())
6120                 emplaceExp!(IntegerExp)(pue, e.loc, 0, e.to);
6121             else if (tobt.isreal())
6122                 emplaceExp!(RealExp)(pue, e.loc, CTFloat.zero, e.to);
6123             result = pue.exp();
6124             return;
6125         }
6126         result = ctfeCast(pue, e.loc, e.type, e.to, e1, true);
6127     }
6128 
6129     override void visit(AssertExp e)
6130     {
6131         debug (LOG)
6132         {
6133             printf("%s AssertExp::interpret() %s\n", e.loc.toChars(), e.toChars());
6134         }
6135         Expression e1 = interpret(pue, e.e1, istate);
6136         if (exceptionOrCant(e1))
6137             return;
6138         if (isTrueBool(e1))
6139         {
6140         }
6141         else if (e1.toBool().hasValue(false))
6142         {
6143             if (e.msg)
6144             {
6145                 UnionExp ue = void;
6146                 result = interpret(&ue, e.msg, istate);
6147                 if (exceptionOrCant(result))
6148                     return;
6149                 result = scrubReturnValue(e.loc, result);
6150                 if (StringExp se = result.toStringExp())
6151                     error(e.loc, "%s", se.toStringz().ptr);
6152                 else
6153                     error(e.loc, "%s", result.toChars());
6154             }
6155             else
6156                 error(e.loc, "`%s` failed", e.toChars());
6157             result = CTFEExp.cantexp;
6158             return;
6159         }
6160         else
6161         {
6162             error(e.loc, "`%s` is not a compile time boolean expression", e1.toChars());
6163             result = CTFEExp.cantexp;
6164             return;
6165         }
6166         result = e1;
6167         return;
6168     }
6169 
6170     override void visit(ThrowExp te)
6171     {
6172         debug (LOG)
6173         {
6174             printf("%s ThrowExpression::interpret()\n", te.loc.toChars());
6175         }
6176         interpretThrow(result, te.e1, te.loc, istate);
6177     }
6178 
6179     override void visit(PtrExp e)
6180     {
6181         // Called for both lvalues and rvalues
6182         const lvalue = goal == CTFEGoal.LValue;
6183         debug (LOG)
6184         {
6185             printf("%s PtrExp::interpret(%d) %s, %s\n", e.loc.toChars(), lvalue, e.type.toChars(), e.toChars());
6186         }
6187 
6188         // Check for int<->float and long<->double casts.
6189         if (auto soe1 = e.e1.isSymOffExp())
6190             if (soe1.offset == 0 && soe1.var.isVarDeclaration() && isFloatIntPaint(e.type, soe1.var.type))
6191             {
6192                 // *(cast(int*)&v), where v is a float variable
6193                 result = paintFloatInt(pue, getVarExp(e.loc, istate, soe1.var, CTFEGoal.RValue), e.type);
6194                 return;
6195             }
6196 
6197         if (auto ce1 = e.e1.isCastExp())
6198             if (auto ae11 = ce1.e1.isAddrExp())
6199             {
6200                 // *(cast(int*)&x), where x is a float expression
6201                 Expression x = ae11.e1;
6202                 if (isFloatIntPaint(e.type, x.type))
6203                 {
6204                     result = paintFloatInt(pue, interpretRegion(x, istate), e.type);
6205                     return;
6206                 }
6207             }
6208 
6209         // Constant fold *(&structliteral + offset)
6210         if (auto ae = e.e1.isAddExp())
6211         {
6212             if (ae.e1.op == EXP.address && ae.e2.op == EXP.int64)
6213             {
6214                 AddrExp ade = ae.e1.isAddrExp();
6215                 Expression ex = interpretRegion(ade.e1, istate);
6216                 if (exceptionOrCant(ex))
6217                     return;
6218                 if (auto se = ex.isStructLiteralExp())
6219                 {
6220                     dinteger_t offset = ae.e2.toInteger();
6221                     result = se.getField(e.type, cast(uint)offset);
6222                     if (result)
6223                         return;
6224                 }
6225             }
6226         }
6227 
6228         // It's possible we have an array bounds error. We need to make sure it
6229         // errors with this line number, not the one where the pointer was set.
6230         result = interpretRegion(e.e1, istate);
6231         if (exceptionOrCant(result))
6232             return;
6233 
6234         if (result.op == EXP.function_)
6235             return;
6236         if (auto soe = result.isSymOffExp())
6237         {
6238             if (soe.offset == 0 && soe.var.isFuncDeclaration())
6239                 return;
6240             error(e.loc, "cannot dereference pointer to static variable `%s` at compile time", soe.var.toChars());
6241             result = CTFEExp.cantexp;
6242             return;
6243         }
6244 
6245         if (!lvalue && result.isArrayLiteralExp() &&
6246             result.type.isTypePointer())
6247         {
6248             /* A pointer variable can point to an array literal like `[3]`.
6249              * Dereferencing it means accessing the first element value.
6250              * Dereference it only if result should be an rvalue
6251              */
6252             auto ae = result.isArrayLiteralExp();
6253             if (ae.elements.length == 1)
6254             {
6255                 result = (*ae.elements)[0];
6256                 return;
6257             }
6258         }
6259         if (result.isStringExp() || result.isArrayLiteralExp())
6260             return;
6261 
6262         if (result.op != EXP.address)
6263         {
6264             if (result.op == EXP.null_)
6265                 error(e.loc, "dereference of null pointer `%s`", e.e1.toChars());
6266             else
6267                 error(e.loc, "dereference of invalid pointer `%s`", result.toChars());
6268             result = CTFEExp.cantexp;
6269             return;
6270         }
6271 
6272         // *(&x) ==> x
6273         result = result.isAddrExp().e1;
6274 
6275         if (result.op == EXP.slice && e.type.toBasetype().ty == Tsarray)
6276         {
6277             /* aggr[lwr..upr]
6278              * upr may exceed the upper boundary of aggr, but the check is deferred
6279              * until those out-of-bounds elements will be touched.
6280              */
6281             return;
6282         }
6283         result = interpret(pue, result, istate, goal);
6284         if (exceptionOrCant(result))
6285             return;
6286 
6287         debug (LOG)
6288         {
6289             if (CTFEExp.isCantExp(result))
6290                 printf("PtrExp::interpret() %s = CTFEExp::cantexp\n", e.toChars());
6291         }
6292     }
6293 
6294     override void visit(DotVarExp e)
6295     {
6296         void notImplementedYet()
6297         {
6298             error(e.loc, "`%s.%s` is not yet implemented at compile time", e.e1.toChars(), e.var.toChars());
6299             result = CTFEExp.cantexp;
6300             return;
6301         }
6302 
6303         debug (LOG)
6304         {
6305             printf("%s DotVarExp::interpret() %s, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
6306         }
6307         Expression ex = interpretRegion(e.e1, istate);
6308         if (exceptionOrCant(ex))
6309             return;
6310 
6311         if (FuncDeclaration f = e.var.isFuncDeclaration())
6312         {
6313             if (ex == e.e1)
6314                 result = e; // optimize: reuse this CTFE reference
6315             else
6316             {
6317                 emplaceExp!(DotVarExp)(pue, e.loc, ex, f, false);
6318                 result = pue.exp();
6319                 result.type = e.type;
6320             }
6321             return;
6322         }
6323 
6324         VarDeclaration v = e.var.isVarDeclaration();
6325         if (!v)
6326         {
6327             error(e.loc, "CTFE internal error: `%s`", e.toChars());
6328             result = CTFEExp.cantexp;
6329             return;
6330         }
6331 
6332         if (ex.op == EXP.null_)
6333         {
6334             if (ex.type.toBasetype().ty == Tclass)
6335                 error(e.loc, "class `%s` is `null` and cannot be dereferenced", e.e1.toChars());
6336             else
6337                 error(e.loc, "CTFE internal error: null this `%s`", e.e1.toChars());
6338             result = CTFEExp.cantexp;
6339             return;
6340         }
6341 
6342         StructLiteralExp se;
6343         int i;
6344 
6345         if (ex.op != EXP.structLiteral && ex.op != EXP.classReference && ex.op != EXP.typeid_)
6346         {
6347             return notImplementedYet();
6348         }
6349 
6350         // We can't use getField, because it makes a copy
6351         if (ex.op == EXP.classReference)
6352         {
6353             se = ex.isClassReferenceExp().value;
6354             i = ex.isClassReferenceExp().findFieldIndexByName(v);
6355         }
6356         else if (ex.op == EXP.typeid_)
6357         {
6358             if (v.ident == Identifier.idPool("name"))
6359             {
6360                 if (auto t = isType(ex.isTypeidExp().obj))
6361                 {
6362                     auto sym = t.toDsymbol(null);
6363                     if (auto ident = (sym ? sym.ident : null))
6364                     {
6365                         result = new StringExp(e.loc, ident.toString());
6366                         result.expressionSemantic(null);
6367                         return ;
6368                     }
6369                 }
6370             }
6371             return notImplementedYet();
6372         }
6373         else
6374         {
6375             se = ex.isStructLiteralExp();
6376             i = findFieldIndexByName(se.sd, v);
6377         }
6378         if (i == -1)
6379         {
6380             error(e.loc, "couldn't find field `%s` of type `%s` in `%s`", v.toChars(), e.type.toChars(), se.toChars());
6381             result = CTFEExp.cantexp;
6382             return;
6383         }
6384 
6385         // https://issues.dlang.org/show_bug.cgi?id=19897
6386         // https://issues.dlang.org/show_bug.cgi?id=20710
6387         // Zero-elements fields don't have an initializer. See: scrubArray function
6388         if ((*se.elements)[i] is null)
6389             (*se.elements)[i] = voidInitLiteral(e.type, v).copy();
6390 
6391         if (goal == CTFEGoal.LValue)
6392         {
6393             // just return the (simplified) dotvar expression as a CTFE reference
6394             if (e.e1 == ex)
6395                 result = e;
6396             else
6397             {
6398                 emplaceExp!(DotVarExp)(pue, e.loc, ex, v);
6399                 result = pue.exp();
6400                 result.type = e.type;
6401             }
6402             return;
6403         }
6404 
6405         result = (*se.elements)[i];
6406         if (!result)
6407         {
6408             error(e.loc, "internal compiler error: null field `%s`", v.toChars());
6409             result = CTFEExp.cantexp;
6410             return;
6411         }
6412         if (auto vie = result.isVoidInitExp())
6413         {
6414             const s = vie.var.toChars();
6415             if (v.overlapped)
6416             {
6417                 error(e.loc, "reinterpretation through overlapped field `%s` is not allowed in CTFE", s);
6418                 result = CTFEExp.cantexp;
6419                 return;
6420             }
6421             error(e.loc, "cannot read uninitialized variable `%s` in CTFE", s);
6422             result = CTFEExp.cantexp;
6423             return;
6424         }
6425 
6426         if (v.type.ty != result.type.ty && v.type.ty == Tsarray)
6427         {
6428             // Block assignment from inside struct literals
6429             auto tsa = cast(TypeSArray)v.type;
6430             auto len = cast(size_t)tsa.dim.toInteger();
6431             UnionExp ue = void;
6432             result = createBlockDuplicatedArrayLiteral(&ue, e.loc, v.type, result, len);
6433             if (result == ue.exp())
6434                 result = ue.copy();
6435             (*se.elements)[i] = result;
6436         }
6437         debug (LOG)
6438         {
6439             if (CTFEExp.isCantExp(result))
6440                 printf("DotVarExp::interpret() %s = CTFEExp::cantexp\n", e.toChars());
6441         }
6442     }
6443 
6444     override void visit(RemoveExp e)
6445     {
6446         debug (LOG)
6447         {
6448             printf("%s RemoveExp::interpret() %s\n", e.loc.toChars(), e.toChars());
6449         }
6450         Expression agg = interpret(e.e1, istate);
6451         if (exceptionOrCant(agg))
6452             return;
6453         Expression index = interpret(e.e2, istate);
6454         if (exceptionOrCant(index))
6455             return;
6456         if (agg.op == EXP.null_)
6457         {
6458             result = CTFEExp.voidexp;
6459             return;
6460         }
6461 
6462         AssocArrayLiteralExp aae = agg.isAssocArrayLiteralExp();
6463         Expressions* keysx = aae.keys;
6464         Expressions* valuesx = aae.values;
6465         size_t removed = 0;
6466         foreach (j, evalue; *valuesx)
6467         {
6468             Expression ekey = (*keysx)[j];
6469             int eq = ctfeEqual(e.loc, EXP.equal, ekey, index);
6470             if (eq)
6471                 ++removed;
6472             else if (removed != 0)
6473             {
6474                 (*keysx)[j - removed] = ekey;
6475                 (*valuesx)[j - removed] = evalue;
6476             }
6477         }
6478         valuesx.length = valuesx.length - removed;
6479         keysx.length = keysx.length - removed;
6480         result = IntegerExp.createBool(removed != 0);
6481     }
6482 
6483     override void visit(ClassReferenceExp e)
6484     {
6485         //printf("ClassReferenceExp::interpret() %s\n", e.value.toChars());
6486         result = e;
6487     }
6488 
6489     override void visit(VoidInitExp e)
6490     {
6491         error(e.loc, "CTFE internal error: trying to read uninitialized variable");
6492         assert(0);
6493     }
6494 
6495     override void visit(ThrownExceptionExp e)
6496     {
6497         assert(0); // This should never be interpreted
6498     }
6499 }
6500 
6501 /// Interpret `throw <exp>` found at the specified location `loc`
6502 private
6503 void interpretThrow(ref Expression result, Expression exp, const ref Loc loc, InterState* istate)
6504 {
6505     incUsageCtfe(istate, loc);
6506 
6507     Expression e = interpretRegion(exp, istate);
6508     if (exceptionOrCantInterpret(e))
6509     {
6510         // Make sure e is not pointing to a stack temporary
6511         result = (e.op == EXP.cantExpression) ? CTFEExp.cantexp : e;
6512     }
6513     else if (e.op == EXP.classReference)
6514     {
6515         result = ctfeEmplaceExp!ThrownExceptionExp(loc, e.isClassReferenceExp());
6516     }
6517     else
6518     {
6519         error(exp.loc, "to be thrown `%s` must be non-null", exp.toChars());
6520         result = ErrorExp.get();
6521     }
6522 }
6523 
6524 /*********************************************
6525  * Checks if the given expresion is a call to the runtime hook `id`.
6526  *
6527  * Params:
6528  *    e = the expression to check
6529  *    id = the identifier of the runtime hook
6530  * Returns:
6531  *    `e` cast to `CallExp` if it's the hook, `null` otherwise
6532  */
6533 public CallExp isRuntimeHook(Expression e, Identifier id)
6534 {
6535     if (auto ce = e.isCallExp())
6536     {
6537         if (auto ve = ce.e1.isVarExp())
6538         {
6539             if (auto fd = ve.var.isFuncDeclaration())
6540             {
6541                 // If `_d_HookTraceImpl` is found, resolve the underlying hook
6542                 // and replace `e` and `fd` with it.
6543                 removeHookTraceImpl(ce, fd);
6544                 return fd.ident == id ? ce : null;
6545             }
6546         }
6547     }
6548 
6549     return null;
6550 }
6551 
6552 /********************************************
6553  * Interpret the expression.
6554  * Params:
6555  *    pue = non-null pointer to temporary storage that can be used to store the return value
6556  *    e = Expression to interpret
6557  *    istate = context
6558  *    goal = what the result will be used for
6559  * Returns:
6560  *    resulting expression
6561  */
6562 
6563 Expression interpret(UnionExp* pue, Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
6564 {
6565     if (!e)
6566         return null;
6567     //printf("+interpret() e : %s, %s\n", e.type.toChars(), e.toChars());
6568     scope Interpreter v = new Interpreter(pue, istate, goal);
6569     e.accept(v);
6570     Expression ex = v.result;
6571     assert(goal == CTFEGoal.Nothing || ex !is null);
6572     //if (ex) printf("-interpret() ex: %s, %s\n", ex.type.toChars(), ex.toChars()); else printf("-interpret()\n");
6573     return ex;
6574 }
6575 
6576 ///
6577 Expression interpret(Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
6578 {
6579     UnionExp ue = void;
6580     auto result = interpret(&ue, e, istate, goal);
6581     if (result == ue.exp())
6582         result = ue.copy();
6583     return result;
6584 }
6585 
6586 /*****************************
6587  * Same as interpret(), but return result allocated in Region.
6588  * Params:
6589  *    e = Expression to interpret
6590  *    istate = context
6591  *    goal = what the result will be used for
6592  * Returns:
6593  *    resulting expression
6594  */
6595 Expression interpretRegion(Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
6596 {
6597     UnionExp ue = void;
6598     auto result = interpret(&ue, e, istate, goal);
6599     auto uexp = ue.exp();
6600     if (result != uexp)
6601         return result;
6602     if (mem.isGCEnabled)
6603         return ue.copy();
6604 
6605     // mimicking UnionExp.copy, but with region allocation
6606     switch (uexp.op)
6607     {
6608         case EXP.cantExpression: return CTFEExp.cantexp;
6609         case EXP.voidExpression: return CTFEExp.voidexp;
6610         case EXP.break_:         return CTFEExp.breakexp;
6611         case EXP.continue_:      return CTFEExp.continueexp;
6612         case EXP.goto_:          return CTFEExp.gotoexp;
6613         default:                 break;
6614     }
6615     auto p = ctfeGlobals.region.malloc(uexp.size);
6616     return cast(Expression)memcpy(p, cast(void*)uexp, uexp.size);
6617 }
6618 
6619 private
6620 Expressions* copyArrayOnWrite(Expressions* exps, Expressions* original)
6621 {
6622     if (exps is original)
6623     {
6624         if (!original)
6625             exps = new Expressions();
6626         else
6627             exps = original.copy();
6628         ++ctfeGlobals.numArrayAllocs;
6629     }
6630     return exps;
6631 }
6632 
6633 /**
6634  Given an expression e which is about to be returned from the current
6635  function, generate an error if it contains pointers to local variables.
6636 
6637  Only checks expressions passed by value (pointers to local variables
6638  may already be stored in members of classes, arrays, or AAs which
6639  were passed as mutable function parameters).
6640  Returns:
6641     true if it is safe to return, false if an error was generated.
6642  */
6643 private
6644 bool stopPointersEscaping(const ref Loc loc, Expression e)
6645 {
6646     if (!e.type.hasPointers())
6647         return true;
6648     if (isPointer(e.type))
6649     {
6650         Expression x = e;
6651         if (auto eaddr = e.isAddrExp())
6652             x = eaddr.e1;
6653         VarDeclaration v;
6654         while (x.op == EXP.variable && (v = x.isVarExp().var.isVarDeclaration()) !is null)
6655         {
6656             if (v.storage_class & STC.ref_)
6657             {
6658                 x = getValue(v);
6659                 if (auto eaddr = e.isAddrExp())
6660                     eaddr.e1 = x;
6661                 continue;
6662             }
6663             if (ctfeGlobals.stack.isInCurrentFrame(v))
6664             {
6665                 error(loc, "returning a pointer to a local stack variable");
6666                 return false;
6667             }
6668             else
6669                 break;
6670         }
6671         // TODO: If it is a EXP.dotVariable or EXP.index, we should check that it is not
6672         // pointing to a local struct or static array.
6673     }
6674     if (auto se = e.isStructLiteralExp())
6675     {
6676         return stopPointersEscapingFromArray(loc, se.elements);
6677     }
6678     if (auto ale = e.isArrayLiteralExp())
6679     {
6680         return stopPointersEscapingFromArray(loc, ale.elements);
6681     }
6682     if (auto aae = e.isAssocArrayLiteralExp())
6683     {
6684         if (!stopPointersEscapingFromArray(loc, aae.keys))
6685             return false;
6686         return stopPointersEscapingFromArray(loc, aae.values);
6687     }
6688     return true;
6689 }
6690 
6691 // Check all elements of an array for escaping local variables. Return false if error
6692 private
6693 bool stopPointersEscapingFromArray(const ref Loc loc, Expressions* elems)
6694 {
6695     foreach (e; *elems)
6696     {
6697         if (e && !stopPointersEscaping(loc, e))
6698             return false;
6699     }
6700     return true;
6701 }
6702 
6703 private
6704 Statement findGotoTarget(InterState* istate, Identifier ident)
6705 {
6706     Statement target = null;
6707     if (ident)
6708     {
6709         LabelDsymbol label = istate.fd.searchLabel(ident);
6710         assert(label && label.statement);
6711         LabelStatement ls = label.statement;
6712         target = ls.gotoTarget ? ls.gotoTarget : ls.statement;
6713     }
6714     return target;
6715 }
6716 
6717 private
6718 ThrownExceptionExp chainExceptions(ThrownExceptionExp oldest, ThrownExceptionExp newest)
6719 {
6720     debug (LOG)
6721     {
6722         printf("Collided exceptions %s %s\n", oldest.thrown.toChars(), newest.thrown.toChars());
6723     }
6724     // Little sanity check to make sure it's really a Throwable
6725     ClassReferenceExp boss = oldest.thrown;
6726     const next = 5;                         // index of Throwable.next
6727     assert((*boss.value.elements)[next].type.ty == Tclass); // Throwable.next
6728     ClassReferenceExp collateral = newest.thrown;
6729     if (collateral.originalClass().isErrorException() && !boss.originalClass().isErrorException())
6730     {
6731         /* Find the index of the Error.bypassException field
6732          */
6733         auto bypass = next + 1;
6734         if ((*collateral.value.elements)[bypass].type.ty == Tuns32)
6735             bypass += 1;  // skip over _refcount field
6736         assert((*collateral.value.elements)[bypass].type.ty == Tclass);
6737 
6738         // The new exception bypass the existing chain
6739         (*collateral.value.elements)[bypass] = boss;
6740         return newest;
6741     }
6742     while ((*boss.value.elements)[next].op == EXP.classReference)
6743     {
6744         boss = (*boss.value.elements)[next].isClassReferenceExp();
6745     }
6746     (*boss.value.elements)[next] = collateral;
6747     return oldest;
6748 }
6749 
6750 /**
6751  * All results destined for use outside of CTFE need to have their CTFE-specific
6752  * features removed.
6753  * In particular,
6754  * 1. all slices must be resolved.
6755  * 2. all .ownedByCtfe set to OwnedBy.code
6756  */
6757 private Expression scrubReturnValue(const ref Loc loc, Expression e)
6758 {
6759     /* Returns: true if e is void,
6760      * or is an array literal or struct literal of void elements.
6761      */
6762     static bool isVoid(const Expression e, bool checkArrayType = false) pure
6763     {
6764         if (e.op == EXP.void_)
6765             return true;
6766 
6767         static bool isEntirelyVoid(const Expressions* elems)
6768         {
6769             foreach (e; *elems)
6770             {
6771                 // It can be NULL for performance reasons,
6772                 // see StructLiteralExp::interpret().
6773                 if (e && !isVoid(e))
6774                     return false;
6775             }
6776             return true;
6777         }
6778 
6779         if (auto sle = e.isStructLiteralExp())
6780             return isEntirelyVoid(sle.elements);
6781 
6782         if (checkArrayType && e.type.ty != Tsarray)
6783             return false;
6784 
6785         if (auto ale = e.isArrayLiteralExp())
6786             return isEntirelyVoid(ale.elements);
6787 
6788         return false;
6789     }
6790 
6791 
6792     /* Scrub all elements of elems[].
6793      * Returns: null for success, error Expression for failure
6794      */
6795     Expression scrubArray(Expressions* elems, bool structlit = false)
6796     {
6797         foreach (ref e; *elems)
6798         {
6799             // It can be NULL for performance reasons,
6800             // see StructLiteralExp::interpret().
6801             if (!e)
6802                 continue;
6803 
6804             // A struct .init may contain void members.
6805             // Static array members are a weird special case https://issues.dlang.org/show_bug.cgi?id=10994
6806             if (structlit && isVoid(e, true))
6807             {
6808                 e = null;
6809             }
6810             else
6811             {
6812                 e = scrubReturnValue(loc, e);
6813                 if (CTFEExp.isCantExp(e) || e.op == EXP.error)
6814                     return e;
6815             }
6816         }
6817         return null;
6818     }
6819 
6820     Expression scrubSE(StructLiteralExp sle)
6821     {
6822         sle.ownedByCtfe = OwnedBy.code;
6823         if (!(sle.stageflags & stageScrub))
6824         {
6825             const old = sle.stageflags;
6826             sle.stageflags |= stageScrub;       // prevent infinite recursion
6827             if (auto ex = scrubArray(sle.elements, true))
6828                 return ex;
6829             sle.stageflags = old;
6830         }
6831         return null;
6832     }
6833 
6834     if (e.op == EXP.classReference)
6835     {
6836         StructLiteralExp sle = e.isClassReferenceExp().value;
6837         if (auto ex = scrubSE(sle))
6838             return ex;
6839     }
6840     else if (auto vie = e.isVoidInitExp())
6841     {
6842         error(loc, "uninitialized variable `%s` cannot be returned from CTFE", vie.var.toChars());
6843         return ErrorExp.get();
6844     }
6845 
6846     e = resolveSlice(e);
6847 
6848     if (auto sle = e.isStructLiteralExp())
6849     {
6850         if (auto ex = scrubSE(sle))
6851             return ex;
6852     }
6853     else if (auto se = e.isStringExp())
6854     {
6855         se.ownedByCtfe = OwnedBy.code;
6856     }
6857     else if (auto ale = e.isArrayLiteralExp())
6858     {
6859         ale.ownedByCtfe = OwnedBy.code;
6860         if (auto ex = scrubArray(ale.elements))
6861             return ex;
6862     }
6863     else if (auto aae = e.isAssocArrayLiteralExp())
6864     {
6865         aae.ownedByCtfe = OwnedBy.code;
6866         if (auto ex = scrubArray(aae.keys))
6867             return ex;
6868         if (auto ex = scrubArray(aae.values))
6869             return ex;
6870         aae.type = toBuiltinAAType(aae.type);
6871     }
6872     else if (auto ve = e.isVectorExp())
6873     {
6874         ve.ownedByCtfe = OwnedBy.code;
6875         if (auto ale = ve.e1.isArrayLiteralExp())
6876         {
6877             ale.ownedByCtfe = OwnedBy.code;
6878             if (auto ex = scrubArray(ale.elements))
6879                 return ex;
6880         }
6881     }
6882     return e;
6883 }
6884 
6885 /**************************************
6886  * Transitively set all .ownedByCtfe to OwnedBy.cache
6887  */
6888 private Expression scrubCacheValue(Expression e)
6889 {
6890     if (!e)
6891         return e;
6892 
6893     Expression scrubArrayCache(Expressions* elems)
6894     {
6895         foreach (ref e; *elems)
6896             e = scrubCacheValue(e);
6897         return null;
6898     }
6899 
6900     Expression scrubSE(StructLiteralExp sle)
6901     {
6902         sle.ownedByCtfe = OwnedBy.cache;
6903         if (!(sle.stageflags & stageScrub))
6904         {
6905             const old = sle.stageflags;
6906             sle.stageflags |= stageScrub;       // prevent infinite recursion
6907             if (auto ex = scrubArrayCache(sle.elements))
6908                 return ex;
6909             sle.stageflags = old;
6910         }
6911         return null;
6912     }
6913 
6914     if (e.op == EXP.classReference)
6915     {
6916         if (auto ex = scrubSE(e.isClassReferenceExp().value))
6917             return ex;
6918     }
6919     else if (auto sle = e.isStructLiteralExp())
6920     {
6921         if (auto ex = scrubSE(sle))
6922             return ex;
6923     }
6924     else if (auto se = e.isStringExp())
6925     {
6926         se.ownedByCtfe = OwnedBy.cache;
6927     }
6928     else if (auto ale = e.isArrayLiteralExp())
6929     {
6930         ale.ownedByCtfe = OwnedBy.cache;
6931         if (Expression ex = scrubArrayCache(ale.elements))
6932             return ex;
6933     }
6934     else if (auto aae = e.isAssocArrayLiteralExp())
6935     {
6936         aae.ownedByCtfe = OwnedBy.cache;
6937         if (auto ex = scrubArrayCache(aae.keys))
6938             return ex;
6939         if (auto ex = scrubArrayCache(aae.values))
6940             return ex;
6941     }
6942     else if (auto ve = e.isVectorExp())
6943     {
6944         ve.ownedByCtfe = OwnedBy.cache;
6945         if (auto ale = ve.e1.isArrayLiteralExp())
6946         {
6947             ale.ownedByCtfe = OwnedBy.cache;
6948             if (auto ex = scrubArrayCache(ale.elements))
6949                 return ex;
6950         }
6951     }
6952     return e;
6953 }
6954 
6955 /********************************************
6956  * Transitively replace all Expressions allocated in ctfeGlobals.region
6957  * with Mem owned copies.
6958  * Params:
6959  *      e = possible ctfeGlobals.region owned expression
6960  * Returns:
6961  *      Mem owned expression
6962  */
6963 private Expression copyRegionExp(Expression e)
6964 {
6965     if (!e)
6966         return e;
6967 
6968     static void copyArray(Expressions* elems)
6969     {
6970         foreach (ref e; *elems)
6971         {
6972             auto ex = e;
6973             e = null;
6974             e = copyRegionExp(ex);
6975         }
6976     }
6977 
6978     static void copySE(StructLiteralExp sle)
6979     {
6980         if (1 || !(sle.stageflags & stageScrub))
6981         {
6982             const old = sle.stageflags;
6983             sle.stageflags |= stageScrub;       // prevent infinite recursion
6984             copyArray(sle.elements);
6985             sle.stageflags = old;
6986         }
6987     }
6988 
6989     switch (e.op)
6990     {
6991         case EXP.classReference:
6992         {
6993             auto cre = e.isClassReferenceExp();
6994             cre.value = copyRegionExp(cre.value).isStructLiteralExp();
6995             break;
6996         }
6997 
6998         case EXP.structLiteral:
6999         {
7000             auto sle = e.isStructLiteralExp();
7001 
7002             /* The following is to take care of updating sle.origin correctly,
7003              * which may have multiple objects pointing to it.
7004              */
7005             if (sle.isOriginal && !ctfeGlobals.region.contains(cast(void*)sle.origin))
7006             {
7007                 /* This means sle has already been moved out of the region,
7008                  * and sle.origin is the new location.
7009                  */
7010                 return sle.origin;
7011             }
7012             copySE(sle);
7013             sle.isOriginal = sle is sle.origin;
7014 
7015             auto slec = ctfeGlobals.region.contains(cast(void*)e)
7016                 ? e.copy().isStructLiteralExp()         // move sle out of region to slec
7017                 : sle;
7018 
7019             if (ctfeGlobals.region.contains(cast(void*)sle.origin))
7020             {
7021                 auto sleo = sle.origin == sle ? slec : sle.origin.copy().isStructLiteralExp();
7022                 sle.origin = sleo;
7023                 slec.origin = sleo;
7024             }
7025             return slec;
7026         }
7027 
7028         case EXP.arrayLiteral:
7029         {
7030             auto ale = e.isArrayLiteralExp();
7031             ale.basis = copyRegionExp(ale.basis);
7032             copyArray(ale.elements);
7033             break;
7034         }
7035 
7036         case EXP.assocArrayLiteral:
7037             copyArray(e.isAssocArrayLiteralExp().keys);
7038             copyArray(e.isAssocArrayLiteralExp().values);
7039             break;
7040 
7041         case EXP.slice:
7042         {
7043             auto se = e.isSliceExp();
7044             se.e1  = copyRegionExp(se.e1);
7045             se.upr = copyRegionExp(se.upr);
7046             se.lwr = copyRegionExp(se.lwr);
7047             break;
7048         }
7049 
7050         case EXP.tuple:
7051         {
7052             auto te = e.isTupleExp();
7053             te.e0 = copyRegionExp(te.e0);
7054             copyArray(te.exps);
7055             break;
7056         }
7057 
7058         case EXP.address:
7059         case EXP.delegate_:
7060         case EXP.vector:
7061         case EXP.dotVariable:
7062         {
7063             UnaExp ue = e.isUnaExp();
7064             ue.e1 = copyRegionExp(ue.e1);
7065             break;
7066         }
7067 
7068         case EXP.index:
7069         {
7070             BinExp be = e.isBinExp();
7071             be.e1 = copyRegionExp(be.e1);
7072             be.e2 = copyRegionExp(be.e2);
7073             break;
7074         }
7075 
7076         case EXP.this_:
7077         case EXP.super_:
7078         case EXP.variable:
7079         case EXP.type:
7080         case EXP.function_:
7081         case EXP.typeid_:
7082         case EXP.string_:
7083         case EXP.int64:
7084         case EXP.error:
7085         case EXP.float64:
7086         case EXP.complex80:
7087         case EXP.null_:
7088         case EXP.void_:
7089         case EXP.symbolOffset:
7090             break;
7091 
7092         case EXP.cantExpression:
7093         case EXP.voidExpression:
7094         case EXP.showCtfeContext:
7095             return e;
7096 
7097         default:
7098             printf("e: %s, %s\n", EXPtoString(e.op).ptr, e.toChars());
7099             assert(0);
7100     }
7101 
7102     if (ctfeGlobals.region.contains(cast(void*)e))
7103     {
7104         return e.copy();
7105     }
7106     return e;
7107 }
7108 
7109 /******************************* Special Functions ***************************/
7110 
7111 private Expression interpret_length(UnionExp* pue, InterState* istate, Expression earg)
7112 {
7113     //printf("interpret_length()\n");
7114     earg = interpret(pue, earg, istate);
7115     if (exceptionOrCantInterpret(earg))
7116         return earg;
7117     dinteger_t len = 0;
7118     if (auto aae = earg.isAssocArrayLiteralExp())
7119         len = aae.keys.length;
7120     else
7121         assert(earg.op == EXP.null_);
7122     emplaceExp!(IntegerExp)(pue, earg.loc, len, Type.tsize_t);
7123     return pue.exp();
7124 }
7125 
7126 private Expression interpret_keys(UnionExp* pue, InterState* istate, Expression earg, Type returnType)
7127 {
7128     debug (LOG)
7129     {
7130         printf("interpret_keys()\n");
7131     }
7132     earg = interpret(pue, earg, istate);
7133     if (exceptionOrCantInterpret(earg))
7134         return earg;
7135     if (earg.op == EXP.null_)
7136     {
7137         emplaceExp!(NullExp)(pue, earg.loc, earg.type);
7138         return pue.exp();
7139     }
7140     if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
7141         return null;
7142     AssocArrayLiteralExp aae = earg.isAssocArrayLiteralExp();
7143     auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.keys);
7144     ae.ownedByCtfe = aae.ownedByCtfe;
7145     *pue = copyLiteral(ae);
7146     return pue.exp();
7147 }
7148 
7149 private Expression interpret_values(UnionExp* pue, InterState* istate, Expression earg, Type returnType)
7150 {
7151     debug (LOG)
7152     {
7153         printf("interpret_values()\n");
7154     }
7155     earg = interpret(pue, earg, istate);
7156     if (exceptionOrCantInterpret(earg))
7157         return earg;
7158     if (earg.op == EXP.null_)
7159     {
7160         emplaceExp!(NullExp)(pue, earg.loc, earg.type);
7161         return pue.exp();
7162     }
7163     if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
7164         return null;
7165     auto aae = earg.isAssocArrayLiteralExp();
7166     auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.values);
7167     ae.ownedByCtfe = aae.ownedByCtfe;
7168     //printf("result is %s\n", e.toChars());
7169     *pue = copyLiteral(ae);
7170     return pue.exp();
7171 }
7172 
7173 private Expression interpret_dup(UnionExp* pue, InterState* istate, Expression earg)
7174 {
7175     debug (LOG)
7176     {
7177         printf("interpret_dup()\n");
7178     }
7179     earg = interpret(pue, earg, istate);
7180     if (exceptionOrCantInterpret(earg))
7181         return earg;
7182     if (earg.op == EXP.null_)
7183     {
7184         emplaceExp!(NullExp)(pue, earg.loc, earg.type);
7185         return pue.exp();
7186     }
7187     if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
7188         return null;
7189     auto aae = copyLiteral(earg).copy().isAssocArrayLiteralExp();
7190     for (size_t i = 0; i < aae.keys.length; i++)
7191     {
7192         if (Expression e = evaluatePostblit(istate, (*aae.keys)[i]))
7193             return e;
7194         if (Expression e = evaluatePostblit(istate, (*aae.values)[i]))
7195             return e;
7196     }
7197     aae.type = earg.type.mutableOf(); // repaint type from const(int[int]) to const(int)[int]
7198     //printf("result is %s\n", aae.toChars());
7199     return aae;
7200 }
7201 
7202 // signature is int delegate(ref Value) OR int delegate(ref Key, ref Value)
7203 private Expression interpret_aaApply(UnionExp* pue, InterState* istate, Expression aa, Expression deleg)
7204 {
7205     aa = interpret(aa, istate);
7206     if (exceptionOrCantInterpret(aa))
7207         return aa;
7208     if (aa.op != EXP.assocArrayLiteral)
7209     {
7210         emplaceExp!(IntegerExp)(pue, deleg.loc, 0, Type.tsize_t);
7211         return pue.exp();
7212     }
7213 
7214     FuncDeclaration fd = null;
7215     Expression pthis = null;
7216     if (auto de = deleg.isDelegateExp())
7217     {
7218         fd = de.func;
7219         pthis = de.e1;
7220     }
7221     else if (auto fe = deleg.isFuncExp())
7222         fd = fe.fd;
7223 
7224     assert(fd && fd.fbody);
7225     assert(fd.parameters);
7226     size_t numParams = fd.parameters.length;
7227     assert(numParams == 1 || numParams == 2);
7228 
7229     Parameter fparam = fd.type.isTypeFunction().parameterList[numParams - 1];
7230     const wantRefValue = fparam.isReference();
7231 
7232     Expressions args = Expressions(numParams);
7233 
7234     AssocArrayLiteralExp ae = aa.isAssocArrayLiteralExp();
7235     if (!ae.keys || ae.keys.length == 0)
7236         return ctfeEmplaceExp!IntegerExp(deleg.loc, 0, Type.tsize_t);
7237     Expression eresult;
7238 
7239     for (size_t i = 0; i < ae.keys.length; ++i)
7240     {
7241         Expression ekey = (*ae.keys)[i];
7242         Expression evalue = (*ae.values)[i];
7243         if (wantRefValue)
7244         {
7245             Type t = evalue.type;
7246             evalue = ctfeEmplaceExp!IndexExp(deleg.loc, ae, ekey);
7247             evalue.type = t;
7248         }
7249         args[numParams - 1] = evalue;
7250         if (numParams == 2)
7251             args[0] = ekey;
7252 
7253         UnionExp ue = void;
7254         eresult = interpretFunction(&ue, fd, istate, &args, pthis);
7255         if (eresult == ue.exp())
7256             eresult = ue.copy();
7257         if (exceptionOrCantInterpret(eresult))
7258             return eresult;
7259 
7260         if (eresult.isIntegerExp().getInteger() != 0)
7261             return eresult;
7262     }
7263     return eresult;
7264 }
7265 
7266 /* Decoding UTF strings for foreach loops. Duplicates the functionality of
7267  * the twelve _aApplyXXn functions in aApply.d in the runtime.
7268  */
7269 private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression str, Expression deleg, bool rvs)
7270 {
7271     debug (LOG)
7272     {
7273         printf("foreachApplyUtf(%s, %s)\n", str.toChars(), deleg.toChars());
7274     }
7275     FuncDeclaration fd = null;
7276     Expression pthis = null;
7277     if (auto de = deleg.isDelegateExp())
7278     {
7279         fd = de.func;
7280         pthis = de.e1;
7281     }
7282     else if (auto fe = deleg.isFuncExp())
7283         fd = fe.fd;
7284 
7285     assert(fd && fd.fbody);
7286     assert(fd.parameters);
7287     size_t numParams = fd.parameters.length;
7288     assert(numParams == 1 || numParams == 2);
7289     Type charType = (*fd.parameters)[numParams - 1].type;
7290     Type indexType = numParams == 2 ? (*fd.parameters)[0].type : Type.tsize_t;
7291     size_t len = cast(size_t)resolveArrayLength(str);
7292     if (len == 0)
7293     {
7294         emplaceExp!(IntegerExp)(pue, deleg.loc, 0, indexType);
7295         return pue.exp();
7296     }
7297 
7298     UnionExp strTmp = void;
7299     str = resolveSlice(str, &strTmp);
7300 
7301     auto se = str.isStringExp();
7302     auto ale = str.isArrayLiteralExp();
7303     if (!se && !ale)
7304     {
7305         error(str.loc, "CTFE internal error: cannot foreach `%s`", str.toChars());
7306         return CTFEExp.cantexp;
7307     }
7308     Expressions args = Expressions(numParams);
7309 
7310     Expression eresult = null; // ded-store to prevent spurious warning
7311 
7312     // Buffers for encoding; also used for decoding array literals
7313     char[4] utf8buf = void;
7314     wchar[2] utf16buf = void;
7315 
7316     size_t start = rvs ? len : 0;
7317     size_t end = rvs ? 0 : len;
7318     for (size_t indx = start; indx != end;)
7319     {
7320         // Step 1: Decode the next dchar from the string.
7321 
7322         string errmsg = null; // Used for reporting decoding errors
7323         dchar rawvalue; // Holds the decoded dchar
7324         size_t currentIndex = indx; // The index of the decoded character
7325 
7326         if (ale)
7327         {
7328             // If it is an array literal, copy the code points into the buffer
7329             size_t buflen = 1; // #code points in the buffer
7330             size_t n = 1; // #code points in this char
7331             size_t sz = cast(size_t)ale.type.nextOf().size();
7332 
7333             switch (sz)
7334             {
7335             case 1:
7336                 if (rvs)
7337                 {
7338                     // find the start of the string
7339                     --indx;
7340                     buflen = 1;
7341                     while (indx > 0 && buflen < 4)
7342                     {
7343                         Expression r = (*ale.elements)[indx];
7344                         char x = cast(char)r.isIntegerExp().getInteger();
7345                         if ((x & 0xC0) != 0x80)
7346                             break;
7347                         --indx;
7348                         ++buflen;
7349                     }
7350                 }
7351                 else
7352                     buflen = (indx + 4 > len) ? len - indx : 4;
7353                 for (size_t i = 0; i < buflen; ++i)
7354                 {
7355                     Expression r = (*ale.elements)[indx + i];
7356                     utf8buf[i] = cast(char)r.isIntegerExp().getInteger();
7357                 }
7358                 n = 0;
7359                 errmsg = utf_decodeChar(utf8buf[0 .. buflen], n, rawvalue);
7360                 break;
7361 
7362             case 2:
7363                 if (rvs)
7364                 {
7365                     // find the start of the string
7366                     --indx;
7367                     buflen = 1;
7368                     Expression r = (*ale.elements)[indx];
7369                     ushort x = cast(ushort)r.isIntegerExp().getInteger();
7370                     if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF)
7371                     {
7372                         --indx;
7373                         ++buflen;
7374                     }
7375                 }
7376                 else
7377                     buflen = (indx + 2 > len) ? len - indx : 2;
7378                 for (size_t i = 0; i < buflen; ++i)
7379                 {
7380                     Expression r = (*ale.elements)[indx + i];
7381                     utf16buf[i] = cast(ushort)r.isIntegerExp().getInteger();
7382                 }
7383                 n = 0;
7384                 errmsg = utf_decodeWchar(utf16buf[0 .. buflen], n, rawvalue);
7385                 break;
7386 
7387             case 4:
7388                 {
7389                     if (rvs)
7390                         --indx;
7391                     Expression r = (*ale.elements)[indx];
7392                     rawvalue = cast(dchar)r.isIntegerExp().getInteger();
7393                     n = 1;
7394                 }
7395                 break;
7396 
7397             default:
7398                 assert(0);
7399             }
7400             if (!rvs)
7401                 indx += n;
7402         }
7403         else
7404         {
7405             // String literals
7406             size_t saveindx; // used for reverse iteration
7407 
7408             switch (se.sz)
7409             {
7410             case 1:
7411             {
7412                 if (rvs)
7413                 {
7414                     // find the start of the string
7415                     --indx;
7416                     while (indx > 0 && ((se.getCodeUnit(indx) & 0xC0) == 0x80))
7417                         --indx;
7418                     saveindx = indx;
7419                 }
7420                 auto slice = se.peekString();
7421                 errmsg = utf_decodeChar(slice, indx, rawvalue);
7422                 if (rvs)
7423                     indx = saveindx;
7424                 break;
7425             }
7426 
7427             case 2:
7428                 if (rvs)
7429                 {
7430                     // find the start
7431                     --indx;
7432                     auto wc = se.getCodeUnit(indx);
7433                     if (wc >= 0xDC00 && wc <= 0xDFFF)
7434                         --indx;
7435                     saveindx = indx;
7436                 }
7437                 const slice = se.peekWstring();
7438                 errmsg = utf_decodeWchar(slice, indx, rawvalue);
7439                 if (rvs)
7440                     indx = saveindx;
7441                 break;
7442 
7443             case 4:
7444                 if (rvs)
7445                     --indx;
7446                 rawvalue = se.getCodeUnit(indx);
7447                 if (!rvs)
7448                     ++indx;
7449                 break;
7450 
7451             default:
7452                 assert(0);
7453             }
7454         }
7455         if (errmsg)
7456         {
7457             error(deleg.loc, "`%.*s`", cast(int)errmsg.length, errmsg.ptr);
7458             return CTFEExp.cantexp;
7459         }
7460 
7461         // Step 2: encode the dchar in the target encoding
7462 
7463         int charlen = 1; // How many codepoints are involved?
7464         switch (charType.size())
7465         {
7466         case 1:
7467             charlen = utf_codeLengthChar(rawvalue);
7468             utf_encodeChar(&utf8buf[0], rawvalue);
7469             break;
7470         case 2:
7471             charlen = utf_codeLengthWchar(rawvalue);
7472             utf_encodeWchar(&utf16buf[0], rawvalue);
7473             break;
7474         case 4:
7475             break;
7476         default:
7477             assert(0);
7478         }
7479         if (rvs)
7480             currentIndex = indx;
7481 
7482         // Step 3: call the delegate once for each code point
7483 
7484         // The index only needs to be set once
7485         if (numParams == 2)
7486             args[0] = ctfeEmplaceExp!IntegerExp(deleg.loc, currentIndex, indexType);
7487 
7488         Expression val = null;
7489 
7490         foreach (k; 0 .. charlen)
7491         {
7492             dchar codepoint;
7493             switch (charType.size())
7494             {
7495             case 1:
7496                 codepoint = utf8buf[k];
7497                 break;
7498             case 2:
7499                 codepoint = utf16buf[k];
7500                 break;
7501             case 4:
7502                 codepoint = rawvalue;
7503                 break;
7504             default:
7505                 assert(0);
7506             }
7507             val = ctfeEmplaceExp!IntegerExp(str.loc, codepoint, charType);
7508 
7509             args[numParams - 1] = val;
7510 
7511             UnionExp ue = void;
7512             eresult = interpretFunction(&ue, fd, istate, &args, pthis);
7513             if (eresult == ue.exp())
7514                 eresult = ue.copy();
7515             if (exceptionOrCantInterpret(eresult))
7516                 return eresult;
7517             if (eresult.isIntegerExp().getInteger() != 0)
7518                 return eresult;
7519         }
7520     }
7521     return eresult;
7522 }
7523 
7524 /* If this is a built-in function, return the interpreted result,
7525  * Otherwise, return NULL.
7526  */
7527 private Expression evaluateIfBuiltin(UnionExp* pue, InterState* istate, const ref Loc loc, FuncDeclaration fd, Expressions* arguments, Expression pthis)
7528 {
7529     Expression e = null;
7530     size_t nargs = arguments ? arguments.length : 0;
7531     if (!pthis)
7532     {
7533         if (isBuiltin(fd) != BUILTIN.unimp)
7534         {
7535             Expressions args = Expressions(nargs);
7536             foreach (i, ref arg; args)
7537             {
7538                 Expression earg = (*arguments)[i];
7539                 earg = interpret(earg, istate);
7540                 if (exceptionOrCantInterpret(earg))
7541                     return earg;
7542                 arg = earg;
7543             }
7544             e = eval_builtin(loc, fd, &args);
7545             if (!e)
7546             {
7547                 error(loc, "cannot evaluate unimplemented builtin `%s` at compile time", fd.toChars());
7548                 e = CTFEExp.cantexp;
7549             }
7550         }
7551     }
7552     if (!pthis)
7553     {
7554         if (nargs == 1 || nargs == 3)
7555         {
7556             Expression firstarg = (*arguments)[0];
7557             if (auto firstAAtype = firstarg.type.toBasetype().isTypeAArray())
7558             {
7559                 const id = fd.ident;
7560                 if (nargs == 1)
7561                 {
7562                     if (id == Id.aaLen)
7563                         return interpret_length(pue, istate, firstarg);
7564 
7565                     if (fd.toParent2().ident == Id.object)
7566                     {
7567                         if (id == Id.keys)
7568                             return interpret_keys(pue, istate, firstarg, firstAAtype.index.arrayOf());
7569                         if (id == Id.values)
7570                             return interpret_values(pue, istate, firstarg, firstAAtype.nextOf().arrayOf());
7571                         if (id == Id.rehash)
7572                             return interpret(pue, firstarg, istate);
7573                         if (id == Id.dup)
7574                             return interpret_dup(pue, istate, firstarg);
7575                     }
7576                 }
7577                 else // (nargs == 3)
7578                 {
7579                     if (id == Id._aaApply)
7580                         return interpret_aaApply(pue, istate, firstarg, (*arguments)[2]);
7581                     if (id == Id._aaApply2)
7582                         return interpret_aaApply(pue, istate, firstarg, (*arguments)[2]);
7583                 }
7584             }
7585         }
7586     }
7587     if (pthis && !fd.fbody && fd.isCtorDeclaration() && fd.parent && fd.parent.parent && fd.parent.parent.ident == Id.object)
7588     {
7589         if (pthis.op == EXP.classReference && fd.parent.ident == Id.Throwable)
7590         {
7591             // At present, the constructors just copy their arguments into the struct.
7592             // But we might need some magic if stack tracing gets added to druntime.
7593             StructLiteralExp se = pthis.isClassReferenceExp().value;
7594             assert(arguments.length <= se.elements.length);
7595             foreach (i, arg; *arguments)
7596             {
7597                 auto elem = interpret(arg, istate);
7598                 if (exceptionOrCantInterpret(elem))
7599                     return elem;
7600                 (*se.elements)[i] = elem;
7601             }
7602             return CTFEExp.voidexp;
7603         }
7604     }
7605     if (nargs == 1 && !pthis && (fd.ident == Id.criticalenter || fd.ident == Id.criticalexit))
7606     {
7607         // Support synchronized{} as a no-op
7608         return CTFEExp.voidexp;
7609     }
7610     if (!pthis)
7611     {
7612         const idlen = fd.ident.toString().length;
7613         const id = fd.ident.toChars();
7614         if (nargs == 2 && (idlen == 10 || idlen == 11) && !strncmp(id, "_aApply", 7))
7615         {
7616             // Functions from aApply.d and aApplyR.d in the runtime
7617             bool rvs = (idlen == 11); // true if foreach_reverse
7618             char c = id[idlen - 3]; // char width: 'c', 'w', or 'd'
7619             char s = id[idlen - 2]; // string width: 'c', 'w', or 'd'
7620             char n = id[idlen - 1]; // numParams: 1 or 2.
7621             // There are 12 combinations
7622             if ((n == '1' || n == '2') &&
7623                 (c == 'c' || c == 'w' || c == 'd') &&
7624                 (s == 'c' || s == 'w' || s == 'd') &&
7625                 c != s)
7626             {
7627                 Expression str = (*arguments)[0];
7628                 str = interpret(str, istate);
7629                 if (exceptionOrCantInterpret(str))
7630                     return str;
7631                 return foreachApplyUtf(pue, istate, str, (*arguments)[1], rvs);
7632             }
7633         }
7634     }
7635     return e;
7636 }
7637 
7638 private Expression evaluatePostblit(InterState* istate, Expression e)
7639 {
7640     auto ts = e.type.baseElemOf().isTypeStruct();
7641     if (!ts)
7642         return null;
7643     StructDeclaration sd = ts.sym;
7644     if (!sd.postblit)
7645         return null;
7646 
7647     if (auto ale = e.isArrayLiteralExp())
7648     {
7649         foreach (elem; *ale.elements)
7650         {
7651             if (auto ex = evaluatePostblit(istate, elem))
7652                 return ex;
7653         }
7654         return null;
7655     }
7656     if (e.op == EXP.structLiteral)
7657     {
7658         // e.__postblit()
7659         UnionExp ue = void;
7660         e = interpretFunction(&ue, sd.postblit, istate, null, e);
7661         if (e == ue.exp())
7662             e = ue.copy();
7663         if (exceptionOrCantInterpret(e))
7664             return e;
7665         return null;
7666     }
7667     assert(0);
7668 }
7669 
7670 private Expression evaluateDtor(InterState* istate, Expression e)
7671 {
7672     auto ts = e.type.baseElemOf().isTypeStruct();
7673     if (!ts)
7674         return null;
7675     StructDeclaration sd = ts.sym;
7676     if (!sd.dtor)
7677         return null;
7678 
7679     UnionExp ue = void;
7680     if (auto ale = e.isArrayLiteralExp())
7681     {
7682         foreach_reverse (elem; *ale.elements)
7683             e = evaluateDtor(istate, elem);
7684     }
7685     else if (e.op == EXP.structLiteral)
7686     {
7687         // e.__dtor()
7688         e = interpretFunction(&ue, sd.dtor, istate, null, e);
7689     }
7690     else
7691         assert(0);
7692     if (exceptionOrCantInterpret(e))
7693     {
7694         if (e == ue.exp())
7695             e = ue.copy();
7696         return e;
7697     }
7698     return null;
7699 }
7700 
7701 /*************************** CTFE Sanity Checks ***************************/
7702 /* Setter functions for CTFE variable values.
7703  * These functions exist to check for compiler CTFE bugs.
7704  */
7705 private bool hasValue(VarDeclaration vd)
7706 {
7707     return vd.ctfeAdrOnStack != VarDeclaration.AdrOnStackNone &&
7708            getValue(vd) !is null;
7709 }
7710 
7711 // Don't check for validity
7712 private void setValueWithoutChecking(VarDeclaration vd, Expression newval)
7713 {
7714     ctfeGlobals.stack.setValue(vd, newval);
7715 }
7716 
7717 private void setValue(VarDeclaration vd, Expression newval)
7718 {
7719     //printf("setValue() vd: %s newval: %s\n", vd.toChars(), newval.toChars());
7720     version (none)
7721     {
7722         if (!((vd.storage_class & (STC.out_ | STC.ref_)) ? isCtfeReferenceValid(newval) : isCtfeValueValid(newval)))
7723         {
7724             printf("[%s] vd = %s %s, newval = %s\n", vd.loc.toChars(), vd.type.toChars(), vd.toChars(), newval.toChars());
7725         }
7726     }
7727     assert((vd.storage_class & (STC.out_ | STC.ref_)) ? isCtfeReferenceValid(newval) : isCtfeValueValid(newval));
7728     ctfeGlobals.stack.setValue(vd, newval);
7729 }
7730 
7731 /**
7732  * Removes `_d_HookTraceImpl` if found from `ce` and `fd`.
7733  * This is needed for the CTFE interception code to be able to find hooks that are called though the hook's `*Trace`
7734  * wrapper.
7735  *
7736  * This is done by replacing `_d_HookTraceImpl!(T, Hook, errMsg)(..., parameters)` with `Hook(parameters)`.
7737  * Parameters:
7738  *  ce = The CallExp that possible will be be replaced
7739  *  fd = Fully resolve function declaration that `ce` would call
7740  */
7741 private void removeHookTraceImpl(ref CallExp ce, ref FuncDeclaration fd)
7742 {
7743     if (fd.ident != Id._d_HookTraceImpl)
7744         return;
7745 
7746     auto oldCE = ce;
7747 
7748     // Get the Hook from the second template parameter
7749     TemplateInstance templateInstance = fd.parent.isTemplateInstance;
7750     RootObject hook = (*templateInstance.tiargs)[1];
7751     assert(hook.isDsymbol(), "Expected _d_HookTraceImpl's second template parameter to be an alias to the hook!");
7752     fd = (cast(Dsymbol)hook).isFuncDeclaration;
7753 
7754     // Remove the first three trace parameters
7755     auto arguments = new Expressions();
7756     arguments.reserve(ce.arguments.length - 3);
7757     arguments.pushSlice((*ce.arguments)[3 .. $]);
7758 
7759     ce = ctfeEmplaceExp!CallExp(ce.loc, ctfeEmplaceExp!VarExp(ce.loc, fd, false), arguments);
7760 
7761     if (global.params.v.verbose)
7762         message("strip     %s =>\n          %s", oldCE.toChars(), ce.toChars());
7763 }