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