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