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