Home | History | Annotate | Line # | Download | only in dmd
dinterpret.d revision 1.1.1.1
      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  */
     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  */
    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 
    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
    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 
    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:
    283     extern (C++) size_t stackPointer()
    284     {
    285         return values.dim;
    286     }
    287 
    288     // The current value of 'this', or NULL if none
    289     extern (C++) Expression getThis()
    290     {
    291         return localThis;
    292     }
    293 
    294     // Largest number of stack positions we've used
    295     extern (C++) size_t maxStackUsage()
    296     {
    297         return maxStackPointer;
    298     }
    299 
    300     // Start a new stack frame, using the provided 'this'.
    301     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 
    309     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 
    319     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 
    326     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 
    338     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 
    346     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 
    362     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 
    376     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 
    391     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  */
    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
    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 
    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.
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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      */
    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
    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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   1260     override void visit(ForeachStatement s)
   1261     {
   1262         assert(0); // rewritten to ForStatement
   1263     }
   1264 
   1265     override void visit(ForeachRangeStatement s)
   1266     {
   1267         assert(0); // rewritten to ForStatement
   1268     }
   1269 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   1509     static bool isAnErrorException(ClassDeclaration cd)
   1510     {
   1511         return cd == ClassDeclaration.errorException || ClassDeclaration.errorException.isBaseOf(cd, null);
   1512     }
   1513 
   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 
   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 
   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`
   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 
   1639     override void visit(ScopeGuardStatement s)
   1640     {
   1641         assert(0);
   1642     }
   1643 
   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 
   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 
   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 
   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 
   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 
   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 
   1801     override void visit(NullExp e)
   1802     {
   1803         result = e;
   1804     }
   1805 
   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 
   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 
   1824     override void visit(ComplexExp e)
   1825     {
   1826         result = e;
   1827     }
   1828 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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..$]
   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 
   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 
   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 
   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 
   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 
   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 
   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'.
   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     {
   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 
   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      */
   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 
   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      */
   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 
   4338     override void visit(AssignExp e)
   4339     {
   4340         interpretAssignCommon(e, null);
   4341     }
   4342 
   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 
   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      */
   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      */
   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 
   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.
   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 
   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 
   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 
   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 
   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      */
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   6354     override void visit(ClassReferenceExp e)
   6355     {
   6356         //printf("ClassReferenceExp::interpret() %s\n", e.value.toChars());
   6357         result = e;
   6358     }
   6359 
   6360     override void visit(VoidInitExp e)
   6361     {
   6362         e.error("CTFE internal error: trying to read uninitialized variable");
   6363         assert(0);
   6364     }
   6365 
   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  */
   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 ///
   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  */
   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  */
   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  */
   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 
   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 
   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 
   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 
   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)
   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  */
   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  */
   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 
   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 
   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  */
   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
   7430 private void setValueWithoutChecking(VarDeclaration vd, Expression newval)
   7431 {
   7432     ctfeGlobals.stack.setValue(vd, newval);
   7433 }
   7434 
   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  */
   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