xref: /netbsd-src/external/gpl3/gcc/dist/gcc/d/dmd/dinterpret.d (revision 0a3071956a3a9fdebdbf7f338cf2d439b45fc728)
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                 td.foreachVar((s)
2295                 {
2296                     VarDeclaration v2 = s.isVarDeclaration();
2297                     assert(v2);
2298                     if (v2.isDataseg() && !v2.isCTFE())
2299                         return 0;
2300 
2301                     ctfeGlobals.stack.push(v2);
2302                     if (v2._init)
2303                     {
2304                         Expression einit;
2305                         if (ExpInitializer ie = v2._init.isExpInitializer())
2306                         {
2307                             einit = interpretRegion(ie.exp, istate, goal);
2308                             if (exceptionOrCant(einit))
2309                                 return 1;
2310                         }
2311                         else if (v2._init.isVoidInitializer())
2312                         {
2313                             einit = voidInitLiteral(v2.type, v2).copy();
2314                         }
2315                         else
2316                         {
2317                             e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
2318                             result = CTFEExp.cantexp;
2319                             return 1;
2320                         }
2321                         setValue(v2, einit);
2322                     }
2323                     return 0;
2324                 });
2325                 return;
2326             }
2327             if (v.isStatic())
2328             {
2329                 // Just ignore static variables which aren't read or written yet
2330                 result = null;
2331                 return;
2332             }
2333             if (!(v.isDataseg() || v.storage_class & STC.manifest) || v.isCTFE())
2334                 ctfeGlobals.stack.push(v);
2335             if (v._init)
2336             {
2337                 if (ExpInitializer ie = v._init.isExpInitializer())
2338                 {
2339                     result = interpretRegion(ie.exp, istate, goal);
2340                 }
2341                 else if (v._init.isVoidInitializer())
2342                 {
2343                     result = voidInitLiteral(v.type, v).copy();
2344                     // There is no AssignExp for void initializers,
2345                     // so set it here.
2346                     setValue(v, result);
2347                 }
2348                 else
2349                 {
2350                     e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
2351                     result = CTFEExp.cantexp;
2352                 }
2353             }
2354             else if (v.type.size() == 0)
2355             {
2356                 // Zero-length arrays don't need an initializer
2357                 result = v.type.defaultInitLiteral(e.loc);
2358             }
2359             else
2360             {
2361                 e.error("variable `%s` cannot be modified at compile time", v.toChars());
2362                 result = CTFEExp.cantexp;
2363             }
2364             return;
2365         }
2366         if (s.isTemplateMixin() || s.isTupleDeclaration())
2367         {
2368             // These can be made to work, too lazy now
2369             e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
2370             result = CTFEExp.cantexp;
2371             return;
2372         }
2373 
2374         // Others should not contain executable code, so are trivial to evaluate
2375         result = null;
2376         debug (LOG)
2377         {
2378             printf("-DeclarationExp::interpret(%s): %p\n", e.toChars(), result);
2379         }
2380     }
2381 
visit(TypeidExp e)2382     override void visit(TypeidExp e)
2383     {
2384         debug (LOG)
2385         {
2386             printf("%s TypeidExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2387         }
2388         if (Type t = isType(e.obj))
2389         {
2390             result = e;
2391             return;
2392         }
2393         if (Expression ex = isExpression(e.obj))
2394         {
2395             result = interpret(pue, ex, istate);
2396             if (exceptionOrCant(ex))
2397                 return;
2398 
2399             if (result.op == EXP.null_)
2400             {
2401                 e.error("null pointer dereference evaluating typeid. `%s` is `null`", ex.toChars());
2402                 result = CTFEExp.cantexp;
2403                 return;
2404             }
2405             if (result.op != EXP.classReference)
2406             {
2407                 e.error("CTFE internal error: determining classinfo");
2408                 result = CTFEExp.cantexp;
2409                 return;
2410             }
2411 
2412             ClassDeclaration cd = result.isClassReferenceExp().originalClass();
2413             assert(cd);
2414 
2415             emplaceExp!(TypeidExp)(pue, e.loc, cd.type);
2416             result = pue.exp();
2417             result.type = e.type;
2418             return;
2419         }
2420         visit(cast(Expression)e);
2421     }
2422 
visit(TupleExp e)2423     override void visit(TupleExp e)
2424     {
2425         debug (LOG)
2426         {
2427             printf("%s TupleExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2428         }
2429         if (exceptionOrCant(interpretRegion(e.e0, istate, CTFEGoal.Nothing)))
2430             return;
2431 
2432         auto expsx = e.exps;
2433         foreach (i, exp; *expsx)
2434         {
2435             Expression ex = interpretRegion(exp, istate);
2436             if (exceptionOrCant(ex))
2437                 return;
2438 
2439             // A tuple of assignments can contain void (Bug 5676).
2440             if (goal == CTFEGoal.Nothing)
2441                 continue;
2442             if (ex.op == EXP.voidExpression)
2443             {
2444                 e.error("CTFE internal error: void element `%s` in tuple", exp.toChars());
2445                 assert(0);
2446             }
2447 
2448             /* If any changes, do Copy On Write
2449              */
2450             if (ex !is exp)
2451             {
2452                 expsx = copyArrayOnWrite(expsx, e.exps);
2453                 (*expsx)[i] = copyRegionExp(ex);
2454             }
2455         }
2456 
2457         if (expsx !is e.exps)
2458         {
2459             expandTuples(expsx);
2460             emplaceExp!(TupleExp)(pue, e.loc, expsx);
2461             result = pue.exp();
2462             result.type = new TypeTuple(expsx);
2463         }
2464         else
2465             result = e;
2466     }
2467 
visit(ArrayLiteralExp e)2468     override void visit(ArrayLiteralExp e)
2469     {
2470         debug (LOG)
2471         {
2472             printf("%s ArrayLiteralExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2473         }
2474         if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
2475         {
2476             result = e;
2477             return;
2478         }
2479 
2480         Type tn = e.type.toBasetype().nextOf().toBasetype();
2481         bool wantCopy = (tn.ty == Tsarray || tn.ty == Tstruct);
2482 
2483         auto basis = interpretRegion(e.basis, istate);
2484         if (exceptionOrCant(basis))
2485             return;
2486 
2487         auto expsx = e.elements;
2488         size_t dim = expsx ? expsx.dim : 0;
2489         for (size_t i = 0; i < dim; i++)
2490         {
2491             Expression exp = (*expsx)[i];
2492             Expression ex;
2493             if (!exp)
2494             {
2495                 ex = copyLiteral(basis).copy();
2496             }
2497             else
2498             {
2499                 // segfault bug 6250
2500                 assert(exp.op != EXP.index || exp.isIndexExp().e1 != e);
2501 
2502                 ex = interpretRegion(exp, istate);
2503                 if (exceptionOrCant(ex))
2504                     return;
2505 
2506                 /* Each elements should have distinct CTFE memory.
2507                  *  int[1] z = 7;
2508                  *  int[1][] pieces = [z,z];    // here
2509                  */
2510                 if (wantCopy)
2511                     ex = copyLiteral(ex).copy();
2512             }
2513 
2514             /* If any changes, do Copy On Write
2515              */
2516             if (ex !is exp)
2517             {
2518                 expsx = copyArrayOnWrite(expsx, e.elements);
2519                 (*expsx)[i] = ex;
2520             }
2521         }
2522 
2523         if (expsx !is e.elements)
2524         {
2525             // todo: all tuple expansions should go in semantic phase.
2526             expandTuples(expsx);
2527             if (expsx.dim != dim)
2528             {
2529                 e.error("CTFE internal error: invalid array literal");
2530                 result = CTFEExp.cantexp;
2531                 return;
2532             }
2533             emplaceExp!(ArrayLiteralExp)(pue, e.loc, e.type, basis, expsx);
2534             auto ale = pue.exp().isArrayLiteralExp();
2535             ale.ownedByCtfe = OwnedBy.ctfe;
2536             result = ale;
2537         }
2538         else if ((cast(TypeNext)e.type).next.mod & (MODFlags.const_ | MODFlags.immutable_))
2539         {
2540             // If it's immutable, we don't need to dup it
2541             result = e;
2542         }
2543         else
2544         {
2545             *pue = copyLiteral(e);
2546             result = pue.exp();
2547         }
2548     }
2549 
visit(AssocArrayLiteralExp e)2550     override void visit(AssocArrayLiteralExp e)
2551     {
2552         debug (LOG)
2553         {
2554             printf("%s AssocArrayLiteralExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2555         }
2556         if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
2557         {
2558             result = e;
2559             return;
2560         }
2561 
2562         auto keysx = e.keys;
2563         auto valuesx = e.values;
2564         foreach (i, ekey; *keysx)
2565         {
2566             auto evalue = (*valuesx)[i];
2567 
2568             auto ek = interpretRegion(ekey, istate);
2569             if (exceptionOrCant(ek))
2570                 return;
2571             auto ev = interpretRegion(evalue, istate);
2572             if (exceptionOrCant(ev))
2573                 return;
2574 
2575             /* If any changes, do Copy On Write
2576              */
2577             if (ek !is ekey ||
2578                 ev !is evalue)
2579             {
2580                 keysx = copyArrayOnWrite(keysx, e.keys);
2581                 valuesx = copyArrayOnWrite(valuesx, e.values);
2582                 (*keysx)[i] = ek;
2583                 (*valuesx)[i] = ev;
2584             }
2585         }
2586         if (keysx !is e.keys)
2587             expandTuples(keysx);
2588         if (valuesx !is e.values)
2589             expandTuples(valuesx);
2590         if (keysx.dim != valuesx.dim)
2591         {
2592             e.error("CTFE internal error: invalid AA");
2593             result = CTFEExp.cantexp;
2594             return;
2595         }
2596 
2597         /* Remove duplicate keys
2598          */
2599         for (size_t i = 1; i < keysx.dim; i++)
2600         {
2601             auto ekey = (*keysx)[i - 1];
2602             for (size_t j = i; j < keysx.dim; j++)
2603             {
2604                 auto ekey2 = (*keysx)[j];
2605                 if (!ctfeEqual(e.loc, EXP.equal, ekey, ekey2))
2606                     continue;
2607 
2608                 // Remove ekey
2609                 keysx = copyArrayOnWrite(keysx, e.keys);
2610                 valuesx = copyArrayOnWrite(valuesx, e.values);
2611                 keysx.remove(i - 1);
2612                 valuesx.remove(i - 1);
2613 
2614                 i -= 1; // redo the i'th iteration
2615                 break;
2616             }
2617         }
2618 
2619         if (keysx !is e.keys ||
2620             valuesx !is e.values)
2621         {
2622             assert(keysx !is e.keys &&
2623                    valuesx !is e.values);
2624             auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
2625             aae.type = e.type;
2626             aae.ownedByCtfe = OwnedBy.ctfe;
2627             result = aae;
2628         }
2629         else
2630         {
2631             *pue = copyLiteral(e);
2632             result = pue.exp();
2633         }
2634     }
2635 
visit(StructLiteralExp e)2636     override void visit(StructLiteralExp e)
2637     {
2638         debug (LOG)
2639         {
2640             printf("%s StructLiteralExp::interpret() %s ownedByCtfe = %d\n", e.loc.toChars(), e.toChars(), e.ownedByCtfe);
2641         }
2642         if (e.ownedByCtfe >= OwnedBy.ctfe)
2643         {
2644             result = e;
2645             return;
2646         }
2647 
2648         size_t dim = e.elements ? e.elements.dim : 0;
2649         auto expsx = e.elements;
2650 
2651         if (dim != e.sd.fields.dim)
2652         {
2653             // guaranteed by AggregateDeclaration.fill and TypeStruct.defaultInitLiteral
2654             const nvthis = e.sd.fields.dim - e.sd.nonHiddenFields();
2655             assert(e.sd.fields.dim - dim == nvthis);
2656 
2657             /* If a nested struct has no initialized hidden pointer,
2658              * set it to null to match the runtime behaviour.
2659              */
2660             foreach (const i; 0 .. nvthis)
2661             {
2662                 auto ne = ctfeEmplaceExp!NullExp(e.loc);
2663                 auto vthis = i == 0 ? e.sd.vthis : e.sd.vthis2;
2664                 ne.type = vthis.type;
2665 
2666                 expsx = copyArrayOnWrite(expsx, e.elements);
2667                 expsx.push(ne);
2668                 ++dim;
2669             }
2670         }
2671         assert(dim == e.sd.fields.dim);
2672 
2673         foreach (i; 0 .. dim)
2674         {
2675             auto v = e.sd.fields[i];
2676             Expression exp = (*expsx)[i];
2677             Expression ex;
2678             if (!exp)
2679             {
2680                 ex = voidInitLiteral(v.type, v).copy();
2681             }
2682             else
2683             {
2684                 ex = interpretRegion(exp, istate);
2685                 if (exceptionOrCant(ex))
2686                     return;
2687                 if ((v.type.ty != ex.type.ty) && v.type.ty == Tsarray)
2688                 {
2689                     // Block assignment from inside struct literals
2690                     auto tsa = cast(TypeSArray)v.type;
2691                     auto len = cast(size_t)tsa.dim.toInteger();
2692                     UnionExp ue = void;
2693                     ex = createBlockDuplicatedArrayLiteral(&ue, ex.loc, v.type, ex, len);
2694                     if (ex == ue.exp())
2695                         ex = ue.copy();
2696                 }
2697             }
2698 
2699             /* If any changes, do Copy On Write
2700              */
2701             if (ex !is exp)
2702             {
2703                 expsx = copyArrayOnWrite(expsx, e.elements);
2704                 (*expsx)[i] = ex;
2705             }
2706         }
2707 
2708         if (expsx !is e.elements)
2709         {
2710             expandTuples(expsx);
2711             if (expsx.dim != e.sd.fields.dim)
2712             {
2713                 e.error("CTFE internal error: invalid struct literal");
2714                 result = CTFEExp.cantexp;
2715                 return;
2716             }
2717             emplaceExp!(StructLiteralExp)(pue, e.loc, e.sd, expsx);
2718             auto sle = pue.exp().isStructLiteralExp();
2719             sle.type = e.type;
2720             sle.ownedByCtfe = OwnedBy.ctfe;
2721             sle.origin = e.origin;
2722             result = sle;
2723         }
2724         else
2725         {
2726             *pue = copyLiteral(e);
2727             result = pue.exp();
2728         }
2729     }
2730 
2731     // Create an array literal of type 'newtype' with dimensions given by
2732     // 'arguments'[argnum..$]
recursivelyCreateArrayLiteral(UnionExp * pue,const ref Loc loc,Type newtype,InterState * istate,Expressions * arguments,int argnum)2733     static Expression recursivelyCreateArrayLiteral(UnionExp* pue, const ref Loc loc, Type newtype, InterState* istate, Expressions* arguments, int argnum)
2734     {
2735         Expression lenExpr = interpret(pue, (*arguments)[argnum], istate);
2736         if (exceptionOrCantInterpret(lenExpr))
2737             return lenExpr;
2738         size_t len = cast(size_t)lenExpr.toInteger();
2739         Type elemType = (cast(TypeArray)newtype).next;
2740         if (elemType.ty == Tarray && argnum < arguments.dim - 1)
2741         {
2742             Expression elem = recursivelyCreateArrayLiteral(pue, loc, elemType, istate, arguments, argnum + 1);
2743             if (exceptionOrCantInterpret(elem))
2744                 return elem;
2745 
2746             auto elements = new Expressions(len);
2747             foreach (ref element; *elements)
2748                 element = copyLiteral(elem).copy();
2749             emplaceExp!(ArrayLiteralExp)(pue, loc, newtype, elements);
2750             auto ae = pue.exp().isArrayLiteralExp();
2751             ae.ownedByCtfe = OwnedBy.ctfe;
2752             return ae;
2753         }
2754         assert(argnum == arguments.dim - 1);
2755         if (elemType.ty.isSomeChar)
2756         {
2757             const ch = cast(dchar)elemType.defaultInitLiteral(loc).toInteger();
2758             const sz = cast(ubyte)elemType.size();
2759             return createBlockDuplicatedStringLiteral(pue, loc, newtype, ch, len, sz);
2760         }
2761         else
2762         {
2763             auto el = interpret(elemType.defaultInitLiteral(loc), istate);
2764             return createBlockDuplicatedArrayLiteral(pue, loc, newtype, el, len);
2765         }
2766     }
2767 
visit(NewExp e)2768     override void visit(NewExp e)
2769     {
2770         debug (LOG)
2771         {
2772             printf("%s NewExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2773         }
2774 
2775         Expression epre = interpret(pue, e.argprefix, istate, CTFEGoal.Nothing);
2776         if (exceptionOrCant(epre))
2777             return;
2778 
2779         if (e.newtype.ty == Tarray && e.arguments)
2780         {
2781             result = recursivelyCreateArrayLiteral(pue, e.loc, e.newtype, istate, e.arguments, 0);
2782             return;
2783         }
2784         if (auto ts = e.newtype.toBasetype().isTypeStruct())
2785         {
2786             if (e.member)
2787             {
2788                 Expression se = e.newtype.defaultInitLiteral(e.loc);
2789                 se = interpret(se, istate);
2790                 if (exceptionOrCant(se))
2791                     return;
2792                 result = interpretFunction(pue, e.member, istate, e.arguments, se);
2793 
2794                 // Repaint as same as CallExp::interpret() does.
2795                 result.loc = e.loc;
2796             }
2797             else
2798             {
2799                 StructDeclaration sd = ts.sym;
2800                 auto exps = new Expressions();
2801                 exps.reserve(sd.fields.dim);
2802                 if (e.arguments)
2803                 {
2804                     exps.setDim(e.arguments.dim);
2805                     foreach (i, ex; *e.arguments)
2806                     {
2807                         ex = interpretRegion(ex, istate);
2808                         if (exceptionOrCant(ex))
2809                             return;
2810                         (*exps)[i] = ex;
2811                     }
2812                 }
2813                 sd.fill(e.loc, exps, false);
2814 
2815                 auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, sd, exps, e.newtype);
2816                 se.origin = se;
2817                 se.type = e.newtype;
2818                 se.ownedByCtfe = OwnedBy.ctfe;
2819                 result = interpret(pue, se, istate);
2820             }
2821             if (exceptionOrCant(result))
2822                 return;
2823             Expression ev = (result == pue.exp()) ? pue.copy() : result;
2824             emplaceExp!(AddrExp)(pue, e.loc, ev, e.type);
2825             result = pue.exp();
2826             return;
2827         }
2828         if (auto tc = e.newtype.toBasetype().isTypeClass())
2829         {
2830             ClassDeclaration cd = tc.sym;
2831             size_t totalFieldCount = 0;
2832             for (ClassDeclaration c = cd; c; c = c.baseClass)
2833                 totalFieldCount += c.fields.dim;
2834             auto elems = new Expressions(totalFieldCount);
2835             size_t fieldsSoFar = totalFieldCount;
2836             for (ClassDeclaration c = cd; c; c = c.baseClass)
2837             {
2838                 fieldsSoFar -= c.fields.dim;
2839                 foreach (i, v; c.fields)
2840                 {
2841                     if (v.inuse)
2842                     {
2843                         e.error("circular reference to `%s`", v.toPrettyChars());
2844                         result = CTFEExp.cantexp;
2845                         return;
2846                     }
2847                     Expression m;
2848                     if (v._init)
2849                     {
2850                         if (v._init.isVoidInitializer())
2851                             m = voidInitLiteral(v.type, v).copy();
2852                         else
2853                             m = v.getConstInitializer(true);
2854                     }
2855                     else
2856                         m = v.type.defaultInitLiteral(e.loc);
2857                     if (exceptionOrCant(m))
2858                         return;
2859                     (*elems)[fieldsSoFar + i] = copyLiteral(m).copy();
2860                 }
2861             }
2862             // Hack: we store a ClassDeclaration instead of a StructDeclaration.
2863             // We probably won't get away with this.
2864 //            auto se = new StructLiteralExp(e.loc, cast(StructDeclaration)cd, elems, e.newtype);
2865             auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, cast(StructDeclaration)cd, elems, e.newtype);
2866             se.origin = se;
2867             se.ownedByCtfe = OwnedBy.ctfe;
2868             Expression eref = ctfeEmplaceExp!ClassReferenceExp(e.loc, se, e.type);
2869             if (e.member)
2870             {
2871                 // Call constructor
2872                 if (!e.member.fbody)
2873                 {
2874                     Expression ctorfail = evaluateIfBuiltin(pue, istate, e.loc, e.member, e.arguments, eref);
2875                     if (ctorfail)
2876                     {
2877                         if (exceptionOrCant(ctorfail))
2878                             return;
2879                         result = eref;
2880                         return;
2881                     }
2882                     e.member.error("`%s` cannot be constructed at compile time, because the constructor has no available source code", e.newtype.toChars());
2883                     result = CTFEExp.cantexp;
2884                     return;
2885                 }
2886                 UnionExp ue = void;
2887                 Expression ctorfail = interpretFunction(&ue, e.member, istate, e.arguments, eref);
2888                 if (exceptionOrCant(ctorfail))
2889                     return;
2890 
2891                 /* https://issues.dlang.org/show_bug.cgi?id=14465
2892                  * Repaint the loc, because a super() call
2893                  * in the constructor modifies the loc of ClassReferenceExp
2894                  * in CallExp::interpret().
2895                  */
2896                 eref.loc = e.loc;
2897             }
2898             result = eref;
2899             return;
2900         }
2901         if (e.newtype.toBasetype().isscalar())
2902         {
2903             Expression newval;
2904             if (e.arguments && e.arguments.dim)
2905                 newval = (*e.arguments)[0];
2906             else
2907                 newval = e.newtype.defaultInitLiteral(e.loc);
2908             newval = interpretRegion(newval, istate);
2909             if (exceptionOrCant(newval))
2910                 return;
2911 
2912             // Create a CTFE pointer &[newval][0]
2913             auto elements = new Expressions(1);
2914             (*elements)[0] = newval;
2915             auto ae = ctfeEmplaceExp!ArrayLiteralExp(e.loc, e.newtype.arrayOf(), elements);
2916             ae.ownedByCtfe = OwnedBy.ctfe;
2917 
2918             auto ei = ctfeEmplaceExp!IndexExp(e.loc, ae, ctfeEmplaceExp!IntegerExp(Loc.initial, 0, Type.tsize_t));
2919             ei.type = e.newtype;
2920             emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
2921             result = pue.exp();
2922             return;
2923         }
2924         e.error("cannot interpret `%s` at compile time", e.toChars());
2925         result = CTFEExp.cantexp;
2926     }
2927 
visit(UnaExp e)2928     override void visit(UnaExp e)
2929     {
2930         debug (LOG)
2931         {
2932             printf("%s UnaExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2933         }
2934         UnionExp ue = void;
2935         Expression e1 = interpret(&ue, e.e1, istate);
2936         if (exceptionOrCant(e1))
2937             return;
2938         switch (e.op)
2939         {
2940         case EXP.negate:
2941             *pue = Neg(e.type, e1);
2942             break;
2943 
2944         case EXP.tilde:
2945             *pue = Com(e.type, e1);
2946             break;
2947 
2948         case EXP.not:
2949             *pue = Not(e.type, e1);
2950             break;
2951 
2952         default:
2953             assert(0);
2954         }
2955         result = (*pue).exp();
2956     }
2957 
visit(DotTypeExp e)2958     override void visit(DotTypeExp e)
2959     {
2960         debug (LOG)
2961         {
2962             printf("%s DotTypeExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2963         }
2964         UnionExp ue = void;
2965         Expression e1 = interpret(&ue, e.e1, istate);
2966         if (exceptionOrCant(e1))
2967             return;
2968         if (e1 == e.e1)
2969             result = e; // optimize: reuse this CTFE reference
2970         else
2971         {
2972             auto edt = e.copy().isDotTypeExp();
2973             edt.e1 = (e1 == ue.exp()) ? e1.copy() : e1; // don't return pointer to ue
2974             result = edt;
2975         }
2976     }
2977 
interpretCommon(BinExp e,fp_t fp)2978     extern (D) private void interpretCommon(BinExp e, fp_t fp)
2979     {
2980         debug (LOG)
2981         {
2982             printf("%s BinExp::interpretCommon() %s\n", e.loc.toChars(), e.toChars());
2983         }
2984         if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer && e.op == EXP.min)
2985         {
2986             UnionExp ue1 = void;
2987             Expression e1 = interpret(&ue1, e.e1, istate);
2988             if (exceptionOrCant(e1))
2989                 return;
2990             UnionExp ue2 = void;
2991             Expression e2 = interpret(&ue2, e.e2, istate);
2992             if (exceptionOrCant(e2))
2993                 return;
2994             result = pointerDifference(pue, e.loc, e.type, e1, e2);
2995             return;
2996         }
2997         if (e.e1.type.ty == Tpointer && e.e2.type.isintegral())
2998         {
2999             UnionExp ue1 = void;
3000             Expression e1 = interpret(&ue1, e.e1, istate);
3001             if (exceptionOrCant(e1))
3002                 return;
3003             UnionExp ue2 = void;
3004             Expression e2 = interpret(&ue2, e.e2, istate);
3005             if (exceptionOrCant(e2))
3006                 return;
3007             result = pointerArithmetic(pue, e.loc, e.op, e.type, e1, e2);
3008             return;
3009         }
3010         if (e.e2.type.ty == Tpointer && e.e1.type.isintegral() && e.op == EXP.add)
3011         {
3012             UnionExp ue1 = void;
3013             Expression e1 = interpret(&ue1, e.e1, istate);
3014             if (exceptionOrCant(e1))
3015                 return;
3016             UnionExp ue2 = void;
3017             Expression e2 = interpret(&ue2, e.e2, istate);
3018             if (exceptionOrCant(e2))
3019                 return;
3020             result = pointerArithmetic(pue, e.loc, e.op, e.type, e2, e1);
3021             return;
3022         }
3023         if (e.e1.type.ty == Tpointer || e.e2.type.ty == Tpointer)
3024         {
3025             e.error("pointer expression `%s` cannot be interpreted at compile time", e.toChars());
3026             result = CTFEExp.cantexp;
3027             return;
3028         }
3029 
3030         bool evalOperand(UnionExp* pue, Expression ex, out Expression er)
3031         {
3032             er = interpret(pue, ex, istate);
3033             if (exceptionOrCant(er))
3034                 return false;
3035             return true;
3036         }
3037 
3038         UnionExp ue1 = void;
3039         Expression e1;
3040         if (!evalOperand(&ue1, e.e1, e1))
3041             return;
3042 
3043         UnionExp ue2 = void;
3044         Expression e2;
3045         if (!evalOperand(&ue2, e.e2, e2))
3046             return;
3047 
3048         if (e.op == EXP.rightShift || e.op == EXP.leftShift || e.op == EXP.unsignedRightShift)
3049         {
3050             const sinteger_t i2 = e2.toInteger();
3051             const uinteger_t sz = e1.type.size() * 8;
3052             if (i2 < 0 || i2 >= sz)
3053             {
3054                 e.error("shift by %lld is outside the range 0..%llu", i2, cast(ulong)sz - 1);
3055                 result = CTFEExp.cantexp;
3056                 return;
3057             }
3058         }
3059 
3060         /******************************************
3061          * Perform the operation fp on operands e1 and e2.
3062          */
3063         UnionExp evaluate(Loc loc, Type type, Expression e1, Expression e2)
3064         {
3065             UnionExp ue = void;
3066             auto ae1 = e1.isArrayLiteralExp();
3067             auto ae2 = e2.isArrayLiteralExp();
3068             if (ae1 || ae2)
3069             {
3070                 /* Cases:
3071                  * 1. T[] op T[]
3072                  * 2. T op T[]
3073                  * 3. T[] op T
3074                  */
3075                 if (ae1 && e2.implicitConvTo(e1.type.toBasetype().nextOf())) // case 3
3076                     ae2 = null;
3077                 else if (ae2 && e1.implicitConvTo(e2.type.toBasetype().nextOf())) // case 2
3078                     ae1 = null;
3079                 // else case 1
3080 
3081                 auto aex = ae1 ? ae1 : ae2;
3082                 if (!aex.elements)
3083                 {
3084                     emplaceExp!ArrayLiteralExp(&ue, loc, type, cast(Expressions*) null);
3085                     return ue;
3086                 }
3087                 const length = aex.elements.length;
3088                 Expressions* elements = new Expressions(length);
3089 
3090                 emplaceExp!ArrayLiteralExp(&ue, loc, type, elements);
3091                 foreach (i; 0 .. length)
3092                 {
3093                     Expression e1x = ae1 ? ae1[i] : e1;
3094                     Expression e2x = ae2 ? ae2[i] : e2;
3095                     UnionExp uex = evaluate(loc, e1x.type, e1x, e2x);
3096                     // This can be made more efficient by making use of ue.basis
3097                     (*elements)[i] = uex.copy();
3098                 }
3099                 return ue;
3100             }
3101 
3102             if (e1.isConst() != 1)
3103             {
3104                 // The following should really be an assert()
3105                 e1.error("CTFE internal error: non-constant value `%s`", e1.toChars());
3106                 emplaceExp!CTFEExp(&ue, EXP.cantExpression);
3107                 return ue;
3108             }
3109             if (e2.isConst() != 1)
3110             {
3111                 e2.error("CTFE internal error: non-constant value `%s`", e2.toChars());
3112                 emplaceExp!CTFEExp(&ue, EXP.cantExpression);
3113                 return ue;
3114             }
3115 
3116             return (*fp)(loc, type, e1, e2);
3117         }
3118 
3119         *pue = evaluate(e.loc, e.type, e1, e2);
3120         result = (*pue).exp();
3121         if (CTFEExp.isCantExp(result))
3122             e.error("`%s` cannot be interpreted at compile time", e.toChars());
3123     }
3124 
interpretCompareCommon(BinExp e,fp2_t fp)3125     extern (D) private void interpretCompareCommon(BinExp e, fp2_t fp)
3126     {
3127         debug (LOG)
3128         {
3129             printf("%s BinExp::interpretCompareCommon() %s\n", e.loc.toChars(), e.toChars());
3130         }
3131         UnionExp ue1 = void;
3132         UnionExp ue2 = void;
3133         if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer)
3134         {
3135             Expression e1 = interpret(&ue1, e.e1, istate);
3136             if (exceptionOrCant(e1))
3137                 return;
3138             Expression e2 = interpret(&ue2, e.e2, istate);
3139             if (exceptionOrCant(e2))
3140                 return;
3141             //printf("e1 = %s %s, e2 = %s %s\n", e1.type.toChars(), e1.toChars(), e2.type.toChars(), e2.toChars());
3142             dinteger_t ofs1, ofs2;
3143             Expression agg1 = getAggregateFromPointer(e1, &ofs1);
3144             Expression agg2 = getAggregateFromPointer(e2, &ofs2);
3145             //printf("agg1 = %p %s, agg2 = %p %s\n", agg1, agg1.toChars(), agg2, agg2.toChars());
3146             const cmp = comparePointers(e.op, agg1, ofs1, agg2, ofs2);
3147             if (cmp == -1)
3148             {
3149                 char dir = (e.op == EXP.greaterThan || e.op == EXP.greaterOrEqual) ? '<' : '>';
3150                 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());
3151                 result = CTFEExp.cantexp;
3152                 return;
3153             }
3154             if (e.type.equals(Type.tbool))
3155                 result = IntegerExp.createBool(cmp != 0);
3156             else
3157             {
3158                 emplaceExp!(IntegerExp)(pue, e.loc, cmp, e.type);
3159                 result = (*pue).exp();
3160             }
3161             return;
3162         }
3163         Expression e1 = interpret(&ue1, e.e1, istate);
3164         if (exceptionOrCant(e1))
3165             return;
3166         if (!isCtfeComparable(e1))
3167         {
3168             e.error("cannot compare `%s` at compile time", e1.toChars());
3169             result = CTFEExp.cantexp;
3170             return;
3171         }
3172         Expression e2 = interpret(&ue2, e.e2, istate);
3173         if (exceptionOrCant(e2))
3174             return;
3175         if (!isCtfeComparable(e2))
3176         {
3177             e.error("cannot compare `%s` at compile time", e2.toChars());
3178             result = CTFEExp.cantexp;
3179             return;
3180         }
3181         const cmp = (*fp)(e.loc, e.op, e1, e2);
3182         if (e.type.equals(Type.tbool))
3183             result = IntegerExp.createBool(cmp);
3184         else
3185         {
3186             emplaceExp!(IntegerExp)(pue, e.loc, cmp, e.type);
3187             result = (*pue).exp();
3188         }
3189     }
3190 
visit(BinExp e)3191     override void visit(BinExp e)
3192     {
3193         switch (e.op)
3194         {
3195         case EXP.add:
3196             interpretCommon(e, &Add);
3197             return;
3198 
3199         case EXP.min:
3200             interpretCommon(e, &Min);
3201             return;
3202 
3203         case EXP.mul:
3204             interpretCommon(e, &Mul);
3205             return;
3206 
3207         case EXP.div:
3208             interpretCommon(e, &Div);
3209             return;
3210 
3211         case EXP.mod:
3212             interpretCommon(e, &Mod);
3213             return;
3214 
3215         case EXP.leftShift:
3216             interpretCommon(e, &Shl);
3217             return;
3218 
3219         case EXP.rightShift:
3220             interpretCommon(e, &Shr);
3221             return;
3222 
3223         case EXP.unsignedRightShift:
3224             interpretCommon(e, &Ushr);
3225             return;
3226 
3227         case EXP.and:
3228             interpretCommon(e, &And);
3229             return;
3230 
3231         case EXP.or:
3232             interpretCommon(e, &Or);
3233             return;
3234 
3235         case EXP.xor:
3236             interpretCommon(e, &Xor);
3237             return;
3238 
3239         case EXP.pow:
3240             interpretCommon(e, &Pow);
3241             return;
3242 
3243         case EXP.equal:
3244         case EXP.notEqual:
3245             interpretCompareCommon(e, &ctfeEqual);
3246             return;
3247 
3248         case EXP.identity:
3249         case EXP.notIdentity:
3250             interpretCompareCommon(e, &ctfeIdentity);
3251             return;
3252 
3253         case EXP.lessThan:
3254         case EXP.lessOrEqual:
3255         case EXP.greaterThan:
3256         case EXP.greaterOrEqual:
3257             interpretCompareCommon(e, &ctfeCmp);
3258             return;
3259 
3260         default:
3261             printf("be = '%s' %s at [%s]\n", EXPtoString(e.op).ptr, e.toChars(), e.loc.toChars());
3262             assert(0);
3263         }
3264     }
3265 
3266     /* Helper functions for BinExp::interpretAssignCommon
3267      */
3268     // Returns the variable which is eventually modified, or NULL if an rvalue.
3269     // thisval is the current value of 'this'.
findParentVar(Expression e)3270     static VarDeclaration findParentVar(Expression e)
3271     {
3272         for (;;)
3273         {
3274             if (auto ve = e.isVarExp())
3275             {
3276                 VarDeclaration v = ve.var.isVarDeclaration();
3277                 assert(v);
3278                 return v;
3279             }
3280             if (auto ie = e.isIndexExp())
3281                 e = ie.e1;
3282             else if (auto dve = e.isDotVarExp())
3283                 e = dve.e1;
3284             else if (auto dtie = e.isDotTemplateInstanceExp())
3285                 e = dtie.e1;
3286             else if (auto se = e.isSliceExp())
3287                 e = se.e1;
3288             else
3289                 return null;
3290         }
3291     }
3292 
3293     extern (D) private void interpretAssignCommon(BinExp e, fp_t fp, int post = 0)
3294     {
debug(LOG)3295         debug (LOG)
3296         {
3297             printf("%s BinExp::interpretAssignCommon() %s\n", e.loc.toChars(), e.toChars());
3298         }
3299         result = CTFEExp.cantexp;
3300 
3301         Expression e1 = e.e1;
3302         if (!istate)
3303         {
3304             e.error("value of `%s` is not known at compile time", e1.toChars());
3305             return;
3306         }
3307 
3308         ++ctfeGlobals.numAssignments;
3309 
3310         /* Before we begin, we need to know if this is a reference assignment
3311          * (dynamic array, AA, or class) or a value assignment.
3312          * Determining this for slice assignments are tricky: we need to know
3313          * if it is a block assignment (a[] = e) rather than a direct slice
3314          * assignment (a[] = b[]). Note that initializers of multi-dimensional
3315          * static arrays can have 2D block assignments (eg, int[7][7] x = 6;).
3316          * So we need to recurse to determine if it is a block assignment.
3317          */
3318         bool isBlockAssignment = false;
3319         if (e1.op == EXP.slice)
3320         {
3321             // a[] = e can have const e. So we compare the naked types.
3322             Type tdst = e1.type.toBasetype();
3323             Type tsrc = e.e2.type.toBasetype();
3324             while (tdst.ty == Tsarray || tdst.ty == Tarray)
3325             {
3326                 tdst = (cast(TypeArray)tdst).next.toBasetype();
3327                 if (tsrc.equivalent(tdst))
3328                 {
3329                     isBlockAssignment = true;
3330                     break;
3331                 }
3332             }
3333         }
3334 
3335         // ---------------------------------------
3336         //      Deal with reference assignment
3337         // ---------------------------------------
3338         // If it is a construction of a ref variable, it is a ref assignment
3339         if ((e.op == EXP.construct || e.op == EXP.blit) &&
3340             ((cast(AssignExp)e).memset == MemorySet.referenceInit))
3341         {
3342             assert(!fp);
3343 
3344             Expression newval = interpretRegion(e.e2, istate, CTFEGoal.LValue);
3345             if (exceptionOrCant(newval))
3346                 return;
3347 
3348             VarDeclaration v = e1.isVarExp().var.isVarDeclaration();
3349             setValue(v, newval);
3350 
3351             // Get the value to return. Note that 'newval' is an Lvalue,
3352             // so if we need an Rvalue, we have to interpret again.
3353             if (goal == CTFEGoal.RValue)
3354                 result = interpretRegion(newval, istate);
3355             else
3356                 result = e1; // VarExp is a CTFE reference
3357             return;
3358         }
3359 
3360         if (fp)
3361         {
3362             while (e1.op == EXP.cast_)
3363             {
3364                 CastExp ce = e1.isCastExp();
3365                 e1 = ce.e1;
3366             }
3367         }
3368 
3369         // ---------------------------------------
3370         //      Interpret left hand side
3371         // ---------------------------------------
3372         AssocArrayLiteralExp existingAA = null;
3373         Expression lastIndex = null;
3374         Expression oldval = null;
3375         if (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
3376         {
3377             // ---------------------------------------
3378             //      Deal with AA index assignment
3379             // ---------------------------------------
3380             /* This needs special treatment if the AA doesn't exist yet.
3381              * There are two special cases:
3382              * (1) If the AA is itself an index of another AA, we may need to create
3383              *     multiple nested AA literals before we can insert the new value.
3384              * (2) If the ultimate AA is null, no insertion happens at all. Instead,
3385              *     we create nested AA literals, and change it into a assignment.
3386              */
3387             IndexExp ie = e1.isIndexExp();
3388             int depth = 0; // how many nested AA indices are there?
3389             while (ie.e1.op == EXP.index && ie.e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
3390             {
3391                 assert(ie.modifiable);
3392                 ie = ie.e1.isIndexExp();
3393                 ++depth;
3394             }
3395 
3396             // Get the AA value to be modified.
3397             Expression aggregate = interpretRegion(ie.e1, istate);
3398             if (exceptionOrCant(aggregate))
3399                 return;
3400             if ((existingAA = aggregate.isAssocArrayLiteralExp()) !is null)
3401             {
3402                 // Normal case, ultimate parent AA already exists
3403                 // We need to walk from the deepest index up, checking that an AA literal
3404                 // already exists on each level.
3405                 lastIndex = interpretRegion(e1.isIndexExp().e2, istate);
3406                 lastIndex = resolveSlice(lastIndex); // only happens with AA assignment
3407                 if (exceptionOrCant(lastIndex))
3408                     return;
3409 
3410                 while (depth > 0)
3411                 {
3412                     // Walk the syntax tree to find the indexExp at this depth
3413                     IndexExp xe = e1.isIndexExp();
3414                     foreach (d; 0 .. depth)
3415                         xe = xe.e1.isIndexExp();
3416 
3417                     Expression ekey = interpretRegion(xe.e2, istate);
3418                     if (exceptionOrCant(ekey))
3419                         return;
3420                     UnionExp ekeyTmp = void;
3421                     ekey = resolveSlice(ekey, &ekeyTmp); // only happens with AA assignment
3422 
3423                     // Look up this index in it up in the existing AA, to get the next level of AA.
3424                     AssocArrayLiteralExp newAA = cast(AssocArrayLiteralExp)findKeyInAA(e.loc, existingAA, ekey);
3425                     if (exceptionOrCant(newAA))
3426                         return;
3427                     if (!newAA)
3428                     {
3429                         // Doesn't exist yet, create an empty AA...
3430                         auto keysx = new Expressions();
3431                         auto valuesx = new Expressions();
3432                         newAA = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
3433                         newAA.type = xe.type;
3434                         newAA.ownedByCtfe = OwnedBy.ctfe;
3435                         //... and insert it into the existing AA.
3436                         existingAA.keys.push(ekey);
3437                         existingAA.values.push(newAA);
3438                     }
3439                     existingAA = newAA;
3440                     --depth;
3441                 }
3442 
3443                 if (fp)
3444                 {
3445                     oldval = findKeyInAA(e.loc, existingAA, lastIndex);
3446                     if (!oldval)
3447                         oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
3448                 }
3449             }
3450             else
3451             {
3452                 /* The AA is currently null. 'aggregate' is actually a reference to
3453                  * whatever contains it. It could be anything: var, dotvarexp, ...
3454                  * We rewrite the assignment from:
3455                  *     aa[i][j] op= newval;
3456                  * into:
3457                  *     aa = [i:[j:T.init]];
3458                  *     aa[j] op= newval;
3459                  */
3460                 oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
3461 
3462                 Expression newaae = oldval;
3463                 while (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
3464                 {
3465                     Expression ekey = interpretRegion(e1.isIndexExp().e2, istate);
3466                     if (exceptionOrCant(ekey))
3467                         return;
3468                     ekey = resolveSlice(ekey); // only happens with AA assignment
3469 
3470                     auto keysx = new Expressions();
3471                     auto valuesx = new Expressions();
3472                     keysx.push(ekey);
3473                     valuesx.push(newaae);
3474 
3475                     auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
3476                     aae.type = e1.isIndexExp().e1.type;
3477                     aae.ownedByCtfe = OwnedBy.ctfe;
3478                     if (!existingAA)
3479                     {
3480                         existingAA = aae;
3481                         lastIndex = ekey;
3482                     }
3483                     newaae = aae;
3484                     e1 = e1.isIndexExp().e1;
3485                 }
3486 
3487                 // We must set to aggregate with newaae
3488                 e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
3489                 if (exceptionOrCant(e1))
3490                     return;
3491                 e1 = assignToLvalue(e, e1, newaae);
3492                 if (exceptionOrCant(e1))
3493                     return;
3494             }
3495             assert(existingAA && lastIndex);
3496             e1 = null; // stomp
3497         }
3498         else if (e1.op == EXP.arrayLength)
3499         {
3500             oldval = interpretRegion(e1, istate);
3501             if (exceptionOrCant(oldval))
3502                 return;
3503         }
3504         else if (e.op == EXP.construct || e.op == EXP.blit)
3505         {
3506             // Unless we have a simple var assignment, we're
3507             // only modifying part of the variable. So we need to make sure
3508             // that the parent variable exists.
3509             VarDeclaration ultimateVar = findParentVar(e1);
3510             if (auto ve = e1.isVarExp())
3511             {
3512                 VarDeclaration v = ve.var.isVarDeclaration();
3513                 assert(v);
3514                 if (v.storage_class & STC.out_)
3515                     goto L1;
3516             }
3517             else if (ultimateVar && !getValue(ultimateVar))
3518             {
3519                 Expression ex = interpretRegion(ultimateVar.type.defaultInitLiteral(e.loc), istate);
3520                 if (exceptionOrCant(ex))
3521                     return;
3522                 setValue(ultimateVar, ex);
3523             }
3524             else
3525                 goto L1;
3526         }
3527         else
3528         {
3529         L1:
3530             e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
3531             if (exceptionOrCant(e1))
3532                 return;
3533 
3534             if (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
3535             {
3536                 IndexExp ie = e1.isIndexExp();
3537                 assert(ie.e1.op == EXP.assocArrayLiteral);
3538                 existingAA = ie.e1.isAssocArrayLiteralExp();
3539                 lastIndex = ie.e2;
3540             }
3541         }
3542 
3543         // ---------------------------------------
3544         //      Interpret right hand side
3545         // ---------------------------------------
3546         Expression newval = interpretRegion(e.e2, istate);
3547         if (exceptionOrCant(newval))
3548             return;
3549         if (e.op == EXP.blit && newval.op == EXP.int64)
3550         {
3551             Type tbn = e.type.baseElemOf();
3552             if (tbn.ty == Tstruct)
3553             {
3554                 /* Look for special case of struct being initialized with 0.
3555                  */
3556                 newval = e.type.defaultInitLiteral(e.loc);
3557                 if (newval.op == EXP.error)
3558                 {
3559                     result = CTFEExp.cantexp;
3560                     return;
3561                 }
3562                 newval = interpretRegion(newval, istate); // copy and set ownedByCtfe flag
3563                 if (exceptionOrCant(newval))
3564                     return;
3565             }
3566         }
3567 
3568         // ----------------------------------------------------
3569         //  Deal with read-modify-write assignments.
3570         //  Set 'newval' to the final assignment value
3571         //  Also determine the return value (except for slice
3572         //  assignments, which are more complicated)
3573         // ----------------------------------------------------
3574         if (fp)
3575         {
3576             if (!oldval)
3577             {
3578                 // Load the left hand side after interpreting the right hand side.
3579                 oldval = interpretRegion(e1, istate);
3580                 if (exceptionOrCant(oldval))
3581                     return;
3582             }
3583 
3584             if (e.e1.type.ty != Tpointer)
3585             {
3586                 // ~= can create new values (see bug 6052)
3587                 if (e.op == EXP.concatenateAssign || e.op == EXP.concatenateElemAssign || e.op == EXP.concatenateDcharAssign)
3588                 {
3589                     // We need to dup it and repaint the type. For a dynamic array
3590                     // we can skip duplication, because it gets copied later anyway.
3591                     if (newval.type.ty != Tarray)
3592                     {
3593                         newval = copyLiteral(newval).copy();
3594                         newval.type = e.e2.type; // repaint type
3595                     }
3596                     else
3597                     {
3598                         newval = paintTypeOntoLiteral(e.e2.type, newval);
3599                         newval = resolveSlice(newval);
3600                     }
3601                 }
3602                 oldval = resolveSlice(oldval);
3603 
3604                 newval = (*fp)(e.loc, e.type, oldval, newval).copy();
3605             }
3606             else if (e.e2.type.isintegral() &&
3607                      (e.op == EXP.addAssign ||
3608                       e.op == EXP.minAssign ||
3609                       e.op == EXP.plusPlus ||
3610                       e.op == EXP.minusMinus))
3611             {
3612                 newval = pointerArithmetic(pue, e.loc, e.op, e.type, oldval, newval).copy();
3613                 if (newval == pue.exp())
3614                     newval = pue.copy();
3615             }
3616             else
3617             {
3618                 e.error("pointer expression `%s` cannot be interpreted at compile time", e.toChars());
3619                 result = CTFEExp.cantexp;
3620                 return;
3621             }
3622             if (exceptionOrCant(newval))
3623             {
3624                 if (CTFEExp.isCantExp(newval))
3625                     e.error("cannot interpret `%s` at compile time", e.toChars());
3626                 return;
3627             }
3628         }
3629 
3630         if (existingAA)
3631         {
3632             if (existingAA.ownedByCtfe != OwnedBy.ctfe)
3633             {
3634                 e.error("cannot modify read-only constant `%s`", existingAA.toChars());
3635                 result = CTFEExp.cantexp;
3636                 return;
3637             }
3638 
3639             //printf("\t+L%d existingAA = %s, lastIndex = %s, oldval = %s, newval = %s\n",
3640             //    __LINE__, existingAA.toChars(), lastIndex.toChars(), oldval ? oldval.toChars() : NULL, newval.toChars());
3641             assignAssocArrayElement(e.loc, existingAA, lastIndex, newval);
3642 
3643             // Determine the return value
3644             result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
3645             return;
3646         }
3647         if (e1.op == EXP.arrayLength)
3648         {
3649             /* Change the assignment from:
3650              *  arr.length = n;
3651              * into:
3652              *  arr = new_length_array; (result is n)
3653              */
3654 
3655             // Determine the return value
3656             result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
3657             if (exceptionOrCant(result))
3658                 return;
3659 
3660             if (result == pue.exp())
3661                 result = pue.copy();
3662 
3663             size_t oldlen = cast(size_t)oldval.toInteger();
3664             size_t newlen = cast(size_t)newval.toInteger();
3665             if (oldlen == newlen) // no change required -- we're done!
3666                 return;
3667 
3668             // We have changed it into a reference assignment
3669             // Note that returnValue is still the new length.
3670             e1 = e1.isArrayLengthExp().e1;
3671             Type t = e1.type.toBasetype();
3672             if (t.ty != Tarray)
3673             {
3674                 e.error("`%s` is not yet supported at compile time", e.toChars());
3675                 result = CTFEExp.cantexp;
3676                 return;
3677             }
3678             e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
3679             if (exceptionOrCant(e1))
3680                 return;
3681 
3682             if (oldlen != 0) // Get the old array literal.
3683                 oldval = interpretRegion(e1, istate);
3684             UnionExp utmp = void;
3685             oldval = resolveSlice(oldval, &utmp);
3686 
3687             newval = changeArrayLiteralLength(pue, e.loc, cast(TypeArray)t, oldval, oldlen, newlen);
3688             if (newval == pue.exp())
3689                 newval = pue.copy();
3690 
3691             e1 = assignToLvalue(e, e1, newval);
3692             if (exceptionOrCant(e1))
3693                 return;
3694 
3695             return;
3696         }
3697 
3698         if (!isBlockAssignment)
3699         {
3700             newval = ctfeCast(pue, e.loc, e.type, e.type, newval);
3701             if (exceptionOrCant(newval))
3702                 return;
3703             if (newval == pue.exp())
3704                 newval = pue.copy();
3705 
3706             // Determine the return value
3707             if (goal == CTFEGoal.LValue) // https://issues.dlang.org/show_bug.cgi?id=14371
3708                 result = e1;
3709             else
3710             {
3711                 result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
3712                 if (result == pue.exp())
3713                     result = pue.copy();
3714             }
3715             if (exceptionOrCant(result))
3716                 return;
3717         }
3718         if (exceptionOrCant(newval))
3719             return;
3720 
debug(LOGASSIGN)3721         debug (LOGASSIGN)
3722         {
3723             printf("ASSIGN: %s=%s\n", e1.toChars(), newval.toChars());
3724             showCtfeExpr(newval);
3725         }
3726 
3727         /* Block assignment or element-wise assignment.
3728          */
3729         if (e1.op == EXP.slice ||
3730             e1.op == EXP.vector ||
3731             e1.op == EXP.arrayLiteral ||
3732             e1.op == EXP.string_ ||
3733             e1.op == EXP.null_ && e1.type.toBasetype().ty == Tarray)
3734         {
3735             // Note that slice assignments don't support things like ++, so
3736             // we don't need to remember 'returnValue'.
3737             result = interpretAssignToSlice(pue, e, e1, newval, isBlockAssignment);
3738             if (exceptionOrCant(result))
3739                 return;
3740             if (auto se = e.e1.isSliceExp())
3741             {
3742                 Expression e1x = interpretRegion(se.e1, istate, CTFEGoal.LValue);
3743                 if (auto dve = e1x.isDotVarExp())
3744                 {
3745                     auto ex = dve.e1;
3746                     auto sle = ex.op == EXP.structLiteral ? ex.isStructLiteralExp()
3747                              : ex.op == EXP.classReference ? ex.isClassReferenceExp().value
3748                              : null;
3749                     auto v = dve.var.isVarDeclaration();
3750                     if (!sle || !v)
3751                     {
3752                         e.error("CTFE internal error: dotvar slice assignment");
3753                         result = CTFEExp.cantexp;
3754                         return;
3755                     }
3756                     stompOverlappedFields(sle, v);
3757                 }
3758             }
3759             return;
3760         }
3761         assert(result);
3762 
3763         /* Assignment to a CTFE reference.
3764          */
3765         if (Expression ex = assignToLvalue(e, e1, newval))
3766             result = ex;
3767 
3768         return;
3769     }
3770 
3771     /* Set all sibling fields which overlap with v to VoidExp.
3772      */
stompOverlappedFields(StructLiteralExp sle,VarDeclaration v)3773     private void stompOverlappedFields(StructLiteralExp sle, VarDeclaration v)
3774     {
3775         if (!v.overlapped)
3776             return;
3777         foreach (size_t i, v2; sle.sd.fields)
3778         {
3779             if (v is v2 || !v.isOverlappedWith(v2))
3780                 continue;
3781             auto e = (*sle.elements)[i];
3782             if (e.op != EXP.void_)
3783                 (*sle.elements)[i] = voidInitLiteral(e.type, v).copy();
3784         }
3785     }
3786 
assignToLvalue(BinExp e,Expression e1,Expression newval)3787     private Expression assignToLvalue(BinExp e, Expression e1, Expression newval)
3788     {
3789         //printf("assignToLvalue() e: %s e1: %s newval: %s\n", e.toChars(), e1.toChars(), newval.toChars());
3790         VarDeclaration vd = null;
3791         Expression* payload = null; // dead-store to prevent spurious warning
3792         Expression oldval;
3793 
3794         if (auto ve = e1.isVarExp())
3795         {
3796             vd = ve.var.isVarDeclaration();
3797             oldval = getValue(vd);
3798         }
3799         else if (auto dve = e1.isDotVarExp())
3800         {
3801             /* Assignment to member variable of the form:
3802              *  e.v = newval
3803              */
3804             auto ex = dve.e1;
3805             auto sle = ex.op == EXP.structLiteral ? ex.isStructLiteralExp()
3806                      : ex.op == EXP.classReference ? ex.isClassReferenceExp().value
3807                      : null;
3808             auto v = e1.isDotVarExp().var.isVarDeclaration();
3809             if (!sle || !v)
3810             {
3811                 e.error("CTFE internal error: dotvar assignment");
3812                 return CTFEExp.cantexp;
3813             }
3814             if (sle.ownedByCtfe != OwnedBy.ctfe)
3815             {
3816                 e.error("cannot modify read-only constant `%s`", sle.toChars());
3817                 return CTFEExp.cantexp;
3818             }
3819 
3820             int fieldi = ex.op == EXP.structLiteral ? findFieldIndexByName(sle.sd, v)
3821                        : ex.isClassReferenceExp().findFieldIndexByName(v);
3822             if (fieldi == -1)
3823             {
3824                 e.error("CTFE internal error: cannot find field `%s` in `%s`", v.toChars(), ex.toChars());
3825                 return CTFEExp.cantexp;
3826             }
3827             assert(0 <= fieldi && fieldi < sle.elements.dim);
3828 
3829             // If it's a union, set all other members of this union to void
3830             stompOverlappedFields(sle, v);
3831 
3832             payload = &(*sle.elements)[fieldi];
3833             oldval = *payload;
3834             if (auto ival = newval.isIntegerExp())
3835             {
3836                 if (auto bf = v.isBitFieldDeclaration())
3837                 {
3838                     sinteger_t value = ival.toInteger();
3839                     if (bf.type.isunsigned())
3840                         value &= (1L << bf.fieldWidth) - 1; // zero extra bits
3841                     else
3842                     {   // sign extend extra bits
3843                         value = value << (64 - bf.fieldWidth);
3844                         value = value >> (64 - bf.fieldWidth);
3845                     }
3846                     ival.setInteger(value);
3847                 }
3848             }
3849         }
3850         else if (auto ie = e1.isIndexExp())
3851         {
3852             assert(ie.e1.type.toBasetype().ty != Taarray);
3853 
3854             Expression aggregate;
3855             uinteger_t indexToModify;
3856             if (!resolveIndexing(ie, istate, &aggregate, &indexToModify, true))
3857             {
3858                 return CTFEExp.cantexp;
3859             }
3860             size_t index = cast(size_t)indexToModify;
3861 
3862             if (auto existingSE = aggregate.isStringExp())
3863             {
3864                 if (existingSE.ownedByCtfe != OwnedBy.ctfe)
3865                 {
3866                     e.error("cannot modify read-only string literal `%s`", ie.e1.toChars());
3867                     return CTFEExp.cantexp;
3868                 }
3869                 existingSE.setCodeUnit(index, cast(dchar)newval.toInteger());
3870                 return null;
3871             }
3872             if (aggregate.op != EXP.arrayLiteral)
3873             {
3874                 e.error("index assignment `%s` is not yet supported in CTFE ", e.toChars());
3875                 return CTFEExp.cantexp;
3876             }
3877 
3878             ArrayLiteralExp existingAE = aggregate.isArrayLiteralExp();
3879             if (existingAE.ownedByCtfe != OwnedBy.ctfe)
3880             {
3881                 e.error("cannot modify read-only constant `%s`", existingAE.toChars());
3882                 return CTFEExp.cantexp;
3883             }
3884 
3885             payload = &(*existingAE.elements)[index];
3886             oldval = *payload;
3887         }
3888         else
3889         {
3890             e.error("`%s` cannot be evaluated at compile time", e.toChars());
3891             return CTFEExp.cantexp;
3892         }
3893 
3894         Type t1b = e1.type.toBasetype();
3895         bool wantCopy = t1b.baseElemOf().ty == Tstruct;
3896 
3897         if (auto ve = newval.isVectorExp())
3898         {
3899             // Ensure ve is an array literal, and not a broadcast
3900             if (ve.e1.op == EXP.int64 || ve.e1.op == EXP.float64) // if broadcast
3901             {
3902                 UnionExp ue = void;
3903                 Expression ex = interpretVectorToArray(&ue, ve);
3904                 ve.e1 = (ex == ue.exp()) ? ue.copy() : ex;
3905             }
3906         }
3907 
3908         if (newval.op == EXP.structLiteral && oldval)
3909         {
3910             assert(oldval.op == EXP.structLiteral || oldval.op == EXP.arrayLiteral || oldval.op == EXP.string_);
3911             newval = copyLiteral(newval).copy();
3912             assignInPlace(oldval, newval);
3913         }
3914         else if (wantCopy && e.op == EXP.assign)
3915         {
3916             // Currently postblit/destructor calls on static array are done
3917             // in the druntime internal functions so they don't appear in AST.
3918             // Therefore interpreter should handle them specially.
3919 
3920             assert(oldval);
3921             version (all) // todo: instead we can directly access to each elements of the slice
3922             {
3923                 newval = resolveSlice(newval);
3924                 if (CTFEExp.isCantExp(newval))
3925                 {
3926                     e.error("CTFE internal error: assignment `%s`", e.toChars());
3927                     return CTFEExp.cantexp;
3928                 }
3929             }
3930             assert(oldval.op == EXP.arrayLiteral);
3931             assert(newval.op == EXP.arrayLiteral);
3932 
3933             Expressions* oldelems = oldval.isArrayLiteralExp().elements;
3934             Expressions* newelems = newval.isArrayLiteralExp().elements;
3935             assert(oldelems.dim == newelems.dim);
3936 
3937             Type elemtype = oldval.type.nextOf();
3938             foreach (i, ref oldelem; *oldelems)
3939             {
3940                 Expression newelem = paintTypeOntoLiteral(elemtype, (*newelems)[i]);
3941                 // https://issues.dlang.org/show_bug.cgi?id=9245
3942                 if (e.e2.isLvalue())
3943                 {
3944                     if (Expression ex = evaluatePostblit(istate, newelem))
3945                         return ex;
3946                 }
3947                 // https://issues.dlang.org/show_bug.cgi?id=13661
3948                 if (Expression ex = evaluateDtor(istate, oldelem))
3949                     return ex;
3950                 oldelem = newelem;
3951             }
3952         }
3953         else
3954         {
3955             // e1 has its own payload, so we have to create a new literal.
3956             if (wantCopy)
3957                 newval = copyLiteral(newval).copy();
3958 
3959             if (t1b.ty == Tsarray && e.op == EXP.construct && e.e2.isLvalue())
3960             {
3961                 // https://issues.dlang.org/show_bug.cgi?id=9245
3962                 if (Expression ex = evaluatePostblit(istate, newval))
3963                     return ex;
3964             }
3965 
3966             oldval = newval;
3967         }
3968 
3969         if (vd)
3970             setValue(vd, oldval);
3971         else
3972             *payload = oldval;
3973 
3974         // Blit assignment should return the newly created value.
3975         if (e.op == EXP.blit)
3976             return oldval;
3977 
3978         return null;
3979     }
3980 
3981     /*************
3982      * Deal with assignments of the form:
3983      *  dest[] = newval
3984      *  dest[low..upp] = newval
3985      * where newval has already been interpreted
3986      *
3987      * This could be a slice assignment or a block assignment, and
3988      * dest could be either an array literal, or a string.
3989      *
3990      * Returns EXP.cantExpression on failure. If there are no errors,
3991      * it returns aggregate[low..upp], except that as an optimisation,
3992      * if goal == CTFEGoal.Nothing, it will return NULL
3993      */
interpretAssignToSlice(UnionExp * pue,BinExp e,Expression e1,Expression newval,bool isBlockAssignment)3994     private Expression interpretAssignToSlice(UnionExp* pue, BinExp e, Expression e1, Expression newval, bool isBlockAssignment)
3995     {
3996         dinteger_t lowerbound;
3997         dinteger_t upperbound;
3998         dinteger_t firstIndex;
3999 
4000         Expression aggregate;
4001 
4002         if (auto se = e1.isSliceExp())
4003         {
4004             // ------------------------------
4005             //   aggregate[] = newval
4006             //   aggregate[low..upp] = newval
4007             // ------------------------------
4008             aggregate = interpretRegion(se.e1, istate);
4009             lowerbound = se.lwr ? se.lwr.toInteger() : 0;
4010             upperbound = se.upr ? se.upr.toInteger() : resolveArrayLength(aggregate);
4011 
4012             // Slice of a slice --> change the bounds
4013             if (auto oldse = aggregate.isSliceExp())
4014             {
4015                 aggregate = oldse.e1;
4016                 firstIndex = lowerbound + oldse.lwr.toInteger();
4017             }
4018             else
4019                 firstIndex = lowerbound;
4020         }
4021         else
4022         {
4023             if (auto ale = e1.isArrayLiteralExp())
4024             {
4025                 lowerbound = 0;
4026                 upperbound = ale.elements.dim;
4027             }
4028             else if (auto se = e1.isStringExp())
4029             {
4030                 lowerbound = 0;
4031                 upperbound = se.len;
4032             }
4033             else if (e1.op == EXP.null_)
4034             {
4035                 lowerbound = 0;
4036                 upperbound = 0;
4037             }
4038             else if (VectorExp ve = e1.isVectorExp())
4039             {
4040                 // ve is not handled but a proper error message is returned
4041                 // this is to prevent https://issues.dlang.org/show_bug.cgi?id=20042
4042                 lowerbound = 0;
4043                 upperbound = ve.dim;
4044             }
4045             else
4046                 assert(0);
4047 
4048             aggregate = e1;
4049             firstIndex = lowerbound;
4050         }
4051         if (upperbound == lowerbound)
4052             return newval;
4053 
4054         // For slice assignment, we check that the lengths match.
4055         if (!isBlockAssignment)
4056         {
4057             const srclen = resolveArrayLength(newval);
4058             if (srclen != (upperbound - lowerbound))
4059             {
4060                 e.error("array length mismatch assigning `[0..%llu]` to `[%llu..%llu]`",
4061                     ulong(srclen), ulong(lowerbound), ulong(upperbound));
4062                 return CTFEExp.cantexp;
4063             }
4064         }
4065 
4066         if (auto existingSE = aggregate.isStringExp())
4067         {
4068             if (existingSE.ownedByCtfe != OwnedBy.ctfe)
4069             {
4070                 e.error("cannot modify read-only string literal `%s`", existingSE.toChars());
4071                 return CTFEExp.cantexp;
4072             }
4073 
4074             if (auto se = newval.isSliceExp())
4075             {
4076                 auto aggr2 = se.e1;
4077                 const srclower = se.lwr.toInteger();
4078                 const srcupper = se.upr.toInteger();
4079 
4080                 if (aggregate == aggr2 &&
4081                     lowerbound < srcupper && srclower < upperbound)
4082                 {
4083                     e.error("overlapping slice assignment `[%llu..%llu] = [%llu..%llu]`",
4084                         ulong(lowerbound), ulong(upperbound), ulong(srclower), ulong(srcupper));
4085                     return CTFEExp.cantexp;
4086                 }
4087                 version (all) // todo: instead we can directly access to each elements of the slice
4088                 {
4089                     Expression orignewval = newval;
4090                     newval = resolveSlice(newval);
4091                     if (CTFEExp.isCantExp(newval))
4092                     {
4093                         e.error("CTFE internal error: slice `%s`", orignewval.toChars());
4094                         return CTFEExp.cantexp;
4095                     }
4096                 }
4097                 assert(newval.op != EXP.slice);
4098             }
4099             if (auto se = newval.isStringExp())
4100             {
4101                 sliceAssignStringFromString(existingSE, se, cast(size_t)firstIndex);
4102                 return newval;
4103             }
4104             if (auto ale = newval.isArrayLiteralExp())
4105             {
4106                 /* Mixed slice: it was initialized as a string literal.
4107                  * Now a slice of it is being set with an array literal.
4108                  */
4109                 sliceAssignStringFromArrayLiteral(existingSE, ale, cast(size_t)firstIndex);
4110                 return newval;
4111             }
4112 
4113             // String literal block slice assign
4114             const value = cast(dchar)newval.toInteger();
4115             foreach (i; 0 .. upperbound - lowerbound)
4116             {
4117                 existingSE.setCodeUnit(cast(size_t)(i + firstIndex), value);
4118             }
4119             if (goal == CTFEGoal.Nothing)
4120                 return null; // avoid creating an unused literal
4121             auto retslice = ctfeEmplaceExp!SliceExp(e.loc, existingSE,
4122                         ctfeEmplaceExp!IntegerExp(e.loc, firstIndex, Type.tsize_t),
4123                         ctfeEmplaceExp!IntegerExp(e.loc, firstIndex + upperbound - lowerbound, Type.tsize_t));
4124             retslice.type = e.type;
4125             return interpret(pue, retslice, istate);
4126         }
4127         if (auto existingAE = aggregate.isArrayLiteralExp())
4128         {
4129             if (existingAE.ownedByCtfe != OwnedBy.ctfe)
4130             {
4131                 e.error("cannot modify read-only constant `%s`", existingAE.toChars());
4132                 return CTFEExp.cantexp;
4133             }
4134 
4135             if (newval.op == EXP.slice && !isBlockAssignment)
4136             {
4137                 auto se = newval.isSliceExp();
4138                 auto aggr2 = se.e1;
4139                 const srclower = se.lwr.toInteger();
4140                 const srcupper = se.upr.toInteger();
4141                 const wantCopy = (newval.type.toBasetype().nextOf().baseElemOf().ty == Tstruct);
4142 
4143                 //printf("oldval = %p %s[%d..%u]\nnewval = %p %s[%llu..%llu] wantCopy = %d\n",
4144                 //    aggregate, aggregate.toChars(), lowerbound, upperbound,
4145                 //    aggr2, aggr2.toChars(), srclower, srcupper, wantCopy);
4146                 if (wantCopy)
4147                 {
4148                     // Currently overlapping for struct array is allowed.
4149                     // The order of elements processing depends on the overlapping.
4150                     // https://issues.dlang.org/show_bug.cgi?id=14024
4151                     assert(aggr2.op == EXP.arrayLiteral);
4152                     Expressions* oldelems = existingAE.elements;
4153                     Expressions* newelems = aggr2.isArrayLiteralExp().elements;
4154 
4155                     Type elemtype = aggregate.type.nextOf();
4156                     bool needsPostblit = e.e2.isLvalue();
4157 
4158                     if (aggregate == aggr2 && srclower < lowerbound && lowerbound < srcupper)
4159                     {
4160                         // reverse order
4161                         for (auto i = upperbound - lowerbound; 0 < i--;)
4162                         {
4163                             Expression oldelem = (*oldelems)[cast(size_t)(i + firstIndex)];
4164                             Expression newelem = (*newelems)[cast(size_t)(i + srclower)];
4165                             newelem = copyLiteral(newelem).copy();
4166                             newelem.type = elemtype;
4167                             if (needsPostblit)
4168                             {
4169                                 if (Expression x = evaluatePostblit(istate, newelem))
4170                                     return x;
4171                             }
4172                             if (Expression x = evaluateDtor(istate, oldelem))
4173                                 return x;
4174                             (*oldelems)[cast(size_t)(lowerbound + i)] = newelem;
4175                         }
4176                     }
4177                     else
4178                     {
4179                         // normal order
4180                         for (auto i = 0; i < upperbound - lowerbound; i++)
4181                         {
4182                             Expression oldelem = (*oldelems)[cast(size_t)(i + firstIndex)];
4183                             Expression newelem = (*newelems)[cast(size_t)(i + srclower)];
4184                             newelem = copyLiteral(newelem).copy();
4185                             newelem.type = elemtype;
4186                             if (needsPostblit)
4187                             {
4188                                 if (Expression x = evaluatePostblit(istate, newelem))
4189                                     return x;
4190                             }
4191                             if (Expression x = evaluateDtor(istate, oldelem))
4192                                 return x;
4193                             (*oldelems)[cast(size_t)(lowerbound + i)] = newelem;
4194                         }
4195                     }
4196 
4197                     //assert(0);
4198                     return newval; // oldval?
4199                 }
4200                 if (aggregate == aggr2 &&
4201                     lowerbound < srcupper && srclower < upperbound)
4202                 {
4203                     e.error("overlapping slice assignment `[%llu..%llu] = [%llu..%llu]`",
4204                         ulong(lowerbound), ulong(upperbound), ulong(srclower), ulong(srcupper));
4205                     return CTFEExp.cantexp;
4206                 }
4207                 version (all) // todo: instead we can directly access to each elements of the slice
4208                 {
4209                     Expression orignewval = newval;
4210                     newval = resolveSlice(newval);
4211                     if (CTFEExp.isCantExp(newval))
4212                     {
4213                         e.error("CTFE internal error: slice `%s`", orignewval.toChars());
4214                         return CTFEExp.cantexp;
4215                     }
4216                 }
4217                 // no overlapping
4218                 //length?
4219                 assert(newval.op != EXP.slice);
4220             }
4221             if (newval.op == EXP.string_ && !isBlockAssignment)
4222             {
4223                 /* Mixed slice: it was initialized as an array literal of chars/integers.
4224                  * Now a slice of it is being set with a string.
4225                  */
4226                 sliceAssignArrayLiteralFromString(existingAE, newval.isStringExp(), cast(size_t)firstIndex);
4227                 return newval;
4228             }
4229             if (newval.op == EXP.arrayLiteral && !isBlockAssignment)
4230             {
4231                 Expressions* oldelems = existingAE.elements;
4232                 Expressions* newelems = newval.isArrayLiteralExp().elements;
4233                 Type elemtype = existingAE.type.nextOf();
4234                 bool needsPostblit = e.op != EXP.blit && e.e2.isLvalue();
4235                 foreach (j, newelem; *newelems)
4236                 {
4237                     newelem = paintTypeOntoLiteral(elemtype, newelem);
4238                     if (needsPostblit)
4239                     {
4240                         Expression x = evaluatePostblit(istate, newelem);
4241                         if (exceptionOrCantInterpret(x))
4242                             return x;
4243                     }
4244                     (*oldelems)[cast(size_t)(j + firstIndex)] = newelem;
4245                 }
4246                 return newval;
4247             }
4248 
4249             /* Block assignment, initialization of static arrays
4250              *   x[] = newval
4251              *  x may be a multidimensional static array. (Note that this
4252              *  only happens with array literals, never with strings).
4253              */
4254             struct RecursiveBlock
4255             {
4256                 InterState* istate;
4257                 Expression newval;
4258                 bool refCopy;
4259                 bool needsPostblit;
4260                 bool needsDtor;
4261 
4262                 extern (C++) Expression assignTo(ArrayLiteralExp ae)
4263                 {
4264                     return assignTo(ae, 0, ae.elements.dim);
4265                 }
4266 
4267                 extern (C++) Expression assignTo(ArrayLiteralExp ae, size_t lwr, size_t upr)
4268                 {
4269                     Expressions* w = ae.elements;
4270                     assert(ae.type.ty == Tsarray || ae.type.ty == Tarray);
4271                     bool directblk = (cast(TypeArray)ae.type).next.equivalent(newval.type);
4272                     for (size_t k = lwr; k < upr; k++)
4273                     {
4274                         if (!directblk && (*w)[k].op == EXP.arrayLiteral)
4275                         {
4276                             // Multidimensional array block assign
4277                             if (Expression ex = assignTo((*w)[k].isArrayLiteralExp()))
4278                                 return ex;
4279                         }
4280                         else if (refCopy)
4281                         {
4282                             (*w)[k] = newval;
4283                         }
4284                         else if (!needsPostblit && !needsDtor)
4285                         {
4286                             assignInPlace((*w)[k], newval);
4287                         }
4288                         else
4289                         {
4290                             Expression oldelem = (*w)[k];
4291                             Expression tmpelem = needsDtor ? copyLiteral(oldelem).copy() : null;
4292                             assignInPlace(oldelem, newval);
4293                             if (needsPostblit)
4294                             {
4295                                 if (Expression ex = evaluatePostblit(istate, oldelem))
4296                                     return ex;
4297                             }
4298                             if (needsDtor)
4299                             {
4300                                 // https://issues.dlang.org/show_bug.cgi?id=14860
4301                                 if (Expression ex = evaluateDtor(istate, tmpelem))
4302                                     return ex;
4303                             }
4304                         }
4305                     }
4306                     return null;
4307                 }
4308             }
4309 
4310             Type tn = newval.type.toBasetype();
4311             bool wantRef = (tn.ty == Tarray || isAssocArray(tn) || tn.ty == Tclass);
4312             bool cow = newval.op != EXP.structLiteral && newval.op != EXP.arrayLiteral && newval.op != EXP.string_;
4313             Type tb = tn.baseElemOf();
4314             StructDeclaration sd = (tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null);
4315 
4316             RecursiveBlock rb;
4317             rb.istate = istate;
4318             rb.newval = newval;
4319             rb.refCopy = wantRef || cow;
4320             rb.needsPostblit = sd && sd.postblit && e.op != EXP.blit && e.e2.isLvalue();
4321             rb.needsDtor = sd && sd.dtor && e.op == EXP.assign;
4322             if (Expression ex = rb.assignTo(existingAE, cast(size_t)lowerbound, cast(size_t)upperbound))
4323                 return ex;
4324 
4325             if (goal == CTFEGoal.Nothing)
4326                 return null; // avoid creating an unused literal
4327             auto retslice = ctfeEmplaceExp!SliceExp(e.loc, existingAE,
4328                 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex, Type.tsize_t),
4329                 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex + upperbound - lowerbound, Type.tsize_t));
4330             retslice.type = e.type;
4331             return interpret(pue, retslice, istate);
4332         }
4333 
4334         e.error("slice operation `%s = %s` cannot be evaluated at compile time", e1.toChars(), newval.toChars());
4335         return CTFEExp.cantexp;
4336     }
4337 
visit(AssignExp e)4338     override void visit(AssignExp e)
4339     {
4340         interpretAssignCommon(e, null);
4341     }
4342 
visit(BinAssignExp e)4343     override void visit(BinAssignExp e)
4344     {
4345         switch (e.op)
4346         {
4347         case EXP.addAssign:
4348             interpretAssignCommon(e, &Add);
4349             return;
4350 
4351         case EXP.minAssign:
4352             interpretAssignCommon(e, &Min);
4353             return;
4354 
4355         case EXP.concatenateAssign:
4356         case EXP.concatenateElemAssign:
4357         case EXP.concatenateDcharAssign:
4358             interpretAssignCommon(e, &ctfeCat);
4359             return;
4360 
4361         case EXP.mulAssign:
4362             interpretAssignCommon(e, &Mul);
4363             return;
4364 
4365         case EXP.divAssign:
4366             interpretAssignCommon(e, &Div);
4367             return;
4368 
4369         case EXP.modAssign:
4370             interpretAssignCommon(e, &Mod);
4371             return;
4372 
4373         case EXP.leftShiftAssign:
4374             interpretAssignCommon(e, &Shl);
4375             return;
4376 
4377         case EXP.rightShiftAssign:
4378             interpretAssignCommon(e, &Shr);
4379             return;
4380 
4381         case EXP.unsignedRightShiftAssign:
4382             interpretAssignCommon(e, &Ushr);
4383             return;
4384 
4385         case EXP.andAssign:
4386             interpretAssignCommon(e, &And);
4387             return;
4388 
4389         case EXP.orAssign:
4390             interpretAssignCommon(e, &Or);
4391             return;
4392 
4393         case EXP.xorAssign:
4394             interpretAssignCommon(e, &Xor);
4395             return;
4396 
4397         case EXP.powAssign:
4398             interpretAssignCommon(e, &Pow);
4399             return;
4400 
4401         default:
4402             assert(0);
4403         }
4404     }
4405 
visit(PostExp e)4406     override void visit(PostExp e)
4407     {
4408         debug (LOG)
4409         {
4410             printf("%s PostExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4411         }
4412         if (e.op == EXP.plusPlus)
4413             interpretAssignCommon(e, &Add, 1);
4414         else
4415             interpretAssignCommon(e, &Min, 1);
4416         debug (LOG)
4417         {
4418             if (CTFEExp.isCantExp(result))
4419                 printf("PostExp::interpret() CANT\n");
4420         }
4421     }
4422 
4423     /* Return 1 if e is a p1 > p2 or p1 >= p2 pointer comparison;
4424      *       -1 if e is a p1 < p2 or p1 <= p2 pointer comparison;
4425      *        0 otherwise
4426      */
isPointerCmpExp(Expression e,Expression * p1,Expression * p2)4427     static int isPointerCmpExp(Expression e, Expression* p1, Expression* p2)
4428     {
4429         int ret = 1;
4430         while (e.op == EXP.not)
4431         {
4432             ret *= -1;
4433             e = e.isNotExp().e1;
4434         }
4435         switch (e.op)
4436         {
4437         case EXP.lessThan:
4438         case EXP.lessOrEqual:
4439             ret *= -1;
4440             goto case; /+ fall through +/
4441         case EXP.greaterThan:
4442         case EXP.greaterOrEqual:
4443             *p1 = e.isBinExp().e1;
4444             *p2 = e.isBinExp().e2;
4445             if (!(isPointer((*p1).type) && isPointer((*p2).type)))
4446                 ret = 0;
4447             break;
4448 
4449         default:
4450             ret = 0;
4451             break;
4452         }
4453         return ret;
4454     }
4455 
4456     /** If this is a four pointer relation, evaluate it, else return NULL.
4457      *
4458      *  This is an expression of the form (p1 > q1 && p2 < q2) or (p1 < q1 || p2 > q2)
4459      *  where p1, p2 are expressions yielding pointers to memory block p,
4460      *  and q1, q2 are expressions yielding pointers to memory block q.
4461      *  This expression is valid even if p and q are independent memory
4462      *  blocks and are therefore not normally comparable; the && form returns true
4463      *  if [p1..p2] lies inside [q1..q2], and false otherwise; the || form returns
4464      *  true if [p1..p2] lies outside [q1..q2], and false otherwise.
4465      *
4466      *  Within the expression, any ordering of p1, p2, q1, q2 is permissible;
4467      *  the comparison operators can be any of >, <, <=, >=, provided that
4468      *  both directions (p > q and p < q) are checked. Additionally the
4469      *  relational sub-expressions can be negated, eg
4470      *  (!(q1 < p1) && p2 <= q2) is valid.
4471      */
interpretFourPointerRelation(UnionExp * pue,BinExp e)4472     private void interpretFourPointerRelation(UnionExp* pue, BinExp e)
4473     {
4474         assert(e.op == EXP.andAnd || e.op == EXP.orOr);
4475 
4476         /*  It can only be an isInside expression, if both e1 and e2 are
4477          *  directional pointer comparisons.
4478          *  Note that this check can be made statically; it does not depends on
4479          *  any runtime values. This allows a JIT implementation to compile a
4480          *  special AndAndPossiblyInside, keeping the normal AndAnd case efficient.
4481          */
4482 
4483         // Save the pointer expressions and the comparison directions,
4484         // so we can use them later.
4485         Expression p1 = null;
4486         Expression p2 = null;
4487         Expression p3 = null;
4488         Expression p4 = null;
4489         int dir1 = isPointerCmpExp(e.e1, &p1, &p2);
4490         int dir2 = isPointerCmpExp(e.e2, &p3, &p4);
4491         if (dir1 == 0 || dir2 == 0)
4492         {
4493             result = null;
4494             return;
4495         }
4496 
4497         //printf("FourPointerRelation %s\n", toChars());
4498 
4499         UnionExp ue1 = void;
4500         UnionExp ue2 = void;
4501         UnionExp ue3 = void;
4502         UnionExp ue4 = void;
4503 
4504         // Evaluate the first two pointers
4505         p1 = interpret(&ue1, p1, istate);
4506         if (exceptionOrCant(p1))
4507             return;
4508         p2 = interpret(&ue2, p2, istate);
4509         if (exceptionOrCant(p2))
4510             return;
4511         dinteger_t ofs1, ofs2;
4512         Expression agg1 = getAggregateFromPointer(p1, &ofs1);
4513         Expression agg2 = getAggregateFromPointer(p2, &ofs2);
4514 
4515         if (!pointToSameMemoryBlock(agg1, agg2) && agg1.op != EXP.null_ && agg2.op != EXP.null_)
4516         {
4517             // Here it is either CANT_INTERPRET,
4518             // or an IsInside comparison returning false.
4519             p3 = interpret(&ue3, p3, istate);
4520             if (CTFEExp.isCantExp(p3))
4521                 return;
4522             // Note that it is NOT legal for it to throw an exception!
4523             Expression except = null;
4524             if (exceptionOrCantInterpret(p3))
4525                 except = p3;
4526             else
4527             {
4528                 p4 = interpret(&ue4, p4, istate);
4529                 if (CTFEExp.isCantExp(p4))
4530                 {
4531                     result = p4;
4532                     return;
4533                 }
4534                 if (exceptionOrCantInterpret(p4))
4535                     except = p4;
4536             }
4537             if (except)
4538             {
4539                 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());
4540                 result = CTFEExp.cantexp;
4541                 return;
4542             }
4543             dinteger_t ofs3, ofs4;
4544             Expression agg3 = getAggregateFromPointer(p3, &ofs3);
4545             Expression agg4 = getAggregateFromPointer(p4, &ofs4);
4546             // The valid cases are:
4547             // p1 > p2 && p3 > p4  (same direction, also for < && <)
4548             // p1 > p2 && p3 < p4  (different direction, also < && >)
4549             // Changing any > into >= doesn't affect the result
4550             if ((dir1 == dir2 && pointToSameMemoryBlock(agg1, agg4) && pointToSameMemoryBlock(agg2, agg3)) ||
4551                 (dir1 != dir2 && pointToSameMemoryBlock(agg1, agg3) && pointToSameMemoryBlock(agg2, agg4)))
4552             {
4553                 // it's a legal two-sided comparison
4554                 emplaceExp!(IntegerExp)(pue, e.loc, (e.op == EXP.andAnd) ? 0 : 1, e.type);
4555                 result = pue.exp();
4556                 return;
4557             }
4558             // It's an invalid four-pointer comparison. Either the second
4559             // comparison is in the same direction as the first, or else
4560             // more than two memory blocks are involved (either two independent
4561             // invalid comparisons are present, or else agg3 == agg4).
4562             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());
4563             result = CTFEExp.cantexp;
4564             return;
4565         }
4566         // The first pointer expression didn't need special treatment, so we
4567         // we need to interpret the entire expression exactly as a normal && or ||.
4568         // This is easy because we haven't evaluated e2 at all yet, and we already
4569         // know it will return a bool.
4570         // But we mustn't evaluate the pointer expressions in e1 again, in case
4571         // they have side-effects.
4572         bool nott = false;
4573         Expression ex = e.e1;
4574         while (1)
4575         {
4576             if (auto ne = ex.isNotExp())
4577             {
4578                 nott = !nott;
4579                 ex = ne.e1;
4580             }
4581             else
4582                 break;
4583         }
4584 
4585         /** Negate relational operator, eg >= becomes <
4586          * Params:
4587          *      op = comparison operator to negate
4588          * Returns:
4589          *      negate operator
4590          */
4591         static EXP negateRelation(EXP op) pure
4592         {
4593             switch (op)
4594             {
4595                 case EXP.greaterOrEqual:  op = EXP.lessThan;       break;
4596                 case EXP.greaterThan:     op = EXP.lessOrEqual;    break;
4597                 case EXP.lessOrEqual:     op = EXP.greaterThan;    break;
4598                 case EXP.lessThan:        op = EXP.greaterOrEqual; break;
4599                 default:                  assert(0);
4600             }
4601             return op;
4602         }
4603 
4604         const EXP cmpop = nott ? negateRelation(ex.op) : ex.op;
4605         const cmp = comparePointers(cmpop, agg1, ofs1, agg2, ofs2);
4606         // We already know this is a valid comparison.
4607         assert(cmp >= 0);
4608         if (e.op == EXP.andAnd && cmp == 1 || e.op == EXP.orOr && cmp == 0)
4609         {
4610             result = interpret(pue, e.e2, istate);
4611             return;
4612         }
4613         emplaceExp!(IntegerExp)(pue, e.loc, (e.op == EXP.andAnd) ? 0 : 1, e.type);
4614         result = pue.exp();
4615     }
4616 
visit(LogicalExp e)4617     override void visit(LogicalExp e)
4618     {
4619         debug (LOG)
4620         {
4621             printf("%s LogicalExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4622         }
4623         // Check for an insidePointer expression, evaluate it if so
4624         interpretFourPointerRelation(pue, e);
4625         if (result)
4626             return;
4627 
4628         UnionExp ue1 = void;
4629         result = interpret(&ue1, e.e1, istate);
4630         if (exceptionOrCant(result))
4631             return;
4632 
4633         bool res;
4634         const andand = e.op == EXP.andAnd;
4635         if (andand ? result.toBool().hasValue(false) : isTrueBool(result))
4636             res = !andand;
4637         else if (andand ? isTrueBool(result) : result.toBool().hasValue(false))
4638         {
4639             UnionExp ue2 = void;
4640             result = interpret(&ue2, e.e2, istate);
4641             if (exceptionOrCant(result))
4642                 return;
4643             if (result.op == EXP.voidExpression)
4644             {
4645                 assert(e.type.ty == Tvoid);
4646                 result = null;
4647                 return;
4648             }
4649             if (result.toBool().hasValue(false))
4650                 res = false;
4651             else if (isTrueBool(result))
4652                 res = true;
4653             else
4654             {
4655                 e.error("`%s` does not evaluate to a `bool`", result.toChars());
4656                 result = CTFEExp.cantexp;
4657                 return;
4658             }
4659         }
4660         else
4661         {
4662             e.error("`%s` cannot be interpreted as a `bool`", result.toChars());
4663             result = CTFEExp.cantexp;
4664             return;
4665         }
4666         incUsageCtfe(istate, e.e2.loc);
4667 
4668         if (goal != CTFEGoal.Nothing)
4669         {
4670             if (e.type.equals(Type.tbool))
4671                 result = IntegerExp.createBool(res);
4672             else
4673             {
4674                 emplaceExp!(IntegerExp)(pue, e.loc, res, e.type);
4675                 result = pue.exp();
4676             }
4677         }
4678     }
4679 
4680 
4681     // Print a stack trace, starting from callingExp which called fd.
4682     // To shorten the stack trace, try to detect recursion.
showCtfeBackTrace(CallExp callingExp,FuncDeclaration fd)4683     private void showCtfeBackTrace(CallExp callingExp, FuncDeclaration fd)
4684     {
4685         if (ctfeGlobals.stackTraceCallsToSuppress > 0)
4686         {
4687             --ctfeGlobals.stackTraceCallsToSuppress;
4688             return;
4689         }
4690         errorSupplemental(callingExp.loc, "called from here: `%s`", callingExp.toChars());
4691         // Quit if it's not worth trying to compress the stack trace
4692         if (ctfeGlobals.callDepth < 6 || global.params.verbose)
4693             return;
4694         // Recursion happens if the current function already exists in the call stack.
4695         int numToSuppress = 0;
4696         int recurseCount = 0;
4697         int depthSoFar = 0;
4698         InterState* lastRecurse = istate;
4699         for (InterState* cur = istate; cur; cur = cur.caller)
4700         {
4701             if (cur.fd == fd)
4702             {
4703                 ++recurseCount;
4704                 numToSuppress = depthSoFar;
4705                 lastRecurse = cur;
4706             }
4707             ++depthSoFar;
4708         }
4709         // We need at least three calls to the same function, to make compression worthwhile
4710         if (recurseCount < 2)
4711             return;
4712         // We found a useful recursion.  Print all the calls involved in the recursion
4713         errorSupplemental(fd.loc, "%d recursive calls to function `%s`", recurseCount, fd.toChars());
4714         for (InterState* cur = istate; cur.fd != fd; cur = cur.caller)
4715         {
4716             errorSupplemental(cur.fd.loc, "recursively called from function `%s`", cur.fd.toChars());
4717         }
4718         // We probably didn't enter the recursion in this function.
4719         // Go deeper to find the real beginning.
4720         InterState* cur = istate;
4721         while (lastRecurse.caller && cur.fd == lastRecurse.caller.fd)
4722         {
4723             cur = cur.caller;
4724             lastRecurse = lastRecurse.caller;
4725             ++numToSuppress;
4726         }
4727         ctfeGlobals.stackTraceCallsToSuppress = numToSuppress;
4728     }
4729 
visit(CallExp e)4730     override void visit(CallExp e)
4731     {
4732         debug (LOG)
4733         {
4734             printf("%s CallExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4735         }
4736         Expression pthis = null;
4737         FuncDeclaration fd = null;
4738 
4739         Expression ecall = interpretRegion(e.e1, istate);
4740         if (exceptionOrCant(ecall))
4741             return;
4742 
4743         if (auto dve = ecall.isDotVarExp())
4744         {
4745             // Calling a member function
4746             pthis = dve.e1;
4747             fd = dve.var.isFuncDeclaration();
4748             assert(fd);
4749 
4750             if (auto dte = pthis.isDotTypeExp())
4751                 pthis = dte.e1;
4752         }
4753         else if (auto ve = ecall.isVarExp())
4754         {
4755             fd = ve.var.isFuncDeclaration();
4756             assert(fd);
4757 
4758             // If `_d_HookTraceImpl` is found, resolve the underlying hook and replace `e` and `fd` with it.
4759             removeHookTraceImpl(e, fd);
4760 
4761             if (fd.ident == Id.__ArrayPostblit || fd.ident == Id.__ArrayDtor)
4762             {
4763                 assert(e.arguments.dim == 1);
4764                 Expression ea = (*e.arguments)[0];
4765                 // printf("1 ea = %s %s\n", ea.type.toChars(), ea.toChars());
4766                 if (auto se = ea.isSliceExp())
4767                     ea = se.e1;
4768                 if (auto ce = ea.isCastExp())
4769                     ea = ce.e1;
4770 
4771                 // printf("2 ea = %s, %s %s\n", ea.type.toChars(), EXPtoString(ea.op).ptr, ea.toChars());
4772                 if (ea.op == EXP.variable || ea.op == EXP.symbolOffset)
4773                     result = getVarExp(e.loc, istate, (cast(SymbolExp)ea).var, CTFEGoal.RValue);
4774                 else if (auto ae = ea.isAddrExp())
4775                     result = interpretRegion(ae.e1, istate);
4776 
4777                 // https://issues.dlang.org/show_bug.cgi?id=18871
4778                 // https://issues.dlang.org/show_bug.cgi?id=18819
4779                 else if (auto ale = ea.isArrayLiteralExp())
4780                     result = interpretRegion(ale, istate);
4781 
4782                 else
4783                     assert(0);
4784                 if (CTFEExp.isCantExp(result))
4785                     return;
4786 
4787                 if (fd.ident == Id.__ArrayPostblit)
4788                     result = evaluatePostblit(istate, result);
4789                 else
4790                     result = evaluateDtor(istate, result);
4791                 if (!result)
4792                     result = CTFEExp.voidexp;
4793                 return;
4794             }
4795             else if (fd.ident == Id._d_arraysetlengthT)
4796             {
4797                 // In expressionsem.d `ea.length = eb;` got lowered to `_d_arraysetlengthT(ea, eb);`.
4798                 // The following code will rewrite it back to `ea.length = eb` and then interpret that expression.
4799                 assert(e.arguments.dim == 2);
4800 
4801                 Expression ea = (*e.arguments)[0];
4802                 Expression eb = (*e.arguments)[1];
4803 
4804                 auto ale = ctfeEmplaceExp!ArrayLengthExp(e.loc, ea);
4805                 ale.type = Type.tsize_t;
4806                 AssignExp ae = ctfeEmplaceExp!AssignExp(e.loc, ale, eb);
4807                 ae.type = ea.type;
4808 
4809                 // if (global.params.verbose)
4810                 //     message("interpret  %s =>\n          %s", e.toChars(), ae.toChars());
4811                 result = interpretRegion(ae, istate);
4812                 return;
4813             }
4814             else if (fd.ident == Id._d_arrayctor || fd.ident == Id._d_arraysetctor)
4815             {
4816                 // In expressionsem.d `T[x] ea = eb;` was lowered to `_d_array{,set}ctor(ea[], eb[]);`.
4817                 // The following code will rewrite it back to `ea = eb` and then interpret that expression.
4818                 if (fd.ident == Id._d_arraysetctor)
4819                     assert(e.arguments.dim == 2);
4820                 else
4821                     assert(e.arguments.dim == 3);
4822 
4823                 Expression ea = (*e.arguments)[0];
4824                 if (ea.isCastExp)
4825                     ea = ea.isCastExp.e1;
4826 
4827                 Expression eb = (*e.arguments)[1];
4828                 if (eb.isCastExp && fd.ident == Id._d_arrayctor)
4829                     eb = eb.isCastExp.e1;
4830 
4831                 ConstructExp ce = new ConstructExp(e.loc, ea, eb);
4832                 ce.type = ea.type;
4833 
4834                 result = interpret(ce, istate);
4835                 return;
4836             }
4837         }
4838         else if (auto soe = ecall.isSymOffExp())
4839         {
4840             fd = soe.var.isFuncDeclaration();
4841             assert(fd && soe.offset == 0);
4842         }
4843         else if (auto de = ecall.isDelegateExp())
4844         {
4845             // Calling a delegate
4846             fd = de.func;
4847             pthis = de.e1;
4848 
4849             // Special handling for: &nestedfunc --> DelegateExp(VarExp(nestedfunc), nestedfunc)
4850             if (auto ve = pthis.isVarExp())
4851                 if (ve.var == fd)
4852                     pthis = null; // context is not necessary for CTFE
4853         }
4854         else if (auto fe = ecall.isFuncExp())
4855         {
4856             // Calling a delegate literal
4857             fd = fe.fd;
4858         }
4859         else
4860         {
4861             // delegate.funcptr()
4862             // others
4863             e.error("cannot call `%s` at compile time", e.toChars());
4864             result = CTFEExp.cantexp;
4865             return;
4866         }
4867         if (!fd)
4868         {
4869             e.error("CTFE internal error: cannot evaluate `%s` at compile time", e.toChars());
4870             result = CTFEExp.cantexp;
4871             return;
4872         }
4873         if (pthis)
4874         {
4875             // Member function call
4876 
4877             // Currently this is satisfied because closure is not yet supported.
4878             assert(!fd.isNested() || fd.needThis());
4879 
4880             if (pthis.op == EXP.typeid_)
4881             {
4882                 pthis.error("static variable `%s` cannot be read at compile time", pthis.toChars());
4883                 result = CTFEExp.cantexp;
4884                 return;
4885             }
4886             assert(pthis);
4887 
4888             if (pthis.op == EXP.null_)
4889             {
4890                 assert(pthis.type.toBasetype().ty == Tclass);
4891                 e.error("function call through null class reference `%s`", pthis.toChars());
4892                 result = CTFEExp.cantexp;
4893                 return;
4894             }
4895 
4896             assert(pthis.op == EXP.structLiteral || pthis.op == EXP.classReference || pthis.op == EXP.type);
4897 
4898             if (fd.isVirtual() && !e.directcall)
4899             {
4900                 // Make a virtual function call.
4901                 // Get the function from the vtable of the original class
4902                 ClassDeclaration cd = pthis.isClassReferenceExp().originalClass();
4903 
4904                 // We can't just use the vtable index to look it up, because
4905                 // vtables for interfaces don't get populated until the glue layer.
4906                 fd = cd.findFunc(fd.ident, fd.type.isTypeFunction());
4907                 assert(fd);
4908             }
4909         }
4910 
4911         if (fd && fd.semanticRun >= PASS.semantic3done && fd.hasSemantic3Errors())
4912         {
4913             e.error("CTFE failed because of previous errors in `%s`", fd.toChars());
4914             result = CTFEExp.cantexp;
4915             return;
4916         }
4917 
4918         // Check for built-in functions
4919         result = evaluateIfBuiltin(pue, istate, e.loc, fd, e.arguments, pthis);
4920         if (result)
4921             return;
4922 
4923         if (!fd.fbody)
4924         {
4925             e.error("`%s` cannot be interpreted at compile time, because it has no available source code", fd.toChars());
4926             result = CTFEExp.showcontext;
4927             return;
4928         }
4929 
4930         result = interpretFunction(pue, fd, istate, e.arguments, pthis);
4931         if (result.op == EXP.voidExpression)
4932             return;
4933         if (!exceptionOrCantInterpret(result))
4934         {
4935             if (goal != CTFEGoal.LValue) // Peel off CTFE reference if it's unnecessary
4936             {
4937                 if (result == pue.exp())
4938                     result = pue.copy();
4939                 result = interpret(pue, result, istate);
4940             }
4941         }
4942         if (!exceptionOrCantInterpret(result))
4943         {
4944             result = paintTypeOntoLiteral(pue, e.type, result);
4945             result.loc = e.loc;
4946         }
4947         else if (CTFEExp.isCantExp(result) && !global.gag)
4948             showCtfeBackTrace(e, fd); // Print a stack trace.
4949     }
4950 
visit(CommaExp e)4951     override void visit(CommaExp e)
4952     {
4953         debug (LOG)
4954         {
4955             printf("%s CommaExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4956         }
4957 
4958         // If it creates a variable, and there's no context for
4959         // the variable to be created in, we need to create one now.
4960         InterState istateComma;
4961         if (!istate && firstComma(e.e1).op == EXP.declaration)
4962         {
4963             ctfeGlobals.stack.startFrame(null);
4964             istate = &istateComma;
4965         }
4966 
4967         void endTempStackFrame()
4968         {
4969             // If we created a temporary stack frame, end it now.
4970             if (istate == &istateComma)
4971                 ctfeGlobals.stack.endFrame();
4972         }
4973 
4974         result = CTFEExp.cantexp;
4975 
4976         // If the comma returns a temporary variable, it needs to be an lvalue
4977         // (this is particularly important for struct constructors)
4978         if (e.e1.op == EXP.declaration &&
4979             e.e2.op == EXP.variable &&
4980             e.e1.isDeclarationExp().declaration == e.e2.isVarExp().var &&
4981             e.e2.isVarExp().var.storage_class & STC.ctfe)
4982         {
4983             VarExp ve = e.e2.isVarExp();
4984             VarDeclaration v = ve.var.isVarDeclaration();
4985             ctfeGlobals.stack.push(v);
4986             if (!v._init && !getValue(v))
4987             {
4988                 setValue(v, copyLiteral(v.type.defaultInitLiteral(e.loc)).copy());
4989             }
4990             if (!getValue(v))
4991             {
4992                 Expression newval = v._init.initializerToExpression();
4993                 // Bug 4027. Copy constructors are a weird case where the
4994                 // initializer is a void function (the variable is modified
4995                 // through a reference parameter instead).
4996                 newval = interpretRegion(newval, istate);
4997                 if (exceptionOrCant(newval))
4998                     return endTempStackFrame();
4999                 if (newval.op != EXP.voidExpression)
5000                 {
5001                     // v isn't necessarily null.
5002                     setValueWithoutChecking(v, copyLiteral(newval).copy());
5003                 }
5004             }
5005         }
5006         else
5007         {
5008             UnionExp ue = void;
5009             auto e1 = interpret(&ue, e.e1, istate, CTFEGoal.Nothing);
5010             if (exceptionOrCant(e1))
5011                 return endTempStackFrame();
5012         }
5013         result = interpret(pue, e.e2, istate, goal);
5014         return endTempStackFrame();
5015     }
5016 
visit(CondExp e)5017     override void visit(CondExp e)
5018     {
5019         debug (LOG)
5020         {
5021             printf("%s CondExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5022         }
5023         UnionExp uecond = void;
5024         Expression econd;
5025         econd = interpret(&uecond, e.econd, istate);
5026         if (exceptionOrCant(econd))
5027             return;
5028 
5029         if (isPointer(e.econd.type))
5030         {
5031             if (econd.op != EXP.null_)
5032             {
5033                 econd = IntegerExp.createBool(true);
5034             }
5035         }
5036 
5037         if (isTrueBool(econd))
5038         {
5039             result = interpret(pue, e.e1, istate, goal);
5040             incUsageCtfe(istate, e.e1.loc);
5041         }
5042         else if (econd.toBool().hasValue(false))
5043         {
5044             result = interpret(pue, e.e2, istate, goal);
5045             incUsageCtfe(istate, e.e2.loc);
5046         }
5047         else
5048         {
5049             e.error("`%s` does not evaluate to boolean result at compile time", e.econd.toChars());
5050             result = CTFEExp.cantexp;
5051         }
5052     }
5053 
visit(ArrayLengthExp e)5054     override void visit(ArrayLengthExp e)
5055     {
5056         debug (LOG)
5057         {
5058             printf("%s ArrayLengthExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5059         }
5060         UnionExp ue1;
5061         Expression e1 = interpret(&ue1, e.e1, istate);
5062         assert(e1);
5063         if (exceptionOrCant(e1))
5064             return;
5065         if (e1.op != EXP.string_ && e1.op != EXP.arrayLiteral && e1.op != EXP.slice && e1.op != EXP.null_)
5066         {
5067             e.error("`%s` cannot be evaluated at compile time", e.toChars());
5068             result = CTFEExp.cantexp;
5069             return;
5070         }
5071         emplaceExp!(IntegerExp)(pue, e.loc, resolveArrayLength(e1), e.type);
5072         result = pue.exp();
5073     }
5074 
5075     /**
5076      * Interpret the vector expression as an array literal.
5077      * Params:
5078      *    pue = non-null pointer to temporary storage that can be used to store the return value
5079      *    e = Expression to interpret
5080      * Returns:
5081      *    resulting array literal or 'e' if unable to interpret
5082      */
interpretVectorToArray(UnionExp * pue,VectorExp e)5083     static Expression interpretVectorToArray(UnionExp* pue, VectorExp e)
5084     {
5085         if (auto ale = e.e1.isArrayLiteralExp())
5086             return ale;         // it's already an array literal
5087         if (e.e1.op == EXP.int64 || e.e1.op == EXP.float64)
5088         {
5089             // Convert literal __vector(int) -> __vector([array])
5090             auto elements = new Expressions(e.dim);
5091             foreach (ref element; *elements)
5092                 element = copyLiteral(e.e1).copy();
5093             auto type = (e.type.ty == Tvector) ? e.type.isTypeVector().basetype : e.type.isTypeSArray();
5094             assert(type);
5095             emplaceExp!(ArrayLiteralExp)(pue, e.loc, type, elements);
5096             auto ale = pue.exp().isArrayLiteralExp();
5097             ale.ownedByCtfe = OwnedBy.ctfe;
5098             return ale;
5099         }
5100         return e;
5101     }
5102 
visit(VectorExp e)5103     override void visit(VectorExp e)
5104     {
5105         debug (LOG)
5106         {
5107             printf("%s VectorExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5108         }
5109         if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
5110         {
5111             result = e;
5112             return;
5113         }
5114         Expression e1 = interpret(pue, e.e1, istate);
5115         assert(e1);
5116         if (exceptionOrCant(e1))
5117             return;
5118         if (e1.op != EXP.arrayLiteral && e1.op != EXP.int64 && e1.op != EXP.float64)
5119         {
5120             e.error("`%s` cannot be evaluated at compile time", e.toChars());
5121             result = CTFEExp.cantexp;
5122             return;
5123         }
5124         if (e1 == pue.exp())
5125             e1 = pue.copy();
5126         emplaceExp!(VectorExp)(pue, e.loc, e1, e.to);
5127         auto ve = pue.exp().isVectorExp();
5128         ve.type = e.type;
5129         ve.dim = e.dim;
5130         ve.ownedByCtfe = OwnedBy.ctfe;
5131         result = ve;
5132     }
5133 
visit(VectorArrayExp e)5134     override void visit(VectorArrayExp e)
5135     {
5136         debug (LOG)
5137         {
5138             printf("%s VectorArrayExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5139         }
5140         Expression e1 = interpret(pue, e.e1, istate);
5141         assert(e1);
5142         if (exceptionOrCant(e1))
5143             return;
5144         if (auto ve = e1.isVectorExp())
5145         {
5146             result = interpretVectorToArray(pue, ve);
5147             if (result.op != EXP.vector)
5148                 return;
5149         }
5150         e.error("`%s` cannot be evaluated at compile time", e.toChars());
5151         result = CTFEExp.cantexp;
5152     }
5153 
visit(DelegatePtrExp e)5154     override void visit(DelegatePtrExp e)
5155     {
5156         debug (LOG)
5157         {
5158             printf("%s DelegatePtrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5159         }
5160         Expression e1 = interpret(pue, e.e1, istate);
5161         assert(e1);
5162         if (exceptionOrCant(e1))
5163             return;
5164         e.error("`%s` cannot be evaluated at compile time", e.toChars());
5165         result = CTFEExp.cantexp;
5166     }
5167 
visit(DelegateFuncptrExp e)5168     override void visit(DelegateFuncptrExp e)
5169     {
5170         debug (LOG)
5171         {
5172             printf("%s DelegateFuncptrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5173         }
5174         Expression e1 = interpret(pue, e.e1, istate);
5175         assert(e1);
5176         if (exceptionOrCant(e1))
5177             return;
5178         e.error("`%s` cannot be evaluated at compile time", e.toChars());
5179         result = CTFEExp.cantexp;
5180     }
5181 
resolveIndexing(IndexExp e,InterState * istate,Expression * pagg,uinteger_t * pidx,bool modify)5182     static bool resolveIndexing(IndexExp e, InterState* istate, Expression* pagg, uinteger_t* pidx, bool modify)
5183     {
5184         assert(e.e1.type.toBasetype().ty != Taarray);
5185 
5186         if (e.e1.type.toBasetype().ty == Tpointer)
5187         {
5188             // Indexing a pointer. Note that there is no $ in this case.
5189             Expression e1 = interpretRegion(e.e1, istate);
5190             if (exceptionOrCantInterpret(e1))
5191                 return false;
5192 
5193             Expression e2 = interpretRegion(e.e2, istate);
5194             if (exceptionOrCantInterpret(e2))
5195                 return false;
5196             sinteger_t indx = e2.toInteger();
5197 
5198             dinteger_t ofs;
5199             Expression agg = getAggregateFromPointer(e1, &ofs);
5200 
5201             if (agg.op == EXP.null_)
5202             {
5203                 e.error("cannot index through null pointer `%s`", e.e1.toChars());
5204                 return false;
5205             }
5206             if (agg.op == EXP.int64)
5207             {
5208                 e.error("cannot index through invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars());
5209                 return false;
5210             }
5211             // Pointer to a non-array variable
5212             if (agg.op == EXP.symbolOffset)
5213             {
5214                 e.error("mutable variable `%s` cannot be %s at compile time, even through a pointer", cast(char*)(modify ? "modified" : "read"), agg.isSymOffExp().var.toChars());
5215                 return false;
5216             }
5217 
5218             if (agg.op == EXP.arrayLiteral || agg.op == EXP.string_)
5219             {
5220                 dinteger_t len = resolveArrayLength(agg);
5221                 if (ofs + indx >= len)
5222                 {
5223                     e.error("pointer index `[%lld]` exceeds allocated memory block `[0..%lld]`", ofs + indx, len);
5224                     return false;
5225                 }
5226             }
5227             else
5228             {
5229                 if (ofs + indx != 0)
5230                 {
5231                     e.error("pointer index `[%lld]` lies outside memory block `[0..1]`", ofs + indx);
5232                     return false;
5233                 }
5234             }
5235             *pagg = agg;
5236             *pidx = ofs + indx;
5237             return true;
5238         }
5239 
5240         Expression e1 = interpretRegion(e.e1, istate);
5241         if (exceptionOrCantInterpret(e1))
5242             return false;
5243         if (e1.op == EXP.null_)
5244         {
5245             e.error("cannot index null array `%s`", e.e1.toChars());
5246             return false;
5247         }
5248         if (auto ve = e1.isVectorExp())
5249         {
5250             UnionExp ue = void;
5251             e1 = interpretVectorToArray(&ue, ve);
5252             e1 = (e1 == ue.exp()) ? ue.copy() : e1;
5253         }
5254 
5255         // Set the $ variable, and find the array literal to modify
5256         dinteger_t len;
5257         if (e1.op == EXP.variable && e1.type.toBasetype().ty == Tsarray)
5258             len = e1.type.toBasetype().isTypeSArray().dim.toInteger();
5259         else
5260         {
5261             if (e1.op != EXP.arrayLiteral && e1.op != EXP.string_ && e1.op != EXP.slice && e1.op != EXP.vector)
5262             {
5263                 e.error("cannot determine length of `%s` at compile time", e.e1.toChars());
5264                 return false;
5265             }
5266             len = resolveArrayLength(e1);
5267         }
5268 
5269         if (e.lengthVar)
5270         {
5271             Expression dollarExp = ctfeEmplaceExp!IntegerExp(e.loc, len, Type.tsize_t);
5272             ctfeGlobals.stack.push(e.lengthVar);
5273             setValue(e.lengthVar, dollarExp);
5274         }
5275         Expression e2 = interpretRegion(e.e2, istate);
5276         if (e.lengthVar)
5277             ctfeGlobals.stack.pop(e.lengthVar); // $ is defined only inside []
5278         if (exceptionOrCantInterpret(e2))
5279             return false;
5280         if (e2.op != EXP.int64)
5281         {
5282             e.error("CTFE internal error: non-integral index `[%s]`", e.e2.toChars());
5283             return false;
5284         }
5285 
5286         if (auto se = e1.isSliceExp())
5287         {
5288             // Simplify index of slice: agg[lwr..upr][indx] --> agg[indx']
5289             uinteger_t index = e2.toInteger();
5290             uinteger_t ilwr = se.lwr.toInteger();
5291             uinteger_t iupr = se.upr.toInteger();
5292 
5293             if (index > iupr - ilwr)
5294             {
5295                 e.error("index %llu exceeds array length %llu", index, iupr - ilwr);
5296                 return false;
5297             }
5298             *pagg = e1.isSliceExp().e1;
5299             *pidx = index + ilwr;
5300         }
5301         else
5302         {
5303             *pagg = e1;
5304             *pidx = e2.toInteger();
5305             if (len <= *pidx)
5306             {
5307                 e.error("array index %lld is out of bounds `[0..%lld]`", *pidx, len);
5308                 return false;
5309             }
5310         }
5311         return true;
5312     }
5313 
visit(IndexExp e)5314     override void visit(IndexExp e)
5315     {
5316         debug (LOG)
5317         {
5318             printf("%s IndexExp::interpret() %s, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
5319         }
5320         if (e.e1.type.toBasetype().ty == Tpointer)
5321         {
5322             Expression agg;
5323             uinteger_t indexToAccess;
5324             if (!resolveIndexing(e, istate, &agg, &indexToAccess, false))
5325             {
5326                 result = CTFEExp.cantexp;
5327                 return;
5328             }
5329             if (agg.op == EXP.arrayLiteral || agg.op == EXP.string_)
5330             {
5331                 if (goal == CTFEGoal.LValue)
5332                 {
5333                     // if we need a reference, IndexExp shouldn't be interpreting
5334                     // the expression to a value, it should stay as a reference
5335                     emplaceExp!(IndexExp)(pue, e.loc, agg, ctfeEmplaceExp!IntegerExp(e.e2.loc, indexToAccess, e.e2.type));
5336                     result = pue.exp();
5337                     result.type = e.type;
5338                     return;
5339                 }
5340                 result = ctfeIndex(pue, e.loc, e.type, agg, indexToAccess);
5341                 return;
5342             }
5343             else
5344             {
5345                 assert(indexToAccess == 0);
5346                 result = interpretRegion(agg, istate, goal);
5347                 if (exceptionOrCant(result))
5348                     return;
5349                 result = paintTypeOntoLiteral(pue, e.type, result);
5350                 return;
5351             }
5352         }
5353 
5354         if (e.e1.type.toBasetype().ty == Taarray)
5355         {
5356             Expression e1 = interpretRegion(e.e1, istate);
5357             if (exceptionOrCant(e1))
5358                 return;
5359             if (e1.op == EXP.null_)
5360             {
5361                 if (goal == CTFEGoal.LValue && e1.type.ty == Taarray && e.modifiable)
5362                 {
5363                     assert(0); // does not reach here?
5364                 }
5365                 e.error("cannot index null array `%s`", e.e1.toChars());
5366                 result = CTFEExp.cantexp;
5367                 return;
5368             }
5369             Expression e2 = interpretRegion(e.e2, istate);
5370             if (exceptionOrCant(e2))
5371                 return;
5372 
5373             if (goal == CTFEGoal.LValue)
5374             {
5375                 // Pointer or reference of a scalar type
5376                 if (e1 == e.e1 && e2 == e.e2)
5377                     result = e;
5378                 else
5379                 {
5380                     emplaceExp!(IndexExp)(pue, e.loc, e1, e2);
5381                     result = pue.exp();
5382                     result.type = e.type;
5383                 }
5384                 return;
5385             }
5386 
5387             assert(e1.op == EXP.assocArrayLiteral);
5388             UnionExp e2tmp = void;
5389             e2 = resolveSlice(e2, &e2tmp);
5390             result = findKeyInAA(e.loc, e1.isAssocArrayLiteralExp(), e2);
5391             if (!result)
5392             {
5393                 e.error("key `%s` not found in associative array `%s`", e2.toChars(), e.e1.toChars());
5394                 result = CTFEExp.cantexp;
5395             }
5396             return;
5397         }
5398 
5399         Expression agg;
5400         uinteger_t indexToAccess;
5401         if (!resolveIndexing(e, istate, &agg, &indexToAccess, false))
5402         {
5403             result = CTFEExp.cantexp;
5404             return;
5405         }
5406 
5407         if (goal == CTFEGoal.LValue)
5408         {
5409             Expression e2 = ctfeEmplaceExp!IntegerExp(e.e2.loc, indexToAccess, Type.tsize_t);
5410             emplaceExp!(IndexExp)(pue, e.loc, agg, e2);
5411             result = pue.exp();
5412             result.type = e.type;
5413             return;
5414         }
5415 
5416         result = ctfeIndex(pue, e.loc, e.type, agg, indexToAccess);
5417         if (exceptionOrCant(result))
5418             return;
5419         if (result.op == EXP.void_)
5420         {
5421             e.error("`%s` is used before initialized", e.toChars());
5422             errorSupplemental(result.loc, "originally uninitialized here");
5423             result = CTFEExp.cantexp;
5424             return;
5425         }
5426         if (result == pue.exp())
5427             result = result.copy();
5428     }
5429 
visit(SliceExp e)5430     override void visit(SliceExp e)
5431     {
5432         debug (LOG)
5433         {
5434             printf("%s SliceExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5435         }
5436         if (e.e1.type.toBasetype().ty == Tpointer)
5437         {
5438             // Slicing a pointer. Note that there is no $ in this case.
5439             Expression e1 = interpretRegion(e.e1, istate);
5440             if (exceptionOrCant(e1))
5441                 return;
5442             if (e1.op == EXP.int64)
5443             {
5444                 e.error("cannot slice invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars());
5445                 result = CTFEExp.cantexp;
5446                 return;
5447             }
5448 
5449             /* Evaluate lower and upper bounds of slice
5450              */
5451             Expression lwr = interpretRegion(e.lwr, istate);
5452             if (exceptionOrCant(lwr))
5453                 return;
5454             Expression upr = interpretRegion(e.upr, istate);
5455             if (exceptionOrCant(upr))
5456                 return;
5457             uinteger_t ilwr = lwr.toInteger();
5458             uinteger_t iupr = upr.toInteger();
5459 
5460             dinteger_t ofs;
5461             Expression agg = getAggregateFromPointer(e1, &ofs);
5462             ilwr += ofs;
5463             iupr += ofs;
5464             if (agg.op == EXP.null_)
5465             {
5466                 if (iupr == ilwr)
5467                 {
5468                     result = ctfeEmplaceExp!NullExp(e.loc);
5469                     result.type = e.type;
5470                     return;
5471                 }
5472                 e.error("cannot slice null pointer `%s`", e.e1.toChars());
5473                 result = CTFEExp.cantexp;
5474                 return;
5475             }
5476             if (agg.op == EXP.symbolOffset)
5477             {
5478                 e.error("slicing pointers to static variables is not supported in CTFE");
5479                 result = CTFEExp.cantexp;
5480                 return;
5481             }
5482             if (agg.op != EXP.arrayLiteral && agg.op != EXP.string_)
5483             {
5484                 e.error("pointer `%s` cannot be sliced at compile time (it does not point to an array)", e.e1.toChars());
5485                 result = CTFEExp.cantexp;
5486                 return;
5487             }
5488             assert(agg.op == EXP.arrayLiteral || agg.op == EXP.string_);
5489             dinteger_t len = ArrayLength(Type.tsize_t, agg).exp().toInteger();
5490             //Type *pointee = ((TypePointer *)agg.type)->next;
5491             if (sliceBoundsCheck(0, len, ilwr, iupr))
5492             {
5493                 e.error("pointer slice `[%lld..%lld]` exceeds allocated memory block `[0..%lld]`", ilwr, iupr, len);
5494                 result = CTFEExp.cantexp;
5495                 return;
5496             }
5497             if (ofs != 0)
5498             {
5499                 lwr = ctfeEmplaceExp!IntegerExp(e.loc, ilwr, lwr.type);
5500                 upr = ctfeEmplaceExp!IntegerExp(e.loc, iupr, upr.type);
5501             }
5502             emplaceExp!(SliceExp)(pue, e.loc, agg, lwr, upr);
5503             result = pue.exp();
5504             result.type = e.type;
5505             return;
5506         }
5507 
5508         CTFEGoal goal1 = CTFEGoal.RValue;
5509         if (goal == CTFEGoal.LValue)
5510         {
5511             if (e.e1.type.toBasetype().ty == Tsarray)
5512                 if (auto ve = e.e1.isVarExp())
5513                     if (auto vd = ve.var.isVarDeclaration())
5514                         if (vd.storage_class & STC.ref_)
5515                             goal1 = CTFEGoal.LValue;
5516         }
5517         Expression e1 = interpret(e.e1, istate, goal1);
5518         if (exceptionOrCant(e1))
5519             return;
5520 
5521         if (!e.lwr)
5522         {
5523             result = paintTypeOntoLiteral(pue, e.type, e1);
5524             return;
5525         }
5526         if (auto ve = e1.isVectorExp())
5527         {
5528             e1 = interpretVectorToArray(pue, ve);
5529             e1 = (e1 == pue.exp()) ? pue.copy() : e1;
5530         }
5531 
5532         /* Set dollar to the length of the array
5533          */
5534         uinteger_t dollar;
5535         if ((e1.op == EXP.variable || e1.op == EXP.dotVariable) && e1.type.toBasetype().ty == Tsarray)
5536             dollar = e1.type.toBasetype().isTypeSArray().dim.toInteger();
5537         else
5538         {
5539             if (e1.op != EXP.arrayLiteral && e1.op != EXP.string_ && e1.op != EXP.null_ && e1.op != EXP.slice && e1.op != EXP.vector)
5540             {
5541                 e.error("cannot determine length of `%s` at compile time", e1.toChars());
5542                 result = CTFEExp.cantexp;
5543                 return;
5544             }
5545             dollar = resolveArrayLength(e1);
5546         }
5547 
5548         /* Set the $ variable
5549          */
5550         if (e.lengthVar)
5551         {
5552             auto dollarExp = ctfeEmplaceExp!IntegerExp(e.loc, dollar, Type.tsize_t);
5553             ctfeGlobals.stack.push(e.lengthVar);
5554             setValue(e.lengthVar, dollarExp);
5555         }
5556 
5557         /* Evaluate lower and upper bounds of slice
5558          */
5559         Expression lwr = interpretRegion(e.lwr, istate);
5560         if (exceptionOrCant(lwr))
5561         {
5562             if (e.lengthVar)
5563                 ctfeGlobals.stack.pop(e.lengthVar);
5564             return;
5565         }
5566         Expression upr = interpretRegion(e.upr, istate);
5567         if (exceptionOrCant(upr))
5568         {
5569             if (e.lengthVar)
5570                 ctfeGlobals.stack.pop(e.lengthVar);
5571             return;
5572         }
5573         if (e.lengthVar)
5574             ctfeGlobals.stack.pop(e.lengthVar); // $ is defined only inside [L..U]
5575 
5576         uinteger_t ilwr = lwr.toInteger();
5577         uinteger_t iupr = upr.toInteger();
5578         if (e1.op == EXP.null_)
5579         {
5580             if (ilwr == 0 && iupr == 0)
5581             {
5582                 result = e1;
5583                 return;
5584             }
5585             e1.error("slice `[%llu..%llu]` is out of bounds", ilwr, iupr);
5586             result = CTFEExp.cantexp;
5587             return;
5588         }
5589         if (auto se = e1.isSliceExp())
5590         {
5591             // Simplify slice of slice:
5592             //  aggregate[lo1..up1][lwr..upr] ---> aggregate[lwr'..upr']
5593             uinteger_t lo1 = se.lwr.toInteger();
5594             uinteger_t up1 = se.upr.toInteger();
5595             if (sliceBoundsCheck(0, up1 - lo1, ilwr, iupr))
5596             {
5597                 e.error("slice `[%llu..%llu]` exceeds array bounds `[0..%llu]`", ilwr, iupr, up1 - lo1);
5598                 result = CTFEExp.cantexp;
5599                 return;
5600             }
5601             ilwr += lo1;
5602             iupr += lo1;
5603             emplaceExp!(SliceExp)(pue, e.loc, se.e1,
5604                 ctfeEmplaceExp!IntegerExp(e.loc, ilwr, lwr.type),
5605                 ctfeEmplaceExp!IntegerExp(e.loc, iupr, upr.type));
5606             result = pue.exp();
5607             result.type = e.type;
5608             return;
5609         }
5610         if (e1.op == EXP.arrayLiteral || e1.op == EXP.string_)
5611         {
5612             if (sliceBoundsCheck(0, dollar, ilwr, iupr))
5613             {
5614                 e.error("slice `[%lld..%lld]` exceeds array bounds `[0..%lld]`", ilwr, iupr, dollar);
5615                 result = CTFEExp.cantexp;
5616                 return;
5617             }
5618         }
5619         emplaceExp!(SliceExp)(pue, e.loc, e1, lwr, upr);
5620         result = pue.exp();
5621         result.type = e.type;
5622     }
5623 
visit(InExp e)5624     override void visit(InExp e)
5625     {
5626         debug (LOG)
5627         {
5628             printf("%s InExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5629         }
5630         Expression e1 = interpretRegion(e.e1, istate);
5631         if (exceptionOrCant(e1))
5632             return;
5633         Expression e2 = interpretRegion(e.e2, istate);
5634         if (exceptionOrCant(e2))
5635             return;
5636         if (e2.op == EXP.null_)
5637         {
5638             emplaceExp!(NullExp)(pue, e.loc, e.type);
5639             result = pue.exp();
5640             return;
5641         }
5642         if (e2.op != EXP.assocArrayLiteral)
5643         {
5644             e.error("`%s` cannot be interpreted at compile time", e.toChars());
5645             result = CTFEExp.cantexp;
5646             return;
5647         }
5648 
5649         e1 = resolveSlice(e1);
5650         result = findKeyInAA(e.loc, e2.isAssocArrayLiteralExp(), e1);
5651         if (exceptionOrCant(result))
5652             return;
5653         if (!result)
5654         {
5655             emplaceExp!(NullExp)(pue, e.loc, e.type);
5656             result = pue.exp();
5657         }
5658         else
5659         {
5660             // Create a CTFE pointer &aa[index]
5661             result = ctfeEmplaceExp!IndexExp(e.loc, e2, e1);
5662             result.type = e.type.nextOf();
5663             emplaceExp!(AddrExp)(pue, e.loc, result, e.type);
5664             result = pue.exp();
5665         }
5666     }
5667 
visit(CatExp e)5668     override void visit(CatExp e)
5669     {
5670         debug (LOG)
5671         {
5672             printf("%s CatExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5673         }
5674 
5675         UnionExp ue1 = void;
5676         Expression e1 = interpret(&ue1, e.e1, istate);
5677         if (exceptionOrCant(e1))
5678             return;
5679 
5680         UnionExp ue2 = void;
5681         Expression e2 = interpret(&ue2, e.e2, istate);
5682         if (exceptionOrCant(e2))
5683             return;
5684 
5685         UnionExp e1tmp = void;
5686         e1 = resolveSlice(e1, &e1tmp);
5687 
5688         UnionExp e2tmp = void;
5689         e2 = resolveSlice(e2, &e2tmp);
5690 
5691         /* e1 and e2 can't go on the stack because of x~[y] and [x]~y will
5692          * result in [x,y] and then x or y is on the stack.
5693          * But if they are both strings, we can, because it isn't the x~[y] case.
5694          */
5695         if (!(e1.op == EXP.string_ && e2.op == EXP.string_))
5696         {
5697             if (e1 == ue1.exp())
5698                 e1 = ue1.copy();
5699             if (e2 == ue2.exp())
5700                 e2 = ue2.copy();
5701         }
5702 
5703         *pue = ctfeCat(e.loc, e.type, e1, e2);
5704         result = pue.exp();
5705 
5706         if (CTFEExp.isCantExp(result))
5707         {
5708             e.error("`%s` cannot be interpreted at compile time", e.toChars());
5709             return;
5710         }
5711         // We know we still own it, because we interpreted both e1 and e2
5712         if (auto ale = result.isArrayLiteralExp())
5713         {
5714             ale.ownedByCtfe = OwnedBy.ctfe;
5715 
5716             // https://issues.dlang.org/show_bug.cgi?id=14686
5717             foreach (elem; *ale.elements)
5718             {
5719                 Expression ex = evaluatePostblit(istate, elem);
5720                 if (exceptionOrCant(ex))
5721                     return;
5722             }
5723         }
5724         else if (auto se = result.isStringExp())
5725             se.ownedByCtfe = OwnedBy.ctfe;
5726     }
5727 
visit(DeleteExp e)5728     override void visit(DeleteExp e)
5729     {
5730         debug (LOG)
5731         {
5732             printf("%s DeleteExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5733         }
5734         result = interpretRegion(e.e1, istate);
5735         if (exceptionOrCant(result))
5736             return;
5737 
5738         if (result.op == EXP.null_)
5739         {
5740             result = CTFEExp.voidexp;
5741             return;
5742         }
5743 
5744         auto tb = e.e1.type.toBasetype();
5745         switch (tb.ty)
5746         {
5747         case Tclass:
5748             if (result.op != EXP.classReference)
5749             {
5750                 e.error("`delete` on invalid class reference `%s`", result.toChars());
5751                 result = CTFEExp.cantexp;
5752                 return;
5753             }
5754 
5755             auto cre = result.isClassReferenceExp();
5756             auto cd = cre.originalClass();
5757 
5758             // Find dtor(s) in inheritance chain
5759             do
5760             {
5761                 if (cd.dtor)
5762                 {
5763                     result = interpretFunction(pue, cd.dtor, istate, null, cre);
5764                     if (exceptionOrCant(result))
5765                         return;
5766 
5767                     // Dtors of Non-extern(D) classes use implicit chaining (like structs)
5768                     import dmd.aggregate : ClassKind;
5769                     if (cd.classKind != ClassKind.d)
5770                         break;
5771                 }
5772 
5773                 // Emulate manual chaining as done in rt_finalize2
5774                 cd = cd.baseClass;
5775 
5776             } while (cd); // Stop after Object
5777 
5778             break;
5779 
5780         default:
5781             assert(0);
5782         }
5783         result = CTFEExp.voidexp;
5784     }
5785 
visit(CastExp e)5786     override void visit(CastExp e)
5787     {
5788         debug (LOG)
5789         {
5790             printf("%s CastExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5791         }
5792         Expression e1 = interpretRegion(e.e1, istate, goal);
5793         if (exceptionOrCant(e1))
5794             return;
5795         // If the expression has been cast to void, do nothing.
5796         if (e.to.ty == Tvoid)
5797         {
5798             result = CTFEExp.voidexp;
5799             return;
5800         }
5801         if (e.to.ty == Tpointer && e1.op != EXP.null_)
5802         {
5803             Type pointee = (cast(TypePointer)e.type).next;
5804             // Implement special cases of normally-unsafe casts
5805             if (e1.op == EXP.int64)
5806             {
5807                 // Happens with Windows HANDLEs, for example.
5808                 result = paintTypeOntoLiteral(pue, e.to, e1);
5809                 return;
5810             }
5811 
5812             bool castToSarrayPointer = false;
5813             bool castBackFromVoid = false;
5814             if (e1.type.ty == Tarray || e1.type.ty == Tsarray || e1.type.ty == Tpointer)
5815             {
5816                 // Check for unsupported type painting operations
5817                 // For slices, we need the type being sliced,
5818                 // since it may have already been type painted
5819                 Type elemtype = e1.type.nextOf();
5820                 if (auto se = e1.isSliceExp())
5821                     elemtype = se.e1.type.nextOf();
5822 
5823                 // Allow casts from X* to void *, and X** to void** for any X.
5824                 // But don't allow cast from X* to void**.
5825                 // So, we strip all matching * from source and target to find X.
5826                 // Allow casts to X* from void* only if the 'void' was originally an X;
5827                 // we check this later on.
5828                 Type ultimatePointee = pointee;
5829                 Type ultimateSrc = elemtype;
5830                 while (ultimatePointee.ty == Tpointer && ultimateSrc.ty == Tpointer)
5831                 {
5832                     ultimatePointee = ultimatePointee.nextOf();
5833                     ultimateSrc = ultimateSrc.nextOf();
5834                 }
5835                 if (ultimatePointee.ty == Tsarray && ultimatePointee.nextOf().equivalent(ultimateSrc))
5836                 {
5837                     castToSarrayPointer = true;
5838                 }
5839                 else if (ultimatePointee.ty != Tvoid && ultimateSrc.ty != Tvoid && !isSafePointerCast(elemtype, pointee))
5840                 {
5841                     e.error("reinterpreting cast from `%s*` to `%s*` is not supported in CTFE", elemtype.toChars(), pointee.toChars());
5842                     result = CTFEExp.cantexp;
5843                     return;
5844                 }
5845                 if (ultimateSrc.ty == Tvoid)
5846                     castBackFromVoid = true;
5847             }
5848 
5849             if (auto se = e1.isSliceExp())
5850             {
5851                 if (se.e1.op == EXP.null_)
5852                 {
5853                     result = paintTypeOntoLiteral(pue, e.type, se.e1);
5854                     return;
5855                 }
5856                 // Create a CTFE pointer &aggregate[1..2]
5857                 auto ei = ctfeEmplaceExp!IndexExp(e.loc, se.e1, se.lwr);
5858                 ei.type = e.type.nextOf();
5859                 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
5860                 result = pue.exp();
5861                 return;
5862             }
5863             if (e1.op == EXP.arrayLiteral || e1.op == EXP.string_)
5864             {
5865                 // Create a CTFE pointer &[1,2,3][0] or &"abc"[0]
5866                 auto ei = ctfeEmplaceExp!IndexExp(e.loc, e1, ctfeEmplaceExp!IntegerExp(e.loc, 0, Type.tsize_t));
5867                 ei.type = e.type.nextOf();
5868                 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
5869                 result = pue.exp();
5870                 return;
5871             }
5872             if (e1.op == EXP.index && !e1.isIndexExp().e1.type.equals(e1.type))
5873             {
5874                 // type painting operation
5875                 IndexExp ie = e1.isIndexExp();
5876                 if (castBackFromVoid)
5877                 {
5878                     // get the original type. For strings, it's just the type...
5879                     Type origType = ie.e1.type.nextOf();
5880                     // ..but for arrays of type void*, it's the type of the element
5881                     if (ie.e1.op == EXP.arrayLiteral && ie.e2.op == EXP.int64)
5882                     {
5883                         ArrayLiteralExp ale = ie.e1.isArrayLiteralExp();
5884                         const indx = cast(size_t)ie.e2.toInteger();
5885                         if (indx < ale.elements.dim)
5886                         {
5887                             if (Expression xx = (*ale.elements)[indx])
5888                             {
5889                                 if (auto iex = xx.isIndexExp())
5890                                     origType = iex.e1.type.nextOf();
5891                                 else if (auto ae = xx.isAddrExp())
5892                                     origType = ae.e1.type;
5893                                 else if (auto ve = xx.isVarExp())
5894                                     origType = ve.var.type;
5895                             }
5896                         }
5897                     }
5898                     if (!isSafePointerCast(origType, pointee))
5899                     {
5900                         e.error("using `void*` to reinterpret cast from `%s*` to `%s*` is not supported in CTFE", origType.toChars(), pointee.toChars());
5901                         result = CTFEExp.cantexp;
5902                         return;
5903                     }
5904                 }
5905                 emplaceExp!(IndexExp)(pue, e1.loc, ie.e1, ie.e2);
5906                 result = pue.exp();
5907                 result.type = e.type;
5908                 return;
5909             }
5910 
5911             if (auto ae = e1.isAddrExp())
5912             {
5913                 Type origType = ae.e1.type;
5914                 if (isSafePointerCast(origType, pointee))
5915                 {
5916                     emplaceExp!(AddrExp)(pue, e.loc, ae.e1, e.type);
5917                     result = pue.exp();
5918                     return;
5919                 }
5920 
5921                 if (castToSarrayPointer && pointee.toBasetype().ty == Tsarray && ae.e1.op == EXP.index)
5922                 {
5923                     // &val[idx]
5924                     dinteger_t dim = (cast(TypeSArray)pointee.toBasetype()).dim.toInteger();
5925                     IndexExp ie = ae.e1.isIndexExp();
5926                     Expression lwr = ie.e2;
5927                     Expression upr = ctfeEmplaceExp!IntegerExp(ie.e2.loc, ie.e2.toInteger() + dim, Type.tsize_t);
5928 
5929                     // Create a CTFE pointer &val[idx..idx+dim]
5930                     auto er = ctfeEmplaceExp!SliceExp(e.loc, ie.e1, lwr, upr);
5931                     er.type = pointee;
5932                     emplaceExp!(AddrExp)(pue, e.loc, er, e.type);
5933                     result = pue.exp();
5934                     return;
5935                 }
5936             }
5937 
5938             if (e1.op == EXP.variable || e1.op == EXP.symbolOffset)
5939             {
5940                 // type painting operation
5941                 Type origType = (cast(SymbolExp)e1).var.type;
5942                 if (castBackFromVoid && !isSafePointerCast(origType, pointee))
5943                 {
5944                     e.error("using `void*` to reinterpret cast from `%s*` to `%s*` is not supported in CTFE", origType.toChars(), pointee.toChars());
5945                     result = CTFEExp.cantexp;
5946                     return;
5947                 }
5948                 if (auto ve = e1.isVarExp())
5949                     emplaceExp!(VarExp)(pue, e.loc, ve.var);
5950                 else
5951                     emplaceExp!(SymOffExp)(pue, e.loc, e1.isSymOffExp().var, e1.isSymOffExp().offset);
5952                 result = pue.exp();
5953                 result.type = e.to;
5954                 return;
5955             }
5956 
5957             // Check if we have a null pointer (eg, inside a struct)
5958             e1 = interpretRegion(e1, istate);
5959             if (e1.op != EXP.null_)
5960             {
5961                 e.error("pointer cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars());
5962                 result = CTFEExp.cantexp;
5963                 return;
5964             }
5965         }
5966         if (e.to.ty == Tsarray && e.e1.type.ty == Tvector)
5967         {
5968             // Special handling for: cast(float[4])__vector([w, x, y, z])
5969             e1 = interpretRegion(e.e1, istate);
5970             if (exceptionOrCant(e1))
5971                 return;
5972             assert(e1.op == EXP.vector);
5973             e1 = interpretVectorToArray(pue, e1.isVectorExp());
5974         }
5975         if (e.to.ty == Tarray && e1.op == EXP.slice)
5976         {
5977             // Note that the slice may be void[], so when checking for dangerous
5978             // casts, we need to use the original type, which is se.e1.
5979             SliceExp se = e1.isSliceExp();
5980             if (!isSafePointerCast(se.e1.type.nextOf(), e.to.nextOf()))
5981             {
5982                 e.error("array cast from `%s` to `%s` is not supported at compile time", se.e1.type.toChars(), e.to.toChars());
5983                 result = CTFEExp.cantexp;
5984                 return;
5985             }
5986             emplaceExp!(SliceExp)(pue, e1.loc, se.e1, se.lwr, se.upr);
5987             result = pue.exp();
5988             result.type = e.to;
5989             return;
5990         }
5991         // Disallow array type painting, except for conversions between built-in
5992         // types of identical size.
5993         if ((e.to.ty == Tsarray || e.to.ty == Tarray) && (e1.type.ty == Tsarray || e1.type.ty == Tarray) && !isSafePointerCast(e1.type.nextOf(), e.to.nextOf()))
5994         {
5995             e.error("array cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars());
5996             result = CTFEExp.cantexp;
5997             return;
5998         }
5999         if (e.to.ty == Tsarray)
6000             e1 = resolveSlice(e1);
6001 
6002         auto tobt = e.to.toBasetype();
6003         if (tobt.ty == Tbool && e1.type.ty == Tpointer)
6004         {
6005             emplaceExp!(IntegerExp)(pue, e.loc, e1.op != EXP.null_, e.to);
6006             result = pue.exp();
6007             return;
6008         }
6009         else if (tobt.isTypeBasic() && e1.op == EXP.null_)
6010         {
6011             if (tobt.isintegral())
6012                 emplaceExp!(IntegerExp)(pue, e.loc, 0, e.to);
6013             else if (tobt.isreal())
6014                 emplaceExp!(RealExp)(pue, e.loc, CTFloat.zero, e.to);
6015             result = pue.exp();
6016             return;
6017         }
6018         result = ctfeCast(pue, e.loc, e.type, e.to, e1, true);
6019     }
6020 
visit(AssertExp e)6021     override void visit(AssertExp e)
6022     {
6023         debug (LOG)
6024         {
6025             printf("%s AssertExp::interpret() %s\n", e.loc.toChars(), e.toChars());
6026         }
6027         Expression e1 = interpret(pue, e.e1, istate);
6028         if (exceptionOrCant(e1))
6029             return;
6030         if (isTrueBool(e1))
6031         {
6032         }
6033         else if (e1.toBool().hasValue(false))
6034         {
6035             if (e.msg)
6036             {
6037                 UnionExp ue = void;
6038                 result = interpret(&ue, e.msg, istate);
6039                 if (exceptionOrCant(result))
6040                     return;
6041                 e.error("`%s`", result.toChars());
6042             }
6043             else
6044                 e.error("`%s` failed", e.toChars());
6045             result = CTFEExp.cantexp;
6046             return;
6047         }
6048         else
6049         {
6050             e.error("`%s` is not a compile time boolean expression", e1.toChars());
6051             result = CTFEExp.cantexp;
6052             return;
6053         }
6054         result = e1;
6055         return;
6056     }
6057 
visit(ThrowExp te)6058     override void visit(ThrowExp te)
6059     {
6060         debug (LOG)
6061         {
6062             printf("%s ThrowExpression::interpret()\n", e.loc.toChars());
6063         }
6064         interpretThrow(te.e1, te.loc);
6065     }
6066 
visit(PtrExp e)6067     override void visit(PtrExp e)
6068     {
6069         debug (LOG)
6070         {
6071             printf("%s PtrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
6072         }
6073         // Check for int<->float and long<->double casts.
6074         if (auto soe1 = e.e1.isSymOffExp())
6075             if (soe1.offset == 0 && soe1.var.isVarDeclaration() && isFloatIntPaint(e.type, soe1.var.type))
6076             {
6077                 // *(cast(int*)&v), where v is a float variable
6078                 result = paintFloatInt(pue, getVarExp(e.loc, istate, soe1.var, CTFEGoal.RValue), e.type);
6079                 return;
6080             }
6081 
6082         if (auto ce1 = e.e1.isCastExp())
6083             if (auto ae11 = ce1.e1.isAddrExp())
6084             {
6085                 // *(cast(int*)&x), where x is a float expression
6086                 Expression x = ae11.e1;
6087                 if (isFloatIntPaint(e.type, x.type))
6088                 {
6089                     result = paintFloatInt(pue, interpretRegion(x, istate), e.type);
6090                     return;
6091                 }
6092             }
6093 
6094         // Constant fold *(&structliteral + offset)
6095         if (auto ae = e.e1.isAddExp())
6096         {
6097             if (ae.e1.op == EXP.address && ae.e2.op == EXP.int64)
6098             {
6099                 AddrExp ade = ae.e1.isAddrExp();
6100                 Expression ex = interpretRegion(ade.e1, istate);
6101                 if (exceptionOrCant(ex))
6102                     return;
6103                 if (auto se = ex.isStructLiteralExp())
6104                 {
6105                     dinteger_t offset = ae.e2.toInteger();
6106                     result = se.getField(e.type, cast(uint)offset);
6107                     if (result)
6108                         return;
6109                 }
6110             }
6111         }
6112 
6113         // It's possible we have an array bounds error. We need to make sure it
6114         // errors with this line number, not the one where the pointer was set.
6115         result = interpretRegion(e.e1, istate);
6116         if (exceptionOrCant(result))
6117             return;
6118 
6119         if (result.op == EXP.function_)
6120             return;
6121         if (auto soe = result.isSymOffExp())
6122         {
6123             if (soe.offset == 0 && soe.var.isFuncDeclaration())
6124                 return;
6125             e.error("cannot dereference pointer to static variable `%s` at compile time", soe.var.toChars());
6126             result = CTFEExp.cantexp;
6127             return;
6128         }
6129 
6130         if (result.isStringExp())
6131             return;
6132 
6133         if (result.op != EXP.address)
6134         {
6135             if (result.op == EXP.null_)
6136                 e.error("dereference of null pointer `%s`", e.e1.toChars());
6137             else
6138                 e.error("dereference of invalid pointer `%s`", result.toChars());
6139             result = CTFEExp.cantexp;
6140             return;
6141         }
6142 
6143         // *(&x) ==> x
6144         result = result.isAddrExp().e1;
6145 
6146         if (result.op == EXP.slice && e.type.toBasetype().ty == Tsarray)
6147         {
6148             /* aggr[lwr..upr]
6149              * upr may exceed the upper boundary of aggr, but the check is deferred
6150              * until those out-of-bounds elements will be touched.
6151              */
6152             return;
6153         }
6154         result = interpret(pue, result, istate, goal);
6155         if (exceptionOrCant(result))
6156             return;
6157 
6158         debug (LOG)
6159         {
6160             if (CTFEExp.isCantExp(result))
6161                 printf("PtrExp::interpret() %s = CTFEExp::cantexp\n", e.toChars());
6162         }
6163     }
6164 
visit(DotVarExp e)6165     override void visit(DotVarExp e)
6166     {
6167         void notImplementedYet()
6168         {
6169             e.error("`%s.%s` is not yet implemented at compile time", e.e1.toChars(), e.var.toChars());
6170             result = CTFEExp.cantexp;
6171             return;
6172         }
6173 
6174         debug (LOG)
6175         {
6176             printf("%s DotVarExp::interpret() %s, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
6177         }
6178         Expression ex = interpretRegion(e.e1, istate);
6179         if (exceptionOrCant(ex))
6180             return;
6181 
6182         if (FuncDeclaration f = e.var.isFuncDeclaration())
6183         {
6184             if (ex == e.e1)
6185                 result = e; // optimize: reuse this CTFE reference
6186             else
6187             {
6188                 emplaceExp!(DotVarExp)(pue, e.loc, ex, f, false);
6189                 result = pue.exp();
6190                 result.type = e.type;
6191             }
6192             return;
6193         }
6194 
6195         VarDeclaration v = e.var.isVarDeclaration();
6196         if (!v)
6197         {
6198             e.error("CTFE internal error: `%s`", e.toChars());
6199             result = CTFEExp.cantexp;
6200             return;
6201         }
6202 
6203         if (ex.op == EXP.null_)
6204         {
6205             if (ex.type.toBasetype().ty == Tclass)
6206                 e.error("class `%s` is `null` and cannot be dereferenced", e.e1.toChars());
6207             else
6208                 e.error("CTFE internal error: null this `%s`", e.e1.toChars());
6209             result = CTFEExp.cantexp;
6210             return;
6211         }
6212 
6213         StructLiteralExp se;
6214         int i;
6215 
6216         if (ex.op != EXP.structLiteral && ex.op != EXP.classReference && ex.op != EXP.typeid_)
6217         {
6218             return notImplementedYet();
6219         }
6220 
6221         // We can't use getField, because it makes a copy
6222         if (ex.op == EXP.classReference)
6223         {
6224             se = ex.isClassReferenceExp().value;
6225             i = ex.isClassReferenceExp().findFieldIndexByName(v);
6226         }
6227         else if (ex.op == EXP.typeid_)
6228         {
6229             if (v.ident == Identifier.idPool("name"))
6230             {
6231                 if (auto t = isType(ex.isTypeidExp().obj))
6232                 {
6233                     auto sym = t.toDsymbol(null);
6234                     if (auto ident = (sym ? sym.ident : null))
6235                     {
6236                         result = new StringExp(e.loc, ident.toString());
6237                         result.expressionSemantic(null);
6238                         return ;
6239                     }
6240                 }
6241             }
6242             return notImplementedYet();
6243         }
6244         else
6245         {
6246             se = ex.isStructLiteralExp();
6247             i = findFieldIndexByName(se.sd, v);
6248         }
6249         if (i == -1)
6250         {
6251             e.error("couldn't find field `%s` of type `%s` in `%s`", v.toChars(), e.type.toChars(), se.toChars());
6252             result = CTFEExp.cantexp;
6253             return;
6254         }
6255 
6256         // https://issues.dlang.org/show_bug.cgi?id=19897
6257         // https://issues.dlang.org/show_bug.cgi?id=20710
6258         // Zero-elements fields don't have an initializer. See: scrubArray function
6259         if ((*se.elements)[i] is null)
6260             (*se.elements)[i] = voidInitLiteral(e.type, v).copy();
6261 
6262         if (goal == CTFEGoal.LValue)
6263         {
6264             // just return the (simplified) dotvar expression as a CTFE reference
6265             if (e.e1 == ex)
6266                 result = e;
6267             else
6268             {
6269                 emplaceExp!(DotVarExp)(pue, e.loc, ex, v);
6270                 result = pue.exp();
6271                 result.type = e.type;
6272             }
6273             return;
6274         }
6275 
6276         result = (*se.elements)[i];
6277         if (!result)
6278         {
6279             e.error("Internal Compiler Error: null field `%s`", v.toChars());
6280             result = CTFEExp.cantexp;
6281             return;
6282         }
6283         if (auto vie = result.isVoidInitExp())
6284         {
6285             const s = vie.var.toChars();
6286             if (v.overlapped)
6287             {
6288                 e.error("reinterpretation through overlapped field `%s` is not allowed in CTFE", s);
6289                 result = CTFEExp.cantexp;
6290                 return;
6291             }
6292             e.error("cannot read uninitialized variable `%s` in CTFE", s);
6293             result = CTFEExp.cantexp;
6294             return;
6295         }
6296 
6297         if (v.type.ty != result.type.ty && v.type.ty == Tsarray)
6298         {
6299             // Block assignment from inside struct literals
6300             auto tsa = cast(TypeSArray)v.type;
6301             auto len = cast(size_t)tsa.dim.toInteger();
6302             UnionExp ue = void;
6303             result = createBlockDuplicatedArrayLiteral(&ue, e.loc, v.type, result, len);
6304             if (result == ue.exp())
6305                 result = ue.copy();
6306             (*se.elements)[i] = result;
6307         }
6308         debug (LOG)
6309         {
6310             if (CTFEExp.isCantExp(result))
6311                 printf("DotVarExp::interpret() %s = CTFEExp::cantexp\n", e.toChars());
6312         }
6313     }
6314 
visit(RemoveExp e)6315     override void visit(RemoveExp e)
6316     {
6317         debug (LOG)
6318         {
6319             printf("%s RemoveExp::interpret() %s\n", e.loc.toChars(), e.toChars());
6320         }
6321         Expression agg = interpret(e.e1, istate);
6322         if (exceptionOrCant(agg))
6323             return;
6324         Expression index = interpret(e.e2, istate);
6325         if (exceptionOrCant(index))
6326             return;
6327         if (agg.op == EXP.null_)
6328         {
6329             result = CTFEExp.voidexp;
6330             return;
6331         }
6332 
6333         AssocArrayLiteralExp aae = agg.isAssocArrayLiteralExp();
6334         Expressions* keysx = aae.keys;
6335         Expressions* valuesx = aae.values;
6336         size_t removed = 0;
6337         foreach (j, evalue; *valuesx)
6338         {
6339             Expression ekey = (*keysx)[j];
6340             int eq = ctfeEqual(e.loc, EXP.equal, ekey, index);
6341             if (eq)
6342                 ++removed;
6343             else if (removed != 0)
6344             {
6345                 (*keysx)[j - removed] = ekey;
6346                 (*valuesx)[j - removed] = evalue;
6347             }
6348         }
6349         valuesx.dim = valuesx.dim - removed;
6350         keysx.dim = keysx.dim - removed;
6351         result = IntegerExp.createBool(removed != 0);
6352     }
6353 
visit(ClassReferenceExp e)6354     override void visit(ClassReferenceExp e)
6355     {
6356         //printf("ClassReferenceExp::interpret() %s\n", e.value.toChars());
6357         result = e;
6358     }
6359 
visit(VoidInitExp e)6360     override void visit(VoidInitExp e)
6361     {
6362         e.error("CTFE internal error: trying to read uninitialized variable");
6363         assert(0);
6364     }
6365 
visit(ThrownExceptionExp e)6366     override void visit(ThrownExceptionExp e)
6367     {
6368         assert(0); // This should never be interpreted
6369     }
6370 }
6371 
6372 /********************************************
6373  * Interpret the expression.
6374  * Params:
6375  *    pue = non-null pointer to temporary storage that can be used to store the return value
6376  *    e = Expression to interpret
6377  *    istate = context
6378  *    goal = what the result will be used for
6379  * Returns:
6380  *    resulting expression
6381  */
6382 
6383 Expression interpret(UnionExp* pue, Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
6384 {
6385     if (!e)
6386         return null;
6387     scope Interpreter v = new Interpreter(pue, istate, goal);
6388     e.accept(v);
6389     Expression ex = v.result;
6390     assert(goal == CTFEGoal.Nothing || ex !is null);
6391     return ex;
6392 }
6393 
6394 ///
6395 Expression interpret(Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
6396 {
6397     UnionExp ue = void;
6398     auto result = interpret(&ue, e, istate, goal);
6399     if (result == ue.exp())
6400         result = ue.copy();
6401     return result;
6402 }
6403 
6404 /*****************************
6405  * Same as interpret(), but return result allocated in Region.
6406  * Params:
6407  *    e = Expression to interpret
6408  *    istate = context
6409  *    goal = what the result will be used for
6410  * Returns:
6411  *    resulting expression
6412  */
6413 Expression interpretRegion(Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
6414 {
6415     UnionExp ue = void;
6416     auto result = interpret(&ue, e, istate, goal);
6417     auto uexp = ue.exp();
6418     if (result != uexp)
6419         return result;
6420     if (mem.isGCEnabled)
6421         return ue.copy();
6422 
6423     // mimicking UnionExp.copy, but with region allocation
6424     switch (uexp.op)
6425     {
6426         case EXP.cantExpression: return CTFEExp.cantexp;
6427         case EXP.voidExpression: return CTFEExp.voidexp;
6428         case EXP.break_:         return CTFEExp.breakexp;
6429         case EXP.continue_:      return CTFEExp.continueexp;
6430         case EXP.goto_:          return CTFEExp.gotoexp;
6431         default:                 break;
6432     }
6433     auto p = ctfeGlobals.region.malloc(uexp.size);
6434     return cast(Expression)memcpy(p, cast(void*)uexp, uexp.size);
6435 }
6436 
6437 /***********************************
6438  * Interpret the statement.
6439  * Params:
6440  *    pue = non-null pointer to temporary storage that can be used to store the return value
6441  *    s = Statement to interpret
6442  *    istate = context
6443  * Returns:
6444  *      NULL    continue to next statement
6445  *      EXP.cantExpression      cannot interpret statement at compile time
6446  *      !NULL   expression from return statement, or thrown exception
6447  */
interpret(UnionExp * pue,Statement s,InterState * istate)6448 Expression interpret(UnionExp* pue, Statement s, InterState* istate)
6449 {
6450     if (!s)
6451         return null;
6452     scope Interpreter v = new Interpreter(pue, istate, CTFEGoal.Nothing);
6453     s.accept(v);
6454     return v.result;
6455 }
6456 
6457 ///
interpret(Statement s,InterState * istate)6458 Expression interpret(Statement s, InterState* istate)
6459 {
6460     UnionExp ue = void;
6461     auto result = interpret(&ue, s, istate);
6462     if (result == ue.exp())
6463         result = ue.copy();
6464     return result;
6465 }
6466 
6467 /**
6468  * All results destined for use outside of CTFE need to have their CTFE-specific
6469  * features removed.
6470  * In particular,
6471  * 1. all slices must be resolved.
6472  * 2. all .ownedByCtfe set to OwnedBy.code
6473  */
scrubReturnValue(const ref Loc loc,Expression e)6474 private Expression scrubReturnValue(const ref Loc loc, Expression e)
6475 {
6476     /* Returns: true if e is void,
6477      * or is an array literal or struct literal of void elements.
6478      */
6479     static bool isVoid(const Expression e, bool checkArrayType = false) pure
6480     {
6481         if (e.op == EXP.void_)
6482             return true;
6483 
6484         static bool isEntirelyVoid(const Expressions* elems)
6485         {
6486             foreach (e; *elems)
6487             {
6488                 // It can be NULL for performance reasons,
6489                 // see StructLiteralExp::interpret().
6490                 if (e && !isVoid(e))
6491                     return false;
6492             }
6493             return true;
6494         }
6495 
6496         if (auto sle = e.isStructLiteralExp())
6497             return isEntirelyVoid(sle.elements);
6498 
6499         if (checkArrayType && e.type.ty != Tsarray)
6500             return false;
6501 
6502         if (auto ale = e.isArrayLiteralExp())
6503             return isEntirelyVoid(ale.elements);
6504 
6505         return false;
6506     }
6507 
6508 
6509     /* Scrub all elements of elems[].
6510      * Returns: null for success, error Expression for failure
6511      */
6512     Expression scrubArray(Expressions* elems, bool structlit = false)
6513     {
6514         foreach (ref e; *elems)
6515         {
6516             // It can be NULL for performance reasons,
6517             // see StructLiteralExp::interpret().
6518             if (!e)
6519                 continue;
6520 
6521             // A struct .init may contain void members.
6522             // Static array members are a weird special case https://issues.dlang.org/show_bug.cgi?id=10994
6523             if (structlit && isVoid(e, true))
6524             {
6525                 e = null;
6526             }
6527             else
6528             {
6529                 e = scrubReturnValue(loc, e);
6530                 if (CTFEExp.isCantExp(e) || e.op == EXP.error)
6531                     return e;
6532             }
6533         }
6534         return null;
6535     }
6536 
6537     Expression scrubSE(StructLiteralExp sle)
6538     {
6539         sle.ownedByCtfe = OwnedBy.code;
6540         if (!(sle.stageflags & stageScrub))
6541         {
6542             const old = sle.stageflags;
6543             sle.stageflags |= stageScrub;       // prevent infinite recursion
6544             if (auto ex = scrubArray(sle.elements, true))
6545                 return ex;
6546             sle.stageflags = old;
6547         }
6548         return null;
6549     }
6550 
6551     if (e.op == EXP.classReference)
6552     {
6553         StructLiteralExp sle = e.isClassReferenceExp().value;
6554         if (auto ex = scrubSE(sle))
6555             return ex;
6556     }
6557     else if (auto vie = e.isVoidInitExp())
6558     {
6559         error(loc, "uninitialized variable `%s` cannot be returned from CTFE", vie.var.toChars());
6560         return ErrorExp.get();
6561     }
6562 
6563     e = resolveSlice(e);
6564 
6565     if (auto sle = e.isStructLiteralExp())
6566     {
6567         if (auto ex = scrubSE(sle))
6568             return ex;
6569     }
6570     else if (auto se = e.isStringExp())
6571     {
6572         se.ownedByCtfe = OwnedBy.code;
6573     }
6574     else if (auto ale = e.isArrayLiteralExp())
6575     {
6576         ale.ownedByCtfe = OwnedBy.code;
6577         if (auto ex = scrubArray(ale.elements))
6578             return ex;
6579     }
6580     else if (auto aae = e.isAssocArrayLiteralExp())
6581     {
6582         aae.ownedByCtfe = OwnedBy.code;
6583         if (auto ex = scrubArray(aae.keys))
6584             return ex;
6585         if (auto ex = scrubArray(aae.values))
6586             return ex;
6587         aae.type = toBuiltinAAType(aae.type);
6588     }
6589     else if (auto ve = e.isVectorExp())
6590     {
6591         ve.ownedByCtfe = OwnedBy.code;
6592         if (auto ale = ve.e1.isArrayLiteralExp())
6593         {
6594             ale.ownedByCtfe = OwnedBy.code;
6595             if (auto ex = scrubArray(ale.elements))
6596                 return ex;
6597         }
6598     }
6599     return e;
6600 }
6601 
6602 /**************************************
6603  * Transitively set all .ownedByCtfe to OwnedBy.cache
6604  */
scrubCacheValue(Expression e)6605 private Expression scrubCacheValue(Expression e)
6606 {
6607     if (!e)
6608         return e;
6609 
6610     Expression scrubArrayCache(Expressions* elems)
6611     {
6612         foreach (ref e; *elems)
6613             e = scrubCacheValue(e);
6614         return null;
6615     }
6616 
6617     Expression scrubSE(StructLiteralExp sle)
6618     {
6619         sle.ownedByCtfe = OwnedBy.cache;
6620         if (!(sle.stageflags & stageScrub))
6621         {
6622             const old = sle.stageflags;
6623             sle.stageflags |= stageScrub;       // prevent infinite recursion
6624             if (auto ex = scrubArrayCache(sle.elements))
6625                 return ex;
6626             sle.stageflags = old;
6627         }
6628         return null;
6629     }
6630 
6631     if (e.op == EXP.classReference)
6632     {
6633         if (auto ex = scrubSE(e.isClassReferenceExp().value))
6634             return ex;
6635     }
6636     else if (auto sle = e.isStructLiteralExp())
6637     {
6638         if (auto ex = scrubSE(sle))
6639             return ex;
6640     }
6641     else if (auto se = e.isStringExp())
6642     {
6643         se.ownedByCtfe = OwnedBy.cache;
6644     }
6645     else if (auto ale = e.isArrayLiteralExp())
6646     {
6647         ale.ownedByCtfe = OwnedBy.cache;
6648         if (Expression ex = scrubArrayCache(ale.elements))
6649             return ex;
6650     }
6651     else if (auto aae = e.isAssocArrayLiteralExp())
6652     {
6653         aae.ownedByCtfe = OwnedBy.cache;
6654         if (auto ex = scrubArrayCache(aae.keys))
6655             return ex;
6656         if (auto ex = scrubArrayCache(aae.values))
6657             return ex;
6658     }
6659     else if (auto ve = e.isVectorExp())
6660     {
6661         ve.ownedByCtfe = OwnedBy.cache;
6662         if (auto ale = ve.e1.isArrayLiteralExp())
6663         {
6664             ale.ownedByCtfe = OwnedBy.cache;
6665             if (auto ex = scrubArrayCache(ale.elements))
6666                 return ex;
6667         }
6668     }
6669     return e;
6670 }
6671 
6672 /********************************************
6673  * Transitively replace all Expressions allocated in ctfeGlobals.region
6674  * with Mem owned copies.
6675  * Params:
6676  *      e = possible ctfeGlobals.region owned expression
6677  * Returns:
6678  *      Mem owned expression
6679  */
copyRegionExp(Expression e)6680 private Expression copyRegionExp(Expression e)
6681 {
6682     if (!e)
6683         return e;
6684 
6685     static void copyArray(Expressions* elems)
6686     {
6687         foreach (ref e; *elems)
6688         {
6689             auto ex = e;
6690             e = null;
6691             e = copyRegionExp(ex);
6692         }
6693     }
6694 
6695     static void copySE(StructLiteralExp sle)
6696     {
6697         if (1 || !(sle.stageflags & stageScrub))
6698         {
6699             const old = sle.stageflags;
6700             sle.stageflags |= stageScrub;       // prevent infinite recursion
6701             copyArray(sle.elements);
6702             sle.stageflags = old;
6703         }
6704     }
6705 
6706     switch (e.op)
6707     {
6708         case EXP.classReference:
6709         {
6710             auto cre = e.isClassReferenceExp();
6711             cre.value = copyRegionExp(cre.value).isStructLiteralExp();
6712             break;
6713         }
6714 
6715         case EXP.structLiteral:
6716         {
6717             auto sle = e.isStructLiteralExp();
6718 
6719             /* The following is to take care of updating sle.origin correctly,
6720              * which may have multiple objects pointing to it.
6721              */
6722             if (sle.isOriginal && !ctfeGlobals.region.contains(cast(void*)sle.origin))
6723             {
6724                 /* This means sle has already been moved out of the region,
6725                  * and sle.origin is the new location.
6726                  */
6727                 return sle.origin;
6728             }
6729             copySE(sle);
6730             sle.isOriginal = sle is sle.origin;
6731 
6732             auto slec = ctfeGlobals.region.contains(cast(void*)e)
6733                 ? e.copy().isStructLiteralExp()         // move sle out of region to slec
6734                 : sle;
6735 
6736             if (ctfeGlobals.region.contains(cast(void*)sle.origin))
6737             {
6738                 auto sleo = sle.origin == sle ? slec : sle.origin.copy().isStructLiteralExp();
6739                 sle.origin = sleo;
6740                 slec.origin = sleo;
6741             }
6742             return slec;
6743         }
6744 
6745         case EXP.arrayLiteral:
6746         {
6747             auto ale = e.isArrayLiteralExp();
6748             ale.basis = copyRegionExp(ale.basis);
6749             copyArray(ale.elements);
6750             break;
6751         }
6752 
6753         case EXP.assocArrayLiteral:
6754             copyArray(e.isAssocArrayLiteralExp().keys);
6755             copyArray(e.isAssocArrayLiteralExp().values);
6756             break;
6757 
6758         case EXP.slice:
6759         {
6760             auto se = e.isSliceExp();
6761             se.e1  = copyRegionExp(se.e1);
6762             se.upr = copyRegionExp(se.upr);
6763             se.lwr = copyRegionExp(se.lwr);
6764             break;
6765         }
6766 
6767         case EXP.tuple:
6768         {
6769             auto te = e.isTupleExp();
6770             te.e0 = copyRegionExp(te.e0);
6771             copyArray(te.exps);
6772             break;
6773         }
6774 
6775         case EXP.address:
6776         case EXP.delegate_:
6777         case EXP.vector:
6778         case EXP.dotVariable:
6779         {
6780             UnaExp ue = e.isUnaExp();
6781             ue.e1 = copyRegionExp(ue.e1);
6782             break;
6783         }
6784 
6785         case EXP.index:
6786         {
6787             BinExp be = e.isBinExp();
6788             be.e1 = copyRegionExp(be.e1);
6789             be.e2 = copyRegionExp(be.e2);
6790             break;
6791         }
6792 
6793         case EXP.this_:
6794         case EXP.super_:
6795         case EXP.variable:
6796         case EXP.type:
6797         case EXP.function_:
6798         case EXP.typeid_:
6799         case EXP.string_:
6800         case EXP.int64:
6801         case EXP.error:
6802         case EXP.float64:
6803         case EXP.complex80:
6804         case EXP.null_:
6805         case EXP.void_:
6806         case EXP.symbolOffset:
6807         case EXP.char_:
6808             break;
6809 
6810         case EXP.cantExpression:
6811         case EXP.voidExpression:
6812         case EXP.showCtfeContext:
6813             return e;
6814 
6815         default:
6816             printf("e: %s, %s\n", EXPtoString(e.op).ptr, e.toChars());
6817             assert(0);
6818     }
6819 
6820     if (ctfeGlobals.region.contains(cast(void*)e))
6821     {
6822         return e.copy();
6823     }
6824     return e;
6825 }
6826 
6827 /******************************* Special Functions ***************************/
6828 
interpret_length(UnionExp * pue,InterState * istate,Expression earg)6829 private Expression interpret_length(UnionExp* pue, InterState* istate, Expression earg)
6830 {
6831     //printf("interpret_length()\n");
6832     earg = interpret(pue, earg, istate);
6833     if (exceptionOrCantInterpret(earg))
6834         return earg;
6835     dinteger_t len = 0;
6836     if (auto aae = earg.isAssocArrayLiteralExp())
6837         len = aae.keys.dim;
6838     else
6839         assert(earg.op == EXP.null_);
6840     emplaceExp!(IntegerExp)(pue, earg.loc, len, Type.tsize_t);
6841     return pue.exp();
6842 }
6843 
interpret_keys(UnionExp * pue,InterState * istate,Expression earg,Type returnType)6844 private Expression interpret_keys(UnionExp* pue, InterState* istate, Expression earg, Type returnType)
6845 {
6846     debug (LOG)
6847     {
6848         printf("interpret_keys()\n");
6849     }
6850     earg = interpret(pue, earg, istate);
6851     if (exceptionOrCantInterpret(earg))
6852         return earg;
6853     if (earg.op == EXP.null_)
6854     {
6855         emplaceExp!(NullExp)(pue, earg.loc, earg.type);
6856         return pue.exp();
6857     }
6858     if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
6859         return null;
6860     AssocArrayLiteralExp aae = earg.isAssocArrayLiteralExp();
6861     auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.keys);
6862     ae.ownedByCtfe = aae.ownedByCtfe;
6863     *pue = copyLiteral(ae);
6864     return pue.exp();
6865 }
6866 
interpret_values(UnionExp * pue,InterState * istate,Expression earg,Type returnType)6867 private Expression interpret_values(UnionExp* pue, InterState* istate, Expression earg, Type returnType)
6868 {
6869     debug (LOG)
6870     {
6871         printf("interpret_values()\n");
6872     }
6873     earg = interpret(pue, earg, istate);
6874     if (exceptionOrCantInterpret(earg))
6875         return earg;
6876     if (earg.op == EXP.null_)
6877     {
6878         emplaceExp!(NullExp)(pue, earg.loc, earg.type);
6879         return pue.exp();
6880     }
6881     if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
6882         return null;
6883     auto aae = earg.isAssocArrayLiteralExp();
6884     auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.values);
6885     ae.ownedByCtfe = aae.ownedByCtfe;
6886     //printf("result is %s\n", e.toChars());
6887     *pue = copyLiteral(ae);
6888     return pue.exp();
6889 }
6890 
interpret_dup(UnionExp * pue,InterState * istate,Expression earg)6891 private Expression interpret_dup(UnionExp* pue, InterState* istate, Expression earg)
6892 {
6893     debug (LOG)
6894     {
6895         printf("interpret_dup()\n");
6896     }
6897     earg = interpret(pue, earg, istate);
6898     if (exceptionOrCantInterpret(earg))
6899         return earg;
6900     if (earg.op == EXP.null_)
6901     {
6902         emplaceExp!(NullExp)(pue, earg.loc, earg.type);
6903         return pue.exp();
6904     }
6905     if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
6906         return null;
6907     auto aae = copyLiteral(earg).copy().isAssocArrayLiteralExp();
6908     for (size_t i = 0; i < aae.keys.dim; i++)
6909     {
6910         if (Expression e = evaluatePostblit(istate, (*aae.keys)[i]))
6911             return e;
6912         if (Expression e = evaluatePostblit(istate, (*aae.values)[i]))
6913             return e;
6914     }
6915     aae.type = earg.type.mutableOf(); // repaint type from const(int[int]) to const(int)[int]
6916     //printf("result is %s\n", aae.toChars());
6917     return aae;
6918 }
6919 
6920 // signature is int delegate(ref Value) OR int delegate(ref Key, ref Value)
interpret_aaApply(UnionExp * pue,InterState * istate,Expression aa,Expression deleg)6921 private Expression interpret_aaApply(UnionExp* pue, InterState* istate, Expression aa, Expression deleg)
6922 {
6923     aa = interpret(aa, istate);
6924     if (exceptionOrCantInterpret(aa))
6925         return aa;
6926     if (aa.op != EXP.assocArrayLiteral)
6927     {
6928         emplaceExp!(IntegerExp)(pue, deleg.loc, 0, Type.tsize_t);
6929         return pue.exp();
6930     }
6931 
6932     FuncDeclaration fd = null;
6933     Expression pthis = null;
6934     if (auto de = deleg.isDelegateExp())
6935     {
6936         fd = de.func;
6937         pthis = de.e1;
6938     }
6939     else if (auto fe = deleg.isFuncExp())
6940         fd = fe.fd;
6941 
6942     assert(fd && fd.fbody);
6943     assert(fd.parameters);
6944     size_t numParams = fd.parameters.dim;
6945     assert(numParams == 1 || numParams == 2);
6946 
6947     Parameter fparam = fd.type.isTypeFunction().parameterList[numParams - 1];
6948     const wantRefValue = fparam.isReference();
6949 
6950     Expressions args = Expressions(numParams);
6951 
6952     AssocArrayLiteralExp ae = aa.isAssocArrayLiteralExp();
6953     if (!ae.keys || ae.keys.dim == 0)
6954         return ctfeEmplaceExp!IntegerExp(deleg.loc, 0, Type.tsize_t);
6955     Expression eresult;
6956 
6957     for (size_t i = 0; i < ae.keys.dim; ++i)
6958     {
6959         Expression ekey = (*ae.keys)[i];
6960         Expression evalue = (*ae.values)[i];
6961         if (wantRefValue)
6962         {
6963             Type t = evalue.type;
6964             evalue = ctfeEmplaceExp!IndexExp(deleg.loc, ae, ekey);
6965             evalue.type = t;
6966         }
6967         args[numParams - 1] = evalue;
6968         if (numParams == 2)
6969             args[0] = ekey;
6970 
6971         UnionExp ue = void;
6972         eresult = interpretFunction(&ue, fd, istate, &args, pthis);
6973         if (eresult == ue.exp())
6974             eresult = ue.copy();
6975         if (exceptionOrCantInterpret(eresult))
6976             return eresult;
6977 
6978         if (eresult.isIntegerExp().getInteger() != 0)
6979             return eresult;
6980     }
6981     return eresult;
6982 }
6983 
6984 /* Decoding UTF strings for foreach loops. Duplicates the functionality of
6985  * the twelve _aApplyXXn functions in aApply.d in the runtime.
6986  */
foreachApplyUtf(UnionExp * pue,InterState * istate,Expression str,Expression deleg,bool rvs)6987 private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression str, Expression deleg, bool rvs)
6988 {
6989     debug (LOG)
6990     {
6991         printf("foreachApplyUtf(%s, %s)\n", str.toChars(), deleg.toChars());
6992     }
6993     FuncDeclaration fd = null;
6994     Expression pthis = null;
6995     if (auto de = deleg.isDelegateExp())
6996     {
6997         fd = de.func;
6998         pthis = de.e1;
6999     }
7000     else if (auto fe = deleg.isFuncExp())
7001         fd = fe.fd;
7002 
7003     assert(fd && fd.fbody);
7004     assert(fd.parameters);
7005     size_t numParams = fd.parameters.dim;
7006     assert(numParams == 1 || numParams == 2);
7007     Type charType = (*fd.parameters)[numParams - 1].type;
7008     Type indexType = numParams == 2 ? (*fd.parameters)[0].type : Type.tsize_t;
7009     size_t len = cast(size_t)resolveArrayLength(str);
7010     if (len == 0)
7011     {
7012         emplaceExp!(IntegerExp)(pue, deleg.loc, 0, indexType);
7013         return pue.exp();
7014     }
7015 
7016     UnionExp strTmp = void;
7017     str = resolveSlice(str, &strTmp);
7018 
7019     auto se = str.isStringExp();
7020     auto ale = str.isArrayLiteralExp();
7021     if (!se && !ale)
7022     {
7023         str.error("CTFE internal error: cannot foreach `%s`", str.toChars());
7024         return CTFEExp.cantexp;
7025     }
7026     Expressions args = Expressions(numParams);
7027 
7028     Expression eresult = null; // ded-store to prevent spurious warning
7029 
7030     // Buffers for encoding; also used for decoding array literals
7031     char[4] utf8buf = void;
7032     wchar[2] utf16buf = void;
7033 
7034     size_t start = rvs ? len : 0;
7035     size_t end = rvs ? 0 : len;
7036     for (size_t indx = start; indx != end;)
7037     {
7038         // Step 1: Decode the next dchar from the string.
7039 
7040         string errmsg = null; // Used for reporting decoding errors
7041         dchar rawvalue; // Holds the decoded dchar
7042         size_t currentIndex = indx; // The index of the decoded character
7043 
7044         if (ale)
7045         {
7046             // If it is an array literal, copy the code points into the buffer
7047             size_t buflen = 1; // #code points in the buffer
7048             size_t n = 1; // #code points in this char
7049             size_t sz = cast(size_t)ale.type.nextOf().size();
7050 
7051             switch (sz)
7052             {
7053             case 1:
7054                 if (rvs)
7055                 {
7056                     // find the start of the string
7057                     --indx;
7058                     buflen = 1;
7059                     while (indx > 0 && buflen < 4)
7060                     {
7061                         Expression r = (*ale.elements)[indx];
7062                         char x = cast(char)r.isIntegerExp().getInteger();
7063                         if ((x & 0xC0) != 0x80)
7064                             break;
7065                         --indx;
7066                         ++buflen;
7067                     }
7068                 }
7069                 else
7070                     buflen = (indx + 4 > len) ? len - indx : 4;
7071                 for (size_t i = 0; i < buflen; ++i)
7072                 {
7073                     Expression r = (*ale.elements)[indx + i];
7074                     utf8buf[i] = cast(char)r.isIntegerExp().getInteger();
7075                 }
7076                 n = 0;
7077                 errmsg = utf_decodeChar(utf8buf[0 .. buflen], n, rawvalue);
7078                 break;
7079 
7080             case 2:
7081                 if (rvs)
7082                 {
7083                     // find the start of the string
7084                     --indx;
7085                     buflen = 1;
7086                     Expression r = (*ale.elements)[indx];
7087                     ushort x = cast(ushort)r.isIntegerExp().getInteger();
7088                     if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF)
7089                     {
7090                         --indx;
7091                         ++buflen;
7092                     }
7093                 }
7094                 else
7095                     buflen = (indx + 2 > len) ? len - indx : 2;
7096                 for (size_t i = 0; i < buflen; ++i)
7097                 {
7098                     Expression r = (*ale.elements)[indx + i];
7099                     utf16buf[i] = cast(ushort)r.isIntegerExp().getInteger();
7100                 }
7101                 n = 0;
7102                 errmsg = utf_decodeWchar(utf16buf[0 .. buflen], n, rawvalue);
7103                 break;
7104 
7105             case 4:
7106                 {
7107                     if (rvs)
7108                         --indx;
7109                     Expression r = (*ale.elements)[indx];
7110                     rawvalue = cast(dchar)r.isIntegerExp().getInteger();
7111                     n = 1;
7112                 }
7113                 break;
7114 
7115             default:
7116                 assert(0);
7117             }
7118             if (!rvs)
7119                 indx += n;
7120         }
7121         else
7122         {
7123             // String literals
7124             size_t saveindx; // used for reverse iteration
7125 
7126             switch (se.sz)
7127             {
7128             case 1:
7129             {
7130                 if (rvs)
7131                 {
7132                     // find the start of the string
7133                     --indx;
7134                     while (indx > 0 && ((se.getCodeUnit(indx) & 0xC0) == 0x80))
7135                         --indx;
7136                     saveindx = indx;
7137                 }
7138                 auto slice = se.peekString();
7139                 errmsg = utf_decodeChar(slice, indx, rawvalue);
7140                 if (rvs)
7141                     indx = saveindx;
7142                 break;
7143             }
7144 
7145             case 2:
7146                 if (rvs)
7147                 {
7148                     // find the start
7149                     --indx;
7150                     auto wc = se.getCodeUnit(indx);
7151                     if (wc >= 0xDC00 && wc <= 0xDFFF)
7152                         --indx;
7153                     saveindx = indx;
7154                 }
7155                 const slice = se.peekWstring();
7156                 errmsg = utf_decodeWchar(slice, indx, rawvalue);
7157                 if (rvs)
7158                     indx = saveindx;
7159                 break;
7160 
7161             case 4:
7162                 if (rvs)
7163                     --indx;
7164                 rawvalue = se.getCodeUnit(indx);
7165                 if (!rvs)
7166                     ++indx;
7167                 break;
7168 
7169             default:
7170                 assert(0);
7171             }
7172         }
7173         if (errmsg)
7174         {
7175             deleg.error("`%.*s`", cast(int)errmsg.length, errmsg.ptr);
7176             return CTFEExp.cantexp;
7177         }
7178 
7179         // Step 2: encode the dchar in the target encoding
7180 
7181         int charlen = 1; // How many codepoints are involved?
7182         switch (charType.size())
7183         {
7184         case 1:
7185             charlen = utf_codeLengthChar(rawvalue);
7186             utf_encodeChar(&utf8buf[0], rawvalue);
7187             break;
7188         case 2:
7189             charlen = utf_codeLengthWchar(rawvalue);
7190             utf_encodeWchar(&utf16buf[0], rawvalue);
7191             break;
7192         case 4:
7193             break;
7194         default:
7195             assert(0);
7196         }
7197         if (rvs)
7198             currentIndex = indx;
7199 
7200         // Step 3: call the delegate once for each code point
7201 
7202         // The index only needs to be set once
7203         if (numParams == 2)
7204             args[0] = ctfeEmplaceExp!IntegerExp(deleg.loc, currentIndex, indexType);
7205 
7206         Expression val = null;
7207 
7208         foreach (k; 0 .. charlen)
7209         {
7210             dchar codepoint;
7211             switch (charType.size())
7212             {
7213             case 1:
7214                 codepoint = utf8buf[k];
7215                 break;
7216             case 2:
7217                 codepoint = utf16buf[k];
7218                 break;
7219             case 4:
7220                 codepoint = rawvalue;
7221                 break;
7222             default:
7223                 assert(0);
7224             }
7225             val = ctfeEmplaceExp!IntegerExp(str.loc, codepoint, charType);
7226 
7227             args[numParams - 1] = val;
7228 
7229             UnionExp ue = void;
7230             eresult = interpretFunction(&ue, fd, istate, &args, pthis);
7231             if (eresult == ue.exp())
7232                 eresult = ue.copy();
7233             if (exceptionOrCantInterpret(eresult))
7234                 return eresult;
7235             if (eresult.isIntegerExp().getInteger() != 0)
7236                 return eresult;
7237         }
7238     }
7239     return eresult;
7240 }
7241 
7242 /* If this is a built-in function, return the interpreted result,
7243  * Otherwise, return NULL.
7244  */
evaluateIfBuiltin(UnionExp * pue,InterState * istate,const ref Loc loc,FuncDeclaration fd,Expressions * arguments,Expression pthis)7245 private Expression evaluateIfBuiltin(UnionExp* pue, InterState* istate, const ref Loc loc, FuncDeclaration fd, Expressions* arguments, Expression pthis)
7246 {
7247     Expression e = null;
7248     size_t nargs = arguments ? arguments.dim : 0;
7249     if (!pthis)
7250     {
7251         if (isBuiltin(fd) != BUILTIN.unimp)
7252         {
7253             Expressions args = Expressions(nargs);
7254             foreach (i, ref arg; args)
7255             {
7256                 Expression earg = (*arguments)[i];
7257                 earg = interpret(earg, istate);
7258                 if (exceptionOrCantInterpret(earg))
7259                     return earg;
7260                 arg = earg;
7261             }
7262             e = eval_builtin(loc, fd, &args);
7263             if (!e)
7264             {
7265                 error(loc, "cannot evaluate unimplemented builtin `%s` at compile time", fd.toChars());
7266                 e = CTFEExp.cantexp;
7267             }
7268         }
7269     }
7270     if (!pthis)
7271     {
7272         if (nargs == 1 || nargs == 3)
7273         {
7274             Expression firstarg = (*arguments)[0];
7275             if (auto firstAAtype = firstarg.type.toBasetype().isTypeAArray())
7276             {
7277                 const id = fd.ident;
7278                 if (nargs == 1)
7279                 {
7280                     if (id == Id.aaLen)
7281                         return interpret_length(pue, istate, firstarg);
7282 
7283                     if (fd.toParent2().ident == Id.object)
7284                     {
7285                         if (id == Id.keys)
7286                             return interpret_keys(pue, istate, firstarg, firstAAtype.index.arrayOf());
7287                         if (id == Id.values)
7288                             return interpret_values(pue, istate, firstarg, firstAAtype.nextOf().arrayOf());
7289                         if (id == Id.rehash)
7290                             return interpret(pue, firstarg, istate);
7291                         if (id == Id.dup)
7292                             return interpret_dup(pue, istate, firstarg);
7293                     }
7294                 }
7295                 else // (nargs == 3)
7296                 {
7297                     if (id == Id._aaApply)
7298                         return interpret_aaApply(pue, istate, firstarg, (*arguments)[2]);
7299                     if (id == Id._aaApply2)
7300                         return interpret_aaApply(pue, istate, firstarg, (*arguments)[2]);
7301                 }
7302             }
7303         }
7304     }
7305     if (pthis && !fd.fbody && fd.isCtorDeclaration() && fd.parent && fd.parent.parent && fd.parent.parent.ident == Id.object)
7306     {
7307         if (pthis.op == EXP.classReference && fd.parent.ident == Id.Throwable)
7308         {
7309             // At present, the constructors just copy their arguments into the struct.
7310             // But we might need some magic if stack tracing gets added to druntime.
7311             StructLiteralExp se = pthis.isClassReferenceExp().value;
7312             assert(arguments.dim <= se.elements.dim);
7313             foreach (i, arg; *arguments)
7314             {
7315                 auto elem = interpret(arg, istate);
7316                 if (exceptionOrCantInterpret(elem))
7317                     return elem;
7318                 (*se.elements)[i] = elem;
7319             }
7320             return CTFEExp.voidexp;
7321         }
7322     }
7323     if (nargs == 1 && !pthis && (fd.ident == Id.criticalenter || fd.ident == Id.criticalexit))
7324     {
7325         // Support synchronized{} as a no-op
7326         return CTFEExp.voidexp;
7327     }
7328     if (!pthis)
7329     {
7330         const idlen = fd.ident.toString().length;
7331         const id = fd.ident.toChars();
7332         if (nargs == 2 && (idlen == 10 || idlen == 11) && !strncmp(id, "_aApply", 7))
7333         {
7334             // Functions from aApply.d and aApplyR.d in the runtime
7335             bool rvs = (idlen == 11); // true if foreach_reverse
7336             char c = id[idlen - 3]; // char width: 'c', 'w', or 'd'
7337             char s = id[idlen - 2]; // string width: 'c', 'w', or 'd'
7338             char n = id[idlen - 1]; // numParams: 1 or 2.
7339             // There are 12 combinations
7340             if ((n == '1' || n == '2') &&
7341                 (c == 'c' || c == 'w' || c == 'd') &&
7342                 (s == 'c' || s == 'w' || s == 'd') &&
7343                 c != s)
7344             {
7345                 Expression str = (*arguments)[0];
7346                 str = interpret(str, istate);
7347                 if (exceptionOrCantInterpret(str))
7348                     return str;
7349                 return foreachApplyUtf(pue, istate, str, (*arguments)[1], rvs);
7350             }
7351         }
7352     }
7353     return e;
7354 }
7355 
evaluatePostblit(InterState * istate,Expression e)7356 private Expression evaluatePostblit(InterState* istate, Expression e)
7357 {
7358     auto ts = e.type.baseElemOf().isTypeStruct();
7359     if (!ts)
7360         return null;
7361     StructDeclaration sd = ts.sym;
7362     if (!sd.postblit)
7363         return null;
7364 
7365     if (auto ale = e.isArrayLiteralExp())
7366     {
7367         foreach (elem; *ale.elements)
7368         {
7369             if (auto ex = evaluatePostblit(istate, elem))
7370                 return ex;
7371         }
7372         return null;
7373     }
7374     if (e.op == EXP.structLiteral)
7375     {
7376         // e.__postblit()
7377         UnionExp ue = void;
7378         e = interpretFunction(&ue, sd.postblit, istate, null, e);
7379         if (e == ue.exp())
7380             e = ue.copy();
7381         if (exceptionOrCantInterpret(e))
7382             return e;
7383         return null;
7384     }
7385     assert(0);
7386 }
7387 
evaluateDtor(InterState * istate,Expression e)7388 private Expression evaluateDtor(InterState* istate, Expression e)
7389 {
7390     auto ts = e.type.baseElemOf().isTypeStruct();
7391     if (!ts)
7392         return null;
7393     StructDeclaration sd = ts.sym;
7394     if (!sd.dtor)
7395         return null;
7396 
7397     UnionExp ue = void;
7398     if (auto ale = e.isArrayLiteralExp())
7399     {
7400         foreach_reverse (elem; *ale.elements)
7401             e = evaluateDtor(istate, elem);
7402     }
7403     else if (e.op == EXP.structLiteral)
7404     {
7405         // e.__dtor()
7406         e = interpretFunction(&ue, sd.dtor, istate, null, e);
7407     }
7408     else
7409         assert(0);
7410     if (exceptionOrCantInterpret(e))
7411     {
7412         if (e == ue.exp())
7413             e = ue.copy();
7414         return e;
7415     }
7416     return null;
7417 }
7418 
7419 /*************************** CTFE Sanity Checks ***************************/
7420 /* Setter functions for CTFE variable values.
7421  * These functions exist to check for compiler CTFE bugs.
7422  */
hasValue(VarDeclaration vd)7423 private bool hasValue(VarDeclaration vd)
7424 {
7425     return vd.ctfeAdrOnStack != VarDeclaration.AdrOnStackNone &&
7426            getValue(vd) !is null;
7427 }
7428 
7429 // Don't check for validity
setValueWithoutChecking(VarDeclaration vd,Expression newval)7430 private void setValueWithoutChecking(VarDeclaration vd, Expression newval)
7431 {
7432     ctfeGlobals.stack.setValue(vd, newval);
7433 }
7434 
setValue(VarDeclaration vd,Expression newval)7435 private void setValue(VarDeclaration vd, Expression newval)
7436 {
7437     //printf("setValue() vd: %s newval: %s\n", vd.toChars(), newval.toChars());
7438     version (none)
7439     {
7440         if (!((vd.storage_class & (STC.out_ | STC.ref_)) ? isCtfeReferenceValid(newval) : isCtfeValueValid(newval)))
7441         {
7442             printf("[%s] vd = %s %s, newval = %s\n", vd.loc.toChars(), vd.type.toChars(), vd.toChars(), newval.toChars());
7443         }
7444     }
7445     assert((vd.storage_class & (STC.out_ | STC.ref_)) ? isCtfeReferenceValid(newval) : isCtfeValueValid(newval));
7446     ctfeGlobals.stack.setValue(vd, newval);
7447 }
7448 
7449 /**
7450  * Removes `_d_HookTraceImpl` if found from `ce` and `fd`.
7451  * This is needed for the CTFE interception code to be able to find hooks that are called though the hook's `*Trace`
7452  * wrapper.
7453  *
7454  * This is done by replacing `_d_HookTraceImpl!(T, Hook, errMsg)(..., parameters)` with `Hook(parameters)`.
7455  * Parameters:
7456  *  ce = The CallExp that possible will be be replaced
7457  *  fd = Fully resolve function declaration that `ce` would call
7458  */
removeHookTraceImpl(ref CallExp ce,ref FuncDeclaration fd)7459 private void removeHookTraceImpl(ref CallExp ce, ref FuncDeclaration fd)
7460 {
7461     if (fd.ident != Id._d_HookTraceImpl)
7462         return;
7463 
7464     auto oldCE = ce;
7465 
7466     // Get the Hook from the second template parameter
7467     TemplateInstance templateInstance = fd.parent.isTemplateInstance;
7468     RootObject hook = (*templateInstance.tiargs)[1];
7469     assert(hook.dyncast() == DYNCAST.dsymbol, "Expected _d_HookTraceImpl's second template parameter to be an alias to the hook!");
7470     fd = (cast(Dsymbol)hook).isFuncDeclaration;
7471 
7472     // Remove the first three trace parameters
7473     auto arguments = new Expressions();
7474     arguments.reserve(ce.arguments.dim - 3);
7475     arguments.pushSlice((*ce.arguments)[3 .. $]);
7476 
7477     ce = ctfeEmplaceExp!CallExp(ce.loc, ctfeEmplaceExp!VarExp(ce.loc, fd, false), arguments);
7478 
7479     if (global.params.verbose)
7480         message("strip     %s =>\n          %s", oldCE.toChars(), ce.toChars());
7481 }
7482