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