"Fossies" - the Fresh Open Source Software Archive

Member "dmd2/src/dmd/dmd/dinterpret.d" (20 Nov 2020, 250414 Bytes) of package /linux/misc/dmd.2.094.2.linux.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) D source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /**
    2  * The entry point for CTFE.
    3  *
    4  * Specification: ($LINK2 https://dlang.org/spec/function.html#interpretation, Compile Time Function Execution (CTFE))
    5  *
    6  * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
    7  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
    8  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
    9  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dinterpret.d, _dinterpret.d)
   10  * Documentation:  https://dlang.org/phobos/dmd_dinterpret.html
   11  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dinterpret.d
   12  */
   13 
   14 module dmd.dinterpret;
   15 
   16 import core.stdc.stdio;
   17 import core.stdc.stdlib;
   18 import core.stdc.string;
   19 import dmd.apply;
   20 import dmd.arraytypes;
   21 import dmd.attrib;
   22 import dmd.builtin;
   23 import dmd.constfold;
   24 import dmd.ctfeexpr;
   25 import dmd.dclass;
   26 import dmd.declaration;
   27 import dmd.dstruct;
   28 import dmd.dsymbol;
   29 import dmd.dsymbolsem;
   30 import dmd.dtemplate;
   31 import dmd.errors;
   32 import dmd.expression;
   33 import dmd.expressionsem;
   34 import dmd.func;
   35 import dmd.globals;
   36 import dmd.id;
   37 import dmd.identifier;
   38 import dmd.init;
   39 import dmd.initsem;
   40 import dmd.mtype;
   41 import dmd.root.rmem;
   42 import dmd.root.array;
   43 import dmd.root.region;
   44 import dmd.root.rootobject;
   45 import dmd.statement;
   46 import dmd.tokens;
   47 import dmd.utf;
   48 import dmd.visitor;
   49 
   50 /*************************************
   51  * Entry point for CTFE.
   52  * A compile-time result is required. Give an error if not possible.
   53  *
   54  * `e` must be semantically valid expression. In other words, it should not
   55  * contain any `ErrorExp`s in it. But, CTFE interpretation will cross over
   56  * functions and may invoke a function that contains `ErrorStatement` in its body.
   57  * If that, the "CTFE failed because of previous errors" error is raised.
   58  */
   59 public Expression ctfeInterpret(Expression e)
   60 {
   61     switch (e.op)
   62     {
   63         case TOK.int64:
   64         case TOK.float64:
   65         case TOK.complex80:
   66         case TOK.null_:
   67         case TOK.void_:
   68         case TOK.string_:
   69         case TOK.this_:
   70         case TOK.super_:
   71         case TOK.type:
   72         case TOK.typeid_:
   73              if (e.type.ty == Terror)
   74                 return ErrorExp.get();
   75             goto case TOK.error;
   76 
   77         case TOK.error:
   78             return e;
   79 
   80         default:
   81             break;
   82     }
   83 
   84     assert(e.type); // https://issues.dlang.org/show_bug.cgi?id=14642
   85     //assert(e.type.ty != Terror);    // FIXME
   86     if (e.type.ty == Terror)
   87         return ErrorExp.get();
   88 
   89     auto rgnpos = ctfeGlobals.region.savePos();
   90 
   91     Expression result = interpret(e, null);
   92 
   93     result = copyRegionExp(result);
   94 
   95     if (!CTFEExp.isCantExp(result))
   96         result = scrubReturnValue(e.loc, result);
   97     if (CTFEExp.isCantExp(result))
   98         result = ErrorExp.get();
   99 
  100     ctfeGlobals.region.release(rgnpos);
  101 
  102     return result;
  103 }
  104 
  105 /* Run CTFE on the expression, but allow the expression to be a TypeExp
  106  *  or a tuple containing a TypeExp. (This is required by pragma(msg)).
  107  */
  108 public Expression ctfeInterpretForPragmaMsg(Expression e)
  109 {
  110     if (e.op == TOK.error || e.op == TOK.type)
  111         return e;
  112 
  113     // It's also OK for it to be a function declaration (happens only with
  114     // __traits(getOverloads))
  115     if (auto ve = e.isVarExp())
  116         if (ve.var.isFuncDeclaration())
  117         {
  118             return e;
  119         }
  120 
  121     auto tup = e.isTupleExp();
  122     if (!tup)
  123         return e.ctfeInterpret();
  124 
  125     // Tuples need to be treated separately, since they are
  126     // allowed to contain a TypeExp in this case.
  127 
  128     Expressions* expsx = null;
  129     foreach (i, g; *tup.exps)
  130     {
  131         auto h = ctfeInterpretForPragmaMsg(g);
  132         if (h != g)
  133         {
  134             if (!expsx)
  135             {
  136                 expsx = tup.exps.copy();
  137             }
  138             (*expsx)[i] = h;
  139         }
  140     }
  141     if (expsx)
  142     {
  143         auto te = new TupleExp(e.loc, expsx);
  144         expandTuples(te.exps);
  145         te.type = new TypeTuple(te.exps);
  146         return te;
  147     }
  148     return e;
  149 }
  150 
  151 public extern (C++) Expression getValue(VarDeclaration vd)
  152 {
  153     return ctfeGlobals.stack.getValue(vd);
  154 }
  155 
  156 /*************************************************
  157  * Allocate an Expression in the ctfe region.
  158  * Params:
  159  *      T = type of Expression to allocate
  160  *      args = arguments to Expression's constructor
  161  * Returns:
  162  *      allocated Expression
  163  */
  164 T ctfeEmplaceExp(T : Expression, Args...)(Args args)
  165 {
  166     if (mem.isGCEnabled)
  167         return new T(args);
  168     auto p = ctfeGlobals.region.malloc(__traits(classInstanceSize, T));
  169     emplaceExp!T(p, args);
  170     return cast(T)p;
  171 }
  172 
  173 // CTFE diagnostic information
  174 public extern (C++) void printCtfePerformanceStats()
  175 {
  176     debug (SHOWPERFORMANCE)
  177     {
  178         printf("        ---- CTFE Performance ----\n");
  179         printf("max call depth = %d\tmax stack = %d\n", ctfeGlobals.maxCallDepth, ctfeGlobals.stack.maxStackUsage());
  180         printf("array allocs = %d\tassignments = %d\n\n", ctfeGlobals.numArrayAllocs, ctfeGlobals.numAssignments);
  181     }
  182 }
  183 
  184 /**************************
  185  */
  186 
  187 void incArrayAllocs()
  188 {
  189     ++ctfeGlobals.numArrayAllocs;
  190 }
  191 
  192 /* ================================================ Implementation ======================================= */
  193 
  194 private:
  195 
  196 /***************
  197  * Collect together globals used by CTFE
  198  */
  199 struct CtfeGlobals
  200 {
  201     Region region;
  202 
  203     CtfeStack stack;
  204 
  205     int callDepth = 0;        // current number of recursive calls
  206 
  207     // When printing a stack trace, suppress this number of calls
  208     int stackTraceCallsToSuppress = 0;
  209 
  210     int maxCallDepth = 0;     // highest number of recursive calls
  211     int numArrayAllocs = 0;   // Number of allocated arrays
  212     int numAssignments = 0;   // total number of assignments executed
  213 }
  214 
  215 __gshared CtfeGlobals ctfeGlobals;
  216 
  217 enum CTFEGoal : int
  218 {
  219     RValue,     /// Must return an Rvalue (== CTFE value)
  220     LValue,     /// Must return an Lvalue (== CTFE reference)
  221     Nothing,    /// The return value is not required
  222 }
  223 
  224 //debug = LOG;
  225 //debug = LOGASSIGN;
  226 //debug = LOGCOMPILE;
  227 //debug = SHOWPERFORMANCE;
  228 
  229 // Maximum allowable recursive function calls in CTFE
  230 enum CTFE_RECURSION_LIMIT = 1000;
  231 
  232 /**
  233  The values of all CTFE variables
  234  */
  235 struct CtfeStack
  236 {
  237 private:
  238     /* The stack. Every declaration we encounter is pushed here,
  239      * together with the VarDeclaration, and the previous
  240      * stack address of that variable, so that we can restore it
  241      * when we leave the stack frame.
  242      * Note that when a function is forward referenced, the interpreter must
  243      * run semantic3, and that may start CTFE again with a NULL istate. Thus
  244      * the stack might not be empty when CTFE begins.
  245      *
  246      * Ctfe Stack addresses are just 0-based integers, but we save
  247      * them as 'void *' because Array can only do pointers.
  248      */
  249     Expressions values;         // values on the stack
  250     VarDeclarations vars;       // corresponding variables
  251     Array!(void*) savedId;      // id of the previous state of that var
  252 
  253     Array!(void*) frames;       // all previous frame pointers
  254     Expressions savedThis;      // all previous values of localThis
  255 
  256     /* Global constants get saved here after evaluation, so we never
  257      * have to redo them. This saves a lot of time and memory.
  258      */
  259     Expressions globalValues;   // values of global constants
  260 
  261     size_t framepointer;        // current frame pointer
  262     size_t maxStackPointer;     // most stack we've ever used
  263     Expression localThis;       // value of 'this', or NULL if none
  264 
  265 public:
  266     extern (C++) size_t stackPointer()
  267     {
  268         return values.dim;
  269     }
  270 
  271     // The current value of 'this', or NULL if none
  272     extern (C++) Expression getThis()
  273     {
  274         return localThis;
  275     }
  276 
  277     // Largest number of stack positions we've used
  278     extern (C++) size_t maxStackUsage()
  279     {
  280         return maxStackPointer;
  281     }
  282 
  283     // Start a new stack frame, using the provided 'this'.
  284     extern (C++) void startFrame(Expression thisexp)
  285     {
  286         frames.push(cast(void*)cast(size_t)framepointer);
  287         savedThis.push(localThis);
  288         framepointer = stackPointer();
  289         localThis = thisexp;
  290     }
  291 
  292     extern (C++) void endFrame()
  293     {
  294         size_t oldframe = cast(size_t)frames[frames.dim - 1];
  295         localThis = savedThis[savedThis.dim - 1];
  296         popAll(framepointer);
  297         framepointer = oldframe;
  298         frames.setDim(frames.dim - 1);
  299         savedThis.setDim(savedThis.dim - 1);
  300     }
  301 
  302     extern (C++) bool isInCurrentFrame(VarDeclaration v)
  303     {
  304         if (v.isDataseg() && !v.isCTFE())
  305             return false; // It's a global
  306         return v.ctfeAdrOnStack >= framepointer;
  307     }
  308 
  309     extern (C++) Expression getValue(VarDeclaration v)
  310     {
  311         if ((v.isDataseg() || v.storage_class & STC.manifest) && !v.isCTFE())
  312         {
  313             assert(v.ctfeAdrOnStack < globalValues.dim);
  314             return globalValues[v.ctfeAdrOnStack];
  315         }
  316         assert(v.ctfeAdrOnStack < stackPointer());
  317         return values[v.ctfeAdrOnStack];
  318     }
  319 
  320     extern (C++) void setValue(VarDeclaration v, Expression e)
  321     {
  322         assert(!v.isDataseg() || v.isCTFE());
  323         assert(v.ctfeAdrOnStack < stackPointer());
  324         values[v.ctfeAdrOnStack] = e;
  325     }
  326 
  327     extern (C++) void push(VarDeclaration v)
  328     {
  329         assert(!v.isDataseg() || v.isCTFE());
  330         if (v.ctfeAdrOnStack != VarDeclaration.AdrOnStackNone && v.ctfeAdrOnStack >= framepointer)
  331         {
  332             // Already exists in this frame, reuse it.
  333             values[v.ctfeAdrOnStack] = null;
  334             return;
  335         }
  336         savedId.push(cast(void*)cast(size_t)v.ctfeAdrOnStack);
  337         v.ctfeAdrOnStack = cast(uint)values.dim;
  338         vars.push(v);
  339         values.push(null);
  340     }
  341 
  342     extern (C++) void pop(VarDeclaration v)
  343     {
  344         assert(!v.isDataseg() || v.isCTFE());
  345         assert(!(v.storage_class & (STC.ref_ | STC.out_)));
  346         const oldid = v.ctfeAdrOnStack;
  347         v.ctfeAdrOnStack = cast(uint)cast(size_t)savedId[oldid];
  348         if (v.ctfeAdrOnStack == values.dim - 1)
  349         {
  350             values.pop();
  351             vars.pop();
  352             savedId.pop();
  353         }
  354     }
  355 
  356     extern (C++) void popAll(size_t stackpointer)
  357     {
  358         if (stackPointer() > maxStackPointer)
  359             maxStackPointer = stackPointer();
  360         assert(values.dim >= stackpointer);
  361         for (size_t i = stackpointer; i < values.dim; ++i)
  362         {
  363             VarDeclaration v = vars[i];
  364             v.ctfeAdrOnStack = cast(uint)cast(size_t)savedId[i];
  365         }
  366         values.setDim(stackpointer);
  367         vars.setDim(stackpointer);
  368         savedId.setDim(stackpointer);
  369     }
  370 
  371     extern (C++) void saveGlobalConstant(VarDeclaration v, Expression e)
  372     {
  373         assert(v._init && (v.isConst() || v.isImmutable() || v.storage_class & STC.manifest) && !v.isCTFE());
  374         v.ctfeAdrOnStack = cast(uint)globalValues.dim;
  375         globalValues.push(copyRegionExp(e));
  376     }
  377 }
  378 
  379 private struct InterState
  380 {
  381     InterState* caller;     // calling function's InterState
  382     FuncDeclaration fd;     // function being interpreted
  383     Statement start;        // if !=NULL, start execution at this statement
  384 
  385     /* target of CTFEExp result; also
  386      * target of labelled CTFEExp or
  387      * CTFEExp. (null if no label).
  388      */
  389     Statement gotoTarget;
  390 }
  391 
  392 /*************************************
  393  * Attempt to interpret a function given the arguments.
  394  * Params:
  395  *      pue       = storage for result
  396  *      fd        = function being called
  397  *      istate    = state for calling function (NULL if none)
  398  *      arguments = function arguments
  399  *      thisarg   = 'this', if a needThis() function, NULL if not.
  400  *
  401  * Returns:
  402  * result expression if successful, TOK.cantExpression if not,
  403  * or CTFEExp if function returned void.
  404  */
  405 private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterState* istate, Expressions* arguments, Expression thisarg)
  406 {
  407     debug (LOG)
  408     {
  409         printf("\n********\n%s FuncDeclaration::interpret(istate = %p) %s\n", fd.loc.toChars(), istate, fd.toChars());
  410     }
  411     assert(pue);
  412     if (fd.semanticRun == PASS.semantic3)
  413     {
  414         fd.error("circular dependency. Functions cannot be interpreted while being compiled");
  415         return CTFEExp.cantexp;
  416     }
  417     if (!fd.functionSemantic3())
  418         return CTFEExp.cantexp;
  419     if (fd.semanticRun < PASS.semantic3done)
  420         return CTFEExp.cantexp;
  421 
  422     Type tb = fd.type.toBasetype();
  423     assert(tb.ty == Tfunction);
  424     TypeFunction tf = cast(TypeFunction)tb;
  425     if (tf.parameterList.varargs != VarArg.none && arguments &&
  426         ((fd.parameters && arguments.dim != fd.parameters.dim) || (!fd.parameters && arguments.dim)))
  427     {
  428         fd.error("C-style variadic functions are not yet implemented in CTFE");
  429         return CTFEExp.cantexp;
  430     }
  431 
  432     // Nested functions always inherit the 'this' pointer from the parent,
  433     // except for delegates. (Note that the 'this' pointer may be null).
  434     // Func literals report isNested() even if they are in global scope,
  435     // so we need to check that the parent is a function.
  436     if (fd.isNested() && fd.toParentLocal().isFuncDeclaration() && !thisarg && istate)
  437         thisarg = ctfeGlobals.stack.getThis();
  438 
  439     if (fd.needThis() && !thisarg)
  440     {
  441         // error, no this. Prevent segfault.
  442         // Here should be unreachable by the strict 'this' check in front-end.
  443         fd.error("need `this` to access member `%s`", fd.toChars());
  444         return CTFEExp.cantexp;
  445     }
  446 
  447     // Place to hold all the arguments to the function while
  448     // we are evaluating them.
  449     size_t dim = arguments ? arguments.dim : 0;
  450     assert((fd.parameters ? fd.parameters.dim : 0) == dim);
  451 
  452     /* Evaluate all the arguments to the function,
  453      * store the results in eargs[]
  454      */
  455     Expressions eargs = Expressions(dim);
  456     for (size_t i = 0; i < dim; i++)
  457     {
  458         Expression earg = (*arguments)[i];
  459         Parameter fparam = tf.parameterList[i];
  460 
  461         if (fparam.isReference())
  462         {
  463             if (!istate && (fparam.storageClass & STC.out_))
  464             {
  465                 // initializing an out parameter involves writing to it.
  466                 earg.error("global `%s` cannot be passed as an `out` parameter at compile time", earg.toChars());
  467                 return CTFEExp.cantexp;
  468             }
  469             // Convert all reference arguments into lvalue references
  470             earg = interpretRegion(earg, istate, CTFEGoal.LValue);
  471             if (CTFEExp.isCantExp(earg))
  472                 return earg;
  473         }
  474         else if (fparam.storageClass & STC.lazy_)
  475         {
  476         }
  477         else
  478         {
  479             /* Value parameters
  480              */
  481             Type ta = fparam.type.toBasetype();
  482             if (ta.ty == Tsarray)
  483                 if (auto eaddr = earg.isAddrExp())
  484                 {
  485                     /* Static arrays are passed by a simple pointer.
  486                      * Skip past this to get at the actual arg.
  487                      */
  488                     earg = eaddr.e1;
  489                 }
  490 
  491             earg = interpretRegion(earg, istate);
  492             if (CTFEExp.isCantExp(earg))
  493                 return earg;
  494 
  495             /* Struct literals are passed by value, but we don't need to
  496              * copy them if they are passed as const
  497              */
  498             if (earg.op == TOK.structLiteral && !(fparam.storageClass & (STC.const_ | STC.immutable_)))
  499                 earg = copyLiteral(earg).copy();
  500         }
  501         if (earg.op == TOK.thrownException)
  502         {
  503             if (istate)
  504                 return earg;
  505             (cast(ThrownExceptionExp)earg).generateUncaughtError();
  506             return CTFEExp.cantexp;
  507         }
  508         eargs[i] = earg;
  509     }
  510 
  511     // Now that we've evaluated all the arguments, we can start the frame
  512     // (this is the moment when the 'call' actually takes place).
  513     InterState istatex;
  514     istatex.caller = istate;
  515     istatex.fd = fd;
  516 
  517     if (fd.isThis2)
  518     {
  519         Expression arg0 = thisarg;
  520         if (arg0 && arg0.type.ty == Tstruct)
  521         {
  522             Type t = arg0.type.pointerTo();
  523             arg0 = ctfeEmplaceExp!AddrExp(arg0.loc, arg0);
  524             arg0.type = t;
  525         }
  526         auto elements = new Expressions(2);
  527         (*elements)[0] = arg0;
  528         (*elements)[1] = ctfeGlobals.stack.getThis();
  529         Type t2 = Type.tvoidptr.sarrayOf(2);
  530         const loc = thisarg ? thisarg.loc : fd.loc;
  531         thisarg = ctfeEmplaceExp!ArrayLiteralExp(loc, t2, elements);
  532         thisarg = ctfeEmplaceExp!AddrExp(loc, thisarg);
  533         thisarg.type = t2.pointerTo();
  534     }
  535 
  536     ctfeGlobals.stack.startFrame(thisarg);
  537     if (fd.vthis && thisarg)
  538     {
  539         ctfeGlobals.stack.push(fd.vthis);
  540         setValue(fd.vthis, thisarg);
  541     }
  542 
  543     for (size_t i = 0; i < dim; i++)
  544     {
  545         Expression earg = eargs[i];
  546         Parameter fparam = tf.parameterList[i];
  547         VarDeclaration v = (*fd.parameters)[i];
  548         debug (LOG)
  549         {
  550             printf("arg[%zu] = %s\n", i, earg.toChars());
  551         }
  552         ctfeGlobals.stack.push(v);
  553 
  554         if (fparam.isReference() && earg.op == TOK.variable &&
  555             (cast(VarExp)earg).var.toParent2() == fd)
  556         {
  557             VarDeclaration vx = (cast(VarExp)earg).var.isVarDeclaration();
  558             if (!vx)
  559             {
  560                 fd.error("cannot interpret `%s` as a `ref` parameter", earg.toChars());
  561                 return CTFEExp.cantexp;
  562             }
  563 
  564             /* vx is a variable that is declared in fd.
  565              * It means that fd is recursively called. e.g.
  566              *
  567              *  void fd(int n, ref int v = dummy) {
  568              *      int vx;
  569              *      if (n == 1) fd(2, vx);
  570              *  }
  571              *  fd(1);
  572              *
  573              * The old value of vx on the stack in fd(1)
  574              * should be saved at the start of fd(2, vx) call.
  575              */
  576             const oldadr = vx.ctfeAdrOnStack;
  577 
  578             ctfeGlobals.stack.push(vx);
  579             assert(!hasValue(vx)); // vx is made uninitialized
  580 
  581             // https://issues.dlang.org/show_bug.cgi?id=14299
  582             // v.ctfeAdrOnStack should be saved already
  583             // in the stack before the overwrite.
  584             v.ctfeAdrOnStack = oldadr;
  585             assert(hasValue(v)); // ref parameter v should refer existing value.
  586         }
  587         else
  588         {
  589             // Value parameters and non-trivial references
  590             setValueWithoutChecking(v, earg);
  591         }
  592         debug (LOG)
  593         {
  594             printf("interpreted arg[%zu] = %s\n", i, earg.toChars());
  595             showCtfeExpr(earg);
  596         }
  597         debug (LOGASSIGN)
  598         {
  599             printf("interpreted arg[%zu] = %s\n", i, earg.toChars());
  600             showCtfeExpr(earg);
  601         }
  602     }
  603 
  604     if (fd.vresult)
  605         ctfeGlobals.stack.push(fd.vresult);
  606 
  607     // Enter the function
  608     ++ctfeGlobals.callDepth;
  609     if (ctfeGlobals.callDepth > ctfeGlobals.maxCallDepth)
  610         ctfeGlobals.maxCallDepth = ctfeGlobals.callDepth;
  611 
  612     Expression e = null;
  613     while (1)
  614     {
  615         if (ctfeGlobals.callDepth > CTFE_RECURSION_LIMIT)
  616         {
  617             // This is a compiler error. It must not be suppressed.
  618             global.gag = 0;
  619             fd.error("CTFE recursion limit exceeded");
  620             e = CTFEExp.cantexp;
  621             break;
  622         }
  623         e = interpret(pue, fd.fbody, &istatex);
  624         if (CTFEExp.isCantExp(e))
  625         {
  626             debug (LOG)
  627             {
  628                 printf("function body failed to interpret\n");
  629             }
  630         }
  631 
  632         if (istatex.start)
  633         {
  634             fd.error("CTFE internal error: failed to resume at statement `%s`", istatex.start.toChars());
  635             return CTFEExp.cantexp;
  636         }
  637 
  638         /* This is how we deal with a recursive statement AST
  639          * that has arbitrary goto statements in it.
  640          * Bubble up a 'result' which is the target of the goto
  641          * statement, then go recursively down the AST looking
  642          * for that statement, then execute starting there.
  643          */
  644         if (CTFEExp.isGotoExp(e))
  645         {
  646             istatex.start = istatex.gotoTarget; // set starting statement
  647             istatex.gotoTarget = null;
  648         }
  649         else
  650         {
  651             assert(!e || (e.op != TOK.continue_ && e.op != TOK.break_));
  652             break;
  653         }
  654     }
  655     // If fell off the end of a void function, return void
  656     if (!e && tf.next.ty == Tvoid)
  657         e = CTFEExp.voidexp;
  658     if (tf.isref && e.op == TOK.variable && (cast(VarExp)e).var == fd.vthis)
  659         e = thisarg;
  660     if (tf.isref && fd.isThis2 && e.op == TOK.index)
  661     {
  662         auto ie = cast(IndexExp)e;
  663         auto pe = ie.e1.isPtrExp();
  664         auto ve = !pe ?  null : pe.e1.isVarExp();
  665         if (ve && ve.var == fd.vthis)
  666         {
  667             auto ne = ie.e2.isIntegerExp();
  668             assert(ne);
  669             assert(thisarg.op == TOK.address);
  670             e = (cast(AddrExp)thisarg).e1;
  671             e = (*(cast(ArrayLiteralExp)e).elements)[cast(size_t)ne.getInteger()];
  672             if (e.op == TOK.address)
  673             {
  674                 e = (cast(AddrExp)e).e1;
  675             }
  676         }
  677     }
  678     assert(e !is null);
  679 
  680     // Leave the function
  681     --ctfeGlobals.callDepth;
  682 
  683     ctfeGlobals.stack.endFrame();
  684 
  685     // If it generated an uncaught exception, report error.
  686     if (!istate && e.op == TOK.thrownException)
  687     {
  688         if (e == pue.exp())
  689             e = pue.copy();
  690         (cast(ThrownExceptionExp)e).generateUncaughtError();
  691         e = CTFEExp.cantexp;
  692     }
  693 
  694     return e;
  695 }
  696 
  697 /// used to collect coverage information in ctfe
  698 void incUsageCtfe(InterState* istate, const ref Loc loc)
  699 {
  700     if (global.params.ctfe_cov && istate)
  701     {
  702         auto line = loc.linnum;
  703         auto mod = istate.fd.getModule();
  704 
  705         ++mod.ctfe_cov[line];
  706     }
  707 }
  708 
  709 private extern (C++) final class Interpreter : Visitor
  710 {
  711     alias visit = Visitor.visit;
  712 public:
  713     InterState* istate;
  714     CTFEGoal goal;
  715     Expression result;
  716     UnionExp* pue;              // storage for `result`
  717 
  718     extern (D) this(UnionExp* pue, InterState* istate, CTFEGoal goal)
  719     {
  720         this.pue = pue;
  721         this.istate = istate;
  722         this.goal = goal;
  723     }
  724 
  725     // If e is TOK.throw_exception or TOK.cantExpression,
  726     // set it to 'result' and returns true.
  727     bool exceptionOrCant(Expression e)
  728     {
  729         if (exceptionOrCantInterpret(e))
  730         {
  731             // Make sure e is not pointing to a stack temporary
  732             result = (e.op == TOK.cantExpression) ? CTFEExp.cantexp : e;
  733             return true;
  734         }
  735         return false;
  736     }
  737 
  738     static Expressions* copyArrayOnWrite(Expressions* exps, Expressions* original)
  739     {
  740         if (exps is original)
  741         {
  742             if (!original)
  743                 exps = new Expressions();
  744             else
  745                 exps = original.copy();
  746             ++ctfeGlobals.numArrayAllocs;
  747         }
  748         return exps;
  749     }
  750 
  751     /******************************** Statement ***************************/
  752 
  753     override void visit(Statement s)
  754     {
  755         debug (LOG)
  756         {
  757             printf("%s Statement::interpret()\n", s.loc.toChars());
  758         }
  759         if (istate.start)
  760         {
  761             if (istate.start != s)
  762                 return;
  763             istate.start = null;
  764         }
  765 
  766         s.error("statement `%s` cannot be interpreted at compile time", s.toChars());
  767         result = CTFEExp.cantexp;
  768     }
  769 
  770     override void visit(ExpStatement s)
  771     {
  772         debug (LOG)
  773         {
  774             printf("%s ExpStatement::interpret(%s)\n", s.loc.toChars(), s.exp ? s.exp.toChars() : "");
  775         }
  776         if (istate.start)
  777         {
  778             if (istate.start != s)
  779                 return;
  780             istate.start = null;
  781         }
  782         if (s.exp && s.exp.hasCode)
  783             incUsageCtfe(istate, s.loc);
  784 
  785         Expression e = interpret(pue, s.exp, istate, CTFEGoal.Nothing);
  786         if (exceptionOrCant(e))
  787             return;
  788     }
  789 
  790     override void visit(CompoundStatement s)
  791     {
  792         debug (LOG)
  793         {
  794             printf("%s CompoundStatement::interpret()\n", s.loc.toChars());
  795         }
  796         if (istate.start == s)
  797             istate.start = null;
  798 
  799         const dim = s.statements ? s.statements.dim : 0;
  800         foreach (i; 0 .. dim)
  801         {
  802             Statement sx = (*s.statements)[i];
  803             result = interpret(pue, sx, istate);
  804             if (result)
  805                 break;
  806         }
  807         debug (LOG)
  808         {
  809             printf("%s -CompoundStatement::interpret() %p\n", s.loc.toChars(), result);
  810         }
  811     }
  812 
  813     override void visit(UnrolledLoopStatement s)
  814     {
  815         debug (LOG)
  816         {
  817             printf("%s UnrolledLoopStatement::interpret()\n", s.loc.toChars());
  818         }
  819         if (istate.start == s)
  820             istate.start = null;
  821 
  822         const dim = s.statements ? s.statements.dim : 0;
  823         foreach (i; 0 .. dim)
  824         {
  825             Statement sx = (*s.statements)[i];
  826             Expression e = interpret(pue, sx, istate);
  827             if (!e) // succeeds to interpret, or goto target was not found
  828                 continue;
  829             if (exceptionOrCant(e))
  830                 return;
  831             if (e.op == TOK.break_)
  832             {
  833                 if (istate.gotoTarget && istate.gotoTarget != s)
  834                 {
  835                     result = e; // break at a higher level
  836                     return;
  837                 }
  838                 istate.gotoTarget = null;
  839                 result = null;
  840                 return;
  841             }
  842             if (e.op == TOK.continue_)
  843             {
  844                 if (istate.gotoTarget && istate.gotoTarget != s)
  845                 {
  846                     result = e; // continue at a higher level
  847                     return;
  848                 }
  849                 istate.gotoTarget = null;
  850                 continue;
  851             }
  852 
  853             // expression from return statement, or thrown exception
  854             result = e;
  855             break;
  856         }
  857     }
  858 
  859     override void visit(IfStatement s)
  860     {
  861         debug (LOG)
  862         {
  863             printf("%s IfStatement::interpret(%s)\n", s.loc.toChars(), s.condition.toChars());
  864         }
  865         incUsageCtfe(istate, s.loc);
  866         if (istate.start == s)
  867             istate.start = null;
  868         if (istate.start)
  869         {
  870             Expression e = null;
  871             e = interpret(s.ifbody, istate);
  872             if (!e && istate.start)
  873                 e = interpret(s.elsebody, istate);
  874             result = e;
  875             return;
  876         }
  877 
  878         UnionExp ue = void;
  879         Expression e = interpret(&ue, s.condition, istate);
  880         assert(e);
  881         if (exceptionOrCant(e))
  882             return;
  883 
  884         if (isTrueBool(e))
  885             result = interpret(pue, s.ifbody, istate);
  886         else if (e.isBool(false))
  887             result = interpret(pue, s.elsebody, istate);
  888         else
  889         {
  890             // no error, or assert(0)?
  891             result = CTFEExp.cantexp;
  892         }
  893     }
  894 
  895     override void visit(ScopeStatement s)
  896     {
  897         debug (LOG)
  898         {
  899             printf("%s ScopeStatement::interpret()\n", s.loc.toChars());
  900         }
  901         if (istate.start == s)
  902             istate.start = null;
  903 
  904         result = interpret(pue, s.statement, istate);
  905     }
  906 
  907     /**
  908      Given an expression e which is about to be returned from the current
  909      function, generate an error if it contains pointers to local variables.
  910 
  911      Only checks expressions passed by value (pointers to local variables
  912      may already be stored in members of classes, arrays, or AAs which
  913      were passed as mutable function parameters).
  914      Returns:
  915         true if it is safe to return, false if an error was generated.
  916      */
  917     static bool stopPointersEscaping(const ref Loc loc, Expression e)
  918     {
  919         if (!e.type.hasPointers())
  920             return true;
  921         if (isPointer(e.type))
  922         {
  923             Expression x = e;
  924             if (auto eaddr = e.isAddrExp())
  925                 x = eaddr.e1;
  926             VarDeclaration v;
  927             while (x.op == TOK.variable && (v = (cast(VarExp)x).var.isVarDeclaration()) !is null)
  928             {
  929                 if (v.storage_class & STC.ref_)
  930                 {
  931                     x = getValue(v);
  932                     if (auto eaddr = e.isAddrExp())
  933                         eaddr.e1 = x;
  934                     continue;
  935                 }
  936                 if (ctfeGlobals.stack.isInCurrentFrame(v))
  937                 {
  938                     error(loc, "returning a pointer to a local stack variable");
  939                     return false;
  940                 }
  941                 else
  942                     break;
  943             }
  944             // TODO: If it is a TOK.dotVariable or TOK.index, we should check that it is not
  945             // pointing to a local struct or static array.
  946         }
  947         if (auto se = e.isStructLiteralExp())
  948         {
  949             return stopPointersEscapingFromArray(loc, se.elements);
  950         }
  951         if (auto ale = e.isArrayLiteralExp())
  952         {
  953             return stopPointersEscapingFromArray(loc, ale.elements);
  954         }
  955         if (auto aae = e.isAssocArrayLiteralExp())
  956         {
  957             if (!stopPointersEscapingFromArray(loc, aae.keys))
  958                 return false;
  959             return stopPointersEscapingFromArray(loc, aae.values);
  960         }
  961         return true;
  962     }
  963 
  964     // Check all elements of an array for escaping local variables. Return false if error
  965     static bool stopPointersEscapingFromArray(const ref Loc loc, Expressions* elems)
  966     {
  967         foreach (e; *elems)
  968         {
  969             if (e && !stopPointersEscaping(loc, e))
  970                 return false;
  971         }
  972         return true;
  973     }
  974 
  975     override void visit(ReturnStatement s)
  976     {
  977         debug (LOG)
  978         {
  979             printf("%s ReturnStatement::interpret(%s)\n", s.loc.toChars(), s.exp ? s.exp.toChars() : "");
  980         }
  981         if (istate.start)
  982         {
  983             if (istate.start != s)
  984                 return;
  985             istate.start = null;
  986         }
  987 
  988         if (!s.exp)
  989         {
  990             result = CTFEExp.voidexp;
  991             return;
  992         }
  993 
  994         incUsageCtfe(istate, s.loc);
  995         assert(istate && istate.fd && istate.fd.type && istate.fd.type.ty == Tfunction);
  996         TypeFunction tf = cast(TypeFunction)istate.fd.type;
  997 
  998         /* If the function returns a ref AND it's been called from an assignment,
  999          * we need to return an lvalue. Otherwise, just do an (rvalue) interpret.
 1000          */
 1001         if (tf.isref)
 1002         {
 1003             result = interpret(pue, s.exp, istate, CTFEGoal.LValue);
 1004             return;
 1005         }
 1006         if (tf.next && tf.next.ty == Tdelegate && istate.fd.closureVars.dim > 0)
 1007         {
 1008             // To support this, we need to copy all the closure vars
 1009             // into the delegate literal.
 1010             s.error("closures are not yet supported in CTFE");
 1011             result = CTFEExp.cantexp;
 1012             return;
 1013         }
 1014 
 1015         // We need to treat pointers specially, because TOK.symbolOffset can be used to
 1016         // return a value OR a pointer
 1017         Expression e = interpret(pue, s.exp, istate);
 1018         if (exceptionOrCant(e))
 1019             return;
 1020 
 1021         // Disallow returning pointers to stack-allocated variables (bug 7876)
 1022         if (!stopPointersEscaping(s.loc, e))
 1023         {
 1024             result = CTFEExp.cantexp;
 1025             return;
 1026         }
 1027 
 1028         if (needToCopyLiteral(e))
 1029             e = copyLiteral(e).copy();
 1030         debug (LOGASSIGN)
 1031         {
 1032             printf("RETURN %s\n", s.loc.toChars());
 1033             showCtfeExpr(e);
 1034         }
 1035         result = e;
 1036     }
 1037 
 1038     static Statement findGotoTarget(InterState* istate, Identifier ident)
 1039     {
 1040         Statement target = null;
 1041         if (ident)
 1042         {
 1043             LabelDsymbol label = istate.fd.searchLabel(ident);
 1044             assert(label && label.statement);
 1045             LabelStatement ls = label.statement;
 1046             target = ls.gotoTarget ? ls.gotoTarget : ls.statement;
 1047         }
 1048         return target;
 1049     }
 1050 
 1051     override void visit(BreakStatement s)
 1052     {
 1053         debug (LOG)
 1054         {
 1055             printf("%s BreakStatement::interpret()\n", s.loc.toChars());
 1056         }
 1057         incUsageCtfe(istate, s.loc);
 1058         if (istate.start)
 1059         {
 1060             if (istate.start != s)
 1061                 return;
 1062             istate.start = null;
 1063         }
 1064 
 1065         istate.gotoTarget = findGotoTarget(istate, s.ident);
 1066         result = CTFEExp.breakexp;
 1067     }
 1068 
 1069     override void visit(ContinueStatement s)
 1070     {
 1071         debug (LOG)
 1072         {
 1073             printf("%s ContinueStatement::interpret()\n", s.loc.toChars());
 1074         }
 1075         incUsageCtfe(istate, s.loc);
 1076         if (istate.start)
 1077         {
 1078             if (istate.start != s)
 1079                 return;
 1080             istate.start = null;
 1081         }
 1082 
 1083         istate.gotoTarget = findGotoTarget(istate, s.ident);
 1084         result = CTFEExp.continueexp;
 1085     }
 1086 
 1087     override void visit(WhileStatement s)
 1088     {
 1089         debug (LOG)
 1090         {
 1091             printf("WhileStatement::interpret()\n");
 1092         }
 1093         assert(0); // rewritten to ForStatement
 1094     }
 1095 
 1096     override void visit(DoStatement s)
 1097     {
 1098         debug (LOG)
 1099         {
 1100             printf("%s DoStatement::interpret()\n", s.loc.toChars());
 1101         }
 1102         if (istate.start == s)
 1103             istate.start = null;
 1104 
 1105         while (1)
 1106         {
 1107             Expression e = interpret(s._body, istate);
 1108             if (!e && istate.start) // goto target was not found
 1109                 return;
 1110             assert(!istate.start);
 1111 
 1112             if (exceptionOrCant(e))
 1113                 return;
 1114             if (e && e.op == TOK.break_)
 1115             {
 1116                 if (istate.gotoTarget && istate.gotoTarget != s)
 1117                 {
 1118                     result = e; // break at a higher level
 1119                     return;
 1120                 }
 1121                 istate.gotoTarget = null;
 1122                 break;
 1123             }
 1124             if (e && e.op == TOK.continue_)
 1125             {
 1126                 if (istate.gotoTarget && istate.gotoTarget != s)
 1127                 {
 1128                     result = e; // continue at a higher level
 1129                     return;
 1130                 }
 1131                 istate.gotoTarget = null;
 1132                 e = null;
 1133             }
 1134             if (e)
 1135             {
 1136                 result = e; // bubbled up from ReturnStatement
 1137                 return;
 1138             }
 1139 
 1140             UnionExp ue = void;
 1141             incUsageCtfe(istate, s.condition.loc);
 1142             e = interpret(&ue, s.condition, istate);
 1143             if (exceptionOrCant(e))
 1144                 return;
 1145             if (!e.isConst())
 1146             {
 1147                 result = CTFEExp.cantexp;
 1148                 return;
 1149             }
 1150             if (e.isBool(false))
 1151                 break;
 1152             assert(isTrueBool(e));
 1153         }
 1154         assert(result is null);
 1155     }
 1156 
 1157     override void visit(ForStatement s)
 1158     {
 1159         debug (LOG)
 1160         {
 1161             printf("%s ForStatement::interpret()\n", s.loc.toChars());
 1162         }
 1163         if (istate.start == s)
 1164             istate.start = null;
 1165 
 1166         UnionExp ueinit = void;
 1167         Expression ei = interpret(&ueinit, s._init, istate);
 1168         if (exceptionOrCant(ei))
 1169             return;
 1170         assert(!ei); // s.init never returns from function, or jumps out from it
 1171 
 1172         while (1)
 1173         {
 1174             if (s.condition && !istate.start)
 1175             {
 1176                 UnionExp ue = void;
 1177                 incUsageCtfe(istate, s.condition.loc);
 1178                 Expression e = interpret(&ue, s.condition, istate);
 1179                 if (exceptionOrCant(e))
 1180                     return;
 1181                 if (e.isBool(false))
 1182                     break;
 1183                 assert(isTrueBool(e));
 1184             }
 1185 
 1186             Expression e = interpret(pue, s._body, istate);
 1187             if (!e && istate.start) // goto target was not found
 1188                 return;
 1189             assert(!istate.start);
 1190 
 1191             if (exceptionOrCant(e))
 1192                 return;
 1193             if (e && e.op == TOK.break_)
 1194             {
 1195                 if (istate.gotoTarget && istate.gotoTarget != s)
 1196                 {
 1197                     result = e; // break at a higher level
 1198                     return;
 1199                 }
 1200                 istate.gotoTarget = null;
 1201                 break;
 1202             }
 1203             if (e && e.op == TOK.continue_)
 1204             {
 1205                 if (istate.gotoTarget && istate.gotoTarget != s)
 1206                 {
 1207                     result = e; // continue at a higher level
 1208                     return;
 1209                 }
 1210                 istate.gotoTarget = null;
 1211                 e = null;
 1212             }
 1213             if (e)
 1214             {
 1215                 result = e; // bubbled up from ReturnStatement
 1216                 return;
 1217             }
 1218 
 1219             UnionExp uei = void;
 1220             if (s.increment)
 1221                 incUsageCtfe(istate, s.increment.loc);
 1222             e = interpret(&uei, s.increment, istate, CTFEGoal.Nothing);
 1223             if (exceptionOrCant(e))
 1224                 return;
 1225         }
 1226         assert(result is null);
 1227     }
 1228 
 1229     override void visit(ForeachStatement s)
 1230     {
 1231         assert(0); // rewritten to ForStatement
 1232     }
 1233 
 1234     override void visit(ForeachRangeStatement s)
 1235     {
 1236         assert(0); // rewritten to ForStatement
 1237     }
 1238 
 1239     override void visit(SwitchStatement s)
 1240     {
 1241         debug (LOG)
 1242         {
 1243             printf("%s SwitchStatement::interpret()\n", s.loc.toChars());
 1244         }
 1245         incUsageCtfe(istate, s.loc);
 1246         if (istate.start == s)
 1247             istate.start = null;
 1248         if (istate.start)
 1249         {
 1250             Expression e = interpret(s._body, istate);
 1251             if (istate.start) // goto target was not found
 1252                 return;
 1253             if (exceptionOrCant(e))
 1254                 return;
 1255             if (e && e.op == TOK.break_)
 1256             {
 1257                 if (istate.gotoTarget && istate.gotoTarget != s)
 1258                 {
 1259                     result = e; // break at a higher level
 1260                     return;
 1261                 }
 1262                 istate.gotoTarget = null;
 1263                 e = null;
 1264             }
 1265             result = e;
 1266             return;
 1267         }
 1268 
 1269         UnionExp uecond = void;
 1270         Expression econdition = interpret(&uecond, s.condition, istate);
 1271         if (exceptionOrCant(econdition))
 1272             return;
 1273 
 1274         Statement scase = null;
 1275         if (s.cases)
 1276             foreach (cs; *s.cases)
 1277             {
 1278                 UnionExp uecase = void;
 1279                 Expression ecase = interpret(&uecase, cs.exp, istate);
 1280                 if (exceptionOrCant(ecase))
 1281                     return;
 1282                 if (ctfeEqual(cs.exp.loc, TOK.equal, econdition, ecase))
 1283                 {
 1284                     scase = cs;
 1285                     break;
 1286                 }
 1287             }
 1288         if (!scase)
 1289         {
 1290             if (s.hasNoDefault)
 1291                 s.error("no `default` or `case` for `%s` in `switch` statement", econdition.toChars());
 1292             scase = s.sdefault;
 1293         }
 1294 
 1295         assert(scase);
 1296 
 1297         /* Jump to scase
 1298          */
 1299         istate.start = scase;
 1300         Expression e = interpret(pue, s._body, istate);
 1301         assert(!istate.start); // jump must not fail
 1302         if (e && e.op == TOK.break_)
 1303         {
 1304             if (istate.gotoTarget && istate.gotoTarget != s)
 1305             {
 1306                 result = e; // break at a higher level
 1307                 return;
 1308             }
 1309             istate.gotoTarget = null;
 1310             e = null;
 1311         }
 1312         result = e;
 1313     }
 1314 
 1315     override void visit(CaseStatement s)
 1316     {
 1317         debug (LOG)
 1318         {
 1319             printf("%s CaseStatement::interpret(%s) this = %p\n", s.loc.toChars(), s.exp.toChars(), s);
 1320         }
 1321         incUsageCtfe(istate, s.loc);
 1322         if (istate.start == s)
 1323             istate.start = null;
 1324 
 1325         result = interpret(pue, s.statement, istate);
 1326     }
 1327 
 1328     override void visit(DefaultStatement s)
 1329     {
 1330         debug (LOG)
 1331         {
 1332             printf("%s DefaultStatement::interpret()\n", s.loc.toChars());
 1333         }
 1334         incUsageCtfe(istate, s.loc);
 1335         if (istate.start == s)
 1336             istate.start = null;
 1337 
 1338         result = interpret(pue, s.statement, istate);
 1339     }
 1340 
 1341     override void visit(GotoStatement s)
 1342     {
 1343         debug (LOG)
 1344         {
 1345             printf("%s GotoStatement::interpret()\n", s.loc.toChars());
 1346         }
 1347         if (istate.start)
 1348         {
 1349             if (istate.start != s)
 1350                 return;
 1351             istate.start = null;
 1352         }
 1353         incUsageCtfe(istate, s.loc);
 1354 
 1355         assert(s.label && s.label.statement);
 1356         istate.gotoTarget = s.label.statement;
 1357         result = CTFEExp.gotoexp;
 1358     }
 1359 
 1360     override void visit(GotoCaseStatement s)
 1361     {
 1362         debug (LOG)
 1363         {
 1364             printf("%s GotoCaseStatement::interpret()\n", s.loc.toChars());
 1365         }
 1366         if (istate.start)
 1367         {
 1368             if (istate.start != s)
 1369                 return;
 1370             istate.start = null;
 1371         }
 1372         incUsageCtfe(istate, s.loc);
 1373 
 1374         assert(s.cs);
 1375         istate.gotoTarget = s.cs;
 1376         result = CTFEExp.gotoexp;
 1377     }
 1378 
 1379     override void visit(GotoDefaultStatement s)
 1380     {
 1381         debug (LOG)
 1382         {
 1383             printf("%s GotoDefaultStatement::interpret()\n", s.loc.toChars());
 1384         }
 1385         if (istate.start)
 1386         {
 1387             if (istate.start != s)
 1388                 return;
 1389             istate.start = null;
 1390         }
 1391         incUsageCtfe(istate, s.loc);
 1392 
 1393         assert(s.sw && s.sw.sdefault);
 1394         istate.gotoTarget = s.sw.sdefault;
 1395         result = CTFEExp.gotoexp;
 1396     }
 1397 
 1398     override void visit(LabelStatement s)
 1399     {
 1400         debug (LOG)
 1401         {
 1402             printf("%s LabelStatement::interpret()\n", s.loc.toChars());
 1403         }
 1404         if (istate.start == s)
 1405             istate.start = null;
 1406 
 1407         result = interpret(pue, s.statement, istate);
 1408     }
 1409 
 1410     override void visit(TryCatchStatement s)
 1411     {
 1412         debug (LOG)
 1413         {
 1414             printf("%s TryCatchStatement::interpret()\n", s.loc.toChars());
 1415         }
 1416         if (istate.start == s)
 1417             istate.start = null;
 1418         if (istate.start)
 1419         {
 1420             Expression e = null;
 1421             e = interpret(pue, s._body, istate);
 1422             foreach (ca; *s.catches)
 1423             {
 1424                 if (e || !istate.start) // goto target was found
 1425                     break;
 1426                 e = interpret(pue, ca.handler, istate);
 1427             }
 1428             result = e;
 1429             return;
 1430         }
 1431 
 1432         Expression e = interpret(s._body, istate);
 1433 
 1434         // An exception was thrown
 1435         if (e && e.op == TOK.thrownException)
 1436         {
 1437             ThrownExceptionExp ex = cast(ThrownExceptionExp)e;
 1438             Type extype = ex.thrown.originalClass().type;
 1439 
 1440             // Search for an appropriate catch clause.
 1441             foreach (ca; *s.catches)
 1442             {
 1443                 Type catype = ca.type;
 1444                 if (!catype.equals(extype) && !catype.isBaseOf(extype, null))
 1445                     continue;
 1446 
 1447                 // Execute the handler
 1448                 if (ca.var)
 1449                 {
 1450                     ctfeGlobals.stack.push(ca.var);
 1451                     setValue(ca.var, ex.thrown);
 1452                 }
 1453                 e = interpret(ca.handler, istate);
 1454                 if (CTFEExp.isGotoExp(e))
 1455                 {
 1456                     /* This is an optimization that relies on the locality of the jump target.
 1457                      * If the label is in the same catch handler, the following scan
 1458                      * would find it quickly and can reduce jump cost.
 1459                      * Otherwise, the catch block may be unnnecessary scanned again
 1460                      * so it would make CTFE speed slower.
 1461                      */
 1462                     InterState istatex = *istate;
 1463                     istatex.start = istate.gotoTarget; // set starting statement
 1464                     istatex.gotoTarget = null;
 1465                     Expression eh = interpret(ca.handler, &istatex);
 1466                     if (!istatex.start)
 1467                     {
 1468                         istate.gotoTarget = null;
 1469                         e = eh;
 1470                     }
 1471                 }
 1472                 break;
 1473             }
 1474         }
 1475         result = e;
 1476     }
 1477 
 1478     static bool isAnErrorException(ClassDeclaration cd)
 1479     {
 1480         return cd == ClassDeclaration.errorException || ClassDeclaration.errorException.isBaseOf(cd, null);
 1481     }
 1482 
 1483     static ThrownExceptionExp chainExceptions(ThrownExceptionExp oldest, ThrownExceptionExp newest)
 1484     {
 1485         debug (LOG)
 1486         {
 1487             printf("Collided exceptions %s %s\n", oldest.thrown.toChars(), newest.thrown.toChars());
 1488         }
 1489         // Little sanity check to make sure it's really a Throwable
 1490         ClassReferenceExp boss = oldest.thrown;
 1491         const next = 4;                         // index of Throwable.next
 1492         assert((*boss.value.elements)[next].type.ty == Tclass); // Throwable.next
 1493         ClassReferenceExp collateral = newest.thrown;
 1494         if (isAnErrorException(collateral.originalClass()) && !isAnErrorException(boss.originalClass()))
 1495         {
 1496             /* Find the index of the Error.bypassException field
 1497              */
 1498             auto bypass = next + 1;
 1499             if ((*collateral.value.elements)[bypass].type.ty == Tuns32)
 1500                 bypass += 1;  // skip over _refcount field
 1501             assert((*collateral.value.elements)[bypass].type.ty == Tclass);
 1502 
 1503             // The new exception bypass the existing chain
 1504             (*collateral.value.elements)[bypass] = boss;
 1505             return newest;
 1506         }
 1507         while ((*boss.value.elements)[next].op == TOK.classReference)
 1508         {
 1509             boss = cast(ClassReferenceExp)(*boss.value.elements)[next];
 1510         }
 1511         (*boss.value.elements)[next] = collateral;
 1512         return oldest;
 1513     }
 1514 
 1515     override void visit(TryFinallyStatement s)
 1516     {
 1517         debug (LOG)
 1518         {
 1519             printf("%s TryFinallyStatement::interpret()\n", s.loc.toChars());
 1520         }
 1521         if (istate.start == s)
 1522             istate.start = null;
 1523         if (istate.start)
 1524         {
 1525             Expression e = null;
 1526             e = interpret(pue, s._body, istate);
 1527             // Jump into/out from finalbody is disabled in semantic analysis.
 1528             // and jump inside will be handled by the ScopeStatement == finalbody.
 1529             result = e;
 1530             return;
 1531         }
 1532 
 1533         Expression ex = interpret(s._body, istate);
 1534         if (CTFEExp.isCantExp(ex))
 1535         {
 1536             result = ex;
 1537             return;
 1538         }
 1539         while (CTFEExp.isGotoExp(ex))
 1540         {
 1541             // If the goto target is within the body, we must not interpret the finally statement,
 1542             // because that will call destructors for objects within the scope, which we should not do.
 1543             InterState istatex = *istate;
 1544             istatex.start = istate.gotoTarget; // set starting statement
 1545             istatex.gotoTarget = null;
 1546             Expression bex = interpret(s._body, &istatex);
 1547             if (istatex.start)
 1548             {
 1549                 // The goto target is outside the current scope.
 1550                 break;
 1551             }
 1552             // The goto target was within the body.
 1553             if (CTFEExp.isCantExp(bex))
 1554             {
 1555                 result = bex;
 1556                 return;
 1557             }
 1558             *istate = istatex;
 1559             ex = bex;
 1560         }
 1561 
 1562         Expression ey = interpret(s.finalbody, istate);
 1563         if (CTFEExp.isCantExp(ey))
 1564         {
 1565             result = ey;
 1566             return;
 1567         }
 1568         if (ey && ey.op == TOK.thrownException)
 1569         {
 1570             // Check for collided exceptions
 1571             if (ex && ex.op == TOK.thrownException)
 1572                 ex = chainExceptions(cast(ThrownExceptionExp)ex, cast(ThrownExceptionExp)ey);
 1573             else
 1574                 ex = ey;
 1575         }
 1576         result = ex;
 1577     }
 1578 
 1579     override void visit(ThrowStatement s)
 1580     {
 1581         debug (LOG)
 1582         {
 1583             printf("%s ThrowStatement::interpret()\n", s.loc.toChars());
 1584         }
 1585         if (istate.start)
 1586         {
 1587             if (istate.start != s)
 1588                 return;
 1589             istate.start = null;
 1590         }
 1591 
 1592         incUsageCtfe(istate, s.loc);
 1593 
 1594         Expression e = interpretRegion(s.exp, istate);
 1595         if (exceptionOrCant(e))
 1596             return;
 1597 
 1598         assert(e.op == TOK.classReference);
 1599         result = ctfeEmplaceExp!ThrownExceptionExp(s.loc, e.isClassReferenceExp());
 1600     }
 1601 
 1602     override void visit(ScopeGuardStatement s)
 1603     {
 1604         assert(0);
 1605     }
 1606 
 1607     override void visit(WithStatement s)
 1608     {
 1609         debug (LOG)
 1610         {
 1611             printf("%s WithStatement::interpret()\n", s.loc.toChars());
 1612         }
 1613         if (istate.start == s)
 1614             istate.start = null;
 1615         if (istate.start)
 1616         {
 1617             result = s._body ? interpret(s._body, istate) : null;
 1618             return;
 1619         }
 1620 
 1621         // If it is with(Enum) {...}, just execute the body.
 1622         if (s.exp.op == TOK.scope_ || s.exp.op == TOK.type)
 1623         {
 1624             result = interpret(pue, s._body, istate);
 1625             return;
 1626         }
 1627 
 1628         incUsageCtfe(istate, s.loc);
 1629 
 1630         Expression e = interpret(s.exp, istate);
 1631         if (exceptionOrCant(e))
 1632             return;
 1633 
 1634         if (s.wthis.type.ty == Tpointer && s.exp.type.ty != Tpointer)
 1635         {
 1636             e = ctfeEmplaceExp!AddrExp(s.loc, e, s.wthis.type);
 1637         }
 1638         ctfeGlobals.stack.push(s.wthis);
 1639         setValue(s.wthis, e);
 1640         e = interpret(s._body, istate);
 1641         if (CTFEExp.isGotoExp(e))
 1642         {
 1643             /* This is an optimization that relies on the locality of the jump target.
 1644              * If the label is in the same WithStatement, the following scan
 1645              * would find it quickly and can reduce jump cost.
 1646              * Otherwise, the statement body may be unnnecessary scanned again
 1647              * so it would make CTFE speed slower.
 1648              */
 1649             InterState istatex = *istate;
 1650             istatex.start = istate.gotoTarget; // set starting statement
 1651             istatex.gotoTarget = null;
 1652             Expression ex = interpret(s._body, &istatex);
 1653             if (!istatex.start)
 1654             {
 1655                 istate.gotoTarget = null;
 1656                 e = ex;
 1657             }
 1658         }
 1659         ctfeGlobals.stack.pop(s.wthis);
 1660         result = e;
 1661     }
 1662 
 1663     override void visit(AsmStatement s)
 1664     {
 1665         debug (LOG)
 1666         {
 1667             printf("%s AsmStatement::interpret()\n", s.loc.toChars());
 1668         }
 1669         if (istate.start)
 1670         {
 1671             if (istate.start != s)
 1672                 return;
 1673             istate.start = null;
 1674         }
 1675         s.error("`asm` statements cannot be interpreted at compile time");
 1676         result = CTFEExp.cantexp;
 1677     }
 1678 
 1679     override void visit(ImportStatement s)
 1680     {
 1681         debug (LOG)
 1682         {
 1683             printf("ImportStatement::interpret()\n");
 1684         }
 1685         if (istate.start)
 1686         {
 1687             if (istate.start != s)
 1688                 return;
 1689             istate.start = null;
 1690         }
 1691     }
 1692 
 1693     /******************************** Expression ***************************/
 1694 
 1695     override void visit(Expression e)
 1696     {
 1697         debug (LOG)
 1698         {
 1699             printf("%s Expression::interpret() '%s' %s\n", e.loc.toChars(), Token.toChars(e.op), e.toChars());
 1700             printf("type = %s\n", e.type.toChars());
 1701             showCtfeExpr(e);
 1702         }
 1703         e.error("cannot interpret `%s` at compile time", e.toChars());
 1704         result = CTFEExp.cantexp;
 1705     }
 1706 
 1707     override void visit(TypeExp e)
 1708     {
 1709         debug (LOG)
 1710         {
 1711             printf("%s TypeExp.interpret() %s\n", e.loc.toChars(), e.toChars());
 1712         }
 1713         result = e;
 1714     }
 1715 
 1716     override void visit(ThisExp e)
 1717     {
 1718         debug (LOG)
 1719         {
 1720             printf("%s ThisExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 1721         }
 1722         if (goal == CTFEGoal.LValue)
 1723         {
 1724             // We might end up here with istate being zero
 1725             // https://issues.dlang.org/show_bug.cgi?id=16382
 1726             if (istate && istate.fd.vthis)
 1727             {
 1728                 result = ctfeEmplaceExp!VarExp(e.loc, istate.fd.vthis);
 1729                 if (istate.fd.isThis2)
 1730                 {
 1731                     result = ctfeEmplaceExp!PtrExp(e.loc, result);
 1732                     result.type = Type.tvoidptr.sarrayOf(2);
 1733                     result = ctfeEmplaceExp!IndexExp(e.loc, result, IntegerExp.literal!0);
 1734                 }
 1735                 result.type = e.type;
 1736             }
 1737             else
 1738                 result = e;
 1739             return;
 1740         }
 1741 
 1742         result = ctfeGlobals.stack.getThis();
 1743         if (result)
 1744         {
 1745             if (istate && istate.fd.isThis2)
 1746             {
 1747                 assert(result.op == TOK.address);
 1748                 result = (cast(AddrExp)result).e1;
 1749                 assert(result.op == TOK.arrayLiteral);
 1750                 result = (*(cast(ArrayLiteralExp)result).elements)[0];
 1751                 if (e.type.ty == Tstruct)
 1752                 {
 1753                     result = (cast(AddrExp)result).e1;
 1754                 }
 1755                 return;
 1756             }
 1757             assert(result.op == TOK.structLiteral || result.op == TOK.classReference || result.op == TOK.type);
 1758             return;
 1759         }
 1760         e.error("value of `this` is not known at compile time");
 1761         result = CTFEExp.cantexp;
 1762     }
 1763 
 1764     override void visit(NullExp e)
 1765     {
 1766         result = e;
 1767     }
 1768 
 1769     override void visit(IntegerExp e)
 1770     {
 1771         debug (LOG)
 1772         {
 1773             printf("%s IntegerExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 1774         }
 1775         result = e;
 1776     }
 1777 
 1778     override void visit(RealExp e)
 1779     {
 1780         debug (LOG)
 1781         {
 1782             printf("%s RealExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 1783         }
 1784         result = e;
 1785     }
 1786 
 1787     override void visit(ComplexExp e)
 1788     {
 1789         result = e;
 1790     }
 1791 
 1792     override void visit(StringExp e)
 1793     {
 1794         debug (LOG)
 1795         {
 1796             printf("%s StringExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 1797         }
 1798         /* Attempts to modify string literals are prevented
 1799          * in BinExp::interpretAssignCommon.
 1800          */
 1801         result = e;
 1802     }
 1803 
 1804     override void visit(FuncExp e)
 1805     {
 1806         debug (LOG)
 1807         {
 1808             printf("%s FuncExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 1809         }
 1810         result = e;
 1811     }
 1812 
 1813     override void visit(SymOffExp e)
 1814     {
 1815         debug (LOG)
 1816         {
 1817             printf("%s SymOffExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 1818         }
 1819         if (e.var.isFuncDeclaration() && e.offset == 0)
 1820         {
 1821             result = e;
 1822             return;
 1823         }
 1824         if (isTypeInfo_Class(e.type) && e.offset == 0)
 1825         {
 1826             result = e;
 1827             return;
 1828         }
 1829         if (e.type.ty != Tpointer)
 1830         {
 1831             // Probably impossible
 1832             e.error("cannot interpret `%s` at compile time", e.toChars());
 1833             result = CTFEExp.cantexp;
 1834             return;
 1835         }
 1836         Type pointee = (cast(TypePointer)e.type).next;
 1837         if (e.var.isThreadlocal())
 1838         {
 1839             e.error("cannot take address of thread-local variable %s at compile time", e.var.toChars());
 1840             result = CTFEExp.cantexp;
 1841             return;
 1842         }
 1843         // Check for taking an address of a shared variable.
 1844         // If the shared variable is an array, the offset might not be zero.
 1845         Type fromType = null;
 1846         if (e.var.type.ty == Tarray || e.var.type.ty == Tsarray)
 1847         {
 1848             fromType = (cast(TypeArray)e.var.type).next;
 1849         }
 1850         if (e.var.isDataseg() && ((e.offset == 0 && isSafePointerCast(e.var.type, pointee)) || (fromType && isSafePointerCast(fromType, pointee))))
 1851         {
 1852             result = e;
 1853             return;
 1854         }
 1855 
 1856         Expression val = getVarExp(e.loc, istate, e.var, goal);
 1857         if (exceptionOrCant(val))
 1858             return;
 1859         if (val.type.ty == Tarray || val.type.ty == Tsarray)
 1860         {
 1861             // Check for unsupported type painting operations
 1862             Type elemtype = (cast(TypeArray)val.type).next;
 1863             d_uns64 elemsize = elemtype.size();
 1864 
 1865             // It's OK to cast from fixed length to fixed length array, eg &int[n] to int[d]*.
 1866             if (val.type.ty == Tsarray && pointee.ty == Tsarray && elemsize == pointee.nextOf().size())
 1867             {
 1868                 size_t d = cast(size_t)(cast(TypeSArray)pointee).dim.toInteger();
 1869                 Expression elwr = ctfeEmplaceExp!IntegerExp(e.loc, e.offset / elemsize, Type.tsize_t);
 1870                 Expression eupr = ctfeEmplaceExp!IntegerExp(e.loc, e.offset / elemsize + d, Type.tsize_t);
 1871 
 1872                 // Create a CTFE pointer &val[ofs..ofs+d]
 1873                 auto se = ctfeEmplaceExp!SliceExp(e.loc, val, elwr, eupr);
 1874                 se.type = pointee;
 1875                 emplaceExp!(AddrExp)(pue, e.loc, se, e.type);
 1876                 result = pue.exp();
 1877                 return;
 1878             }
 1879 
 1880             if (!isSafePointerCast(elemtype, pointee))
 1881             {
 1882                 // It's also OK to cast from &string to string*.
 1883                 if (e.offset == 0 && isSafePointerCast(e.var.type, pointee))
 1884                 {
 1885                     // Create a CTFE pointer &var
 1886                     auto ve = ctfeEmplaceExp!VarExp(e.loc, e.var);
 1887                     ve.type = elemtype;
 1888                     emplaceExp!(AddrExp)(pue, e.loc, ve, e.type);
 1889                     result = pue.exp();
 1890                     return;
 1891                 }
 1892                 e.error("reinterpreting cast from `%s` to `%s` is not supported in CTFE", val.type.toChars(), e.type.toChars());
 1893                 result = CTFEExp.cantexp;
 1894                 return;
 1895             }
 1896 
 1897             const dinteger_t sz = pointee.size();
 1898             dinteger_t indx = e.offset / sz;
 1899             assert(sz * indx == e.offset);
 1900             Expression aggregate = null;
 1901             if (val.op == TOK.arrayLiteral || val.op == TOK.string_)
 1902             {
 1903                 aggregate = val;
 1904             }
 1905             else if (auto se = val.isSliceExp())
 1906             {
 1907                 aggregate = se.e1;
 1908                 UnionExp uelwr = void;
 1909                 Expression lwr = interpret(&uelwr, se.lwr, istate);
 1910                 indx += lwr.toInteger();
 1911             }
 1912             if (aggregate)
 1913             {
 1914                 // Create a CTFE pointer &aggregate[ofs]
 1915                 auto ofs = ctfeEmplaceExp!IntegerExp(e.loc, indx, Type.tsize_t);
 1916                 auto ei = ctfeEmplaceExp!IndexExp(e.loc, aggregate, ofs);
 1917                 ei.type = elemtype;
 1918                 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
 1919                 result = pue.exp();
 1920                 return;
 1921             }
 1922         }
 1923         else if (e.offset == 0 && isSafePointerCast(e.var.type, pointee))
 1924         {
 1925             // Create a CTFE pointer &var
 1926             auto ve = ctfeEmplaceExp!VarExp(e.loc, e.var);
 1927             ve.type = e.var.type;
 1928             emplaceExp!(AddrExp)(pue, e.loc, ve, e.type);
 1929             result = pue.exp();
 1930             return;
 1931         }
 1932 
 1933         e.error("cannot convert `&%s` to `%s` at compile time", e.var.type.toChars(), e.type.toChars());
 1934         result = CTFEExp.cantexp;
 1935     }
 1936 
 1937     override void visit(AddrExp e)
 1938     {
 1939         debug (LOG)
 1940         {
 1941             printf("%s AddrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 1942         }
 1943         if (auto ve = e.e1.isVarExp())
 1944         {
 1945             Declaration decl = ve.var;
 1946 
 1947             // We cannot take the address of an imported symbol at compile time
 1948             if (decl.isImportedSymbol()) {
 1949                 e.error("cannot take address of imported symbol `%s` at compile time", decl.toChars());
 1950                 result = CTFEExp.cantexp;
 1951                 return;
 1952             }
 1953 
 1954             if (decl.isDataseg()) {
 1955                 // Normally this is already done by optimize()
 1956                 // Do it here in case optimize(WANTvalue) wasn't run before CTFE
 1957                 emplaceExp!(SymOffExp)(pue, e.loc, (cast(VarExp)e.e1).var, 0);
 1958                 result = pue.exp();
 1959                 result.type = e.type;
 1960                 return;
 1961             }
 1962         }
 1963         auto er = interpret(e.e1, istate, CTFEGoal.LValue);
 1964         if (auto ve = er.isVarExp())
 1965             if (ve.var == istate.fd.vthis)
 1966                 er = interpret(er, istate);
 1967 
 1968         if (exceptionOrCant(er))
 1969             return;
 1970 
 1971         // Return a simplified address expression
 1972         emplaceExp!(AddrExp)(pue, e.loc, er, e.type);
 1973         result = pue.exp();
 1974     }
 1975 
 1976     override void visit(DelegateExp e)
 1977     {
 1978         debug (LOG)
 1979         {
 1980             printf("%s DelegateExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 1981         }
 1982         // TODO: Really we should create a CTFE-only delegate expression
 1983         // of a pointer and a funcptr.
 1984 
 1985         // If it is &nestedfunc, just return it
 1986         // TODO: We should save the context pointer
 1987         if (auto ve1 = e.e1.isVarExp())
 1988             if (ve1.var == e.func)
 1989             {
 1990                 result = e;
 1991                 return;
 1992             }
 1993 
 1994         auto er = interpret(pue, e.e1, istate);
 1995         if (exceptionOrCant(er))
 1996             return;
 1997         if (er == e.e1)
 1998         {
 1999             // If it has already been CTFE'd, just return it
 2000             result = e;
 2001         }
 2002         else
 2003         {
 2004             er = (er == pue.exp()) ? pue.copy() : er;
 2005             emplaceExp!(DelegateExp)(pue, e.loc, er, e.func, false);
 2006             result = pue.exp();
 2007             result.type = e.type;
 2008         }
 2009     }
 2010 
 2011     static Expression getVarExp(const ref Loc loc, InterState* istate, Declaration d, CTFEGoal goal)
 2012     {
 2013         Expression e = CTFEExp.cantexp;
 2014         if (VarDeclaration v = d.isVarDeclaration())
 2015         {
 2016             /* Magic variable __ctfe always returns true when interpreting
 2017              */
 2018             if (v.ident == Id.ctfe)
 2019                 return IntegerExp.createBool(true);
 2020 
 2021             if (!v.originalType && v.semanticRun < PASS.semanticdone) // semantic() not yet run
 2022             {
 2023                 v.dsymbolSemantic(null);
 2024                 if (v.type.ty == Terror)
 2025                     return CTFEExp.cantexp;
 2026             }
 2027 
 2028             if ((v.isConst() || v.isImmutable() || v.storage_class & STC.manifest) && !hasValue(v) && v._init && !v.isCTFE())
 2029             {
 2030                 if (v.inuse)
 2031                 {
 2032                     error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
 2033                     return CTFEExp.cantexp;
 2034                 }
 2035                 if (v._scope)
 2036                 {
 2037                     v.inuse++;
 2038                     v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret); // might not be run on aggregate members
 2039                     v.inuse--;
 2040                 }
 2041                 e = v._init.initializerToExpression(v.type);
 2042                 if (!e)
 2043                     return CTFEExp.cantexp;
 2044                 assert(e.type);
 2045 
 2046                 if (e.op == TOK.construct || e.op == TOK.blit)
 2047                 {
 2048                     AssignExp ae = cast(AssignExp)e;
 2049                     e = ae.e2;
 2050                 }
 2051 
 2052                 if (e.op == TOK.error)
 2053                 {
 2054                     // FIXME: Ultimately all errors should be detected in prior semantic analysis stage.
 2055                 }
 2056                 else if (v.isDataseg() || (v.storage_class & STC.manifest))
 2057                 {
 2058                     /* https://issues.dlang.org/show_bug.cgi?id=14304
 2059                      * e is a value that is not yet owned by CTFE.
 2060                      * Mark as "cached", and use it directly during interpretation.
 2061                      */
 2062                     e = scrubCacheValue(e);
 2063                     ctfeGlobals.stack.saveGlobalConstant(v, e);
 2064                 }
 2065                 else
 2066                 {
 2067                     v.inuse++;
 2068                     e = interpret(e, istate);
 2069                     v.inuse--;
 2070                     if (CTFEExp.isCantExp(e) && !global.gag && !ctfeGlobals.stackTraceCallsToSuppress)
 2071                         errorSupplemental(loc, "while evaluating %s.init", v.toChars());
 2072                     if (exceptionOrCantInterpret(e))
 2073                         return e;
 2074                 }
 2075             }
 2076             else if (v.isCTFE() && !hasValue(v))
 2077             {
 2078                 if (v._init && v.type.size() != 0)
 2079                 {
 2080                     if (v._init.isVoidInitializer())
 2081                     {
 2082                         // var should have been initialized when it was created
 2083                         error(loc, "CTFE internal error: trying to access uninitialized var");
 2084                         assert(0);
 2085                     }
 2086                     e = v._init.initializerToExpression();
 2087                 }
 2088                 else
 2089                     e = v.type.defaultInitLiteral(e.loc);
 2090 
 2091                 e = interpret(e, istate);
 2092             }
 2093             else if (!(v.isDataseg() || v.storage_class & STC.manifest) && !v.isCTFE() && !istate)
 2094             {
 2095                 error(loc, "variable `%s` cannot be read at compile time", v.toChars());
 2096                 return CTFEExp.cantexp;
 2097             }
 2098             else
 2099             {
 2100                 e = hasValue(v) ? getValue(v) : null;
 2101                 if (!e && !v.isCTFE() && v.isDataseg())
 2102                 {
 2103                     error(loc, "static variable `%s` cannot be read at compile time", v.toChars());
 2104                     return CTFEExp.cantexp;
 2105                 }
 2106                 if (!e)
 2107                 {
 2108                     assert(!(v._init && v._init.isVoidInitializer()));
 2109                     // CTFE initiated from inside a function
 2110                     error(loc, "variable `%s` cannot be read at compile time", v.toChars());
 2111                     return CTFEExp.cantexp;
 2112                 }
 2113                 if (auto vie = e.isVoidInitExp())
 2114                 {
 2115                     error(loc, "cannot read uninitialized variable `%s` in ctfe", v.toPrettyChars());
 2116                     errorSupplemental(vie.var.loc, "`%s` was uninitialized and used before set", vie.var.toChars());
 2117                     return CTFEExp.cantexp;
 2118                 }
 2119                 if (goal != CTFEGoal.LValue && (v.isRef() || v.isOut()))
 2120                     e = interpret(e, istate, goal);
 2121             }
 2122             if (!e)
 2123                 e = CTFEExp.cantexp;
 2124         }
 2125         else if (SymbolDeclaration s = d.isSymbolDeclaration())
 2126         {
 2127             // Struct static initializers, for example
 2128             e = s.dsym.type.defaultInitLiteral(loc);
 2129             if (e.op == TOK.error)
 2130                 error(loc, "CTFE failed because of previous errors in `%s.init`", s.toChars());
 2131             e = e.expressionSemantic(null);
 2132             if (e.op == TOK.error)
 2133                 e = CTFEExp.cantexp;
 2134             else // Convert NULL to CTFEExp
 2135                 e = interpret(e, istate, goal);
 2136         }
 2137         else
 2138             error(loc, "cannot interpret declaration `%s` at compile time", d.toChars());
 2139         return e;
 2140     }
 2141 
 2142     override void visit(VarExp e)
 2143     {
 2144         debug (LOG)
 2145         {
 2146             printf("%s VarExp::interpret() `%s`, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
 2147         }
 2148         if (e.var.isFuncDeclaration())
 2149         {
 2150             result = e;
 2151             return;
 2152         }
 2153 
 2154         // Note: This is a workaround for
 2155         // https://issues.dlang.org/show_bug.cgi?id=17351
 2156         // The aforementioned bug triggers when passing manifest constant by `ref`.
 2157         // If there was not a previous reference to them, they are
 2158         // not cached and trigger a "cannot be read at compile time".
 2159         // This fix is a crude solution to get it to work. A more proper
 2160         // approach would be to resolve the forward reference, but that is
 2161         // much more involved.
 2162         if (goal == CTFEGoal.LValue && e.var.type.isMutable())
 2163         {
 2164             if (auto v = e.var.isVarDeclaration())
 2165             {
 2166                 if (!v.isDataseg() && !v.isCTFE() && !istate)
 2167                 {
 2168                     e.error("variable `%s` cannot be read at compile time", v.toChars());
 2169                     result = CTFEExp.cantexp;
 2170                     return;
 2171                 }
 2172                 if (!hasValue(v))
 2173                 {
 2174                     if (!v.isCTFE() && v.isDataseg())
 2175                         e.error("static variable `%s` cannot be read at compile time", v.toChars());
 2176                     else // CTFE initiated from inside a function
 2177                         e.error("variable `%s` cannot be read at compile time", v.toChars());
 2178                     result = CTFEExp.cantexp;
 2179                     return;
 2180                 }
 2181 
 2182                 if (v.storage_class & (STC.out_ | STC.ref_))
 2183                 {
 2184                     // Strip off the nest of ref variables
 2185                     Expression ev = getValue(v);
 2186                     if (ev.op == TOK.variable ||
 2187                         ev.op == TOK.index ||
 2188                         ev.op == TOK.slice ||
 2189                         ev.op == TOK.dotVariable)
 2190                     {
 2191                         result = interpret(pue, ev, istate, goal);
 2192                         return;
 2193                     }
 2194                 }
 2195             }
 2196             result = e;
 2197             return;
 2198         }
 2199         result = getVarExp(e.loc, istate, e.var, goal);
 2200         if (exceptionOrCant(result))
 2201             return;
 2202         if ((e.var.storage_class & (STC.ref_ | STC.out_)) == 0 && e.type.baseElemOf().ty != Tstruct)
 2203         {
 2204             /* Ultimately, STC.ref_|STC.out_ check should be enough to see the
 2205              * necessity of type repainting. But currently front-end paints
 2206              * non-ref struct variables by the const type.
 2207              *
 2208              *  auto foo(ref const S cs);
 2209              *  S s;
 2210              *  foo(s); // VarExp('s') will have const(S)
 2211              */
 2212             // A VarExp may include an implicit cast. It must be done explicitly.
 2213             result = paintTypeOntoLiteral(pue, e.type, result);
 2214         }
 2215     }
 2216 
 2217     override void visit(DeclarationExp e)
 2218     {
 2219         debug (LOG)
 2220         {
 2221             printf("%s DeclarationExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 2222         }
 2223         Dsymbol s = e.declaration;
 2224         if (VarDeclaration v = s.isVarDeclaration())
 2225         {
 2226             if (TupleDeclaration td = v.toAlias().isTupleDeclaration())
 2227             {
 2228                 result = null;
 2229 
 2230                 // Reserve stack space for all tuple members
 2231                 if (!td.objects)
 2232                     return;
 2233                 foreach (o; *td.objects)
 2234                 {
 2235                     Expression ex = isExpression(o);
 2236                     DsymbolExp ds = ex ? ex.isDsymbolExp() : null;
 2237                     VarDeclaration v2 = ds ? ds.s.isVarDeclaration() : null;
 2238                     assert(v2);
 2239                     if (v2.isDataseg() && !v2.isCTFE())
 2240                         continue;
 2241 
 2242                     ctfeGlobals.stack.push(v2);
 2243                     if (v2._init)
 2244                     {
 2245                         Expression einit;
 2246                         if (ExpInitializer ie = v2._init.isExpInitializer())
 2247                         {
 2248                             einit = interpretRegion(ie.exp, istate, goal);
 2249                             if (exceptionOrCant(einit))
 2250                                 return;
 2251                         }
 2252                         else if (v2._init.isVoidInitializer())
 2253                         {
 2254                             einit = voidInitLiteral(v2.type, v2).copy();
 2255                         }
 2256                         else
 2257                         {
 2258                             e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
 2259                             result = CTFEExp.cantexp;
 2260                             return;
 2261                         }
 2262                         setValue(v2, einit);
 2263                     }
 2264                 }
 2265                 return;
 2266             }
 2267             if (v.isStatic())
 2268             {
 2269                 // Just ignore static variables which aren't read or written yet
 2270                 result = null;
 2271                 return;
 2272             }
 2273             if (!(v.isDataseg() || v.storage_class & STC.manifest) || v.isCTFE())
 2274                 ctfeGlobals.stack.push(v);
 2275             if (v._init)
 2276             {
 2277                 if (ExpInitializer ie = v._init.isExpInitializer())
 2278                 {
 2279                     result = interpretRegion(ie.exp, istate, goal);
 2280                 }
 2281                 else if (v._init.isVoidInitializer())
 2282                 {
 2283                     result = voidInitLiteral(v.type, v).copy();
 2284                     // There is no AssignExp for void initializers,
 2285                     // so set it here.
 2286                     setValue(v, result);
 2287                 }
 2288                 else
 2289                 {
 2290                     e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
 2291                     result = CTFEExp.cantexp;
 2292                 }
 2293             }
 2294             else if (v.type.size() == 0)
 2295             {
 2296                 // Zero-length arrays don't need an initializer
 2297                 result = v.type.defaultInitLiteral(e.loc);
 2298             }
 2299             else
 2300             {
 2301                 e.error("variable `%s` cannot be modified at compile time", v.toChars());
 2302                 result = CTFEExp.cantexp;
 2303             }
 2304             return;
 2305         }
 2306         if (s.isAttribDeclaration() || s.isTemplateMixin() || s.isTupleDeclaration())
 2307         {
 2308             // Check for static struct declarations, which aren't executable
 2309             AttribDeclaration ad = e.declaration.isAttribDeclaration();
 2310             if (ad && ad.decl && ad.decl.dim == 1)
 2311             {
 2312                 Dsymbol sparent = (*ad.decl)[0];
 2313                 if (sparent.isAggregateDeclaration() || sparent.isTemplateDeclaration() || sparent.isAliasDeclaration())
 2314                 {
 2315                     result = null;
 2316                     return; // static (template) struct declaration. Nothing to do.
 2317                 }
 2318             }
 2319 
 2320             // These can be made to work, too lazy now
 2321             e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
 2322             result = CTFEExp.cantexp;
 2323             return;
 2324         }
 2325 
 2326         // Others should not contain executable code, so are trivial to evaluate
 2327         result = null;
 2328         debug (LOG)
 2329         {
 2330             printf("-DeclarationExp::interpret(%s): %p\n", e.toChars(), result);
 2331         }
 2332     }
 2333 
 2334     override void visit(TypeidExp e)
 2335     {
 2336         debug (LOG)
 2337         {
 2338             printf("%s TypeidExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 2339         }
 2340         if (Type t = isType(e.obj))
 2341         {
 2342             result = e;
 2343             return;
 2344         }
 2345         if (Expression ex = isExpression(e.obj))
 2346         {
 2347             result = interpret(pue, ex, istate);
 2348             if (exceptionOrCant(ex))
 2349                 return;
 2350 
 2351             if (result.op == TOK.null_)
 2352             {
 2353                 e.error("null pointer dereference evaluating typeid. `%s` is `null`", ex.toChars());
 2354                 result = CTFEExp.cantexp;
 2355                 return;
 2356             }
 2357             if (result.op != TOK.classReference)
 2358             {
 2359                 e.error("CTFE internal error: determining classinfo");
 2360                 result = CTFEExp.cantexp;
 2361                 return;
 2362             }
 2363 
 2364             ClassDeclaration cd = (cast(ClassReferenceExp)result).originalClass();
 2365             assert(cd);
 2366 
 2367             emplaceExp!(TypeidExp)(pue, e.loc, cd.type);
 2368             result = pue.exp();
 2369             result.type = e.type;
 2370             return;
 2371         }
 2372         visit(cast(Expression)e);
 2373     }
 2374 
 2375     override void visit(TupleExp e)
 2376     {
 2377         debug (LOG)
 2378         {
 2379             printf("%s TupleExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 2380         }
 2381         if (exceptionOrCant(interpretRegion(e.e0, istate, CTFEGoal.Nothing)))
 2382             return;
 2383 
 2384         auto expsx = e.exps;
 2385         foreach (i, exp; *expsx)
 2386         {
 2387             Expression ex = interpretRegion(exp, istate);
 2388             if (exceptionOrCant(ex))
 2389                 return;
 2390 
 2391             // A tuple of assignments can contain void (Bug 5676).
 2392             if (goal == CTFEGoal.Nothing)
 2393                 continue;
 2394             if (ex.op == TOK.voidExpression)
 2395             {
 2396                 e.error("CTFE internal error: void element `%s` in tuple", exp.toChars());
 2397                 assert(0);
 2398             }
 2399 
 2400             /* If any changes, do Copy On Write
 2401              */
 2402             if (ex !is exp)
 2403             {
 2404                 expsx = copyArrayOnWrite(expsx, e.exps);
 2405                 (*expsx)[i] = copyRegionExp(ex);
 2406             }
 2407         }
 2408 
 2409         if (expsx !is e.exps)
 2410         {
 2411             expandTuples(expsx);
 2412             emplaceExp!(TupleExp)(pue, e.loc, expsx);
 2413             result = pue.exp();
 2414             result.type = new TypeTuple(expsx);
 2415         }
 2416         else
 2417             result = e;
 2418     }
 2419 
 2420     override void visit(ArrayLiteralExp e)
 2421     {
 2422         debug (LOG)
 2423         {
 2424             printf("%s ArrayLiteralExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 2425         }
 2426         if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
 2427         {
 2428             result = e;
 2429             return;
 2430         }
 2431 
 2432         Type tn = e.type.toBasetype().nextOf().toBasetype();
 2433         bool wantCopy = (tn.ty == Tsarray || tn.ty == Tstruct);
 2434 
 2435         auto basis = interpretRegion(e.basis, istate);
 2436         if (exceptionOrCant(basis))
 2437             return;
 2438 
 2439         auto expsx = e.elements;
 2440         size_t dim = expsx ? expsx.dim : 0;
 2441         for (size_t i = 0; i < dim; i++)
 2442         {
 2443             Expression exp = (*expsx)[i];
 2444             Expression ex;
 2445             if (!exp)
 2446             {
 2447                 ex = copyLiteral(basis).copy();
 2448             }
 2449             else
 2450             {
 2451                 // segfault bug 6250
 2452                 assert(exp.op != TOK.index || (cast(IndexExp)exp).e1 != e);
 2453 
 2454                 ex = interpretRegion(exp, istate);
 2455                 if (exceptionOrCant(ex))
 2456                     return;
 2457 
 2458                 /* Each elements should have distinct CTFE memory.
 2459                  *  int[1] z = 7;
 2460                  *  int[1][] pieces = [z,z];    // here
 2461                  */
 2462                 if (wantCopy)
 2463                     ex = copyLiteral(ex).copy();
 2464             }
 2465 
 2466             /* If any changes, do Copy On Write
 2467              */
 2468             if (ex !is exp)
 2469             {
 2470                 expsx = copyArrayOnWrite(expsx, e.elements);
 2471                 (*expsx)[i] = ex;
 2472             }
 2473         }
 2474 
 2475         if (expsx !is e.elements)
 2476         {
 2477             // todo: all tuple expansions should go in semantic phase.
 2478             expandTuples(expsx);
 2479             if (expsx.dim != dim)
 2480             {
 2481                 e.error("CTFE internal error: invalid array literal");
 2482                 result = CTFEExp.cantexp;
 2483                 return;
 2484             }
 2485             emplaceExp!(ArrayLiteralExp)(pue, e.loc, e.type, basis, expsx);
 2486             auto ale = cast(ArrayLiteralExp)pue.exp();
 2487             ale.ownedByCtfe = OwnedBy.ctfe;
 2488             result = ale;
 2489         }
 2490         else if ((cast(TypeNext)e.type).next.mod & (MODFlags.const_ | MODFlags.immutable_))
 2491         {
 2492             // If it's immutable, we don't need to dup it
 2493             result = e;
 2494         }
 2495         else
 2496         {
 2497             *pue = copyLiteral(e);
 2498             result = pue.exp();
 2499         }
 2500     }
 2501 
 2502     override void visit(AssocArrayLiteralExp e)
 2503     {
 2504         debug (LOG)
 2505         {
 2506             printf("%s AssocArrayLiteralExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 2507         }
 2508         if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
 2509         {
 2510             result = e;
 2511             return;
 2512         }
 2513 
 2514         auto keysx = e.keys;
 2515         auto valuesx = e.values;
 2516         foreach (i, ekey; *keysx)
 2517         {
 2518             auto evalue = (*valuesx)[i];
 2519 
 2520             auto ek = interpretRegion(ekey, istate);
 2521             if (exceptionOrCant(ek))
 2522                 return;
 2523             auto ev = interpretRegion(evalue, istate);
 2524             if (exceptionOrCant(ev))
 2525                 return;
 2526 
 2527             /* If any changes, do Copy On Write
 2528              */
 2529             if (ek !is ekey ||
 2530                 ev !is evalue)
 2531             {
 2532                 keysx = copyArrayOnWrite(keysx, e.keys);
 2533                 valuesx = copyArrayOnWrite(valuesx, e.values);
 2534                 (*keysx)[i] = ek;
 2535                 (*valuesx)[i] = ev;
 2536             }
 2537         }
 2538         if (keysx !is e.keys)
 2539             expandTuples(keysx);
 2540         if (valuesx !is e.values)
 2541             expandTuples(valuesx);
 2542         if (keysx.dim != valuesx.dim)
 2543         {
 2544             e.error("CTFE internal error: invalid AA");
 2545             result = CTFEExp.cantexp;
 2546             return;
 2547         }
 2548 
 2549         /* Remove duplicate keys
 2550          */
 2551         for (size_t i = 1; i < keysx.dim; i++)
 2552         {
 2553             auto ekey = (*keysx)[i - 1];
 2554             for (size_t j = i; j < keysx.dim; j++)
 2555             {
 2556                 auto ekey2 = (*keysx)[j];
 2557                 if (!ctfeEqual(e.loc, TOK.equal, ekey, ekey2))
 2558                     continue;
 2559 
 2560                 // Remove ekey
 2561                 keysx = copyArrayOnWrite(keysx, e.keys);
 2562                 valuesx = copyArrayOnWrite(valuesx, e.values);
 2563                 keysx.remove(i - 1);
 2564                 valuesx.remove(i - 1);
 2565 
 2566                 i -= 1; // redo the i'th iteration
 2567                 break;
 2568             }
 2569         }
 2570 
 2571         if (keysx !is e.keys ||
 2572             valuesx !is e.values)
 2573         {
 2574             assert(keysx !is e.keys &&
 2575                    valuesx !is e.values);
 2576             auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
 2577             aae.type = e.type;
 2578             aae.ownedByCtfe = OwnedBy.ctfe;
 2579             result = aae;
 2580         }
 2581         else
 2582         {
 2583             *pue = copyLiteral(e);
 2584             result = pue.exp();
 2585         }
 2586     }
 2587 
 2588     override void visit(StructLiteralExp e)
 2589     {
 2590         debug (LOG)
 2591         {
 2592             printf("%s StructLiteralExp::interpret() %s ownedByCtfe = %d\n", e.loc.toChars(), e.toChars(), e.ownedByCtfe);
 2593         }
 2594         if (e.ownedByCtfe >= OwnedBy.ctfe)
 2595         {
 2596             result = e;
 2597             return;
 2598         }
 2599 
 2600         size_t dim = e.elements ? e.elements.dim : 0;
 2601         auto expsx = e.elements;
 2602 
 2603         if (dim != e.sd.fields.dim)
 2604         {
 2605             // guaranteed by AggregateDeclaration.fill and TypeStruct.defaultInitLiteral
 2606             const nvthis = e.sd.fields.dim - e.sd.nonHiddenFields();
 2607             assert(e.sd.fields.dim - dim == nvthis);
 2608 
 2609             /* If a nested struct has no initialized hidden pointer,
 2610              * set it to null to match the runtime behaviour.
 2611              */
 2612             foreach (const i; 0 .. nvthis)
 2613             {
 2614                 auto ne = ctfeEmplaceExp!NullExp(e.loc);
 2615                 auto vthis = i == 0 ? e.sd.vthis : e.sd.vthis2;
 2616                 ne.type = vthis.type;
 2617 
 2618                 expsx = copyArrayOnWrite(expsx, e.elements);
 2619                 expsx.push(ne);
 2620                 ++dim;
 2621             }
 2622         }
 2623         assert(dim == e.sd.fields.dim);
 2624 
 2625         foreach (i; 0 .. dim)
 2626         {
 2627             auto v = e.sd.fields[i];
 2628             Expression exp = (*expsx)[i];
 2629             Expression ex;
 2630             if (!exp)
 2631             {
 2632                 ex = voidInitLiteral(v.type, v).copy();
 2633             }
 2634             else
 2635             {
 2636                 ex = interpretRegion(exp, istate);
 2637                 if (exceptionOrCant(ex))
 2638                     return;
 2639                 if ((v.type.ty != ex.type.ty) && v.type.ty == Tsarray)
 2640                 {
 2641                     // Block assignment from inside struct literals
 2642                     auto tsa = cast(TypeSArray)v.type;
 2643                     auto len = cast(size_t)tsa.dim.toInteger();
 2644                     UnionExp ue = void;
 2645                     ex = createBlockDuplicatedArrayLiteral(&ue, ex.loc, v.type, ex, len);
 2646                     if (ex == ue.exp())
 2647                         ex = ue.copy();
 2648                 }
 2649             }
 2650 
 2651             /* If any changes, do Copy On Write
 2652              */
 2653             if (ex !is exp)
 2654             {
 2655                 expsx = copyArrayOnWrite(expsx, e.elements);
 2656                 (*expsx)[i] = ex;
 2657             }
 2658         }
 2659 
 2660         if (expsx !is e.elements)
 2661         {
 2662             expandTuples(expsx);
 2663             if (expsx.dim != e.sd.fields.dim)
 2664             {
 2665                 e.error("CTFE internal error: invalid struct literal");
 2666                 result = CTFEExp.cantexp;
 2667                 return;
 2668             }
 2669             emplaceExp!(StructLiteralExp)(pue, e.loc, e.sd, expsx);
 2670             auto sle = cast(StructLiteralExp)pue.exp();
 2671             sle.type = e.type;
 2672             sle.ownedByCtfe = OwnedBy.ctfe;
 2673             sle.origin = e.origin;
 2674             result = sle;
 2675         }
 2676         else
 2677         {
 2678             *pue = copyLiteral(e);
 2679             result = pue.exp();
 2680         }
 2681     }
 2682 
 2683     // Create an array literal of type 'newtype' with dimensions given by
 2684     // 'arguments'[argnum..$]
 2685     static Expression recursivelyCreateArrayLiteral(UnionExp* pue, const ref Loc loc, Type newtype, InterState* istate, Expressions* arguments, int argnum)
 2686     {
 2687         Expression lenExpr = interpret(pue, (*arguments)[argnum], istate);
 2688         if (exceptionOrCantInterpret(lenExpr))
 2689             return lenExpr;
 2690         size_t len = cast(size_t)lenExpr.toInteger();
 2691         Type elemType = (cast(TypeArray)newtype).next;
 2692         if (elemType.ty == Tarray && argnum < arguments.dim - 1)
 2693         {
 2694             Expression elem = recursivelyCreateArrayLiteral(pue, loc, elemType, istate, arguments, argnum + 1);
 2695             if (exceptionOrCantInterpret(elem))
 2696                 return elem;
 2697 
 2698             auto elements = new Expressions(len);
 2699             foreach (ref element; *elements)
 2700                 element = copyLiteral(elem).copy();
 2701             emplaceExp!(ArrayLiteralExp)(pue, loc, newtype, elements);
 2702             auto ae = cast(ArrayLiteralExp)pue.exp();
 2703             ae.ownedByCtfe = OwnedBy.ctfe;
 2704             return ae;
 2705         }
 2706         assert(argnum == arguments.dim - 1);
 2707         if (elemType.ty.isSomeChar)
 2708         {
 2709             const ch = cast(dchar)elemType.defaultInitLiteral(loc).toInteger();
 2710             const sz = cast(ubyte)elemType.size();
 2711             return createBlockDuplicatedStringLiteral(pue, loc, newtype, ch, len, sz);
 2712         }
 2713         else
 2714         {
 2715             auto el = interpret(elemType.defaultInitLiteral(loc), istate);
 2716             return createBlockDuplicatedArrayLiteral(pue, loc, newtype, el, len);
 2717         }
 2718     }
 2719 
 2720     override void visit(NewExp e)
 2721     {
 2722         debug (LOG)
 2723         {
 2724             printf("%s NewExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 2725         }
 2726         if (e.allocator)
 2727         {
 2728             e.error("member allocators not supported by CTFE");
 2729             result = CTFEExp.cantexp;
 2730             return;
 2731         }
 2732 
 2733         Expression epre = interpret(pue, e.argprefix, istate, CTFEGoal.Nothing);
 2734         if (exceptionOrCant(epre))
 2735             return;
 2736 
 2737         if (e.newtype.ty == Tarray && e.arguments)
 2738         {
 2739             result = recursivelyCreateArrayLiteral(pue, e.loc, e.newtype, istate, e.arguments, 0);
 2740             return;
 2741         }
 2742         if (auto ts = e.newtype.toBasetype().isTypeStruct())
 2743         {
 2744             if (e.member)
 2745             {
 2746                 Expression se = e.newtype.defaultInitLiteral(e.loc);
 2747                 se = interpret(se, istate);
 2748                 if (exceptionOrCant(se))
 2749                     return;
 2750                 result = interpretFunction(pue, e.member, istate, e.arguments, se);
 2751 
 2752                 // Repaint as same as CallExp::interpret() does.
 2753                 result.loc = e.loc;
 2754             }
 2755             else
 2756             {
 2757                 StructDeclaration sd = ts.sym;
 2758                 auto exps = new Expressions();
 2759                 exps.reserve(sd.fields.dim);
 2760                 if (e.arguments)
 2761                 {
 2762                     exps.setDim(e.arguments.dim);
 2763                     foreach (i, ex; *e.arguments)
 2764                     {
 2765                         ex = interpretRegion(ex, istate);
 2766                         if (exceptionOrCant(ex))
 2767                             return;
 2768                         (*exps)[i] = ex;
 2769                     }
 2770                 }
 2771                 sd.fill(e.loc, exps, false);
 2772 
 2773                 auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, sd, exps, e.newtype);
 2774                 se.origin = se;
 2775                 se.type = e.newtype;
 2776                 se.ownedByCtfe = OwnedBy.ctfe;
 2777                 result = interpret(pue, se, istate);
 2778             }
 2779             if (exceptionOrCant(result))
 2780                 return;
 2781             Expression ev = (result == pue.exp()) ? pue.copy() : result;
 2782             emplaceExp!(AddrExp)(pue, e.loc, ev, e.type);
 2783             result = pue.exp();
 2784             return;
 2785         }
 2786         if (auto tc = e.newtype.toBasetype().isTypeClass())
 2787         {
 2788             ClassDeclaration cd = tc.sym;
 2789             size_t totalFieldCount = 0;
 2790             for (ClassDeclaration c = cd; c; c = c.baseClass)
 2791                 totalFieldCount += c.fields.dim;
 2792             auto elems = new Expressions(totalFieldCount);
 2793             size_t fieldsSoFar = totalFieldCount;
 2794             for (ClassDeclaration c = cd; c; c = c.baseClass)
 2795             {
 2796                 fieldsSoFar -= c.fields.dim;
 2797                 foreach (i, v; c.fields)
 2798                 {
 2799                     if (v.inuse)
 2800                     {
 2801                         e.error("circular reference to `%s`", v.toPrettyChars());
 2802                         result = CTFEExp.cantexp;
 2803                         return;
 2804                     }
 2805                     Expression m;
 2806                     if (v._init)
 2807                     {
 2808                         if (v._init.isVoidInitializer())
 2809                             m = voidInitLiteral(v.type, v).copy();
 2810                         else
 2811                             m = v.getConstInitializer(true);
 2812                     }
 2813                     else
 2814                         m = v.type.defaultInitLiteral(e.loc);
 2815                     if (exceptionOrCant(m))
 2816                         return;
 2817                     (*elems)[fieldsSoFar + i] = copyLiteral(m).copy();
 2818                 }
 2819             }
 2820             // Hack: we store a ClassDeclaration instead of a StructDeclaration.
 2821             // We probably won't get away with this.
 2822 //            auto se = new StructLiteralExp(e.loc, cast(StructDeclaration)cd, elems, e.newtype);
 2823             auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, cast(StructDeclaration)cd, elems, e.newtype);
 2824             se.origin = se;
 2825             se.ownedByCtfe = OwnedBy.ctfe;
 2826             emplaceExp!(ClassReferenceExp)(pue, e.loc, se, e.type);
 2827             Expression eref = pue.exp();
 2828             if (e.member)
 2829             {
 2830                 // Call constructor
 2831                 if (!e.member.fbody)
 2832                 {
 2833                     Expression ctorfail = evaluateIfBuiltin(pue, istate, e.loc, e.member, e.arguments, eref);
 2834                     if (ctorfail)
 2835                     {
 2836                         if (exceptionOrCant(ctorfail))
 2837                             return;
 2838                         result = eref;
 2839                         return;
 2840                     }
 2841                     e.member.error("`%s` cannot be constructed at compile time, because the constructor has no available source code", e.newtype.toChars());
 2842                     result = CTFEExp.cantexp;
 2843                     return;
 2844                 }
 2845                 UnionExp ue = void;
 2846                 Expression ctorfail = interpretFunction(&ue, e.member, istate, e.arguments, eref);
 2847                 if (exceptionOrCant(ctorfail))
 2848                     return;
 2849 
 2850                 /* https://issues.dlang.org/show_bug.cgi?id=14465
 2851                  * Repaint the loc, because a super() call
 2852                  * in the constructor modifies the loc of ClassReferenceExp
 2853                  * in CallExp::interpret().
 2854                  */
 2855                 eref.loc = e.loc;
 2856             }
 2857             result = eref;
 2858             return;
 2859         }
 2860         if (e.newtype.toBasetype().isscalar())
 2861         {
 2862             Expression newval;
 2863             if (e.arguments && e.arguments.dim)
 2864                 newval = (*e.arguments)[0];
 2865             else
 2866                 newval = e.newtype.defaultInitLiteral(e.loc);
 2867             newval = interpretRegion(newval, istate);
 2868             if (exceptionOrCant(newval))
 2869                 return;
 2870 
 2871             // Create a CTFE pointer &[newval][0]
 2872             auto elements = new Expressions(1);
 2873             (*elements)[0] = newval;
 2874             auto ae = ctfeEmplaceExp!ArrayLiteralExp(e.loc, e.newtype.arrayOf(), elements);
 2875             ae.ownedByCtfe = OwnedBy.ctfe;
 2876 
 2877             auto ei = ctfeEmplaceExp!IndexExp(e.loc, ae, ctfeEmplaceExp!IntegerExp(Loc.initial, 0, Type.tsize_t));
 2878             ei.type = e.newtype;
 2879             emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
 2880             result = pue.exp();
 2881             return;
 2882         }
 2883         e.error("cannot interpret `%s` at compile time", e.toChars());
 2884         result = CTFEExp.cantexp;
 2885     }
 2886 
 2887     override void visit(UnaExp e)
 2888     {
 2889         debug (LOG)
 2890         {
 2891             printf("%s UnaExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 2892         }
 2893         UnionExp ue = void;
 2894         Expression e1 = interpret(&ue, e.e1, istate);
 2895         if (exceptionOrCant(e1))
 2896             return;
 2897         switch (e.op)
 2898         {
 2899         case TOK.negate:
 2900             *pue = Neg(e.type, e1);
 2901             break;
 2902 
 2903         case TOK.tilde:
 2904             *pue = Com(e.type, e1);
 2905             break;
 2906 
 2907         case TOK.not:
 2908             *pue = Not(e.type, e1);
 2909             break;
 2910 
 2911         default:
 2912             assert(0);
 2913         }
 2914         result = (*pue).exp();
 2915     }
 2916 
 2917     override void visit(DotTypeExp e)
 2918     {
 2919         debug (LOG)
 2920         {
 2921             printf("%s DotTypeExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 2922         }
 2923         UnionExp ue = void;
 2924         Expression e1 = interpret(&ue, e.e1, istate);
 2925         if (exceptionOrCant(e1))
 2926             return;
 2927         if (e1 == e.e1)
 2928             result = e; // optimize: reuse this CTFE reference
 2929         else
 2930         {
 2931             auto edt = cast(DotTypeExp)e.copy();
 2932             edt.e1 = (e1 == ue.exp()) ? e1.copy() : e1; // don't return pointer to ue
 2933             result = edt;
 2934         }
 2935     }
 2936 
 2937     extern (D) private void interpretCommon(BinExp e, fp_t fp)
 2938     {
 2939         debug (LOG)
 2940         {
 2941             printf("%s BinExp::interpretCommon() %s\n", e.loc.toChars(), e.toChars());
 2942         }
 2943         if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer && e.op == TOK.min)
 2944         {
 2945             UnionExp ue1 = void;
 2946             Expression e1 = interpret(&ue1, e.e1, istate);
 2947             if (exceptionOrCant(e1))
 2948                 return;
 2949             UnionExp ue2 = void;
 2950             Expression e2 = interpret(&ue2, e.e2, istate);
 2951             if (exceptionOrCant(e2))
 2952                 return;
 2953             *pue = pointerDifference(e.loc, e.type, e1, e2);
 2954             result = (*pue).exp();
 2955             return;
 2956         }
 2957         if (e.e1.type.ty == Tpointer && e.e2.type.isintegral())
 2958         {
 2959             UnionExp ue1 = void;
 2960             Expression e1 = interpret(&ue1, e.e1, istate);
 2961             if (exceptionOrCant(e1))
 2962                 return;
 2963             UnionExp ue2 = void;
 2964             Expression e2 = interpret(&ue2, e.e2, istate);
 2965             if (exceptionOrCant(e2))
 2966                 return;
 2967             *pue = pointerArithmetic(e.loc, e.op, e.type, e1, e2);
 2968             result = (*pue).exp();
 2969             return;
 2970         }
 2971         if (e.e2.type.ty == Tpointer && e.e1.type.isintegral() && e.op == TOK.add)
 2972         {
 2973             UnionExp ue1 = void;
 2974             Expression e1 = interpret(&ue1, e.e1, istate);
 2975             if (exceptionOrCant(e1))
 2976                 return;
 2977             UnionExp ue2 = void;
 2978             Expression e2 = interpret(&ue2, e.e2, istate);
 2979             if (exceptionOrCant(e2))
 2980                 return;
 2981             *pue = pointerArithmetic(e.loc, e.op, e.type, e2, e1);
 2982             result = (*pue).exp();
 2983             return;
 2984         }
 2985         if (e.e1.type.ty == Tpointer || e.e2.type.ty == Tpointer)
 2986         {
 2987             e.error("pointer expression `%s` cannot be interpreted at compile time", e.toChars());
 2988             result = CTFEExp.cantexp;
 2989             return;
 2990         }
 2991 
 2992         bool evalOperand(UnionExp* pue, Expression ex, out Expression er)
 2993         {
 2994             er = interpret(pue, ex, istate);
 2995             if (exceptionOrCant(er))
 2996                 return false;
 2997             if (er.isConst() != 1)
 2998             {
 2999                 if (er.op == TOK.arrayLiteral)
 3000                     // Until we get it to work, issue a reasonable error message
 3001                     e.error("cannot interpret array literal expression `%s` at compile time", e.toChars());
 3002                 else
 3003                     e.error("CTFE internal error: non-constant value `%s`", ex.toChars());
 3004                 result = CTFEExp.cantexp;
 3005                 return false;
 3006             }
 3007             return true;
 3008         }
 3009 
 3010         UnionExp ue1 = void;
 3011         Expression e1;
 3012         if (!evalOperand(&ue1, e.e1, e1))
 3013             return;
 3014 
 3015         UnionExp ue2 = void;
 3016         Expression e2;
 3017         if (!evalOperand(&ue2, e.e2, e2))
 3018             return;
 3019 
 3020         if (e.op == TOK.rightShift || e.op == TOK.leftShift || e.op == TOK.unsignedRightShift)
 3021         {
 3022             const sinteger_t i2 = e2.toInteger();
 3023             const d_uns64 sz = e1.type.size() * 8;
 3024             if (i2 < 0 || i2 >= sz)
 3025             {
 3026                 e.error("shift by %lld is outside the range 0..%llu", i2, cast(ulong)sz - 1);
 3027                 result = CTFEExp.cantexp;
 3028                 return;
 3029             }
 3030         }
 3031         *pue = (*fp)(e.loc, e.type, e1, e2);
 3032         result = (*pue).exp();
 3033         if (CTFEExp.isCantExp(result))
 3034             e.error("`%s` cannot be interpreted at compile time", e.toChars());
 3035     }
 3036 
 3037     extern (D) private void interpretCompareCommon(BinExp e, fp2_t fp)
 3038     {
 3039         debug (LOG)
 3040         {
 3041             printf("%s BinExp::interpretCompareCommon() %s\n", e.loc.toChars(), e.toChars());
 3042         }
 3043         UnionExp ue1 = void;
 3044         UnionExp ue2 = void;
 3045         if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer)
 3046         {
 3047             Expression e1 = interpret(&ue1, e.e1, istate);
 3048             if (exceptionOrCant(e1))
 3049                 return;
 3050             Expression e2 = interpret(&ue2, e.e2, istate);
 3051             if (exceptionOrCant(e2))
 3052                 return;
 3053             //printf("e1 = %s %s, e2 = %s %s\n", e1.type.toChars(), e1.toChars(), e2.type.toChars(), e2.toChars());
 3054             dinteger_t ofs1, ofs2;
 3055             Expression agg1 = getAggregateFromPointer(e1, &ofs1);
 3056             Expression agg2 = getAggregateFromPointer(e2, &ofs2);
 3057             //printf("agg1 = %p %s, agg2 = %p %s\n", agg1, agg1.toChars(), agg2, agg2.toChars());
 3058             const cmp = comparePointers(e.op, agg1, ofs1, agg2, ofs2);
 3059             if (cmp == -1)
 3060             {
 3061                 char dir = (e.op == TOK.greaterThan || e.op == TOK.greaterOrEqual) ? '<' : '>';
 3062                 e.error("the ordering of pointers to unrelated memory blocks is indeterminate in CTFE. To check if they point to the same memory block, use both `>` and `<` inside `&&` or `||`, eg `%s && %s %c= %s + 1`", e.toChars(), e.e1.toChars(), dir, e.e2.toChars());
 3063                 result = CTFEExp.cantexp;
 3064                 return;
 3065             }
 3066             if (e.type.equals(Type.tbool))
 3067                 result = IntegerExp.createBool(cmp != 0);
 3068             else
 3069             {
 3070                 emplaceExp!(IntegerExp)(pue, e.loc, cmp, e.type);
 3071                 result = (*pue).exp();
 3072             }
 3073             return;
 3074         }
 3075         Expression e1 = interpret(&ue1, e.e1, istate);
 3076         if (exceptionOrCant(e1))
 3077             return;
 3078         if (!isCtfeComparable(e1))
 3079         {
 3080             e.error("cannot compare `%s` at compile time", e1.toChars());
 3081             result = CTFEExp.cantexp;
 3082             return;
 3083         }
 3084         Expression e2 = interpret(&ue2, e.e2, istate);
 3085         if (exceptionOrCant(e2))
 3086             return;
 3087         if (!isCtfeComparable(e2))
 3088         {
 3089             e.error("cannot compare `%s` at compile time", e2.toChars());
 3090             result = CTFEExp.cantexp;
 3091             return;
 3092         }
 3093         const cmp = (*fp)(e.loc, e.op, e1, e2);
 3094         if (e.type.equals(Type.tbool))
 3095             result = IntegerExp.createBool(cmp);
 3096         else
 3097         {
 3098             emplaceExp!(IntegerExp)(pue, e.loc, cmp, e.type);
 3099             result = (*pue).exp();
 3100         }
 3101     }
 3102 
 3103     override void visit(BinExp e)
 3104     {
 3105         switch (e.op)
 3106         {
 3107         case TOK.add:
 3108             interpretCommon(e, &Add);
 3109             return;
 3110 
 3111         case TOK.min:
 3112             interpretCommon(e, &Min);
 3113             return;
 3114 
 3115         case TOK.mul:
 3116             interpretCommon(e, &Mul);
 3117             return;
 3118 
 3119         case TOK.div:
 3120             interpretCommon(e, &Div);
 3121             return;
 3122 
 3123         case TOK.mod:
 3124             interpretCommon(e, &Mod);
 3125             return;
 3126 
 3127         case TOK.leftShift:
 3128             interpretCommon(e, &Shl);
 3129             return;
 3130 
 3131         case TOK.rightShift:
 3132             interpretCommon(e, &Shr);
 3133             return;
 3134 
 3135         case TOK.unsignedRightShift:
 3136             interpretCommon(e, &Ushr);
 3137             return;
 3138 
 3139         case TOK.and:
 3140             interpretCommon(e, &And);
 3141             return;
 3142 
 3143         case TOK.or:
 3144             interpretCommon(e, &Or);
 3145             return;
 3146 
 3147         case TOK.xor:
 3148             interpretCommon(e, &Xor);
 3149             return;
 3150 
 3151         case TOK.pow:
 3152             interpretCommon(e, &Pow);
 3153             return;
 3154 
 3155         case TOK.equal:
 3156         case TOK.notEqual:
 3157             interpretCompareCommon(e, &ctfeEqual);
 3158             return;
 3159 
 3160         case TOK.identity:
 3161         case TOK.notIdentity:
 3162             interpretCompareCommon(e, &ctfeIdentity);
 3163             return;
 3164 
 3165         case TOK.lessThan:
 3166         case TOK.lessOrEqual:
 3167         case TOK.greaterThan:
 3168         case TOK.greaterOrEqual:
 3169             interpretCompareCommon(e, &ctfeCmp);
 3170             return;
 3171 
 3172         default:
 3173             printf("be = '%s' %s at [%s]\n", Token.toChars(e.op), e.toChars(), e.loc.toChars());
 3174             assert(0);
 3175         }
 3176     }
 3177 
 3178     /* Helper functions for BinExp::interpretAssignCommon
 3179      */
 3180     // Returns the variable which is eventually modified, or NULL if an rvalue.
 3181     // thisval is the current value of 'this'.
 3182     static VarDeclaration findParentVar(Expression e)
 3183     {
 3184         for (;;)
 3185         {
 3186             if (auto ve = e.isVarExp())
 3187             {
 3188                 VarDeclaration v = ve.var.isVarDeclaration();
 3189                 assert(v);
 3190                 return v;
 3191             }
 3192             if (auto ie = e.isIndexExp())
 3193                 e = ie.e1;
 3194             else if (auto dve = e.isDotVarExp())
 3195                 e = dve.e1;
 3196             else if (auto dtie = e.isDotTemplateInstanceExp())
 3197                 e = dtie.e1;
 3198             else if (auto se = e.isSliceExp())
 3199                 e = se.e1;
 3200             else
 3201                 return null;
 3202         }
 3203     }
 3204 
 3205     extern (D) private void interpretAssignCommon(BinExp e, fp_t fp, int post = 0)
 3206     {
 3207         debug (LOG)
 3208         {
 3209             printf("%s BinExp::interpretAssignCommon() %s\n", e.loc.toChars(), e.toChars());
 3210         }
 3211         result = CTFEExp.cantexp;
 3212 
 3213         Expression e1 = e.e1;
 3214         if (!istate)
 3215         {
 3216             e.error("value of `%s` is not known at compile time", e1.toChars());
 3217             return;
 3218         }
 3219 
 3220         ++ctfeGlobals.numAssignments;
 3221 
 3222         /* Before we begin, we need to know if this is a reference assignment
 3223          * (dynamic array, AA, or class) or a value assignment.
 3224          * Determining this for slice assignments are tricky: we need to know
 3225          * if it is a block assignment (a[] = e) rather than a direct slice
 3226          * assignment (a[] = b[]). Note that initializers of multi-dimensional
 3227          * static arrays can have 2D block assignments (eg, int[7][7] x = 6;).
 3228          * So we need to recurse to determine if it is a block assignment.
 3229          */
 3230         bool isBlockAssignment = false;
 3231         if (e1.op == TOK.slice)
 3232         {
 3233             // a[] = e can have const e. So we compare the naked types.
 3234             Type tdst = e1.type.toBasetype();
 3235             Type tsrc = e.e2.type.toBasetype();
 3236             while (tdst.ty == Tsarray || tdst.ty == Tarray)
 3237             {
 3238                 tdst = (cast(TypeArray)tdst).next.toBasetype();
 3239                 if (tsrc.equivalent(tdst))
 3240                 {
 3241                     isBlockAssignment = true;
 3242                     break;
 3243                 }
 3244             }
 3245         }
 3246 
 3247         // ---------------------------------------
 3248         //      Deal with reference assignment
 3249         // ---------------------------------------
 3250         // If it is a construction of a ref variable, it is a ref assignment
 3251         if ((e.op == TOK.construct || e.op == TOK.blit) &&
 3252             ((cast(AssignExp)e).memset == MemorySet.referenceInit))
 3253         {
 3254             assert(!fp);
 3255 
 3256             Expression newval = interpretRegion(e.e2, istate, CTFEGoal.LValue);
 3257             if (exceptionOrCant(newval))
 3258                 return;
 3259 
 3260             VarDeclaration v = (cast(VarExp)e1).var.isVarDeclaration();
 3261             setValue(v, newval);
 3262 
 3263             // Get the value to return. Note that 'newval' is an Lvalue,
 3264             // so if we need an Rvalue, we have to interpret again.
 3265             if (goal == CTFEGoal.RValue)
 3266                 result = interpretRegion(newval, istate);
 3267             else
 3268                 result = e1; // VarExp is a CTFE reference
 3269             return;
 3270         }
 3271 
 3272         if (fp)
 3273         {
 3274             while (e1.op == TOK.cast_)
 3275             {
 3276                 CastExp ce = cast(CastExp)e1;
 3277                 e1 = ce.e1;
 3278             }
 3279         }
 3280 
 3281         // ---------------------------------------
 3282         //      Interpret left hand side
 3283         // ---------------------------------------
 3284         AssocArrayLiteralExp existingAA = null;
 3285         Expression lastIndex = null;
 3286         Expression oldval = null;
 3287         if (e1.op == TOK.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
 3288         {
 3289             // ---------------------------------------
 3290             //      Deal with AA index assignment
 3291             // ---------------------------------------
 3292             /* This needs special treatment if the AA doesn't exist yet.
 3293              * There are two special cases:
 3294              * (1) If the AA is itself an index of another AA, we may need to create
 3295              *     multiple nested AA literals before we can insert the new value.
 3296              * (2) If the ultimate AA is null, no insertion happens at all. Instead,
 3297              *     we create nested AA literals, and change it into a assignment.
 3298              */
 3299             IndexExp ie = cast(IndexExp)e1;
 3300             int depth = 0; // how many nested AA indices are there?
 3301             while (ie.e1.op == TOK.index && (cast(IndexExp)ie.e1).e1.type.toBasetype().ty == Taarray)
 3302             {
 3303                 assert(ie.modifiable);
 3304                 ie = cast(IndexExp)ie.e1;
 3305                 ++depth;
 3306             }
 3307 
 3308             // Get the AA value to be modified.
 3309             Expression aggregate = interpretRegion(ie.e1, istate);
 3310             if (exceptionOrCant(aggregate))
 3311                 return;
 3312             if ((existingAA = aggregate.isAssocArrayLiteralExp()) !is null)
 3313             {
 3314                 // Normal case, ultimate parent AA already exists
 3315                 // We need to walk from the deepest index up, checking that an AA literal
 3316                 // already exists on each level.
 3317                 lastIndex = interpretRegion((cast(IndexExp)e1).e2, istate);
 3318                 lastIndex = resolveSlice(lastIndex); // only happens with AA assignment
 3319                 if (exceptionOrCant(lastIndex))
 3320                     return;
 3321 
 3322                 while (depth > 0)
 3323                 {
 3324                     // Walk the syntax tree to find the indexExp at this depth
 3325                     IndexExp xe = cast(IndexExp)e1;
 3326                     foreach (d; 0 .. depth)
 3327                         xe = cast(IndexExp)xe.e1;
 3328 
 3329                     Expression ekey = interpretRegion(xe.e2, istate);
 3330                     if (exceptionOrCant(ekey))
 3331                         return;
 3332                     UnionExp ekeyTmp = void;
 3333                     ekey = resolveSlice(ekey, &ekeyTmp); // only happens with AA assignment
 3334 
 3335                     // Look up this index in it up in the existing AA, to get the next level of AA.
 3336                     AssocArrayLiteralExp newAA = cast(AssocArrayLiteralExp)findKeyInAA(e.loc, existingAA, ekey);
 3337                     if (exceptionOrCant(newAA))
 3338                         return;
 3339                     if (!newAA)
 3340                     {
 3341                         // Doesn't exist yet, create an empty AA...
 3342                         auto keysx = new Expressions();
 3343                         auto valuesx = new Expressions();
 3344                         newAA = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
 3345                         newAA.type = xe.type;
 3346                         newAA.ownedByCtfe = OwnedBy.ctfe;
 3347                         //... and insert it into the existing AA.
 3348                         existingAA.keys.push(ekey);
 3349                         existingAA.values.push(newAA);
 3350                     }
 3351                     existingAA = newAA;
 3352                     --depth;
 3353                 }
 3354 
 3355                 if (fp)
 3356                 {
 3357                     oldval = findKeyInAA(e.loc, existingAA, lastIndex);
 3358                     if (!oldval)
 3359                         oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
 3360                 }
 3361             }
 3362             else
 3363             {
 3364                 /* The AA is currently null. 'aggregate' is actually a reference to
 3365                  * whatever contains it. It could be anything: var, dotvarexp, ...
 3366                  * We rewrite the assignment from:
 3367                  *     aa[i][j] op= newval;
 3368                  * into:
 3369                  *     aa = [i:[j:T.init]];
 3370                  *     aa[j] op= newval;
 3371                  */
 3372                 oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
 3373 
 3374                 Expression newaae = oldval;
 3375                 while (e1.op == TOK.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
 3376                 {
 3377                     Expression ekey = interpretRegion((cast(IndexExp)e1).e2, istate);
 3378                     if (exceptionOrCant(ekey))
 3379                         return;
 3380                     ekey = resolveSlice(ekey); // only happens with AA assignment
 3381 
 3382                     auto keysx = new Expressions();
 3383                     auto valuesx = new Expressions();
 3384                     keysx.push(ekey);
 3385                     valuesx.push(newaae);
 3386 
 3387                     auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
 3388                     aae.type = (cast(IndexExp)e1).e1.type;
 3389                     aae.ownedByCtfe = OwnedBy.ctfe;
 3390                     if (!existingAA)
 3391                     {
 3392                         existingAA = aae;
 3393                         lastIndex = ekey;
 3394                     }
 3395                     newaae = aae;
 3396                     e1 = (cast(IndexExp)e1).e1;
 3397                 }
 3398 
 3399                 // We must set to aggregate with newaae
 3400                 e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
 3401                 if (exceptionOrCant(e1))
 3402                     return;
 3403                 e1 = assignToLvalue(e, e1, newaae);
 3404                 if (exceptionOrCant(e1))
 3405                     return;
 3406             }
 3407             assert(existingAA && lastIndex);
 3408             e1 = null; // stomp
 3409         }
 3410         else if (e1.op == TOK.arrayLength)
 3411         {
 3412             oldval = interpretRegion(e1, istate);
 3413             if (exceptionOrCant(oldval))
 3414                 return;
 3415         }
 3416         else if (e.op == TOK.construct || e.op == TOK.blit)
 3417         {
 3418             // Unless we have a simple var assignment, we're
 3419             // only modifying part of the variable. So we need to make sure
 3420             // that the parent variable exists.
 3421             VarDeclaration ultimateVar = findParentVar(e1);
 3422             if (auto ve = e1.isVarExp())
 3423             {
 3424                 VarDeclaration v = ve.var.isVarDeclaration();
 3425                 assert(v);
 3426                 if (v.storage_class & STC.out_)
 3427                     goto L1;
 3428             }
 3429             else if (ultimateVar && !getValue(ultimateVar))
 3430             {
 3431                 Expression ex = interpretRegion(ultimateVar.type.defaultInitLiteral(e.loc), istate);
 3432                 if (exceptionOrCant(ex))
 3433                     return;
 3434                 setValue(ultimateVar, ex);
 3435             }
 3436             else
 3437                 goto L1;
 3438         }
 3439         else
 3440         {
 3441         L1:
 3442             e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
 3443             if (exceptionOrCant(e1))
 3444                 return;
 3445 
 3446             if (e1.op == TOK.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
 3447             {
 3448                 IndexExp ie = cast(IndexExp)e1;
 3449                 assert(ie.e1.op == TOK.assocArrayLiteral);
 3450                 existingAA = cast(AssocArrayLiteralExp)ie.e1;
 3451                 lastIndex = ie.e2;
 3452             }
 3453         }
 3454 
 3455         // ---------------------------------------
 3456         //      Interpret right hand side
 3457         // ---------------------------------------
 3458         Expression newval = interpretRegion(e.e2, istate);
 3459         if (exceptionOrCant(newval))
 3460             return;
 3461         if (e.op == TOK.blit && newval.op == TOK.int64)
 3462         {
 3463             Type tbn = e.type.baseElemOf();
 3464             if (tbn.ty == Tstruct)
 3465             {
 3466                 /* Look for special case of struct being initialized with 0.
 3467                  */
 3468                 newval = e.type.defaultInitLiteral(e.loc);
 3469                 if (newval.op == TOK.error)
 3470                 {
 3471                     result = CTFEExp.cantexp;
 3472                     return;
 3473                 }
 3474                 newval = interpretRegion(newval, istate); // copy and set ownedByCtfe flag
 3475                 if (exceptionOrCant(newval))
 3476                     return;
 3477             }
 3478         }
 3479 
 3480         // ----------------------------------------------------
 3481         //  Deal with read-modify-write assignments.
 3482         //  Set 'newval' to the final assignment value
 3483         //  Also determine the return value (except for slice
 3484         //  assignments, which are more complicated)
 3485         // ----------------------------------------------------
 3486         if (fp)
 3487         {
 3488             if (!oldval)
 3489             {
 3490                 // Load the left hand side after interpreting the right hand side.
 3491                 oldval = interpretRegion(e1, istate);
 3492                 if (exceptionOrCant(oldval))
 3493                     return;
 3494             }
 3495 
 3496             if (e.e1.type.ty != Tpointer)
 3497             {
 3498                 // ~= can create new values (see bug 6052)
 3499                 if (e.op == TOK.concatenateAssign || e.op == TOK.concatenateElemAssign || e.op == TOK.concatenateDcharAssign)
 3500                 {
 3501                     // We need to dup it and repaint the type. For a dynamic array
 3502                     // we can skip duplication, because it gets copied later anyway.
 3503                     if (newval.type.ty != Tarray)
 3504                     {
 3505                         newval = copyLiteral(newval).copy();
 3506                         newval.type = e.e2.type; // repaint type
 3507                     }
 3508                     else
 3509                     {
 3510                         newval = paintTypeOntoLiteral(e.e2.type, newval);
 3511                         newval = resolveSlice(newval);
 3512                     }
 3513                 }
 3514                 oldval = resolveSlice(oldval);
 3515 
 3516                 newval = (*fp)(e.loc, e.type, oldval, newval).copy();
 3517             }
 3518             else if (e.e2.type.isintegral() &&
 3519                      (e.op == TOK.addAssign ||
 3520                       e.op == TOK.minAssign ||
 3521                       e.op == TOK.plusPlus ||
 3522                       e.op == TOK.minusMinus))
 3523             {
 3524                 newval = pointerArithmetic(e.loc, e.op, e.type, oldval, newval).copy();
 3525             }
 3526             else
 3527             {
 3528                 e.error("pointer expression `%s` cannot be interpreted at compile time", e.toChars());
 3529                 result = CTFEExp.cantexp;
 3530                 return;
 3531             }
 3532             if (exceptionOrCant(newval))
 3533             {
 3534                 if (CTFEExp.isCantExp(newval))
 3535                     e.error("cannot interpret `%s` at compile time", e.toChars());
 3536                 return;
 3537             }
 3538         }
 3539 
 3540         if (existingAA)
 3541         {
 3542             if (existingAA.ownedByCtfe != OwnedBy.ctfe)
 3543             {
 3544                 e.error("cannot modify read-only constant `%s`", existingAA.toChars());
 3545                 result = CTFEExp.cantexp;
 3546                 return;
 3547             }
 3548 
 3549             //printf("\t+L%d existingAA = %s, lastIndex = %s, oldval = %s, newval = %s\n",
 3550             //    __LINE__, existingAA.toChars(), lastIndex.toChars(), oldval ? oldval.toChars() : NULL, newval.toChars());
 3551             assignAssocArrayElement(e.loc, existingAA, lastIndex, newval);
 3552 
 3553             // Determine the return value
 3554             result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
 3555             return;
 3556         }
 3557         if (e1.op == TOK.arrayLength)
 3558         {
 3559             /* Change the assignment from:
 3560              *  arr.length = n;
 3561              * into:
 3562              *  arr = new_length_array; (result is n)
 3563              */
 3564 
 3565             // Determine the return value
 3566             result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
 3567             if (exceptionOrCant(result))
 3568                 return;
 3569 
 3570             if (result == pue.exp())
 3571                 result = pue.copy();
 3572 
 3573             size_t oldlen = cast(size_t)oldval.toInteger();
 3574             size_t newlen = cast(size_t)newval.toInteger();
 3575             if (oldlen == newlen) // no change required -- we're done!
 3576                 return;
 3577 
 3578             // We have changed it into a reference assignment
 3579             // Note that returnValue is still the new length.
 3580             e1 = (cast(ArrayLengthExp)e1).e1;
 3581             Type t = e1.type.toBasetype();
 3582             if (t.ty != Tarray)
 3583             {
 3584                 e.error("`%s` is not yet supported at compile time", e.toChars());
 3585                 result = CTFEExp.cantexp;
 3586                 return;
 3587             }
 3588             e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
 3589             if (exceptionOrCant(e1))
 3590                 return;
 3591 
 3592             if (oldlen != 0) // Get the old array literal.
 3593                 oldval = interpretRegion(e1, istate);
 3594             UnionExp utmp = void;
 3595             oldval = resolveSlice(oldval, &utmp);
 3596 
 3597             newval = changeArrayLiteralLength(e.loc, cast(TypeArray)t, oldval, oldlen, newlen).copy();
 3598 
 3599             e1 = assignToLvalue(e, e1, newval);
 3600             if (exceptionOrCant(e1))
 3601                 return;
 3602 
 3603             return;
 3604         }
 3605 
 3606         if (!isBlockAssignment)
 3607         {
 3608             newval = ctfeCast(pue, e.loc, e.type, e.type, newval);
 3609             if (exceptionOrCant(newval))
 3610                 return;
 3611             if (newval == pue.exp())
 3612                 newval = pue.copy();
 3613 
 3614             // Determine the return value
 3615             if (goal == CTFEGoal.LValue) // https://issues.dlang.org/show_bug.cgi?id=14371
 3616                 result = e1;
 3617             else
 3618             {
 3619                 result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
 3620                 if (result == pue.exp())
 3621                     result = pue.copy();
 3622             }
 3623             if (exceptionOrCant(result))
 3624                 return;
 3625         }
 3626         if (exceptionOrCant(newval))
 3627             return;
 3628 
 3629         debug (LOGASSIGN)
 3630         {
 3631             printf("ASSIGN: %s=%s\n", e1.toChars(), newval.toChars());
 3632             showCtfeExpr(newval);
 3633         }
 3634 
 3635         /* Block assignment or element-wise assignment.
 3636          */
 3637         if (e1.op == TOK.slice ||
 3638             e1.op == TOK.vector ||
 3639             e1.op == TOK.arrayLiteral ||
 3640             e1.op == TOK.string_ ||
 3641             e1.op == TOK.null_ && e1.type.toBasetype().ty == Tarray)
 3642         {
 3643             // Note that slice assignments don't support things like ++, so
 3644             // we don't need to remember 'returnValue'.
 3645             result = interpretAssignToSlice(pue, e, e1, newval, isBlockAssignment);
 3646             if (exceptionOrCant(result))
 3647                 return;
 3648             if (auto se = e.e1.isSliceExp())
 3649             {
 3650                 Expression e1x = interpretRegion(se.e1, istate, CTFEGoal.LValue);
 3651                 if (auto dve = e1x.isDotVarExp())
 3652                 {
 3653                     auto ex = dve.e1;
 3654                     auto sle = ex.op == TOK.structLiteral ? (cast(StructLiteralExp)ex)
 3655                              : ex.op == TOK.classReference ? (cast(ClassReferenceExp)ex).value
 3656                              : null;
 3657                     auto v = dve.var.isVarDeclaration();
 3658                     if (!sle || !v)
 3659                     {
 3660                         e.error("CTFE internal error: dotvar slice assignment");
 3661                         result = CTFEExp.cantexp;
 3662                         return;
 3663                     }
 3664                     stompOverlappedFields(sle, v);
 3665                 }
 3666             }
 3667             return;
 3668         }
 3669         assert(result);
 3670 
 3671         /* Assignment to a CTFE reference.
 3672          */
 3673         if (Expression ex = assignToLvalue(e, e1, newval))
 3674             result = ex;
 3675 
 3676         return;
 3677     }
 3678 
 3679     /* Set all sibling fields which overlap with v to VoidExp.
 3680      */
 3681     private void stompOverlappedFields(StructLiteralExp sle, VarDeclaration v)
 3682     {
 3683         if (!v.overlapped)
 3684             return;
 3685         foreach (size_t i, v2; sle.sd.fields)
 3686         {
 3687             if (v is v2 || !v.isOverlappedWith(v2))
 3688                 continue;
 3689             auto e = (*sle.elements)[i];
 3690             if (e.op != TOK.void_)
 3691                 (*sle.elements)[i] = voidInitLiteral(e.type, v).copy();
 3692         }
 3693     }
 3694 
 3695     private Expression assignToLvalue(BinExp e, Expression e1, Expression newval)
 3696     {
 3697         VarDeclaration vd = null;
 3698         Expression* payload = null; // dead-store to prevent spurious warning
 3699         Expression oldval;
 3700 
 3701         if (auto ve = e1.isVarExp())
 3702         {
 3703             vd = ve.var.isVarDeclaration();
 3704             oldval = getValue(vd);
 3705         }
 3706         else if (auto dve = e1.isDotVarExp())
 3707         {
 3708             /* Assignment to member variable of the form:
 3709              *  e.v = newval
 3710              */
 3711             auto ex = dve.e1;
 3712             auto sle = ex.op == TOK.structLiteral ? (cast(StructLiteralExp)ex)
 3713                      : ex.op == TOK.classReference ? (cast(ClassReferenceExp)ex).value
 3714                      : null;
 3715             auto v = (cast(DotVarExp)e1).var.isVarDeclaration();
 3716             if (!sle || !v)
 3717             {
 3718                 e.error("CTFE internal error: dotvar assignment");
 3719                 return CTFEExp.cantexp;
 3720             }
 3721             if (sle.ownedByCtfe != OwnedBy.ctfe)
 3722             {
 3723                 e.error("cannot modify read-only constant `%s`", sle.toChars());
 3724                 return CTFEExp.cantexp;
 3725             }
 3726 
 3727             int fieldi = ex.op == TOK.structLiteral ? findFieldIndexByName(sle.sd, v)
 3728                        : (cast(ClassReferenceExp)ex).findFieldIndexByName(v);
 3729             if (fieldi == -1)
 3730             {
 3731                 e.error("CTFE internal error: cannot find field `%s` in `%s`", v.toChars(), ex.toChars());
 3732                 return CTFEExp.cantexp;
 3733             }
 3734             assert(0 <= fieldi && fieldi < sle.elements.dim);
 3735 
 3736             // If it's a union, set all other members of this union to void
 3737             stompOverlappedFields(sle, v);
 3738 
 3739             payload = &(*sle.elements)[fieldi];
 3740             oldval = *payload;
 3741         }
 3742         else if (auto ie = e1.isIndexExp())
 3743         {
 3744             assert(ie.e1.type.toBasetype().ty != Taarray);
 3745 
 3746             Expression aggregate;
 3747             uinteger_t indexToModify;
 3748             if (!resolveIndexing(ie, istate, &aggregate, &indexToModify, true))
 3749             {
 3750                 return CTFEExp.cantexp;
 3751             }
 3752             size_t index = cast(size_t)indexToModify;
 3753 
 3754             if (auto existingSE = aggregate.isStringExp())
 3755             {
 3756                 if (existingSE.ownedByCtfe != OwnedBy.ctfe)
 3757                 {
 3758                     e.error("cannot modify read-only string literal `%s`", ie.e1.toChars());
 3759                     return CTFEExp.cantexp;
 3760                 }
 3761                 existingSE.setCodeUnit(index, cast(dchar)newval.toInteger());
 3762                 return null;
 3763             }
 3764             if (aggregate.op != TOK.arrayLiteral)
 3765             {
 3766                 e.error("index assignment `%s` is not yet supported in CTFE ", e.toChars());
 3767                 return CTFEExp.cantexp;
 3768             }
 3769 
 3770             ArrayLiteralExp existingAE = cast(ArrayLiteralExp)aggregate;
 3771             if (existingAE.ownedByCtfe != OwnedBy.ctfe)
 3772             {
 3773                 e.error("cannot modify read-only constant `%s`", existingAE.toChars());
 3774                 return CTFEExp.cantexp;
 3775             }
 3776 
 3777             payload = &(*existingAE.elements)[index];
 3778             oldval = *payload;
 3779         }
 3780         else
 3781         {
 3782             e.error("`%s` cannot be evaluated at compile time", e.toChars());
 3783             return CTFEExp.cantexp;
 3784         }
 3785 
 3786         Type t1b = e1.type.toBasetype();
 3787         bool wantCopy = t1b.baseElemOf().ty == Tstruct;
 3788 
 3789         if (newval.op == TOK.structLiteral && oldval)
 3790         {
 3791             assert(oldval.op == TOK.structLiteral || oldval.op == TOK.arrayLiteral || oldval.op == TOK.string_);
 3792             newval = copyLiteral(newval).copy();
 3793             assignInPlace(oldval, newval);
 3794         }
 3795         else if (wantCopy && e.op == TOK.assign)
 3796         {
 3797             // Currently postblit/destructor calls on static array are done
 3798             // in the druntime internal functions so they don't appear in AST.
 3799             // Therefore interpreter should handle them specially.
 3800 
 3801             assert(oldval);
 3802             version (all) // todo: instead we can directly access to each elements of the slice
 3803             {
 3804                 newval = resolveSlice(newval);
 3805                 if (CTFEExp.isCantExp(newval))
 3806                 {
 3807                     e.error("CTFE internal error: assignment `%s`", e.toChars());
 3808                     return CTFEExp.cantexp;
 3809                 }
 3810             }
 3811             assert(oldval.op == TOK.arrayLiteral);
 3812             assert(newval.op == TOK.arrayLiteral);
 3813 
 3814             Expressions* oldelems = (cast(ArrayLiteralExp)oldval).elements;
 3815             Expressions* newelems = (cast(ArrayLiteralExp)newval).elements;
 3816             assert(oldelems.dim == newelems.dim);
 3817 
 3818             Type elemtype = oldval.type.nextOf();
 3819             foreach (i, ref oldelem; *oldelems)
 3820             {
 3821                 Expression newelem = paintTypeOntoLiteral(elemtype, (*newelems)[i]);
 3822                 // https://issues.dlang.org/show_bug.cgi?id=9245
 3823                 if (e.e2.isLvalue())
 3824                 {
 3825                     if (Expression ex = evaluatePostblit(istate, newelem))
 3826                         return ex;
 3827                 }
 3828                 // https://issues.dlang.org/show_bug.cgi?id=13661
 3829                 if (Expression ex = evaluateDtor(istate, oldelem))
 3830                     return ex;
 3831                 oldelem = newelem;
 3832             }
 3833         }
 3834         else
 3835         {
 3836             // e1 has its own payload, so we have to create a new literal.
 3837             if (wantCopy)
 3838                 newval = copyLiteral(newval).copy();
 3839 
 3840             if (t1b.ty == Tsarray && e.op == TOK.construct && e.e2.isLvalue())
 3841             {
 3842                 // https://issues.dlang.org/show_bug.cgi?id=9245
 3843                 if (Expression ex = evaluatePostblit(istate, newval))
 3844                     return ex;
 3845             }
 3846 
 3847             oldval = newval;
 3848         }
 3849 
 3850         if (vd)
 3851             setValue(vd, oldval);
 3852         else
 3853             *payload = oldval;
 3854 
 3855         // Blit assignment should return the newly created value.
 3856         if (e.op == TOK.blit)
 3857             return oldval;
 3858 
 3859         return null;
 3860     }
 3861 
 3862     /*************
 3863      * Deal with assignments of the form:
 3864      *  dest[] = newval
 3865      *  dest[low..upp] = newval
 3866      * where newval has already been interpreted
 3867      *
 3868      * This could be a slice assignment or a block assignment, and
 3869      * dest could be either an array literal, or a string.
 3870      *
 3871      * Returns TOK.cantExpression on failure. If there are no errors,
 3872      * it returns aggregate[low..upp], except that as an optimisation,
 3873      * if goal == CTFEGoal.Nothing, it will return NULL
 3874      */
 3875     private Expression interpretAssignToSlice(UnionExp* pue, BinExp e, Expression e1, Expression newval, bool isBlockAssignment)
 3876     {
 3877         dinteger_t lowerbound;
 3878         dinteger_t upperbound;
 3879         dinteger_t firstIndex;
 3880 
 3881         Expression aggregate;
 3882 
 3883         if (auto se = e1.isSliceExp())
 3884         {
 3885             // ------------------------------
 3886             //   aggregate[] = newval
 3887             //   aggregate[low..upp] = newval
 3888             // ------------------------------
 3889             version (all) // should be move in interpretAssignCommon as the evaluation of e1
 3890             {
 3891                 Expression oldval = interpretRegion(se.e1, istate);
 3892 
 3893                 // Set the $ variable
 3894                 uinteger_t dollar = resolveArrayLength(oldval);
 3895                 if (se.lengthVar)
 3896                 {
 3897                     Expression dollarExp = ctfeEmplaceExp!IntegerExp(e1.loc, dollar, Type.tsize_t);
 3898                     ctfeGlobals.stack.push(se.lengthVar);
 3899                     setValue(se.lengthVar, dollarExp);
 3900                 }
 3901                 Expression lwr = interpretRegion(se.lwr, istate);
 3902                 if (exceptionOrCantInterpret(lwr))
 3903                 {
 3904                     if (se.lengthVar)
 3905                         ctfeGlobals.stack.pop(se.lengthVar);
 3906                     return lwr;
 3907                 }
 3908                 Expression upr = interpretRegion(se.upr, istate);
 3909                 if (exceptionOrCantInterpret(upr))
 3910                 {
 3911                     if (se.lengthVar)
 3912                         ctfeGlobals.stack.pop(se.lengthVar);
 3913                     return upr;
 3914                 }
 3915                 if (se.lengthVar)
 3916                     ctfeGlobals.stack.pop(se.lengthVar); // $ is defined only in [L..U]
 3917 
 3918                 const dim = dollar;
 3919                 lowerbound = lwr ? lwr.toInteger() : 0;
 3920                 upperbound = upr ? upr.toInteger() : dim;
 3921 
 3922                 if (lowerbound < 0 || dim < upperbound)
 3923                 {
 3924                     e.error("array bounds `[0..%llu]` exceeded in slice `[%llu..%llu]`",
 3925                         ulong(dim), ulong(lowerbound), ulong(upperbound));
 3926                     return CTFEExp.cantexp;
 3927                 }
 3928             }
 3929             aggregate = oldval;
 3930             firstIndex = lowerbound;
 3931 
 3932             if (auto oldse = aggregate.isSliceExp())
 3933             {
 3934                 // Slice of a slice --> change the bounds
 3935                 if (oldse.upr.toInteger() < upperbound + oldse.lwr.toInteger())
 3936                 {
 3937                     e.error("slice `[%llu..%llu]` exceeds array bounds `[0..%llu]`",
 3938                         ulong(lowerbound), ulong(upperbound), oldse.upr.toInteger() - oldse.lwr.toInteger());
 3939                     return CTFEExp.cantexp;
 3940                 }
 3941                 aggregate = oldse.e1;
 3942                 firstIndex = lowerbound + oldse.lwr.toInteger();
 3943             }
 3944         }
 3945         else
 3946         {
 3947             if (auto ale = e1.isArrayLiteralExp())
 3948             {
 3949                 lowerbound = 0;
 3950                 upperbound = ale.elements.dim;
 3951             }
 3952             else if (auto se = e1.isStringExp())
 3953             {
 3954                 lowerbound = 0;
 3955                 upperbound = se.len;
 3956             }
 3957             else if (e1.op == TOK.null_)
 3958             {
 3959                 lowerbound = 0;
 3960                 upperbound = 0;
 3961             }
 3962             else if (VectorExp ve = e1.isVectorExp())
 3963             {
 3964                 // ve is not handled but a proper error message is returned
 3965                 // this is to prevent https://issues.dlang.org/show_bug.cgi?id=20042
 3966                 lowerbound = 0;
 3967                 upperbound = ve.dim;
 3968             }
 3969             else
 3970                 assert(0);
 3971 
 3972             aggregate = e1;
 3973             firstIndex = lowerbound;
 3974         }
 3975         if (upperbound == lowerbound)
 3976             return newval;
 3977 
 3978         // For slice assignment, we check that the lengths match.
 3979         if (!isBlockAssignment)
 3980         {
 3981             const srclen = resolveArrayLength(newval);
 3982             if (srclen != (upperbound - lowerbound))
 3983             {
 3984                 e.error("array length mismatch assigning `[0..%llu]` to `[%llu..%llu]`",
 3985                     ulong(srclen), ulong(lowerbound), ulong(upperbound));
 3986                 return CTFEExp.cantexp;
 3987             }
 3988         }
 3989 
 3990         if (auto existingSE = aggregate.isStringExp())
 3991         {
 3992             if (existingSE.ownedByCtfe != OwnedBy.ctfe)
 3993             {
 3994                 e.error("cannot modify read-only string literal `%s`", existingSE.toChars());
 3995                 return CTFEExp.cantexp;
 3996             }
 3997 
 3998             if (auto se = newval.isSliceExp())
 3999             {
 4000                 auto aggr2 = se.e1;
 4001                 const srclower = se.lwr.toInteger();
 4002                 const srcupper = se.upr.toInteger();
 4003 
 4004                 if (aggregate == aggr2 &&
 4005                     lowerbound < srcupper && srclower < upperbound)
 4006                 {
 4007                     e.error("overlapping slice assignment `[%llu..%llu] = [%llu..%llu]`",
 4008                         ulong(lowerbound), ulong(upperbound), ulong(srclower), ulong(srcupper));
 4009                     return CTFEExp.cantexp;
 4010                 }
 4011                 version (all) // todo: instead we can directly access to each elements of the slice
 4012                 {
 4013                     Expression orignewval = newval;
 4014                     newval = resolveSlice(newval);
 4015                     if (CTFEExp.isCantExp(newval))
 4016                     {
 4017                         e.error("CTFE internal error: slice `%s`", orignewval.toChars());
 4018                         return CTFEExp.cantexp;
 4019                     }
 4020                 }
 4021                 assert(newval.op != TOK.slice);
 4022             }
 4023             if (auto se = newval.isStringExp())
 4024             {
 4025                 sliceAssignStringFromString(existingSE, se, cast(size_t)firstIndex);
 4026                 return newval;
 4027             }
 4028             if (auto ale = newval.isArrayLiteralExp())
 4029             {
 4030                 /* Mixed slice: it was initialized as a string literal.
 4031                  * Now a slice of it is being set with an array literal.
 4032                  */
 4033                 sliceAssignStringFromArrayLiteral(existingSE, ale, cast(size_t)firstIndex);
 4034                 return newval;
 4035             }
 4036 
 4037             // String literal block slice assign
 4038             const value = cast(dchar)newval.toInteger();
 4039             foreach (i; 0 .. upperbound - lowerbound)
 4040             {
 4041                 existingSE.setCodeUnit(cast(size_t)(i + firstIndex), value);
 4042             }
 4043             if (goal == CTFEGoal.Nothing)
 4044                 return null; // avoid creating an unused literal
 4045             auto retslice = ctfeEmplaceExp!SliceExp(e.loc, existingSE,
 4046                         ctfeEmplaceExp!IntegerExp(e.loc, firstIndex, Type.tsize_t),
 4047                         ctfeEmplaceExp!IntegerExp(e.loc, firstIndex + upperbound - lowerbound, Type.tsize_t));
 4048             retslice.type = e.type;
 4049             return interpret(pue, retslice, istate);
 4050         }
 4051         if (auto existingAE = aggregate.isArrayLiteralExp())
 4052         {
 4053             if (existingAE.ownedByCtfe != OwnedBy.ctfe)
 4054             {
 4055                 e.error("cannot modify read-only constant `%s`", existingAE.toChars());
 4056                 return CTFEExp.cantexp;
 4057             }
 4058 
 4059             if (newval.op == TOK.slice && !isBlockAssignment)
 4060             {
 4061                 auto se = cast(SliceExp)newval;
 4062                 auto aggr2 = se.e1;
 4063                 const srclower = se.lwr.toInteger();
 4064                 const srcupper = se.upr.toInteger();
 4065                 const wantCopy = (newval.type.toBasetype().nextOf().baseElemOf().ty == Tstruct);
 4066 
 4067                 //printf("oldval = %p %s[%d..%u]\nnewval = %p %s[%llu..%llu] wantCopy = %d\n",
 4068                 //    aggregate, aggregate.toChars(), lowerbound, upperbound,
 4069                 //    aggr2, aggr2.toChars(), srclower, srcupper, wantCopy);
 4070                 if (wantCopy)
 4071                 {
 4072                     // Currently overlapping for struct array is allowed.
 4073                     // The order of elements processing depends on the overlapping.
 4074                     // https://issues.dlang.org/show_bug.cgi?id=14024
 4075                     assert(aggr2.op == TOK.arrayLiteral);
 4076                     Expressions* oldelems = existingAE.elements;
 4077                     Expressions* newelems = (cast(ArrayLiteralExp)aggr2).elements;
 4078 
 4079                     Type elemtype = aggregate.type.nextOf();
 4080                     bool needsPostblit = e.e2.isLvalue();
 4081 
 4082                     if (aggregate == aggr2 && srclower < lowerbound && lowerbound < srcupper)
 4083                     {
 4084                         // reverse order
 4085                         for (auto i = upperbound - lowerbound; 0 < i--;)
 4086                         {
 4087                             Expression oldelem = (*oldelems)[cast(size_t)(i + firstIndex)];
 4088                             Expression newelem = (*newelems)[cast(size_t)(i + srclower)];
 4089                             newelem = copyLiteral(newelem).copy();
 4090                             newelem.type = elemtype;
 4091                             if (needsPostblit)
 4092                             {
 4093                                 if (Expression x = evaluatePostblit(istate, newelem))
 4094                                     return x;
 4095                             }
 4096                             if (Expression x = evaluateDtor(istate, oldelem))
 4097                                 return x;
 4098                             (*oldelems)[cast(size_t)(lowerbound + i)] = newelem;
 4099                         }
 4100                     }
 4101                     else
 4102                     {
 4103                         // normal order
 4104                         for (auto i = 0; i < upperbound - lowerbound; i++)
 4105                         {
 4106                             Expression oldelem = (*oldelems)[cast(size_t)(i + firstIndex)];
 4107                             Expression newelem = (*newelems)[cast(size_t)(i + srclower)];
 4108                             newelem = copyLiteral(newelem).copy();
 4109                             newelem.type = elemtype;
 4110                             if (needsPostblit)
 4111                             {
 4112                                 if (Expression x = evaluatePostblit(istate, newelem))
 4113                                     return x;
 4114                             }
 4115                             if (Expression x = evaluateDtor(istate, oldelem))
 4116                                 return x;
 4117                             (*oldelems)[cast(size_t)(lowerbound + i)] = newelem;
 4118                         }
 4119                     }
 4120 
 4121                     //assert(0);
 4122                     return newval; // oldval?
 4123                 }
 4124                 if (aggregate == aggr2 &&
 4125                     lowerbound < srcupper && srclower < upperbound)
 4126                 {
 4127                     e.error("overlapping slice assignment `[%llu..%llu] = [%llu..%llu]`",
 4128                         ulong(lowerbound), ulong(upperbound), ulong(srclower), ulong(srcupper));
 4129                     return CTFEExp.cantexp;
 4130                 }
 4131                 version (all) // todo: instead we can directly access to each elements of the slice
 4132                 {
 4133                     Expression orignewval = newval;
 4134                     newval = resolveSlice(newval);
 4135                     if (CTFEExp.isCantExp(newval))
 4136                     {
 4137                         e.error("CTFE internal error: slice `%s`", orignewval.toChars());
 4138                         return CTFEExp.cantexp;
 4139                     }
 4140                 }
 4141                 // no overlapping
 4142                 //length?
 4143                 assert(newval.op != TOK.slice);
 4144             }
 4145             if (newval.op == TOK.string_ && !isBlockAssignment)
 4146             {
 4147                 /* Mixed slice: it was initialized as an array literal of chars/integers.
 4148                  * Now a slice of it is being set with a string.
 4149                  */
 4150                 sliceAssignArrayLiteralFromString(existingAE, cast(StringExp)newval, cast(size_t)firstIndex);
 4151                 return newval;
 4152             }
 4153             if (newval.op == TOK.arrayLiteral && !isBlockAssignment)
 4154             {
 4155                 Expressions* oldelems = existingAE.elements;
 4156                 Expressions* newelems = (cast(ArrayLiteralExp)newval).elements;
 4157                 Type elemtype = existingAE.type.nextOf();
 4158                 bool needsPostblit = e.op != TOK.blit && e.e2.isLvalue();
 4159                 foreach (j, newelem; *newelems)
 4160                 {
 4161                     newelem = paintTypeOntoLiteral(elemtype, newelem);
 4162                     if (needsPostblit)
 4163                     {
 4164                         Expression x = evaluatePostblit(istate, newelem);
 4165                         if (exceptionOrCantInterpret(x))
 4166                             return x;
 4167                     }
 4168                     (*oldelems)[cast(size_t)(j + firstIndex)] = newelem;
 4169                 }
 4170                 return newval;
 4171             }
 4172 
 4173             /* Block assignment, initialization of static arrays
 4174              *   x[] = newval
 4175              *  x may be a multidimensional static array. (Note that this
 4176              *  only happens with array literals, never with strings).
 4177              */
 4178             struct RecursiveBlock
 4179             {
 4180                 InterState* istate;
 4181                 Expression newval;
 4182                 bool refCopy;
 4183                 bool needsPostblit;
 4184                 bool needsDtor;
 4185 
 4186                 extern (C++) Expression assignTo(ArrayLiteralExp ae)
 4187                 {
 4188                     return assignTo(ae, 0, ae.elements.dim);
 4189                 }
 4190 
 4191                 extern (C++) Expression assignTo(ArrayLiteralExp ae, size_t lwr, size_t upr)
 4192                 {
 4193                     Expressions* w = ae.elements;
 4194                     assert(ae.type.ty == Tsarray || ae.type.ty == Tarray);
 4195                     bool directblk = (cast(TypeArray)ae.type).next.equivalent(newval.type);
 4196                     for (size_t k = lwr; k < upr; k++)
 4197                     {
 4198                         if (!directblk && (*w)[k].op == TOK.arrayLiteral)
 4199                         {
 4200                             // Multidimensional array block assign
 4201                             if (Expression ex = assignTo(cast(ArrayLiteralExp)(*w)[k]))
 4202                                 return ex;
 4203                         }
 4204                         else if (refCopy)
 4205                         {
 4206                             (*w)[k] = newval;
 4207                         }
 4208                         else if (!needsPostblit && !needsDtor)
 4209                         {
 4210                             assignInPlace((*w)[k], newval);
 4211                         }
 4212                         else
 4213                         {
 4214                             Expression oldelem = (*w)[k];
 4215                             Expression tmpelem = needsDtor ? copyLiteral(oldelem).copy() : null;
 4216                             assignInPlace(oldelem, newval);
 4217                             if (needsPostblit)
 4218                             {
 4219                                 if (Expression ex = evaluatePostblit(istate, oldelem))
 4220                                     return ex;
 4221                             }
 4222                             if (needsDtor)
 4223                             {
 4224                                 // https://issues.dlang.org/show_bug.cgi?id=14860
 4225                                 if (Expression ex = evaluateDtor(istate, tmpelem))
 4226                                     return ex;
 4227                             }
 4228                         }
 4229                     }
 4230                     return null;
 4231                 }
 4232             }
 4233 
 4234             Type tn = newval.type.toBasetype();
 4235             bool wantRef = (tn.ty == Tarray || isAssocArray(tn) || tn.ty == Tclass);
 4236             bool cow = newval.op != TOK.structLiteral && newval.op != TOK.arrayLiteral && newval.op != TOK.string_;
 4237             Type tb = tn.baseElemOf();
 4238             StructDeclaration sd = (tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null);
 4239 
 4240             RecursiveBlock rb;
 4241             rb.istate = istate;
 4242             rb.newval = newval;
 4243             rb.refCopy = wantRef || cow;
 4244             rb.needsPostblit = sd && sd.postblit && e.op != TOK.blit && e.e2.isLvalue();
 4245             rb.needsDtor = sd && sd.dtor && e.op == TOK.assign;
 4246             if (Expression ex = rb.assignTo(existingAE, cast(size_t)lowerbound, cast(size_t)upperbound))
 4247                 return ex;
 4248 
 4249             if (goal == CTFEGoal.Nothing)
 4250                 return null; // avoid creating an unused literal
 4251             auto retslice = ctfeEmplaceExp!SliceExp(e.loc, existingAE,
 4252                 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex, Type.tsize_t),
 4253                 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex + upperbound - lowerbound, Type.tsize_t));
 4254             retslice.type = e.type;
 4255             return interpret(pue, retslice, istate);
 4256         }
 4257 
 4258         e.error("slice operation `%s = %s` cannot be evaluated at compile time", e1.toChars(), newval.toChars());
 4259         return CTFEExp.cantexp;
 4260     }
 4261 
 4262     override void visit(AssignExp e)
 4263     {
 4264         interpretAssignCommon(e, null);
 4265     }
 4266 
 4267     override void visit(BinAssignExp e)
 4268     {
 4269         switch (e.op)
 4270         {
 4271         case TOK.addAssign:
 4272             interpretAssignCommon(e, &Add);
 4273             return;
 4274 
 4275         case TOK.minAssign:
 4276             interpretAssignCommon(e, &Min);
 4277             return;
 4278 
 4279         case TOK.concatenateAssign:
 4280         case TOK.concatenateElemAssign:
 4281         case TOK.concatenateDcharAssign:
 4282             interpretAssignCommon(e, &ctfeCat);
 4283             return;
 4284 
 4285         case TOK.mulAssign:
 4286             interpretAssignCommon(e, &Mul);
 4287             return;
 4288 
 4289         case TOK.divAssign:
 4290             interpretAssignCommon(e, &Div);
 4291             return;
 4292 
 4293         case TOK.modAssign:
 4294             interpretAssignCommon(e, &Mod);
 4295             return;
 4296 
 4297         case TOK.leftShiftAssign:
 4298             interpretAssignCommon(e, &Shl);
 4299             return;
 4300 
 4301         case TOK.rightShiftAssign:
 4302             interpretAssignCommon(e, &Shr);
 4303             return;
 4304 
 4305         case TOK.unsignedRightShiftAssign:
 4306             interpretAssignCommon(e, &Ushr);
 4307             return;
 4308 
 4309         case TOK.andAssign:
 4310             interpretAssignCommon(e, &And);
 4311             return;
 4312 
 4313         case TOK.orAssign:
 4314             interpretAssignCommon(e, &Or);
 4315             return;
 4316 
 4317         case TOK.xorAssign:
 4318             interpretAssignCommon(e, &Xor);
 4319             return;
 4320 
 4321         case TOK.powAssign:
 4322             interpretAssignCommon(e, &Pow);
 4323             return;
 4324 
 4325         default:
 4326             assert(0);
 4327         }
 4328     }
 4329 
 4330     override void visit(PostExp e)
 4331     {
 4332         debug (LOG)
 4333         {
 4334             printf("%s PostExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 4335         }
 4336         if (e.op == TOK.plusPlus)
 4337             interpretAssignCommon(e, &Add, 1);
 4338         else
 4339             interpretAssignCommon(e, &Min, 1);
 4340         debug (LOG)
 4341         {
 4342             if (CTFEExp.isCantExp(result))
 4343                 printf("PostExp::interpret() CANT\n");
 4344         }
 4345     }
 4346 
 4347     /* Return 1 if e is a p1 > p2 or p1 >= p2 pointer comparison;
 4348      *       -1 if e is a p1 < p2 or p1 <= p2 pointer comparison;
 4349      *        0 otherwise
 4350      */
 4351     static int isPointerCmpExp(Expression e, Expression* p1, Expression* p2)
 4352     {
 4353         int ret = 1;
 4354         while (e.op == TOK.not)
 4355         {
 4356             ret *= -1;
 4357             e = (cast(NotExp)e).e1;
 4358         }
 4359         switch (e.op)
 4360         {
 4361         case TOK.lessThan:
 4362         case TOK.lessOrEqual:
 4363             ret *= -1;
 4364             goto case; /+ fall through +/
 4365         case TOK.greaterThan:
 4366         case TOK.greaterOrEqual:
 4367             *p1 = (cast(BinExp)e).e1;
 4368             *p2 = (cast(BinExp)e).e2;
 4369             if (!(isPointer((*p1).type) && isPointer((*p2).type)))
 4370                 ret = 0;
 4371             break;
 4372 
 4373         default:
 4374             ret = 0;
 4375             break;
 4376         }
 4377         return ret;
 4378     }
 4379 
 4380     /** If this is a four pointer relation, evaluate it, else return NULL.
 4381      *
 4382      *  This is an expression of the form (p1 > q1 && p2 < q2) or (p1 < q1 || p2 > q2)
 4383      *  where p1, p2 are expressions yielding pointers to memory block p,
 4384      *  and q1, q2 are expressions yielding pointers to memory block q.
 4385      *  This expression is valid even if p and q are independent memory
 4386      *  blocks and are therefore not normally comparable; the && form returns true
 4387      *  if [p1..p2] lies inside [q1..q2], and false otherwise; the || form returns
 4388      *  true if [p1..p2] lies outside [q1..q2], and false otherwise.
 4389      *
 4390      *  Within the expression, any ordering of p1, p2, q1, q2 is permissible;
 4391      *  the comparison operators can be any of >, <, <=, >=, provided that
 4392      *  both directions (p > q and p < q) are checked. Additionally the
 4393      *  relational sub-expressions can be negated, eg
 4394      *  (!(q1 < p1) && p2 <= q2) is valid.
 4395      */
 4396     private void interpretFourPointerRelation(UnionExp* pue, BinExp e)
 4397     {
 4398         assert(e.op == TOK.andAnd || e.op == TOK.orOr);
 4399 
 4400         /*  It can only be an isInside expression, if both e1 and e2 are
 4401          *  directional pointer comparisons.
 4402          *  Note that this check can be made statically; it does not depends on
 4403          *  any runtime values. This allows a JIT implementation to compile a
 4404          *  special AndAndPossiblyInside, keeping the normal AndAnd case efficient.
 4405          */
 4406 
 4407         // Save the pointer expressions and the comparison directions,
 4408         // so we can use them later.
 4409         Expression p1 = null;
 4410         Expression p2 = null;
 4411         Expression p3 = null;
 4412         Expression p4 = null;
 4413         int dir1 = isPointerCmpExp(e.e1, &p1, &p2);
 4414         int dir2 = isPointerCmpExp(e.e2, &p3, &p4);
 4415         if (dir1 == 0 || dir2 == 0)
 4416         {
 4417             result = null;
 4418             return;
 4419         }
 4420 
 4421         //printf("FourPointerRelation %s\n", toChars());
 4422 
 4423         UnionExp ue1 = void;
 4424         UnionExp ue2 = void;
 4425         UnionExp ue3 = void;
 4426         UnionExp ue4 = void;
 4427 
 4428         // Evaluate the first two pointers
 4429         p1 = interpret(&ue1, p1, istate);
 4430         if (exceptionOrCant(p1))
 4431             return;
 4432         p2 = interpret(&ue2, p2, istate);
 4433         if (exceptionOrCant(p2))
 4434             return;
 4435         dinteger_t ofs1, ofs2;
 4436         Expression agg1 = getAggregateFromPointer(p1, &ofs1);
 4437         Expression agg2 = getAggregateFromPointer(p2, &ofs2);
 4438 
 4439         if (!pointToSameMemoryBlock(agg1, agg2) && agg1.op != TOK.null_ && agg2.op != TOK.null_)
 4440         {
 4441             // Here it is either CANT_INTERPRET,
 4442             // or an IsInside comparison returning false.
 4443             p3 = interpret(&ue3, p3, istate);
 4444             if (CTFEExp.isCantExp(p3))
 4445                 return;
 4446             // Note that it is NOT legal for it to throw an exception!
 4447             Expression except = null;
 4448             if (exceptionOrCantInterpret(p3))
 4449                 except = p3;
 4450             else
 4451             {
 4452                 p4 = interpret(&ue4, p4, istate);
 4453                 if (CTFEExp.isCantExp(p4))
 4454                 {
 4455                     result = p4;
 4456                     return;
 4457                 }
 4458                 if (exceptionOrCantInterpret(p4))
 4459                     except = p4;
 4460             }
 4461             if (except)
 4462             {
 4463                 e.error("comparison `%s` of pointers to unrelated memory blocks remains indeterminate at compile time because exception `%s` was thrown while evaluating `%s`", e.e1.toChars(), except.toChars(), e.e2.toChars());
 4464                 result = CTFEExp.cantexp;
 4465                 return;
 4466             }
 4467             dinteger_t ofs3, ofs4;
 4468             Expression agg3 = getAggregateFromPointer(p3, &ofs3);
 4469             Expression agg4 = getAggregateFromPointer(p4, &ofs4);
 4470             // The valid cases are:
 4471             // p1 > p2 && p3 > p4  (same direction, also for < && <)
 4472             // p1 > p2 && p3 < p4  (different direction, also < && >)
 4473             // Changing any > into >= doesn't affect the result
 4474             if ((dir1 == dir2 && pointToSameMemoryBlock(agg1, agg4) && pointToSameMemoryBlock(agg2, agg3)) ||
 4475                 (dir1 != dir2 && pointToSameMemoryBlock(agg1, agg3) && pointToSameMemoryBlock(agg2, agg4)))
 4476             {
 4477                 // it's a legal two-sided comparison
 4478                 emplaceExp!(IntegerExp)(pue, e.loc, (e.op == TOK.andAnd) ? 0 : 1, e.type);
 4479                 result = pue.exp();
 4480                 return;
 4481             }
 4482             // It's an invalid four-pointer comparison. Either the second
 4483             // comparison is in the same direction as the first, or else
 4484             // more than two memory blocks are involved (either two independent
 4485             // invalid comparisons are present, or else agg3 == agg4).
 4486             e.error("comparison `%s` of pointers to unrelated memory blocks is indeterminate at compile time, even when combined with `%s`.", e.e1.toChars(), e.e2.toChars());
 4487             result = CTFEExp.cantexp;
 4488             return;
 4489         }
 4490         // The first pointer expression didn't need special treatment, so we
 4491         // we need to interpret the entire expression exactly as a normal && or ||.
 4492         // This is easy because we haven't evaluated e2 at all yet, and we already
 4493         // know it will return a bool.
 4494         // But we mustn't evaluate the pointer expressions in e1 again, in case
 4495         // they have side-effects.
 4496         bool nott = false;
 4497         Expression ex = e.e1;
 4498         while (1)
 4499         {
 4500             if (auto ne = ex.isNotExp())
 4501             {
 4502                 nott = !nott;
 4503                 ex = ne.e1;
 4504             }
 4505             else
 4506                 break;
 4507         }
 4508 
 4509         /** Negate relational operator, eg >= becomes <
 4510          * Params:
 4511          *      op = comparison operator to negate
 4512          * Returns:
 4513          *      negate operator
 4514          */
 4515         static TOK negateRelation(TOK op) pure
 4516         {
 4517             switch (op)
 4518             {
 4519                 case TOK.greaterOrEqual:  op = TOK.lessThan;       break;
 4520                 case TOK.greaterThan:     op = TOK.lessOrEqual;    break;
 4521                 case TOK.lessOrEqual:     op = TOK.greaterThan;    break;
 4522                 case TOK.lessThan:        op = TOK.greaterOrEqual; break;
 4523                 default:                  assert(0);
 4524             }
 4525             return op;
 4526         }
 4527 
 4528         const TOK cmpop = nott ? negateRelation(ex.op) : ex.op;
 4529         const cmp = comparePointers(cmpop, agg1, ofs1, agg2, ofs2);
 4530         // We already know this is a valid comparison.
 4531         assert(cmp >= 0);
 4532         if (e.op == TOK.andAnd && cmp == 1 || e.op == TOK.orOr && cmp == 0)
 4533         {
 4534             result = interpret(pue, e.e2, istate);
 4535             return;
 4536         }
 4537         emplaceExp!(IntegerExp)(pue, e.loc, (e.op == TOK.andAnd) ? 0 : 1, e.type);
 4538         result = pue.exp();
 4539     }
 4540 
 4541     override void visit(LogicalExp e)
 4542     {
 4543         debug (LOG)
 4544         {
 4545             printf("%s LogicalExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 4546         }
 4547         // Check for an insidePointer expression, evaluate it if so
 4548         interpretFourPointerRelation(pue, e);
 4549         if (result)
 4550             return;
 4551 
 4552         UnionExp ue1 = void;
 4553         result = interpret(&ue1, e.e1, istate);
 4554         if (exceptionOrCant(result))
 4555             return;
 4556 
 4557         bool res;
 4558         const andand = e.op == TOK.andAnd;
 4559         if (andand ? result.isBool(false) : isTrueBool(result))
 4560             res = !andand;
 4561         else if (andand ? isTrueBool(result) : result.isBool(false))
 4562         {
 4563             UnionExp ue2 = void;
 4564             result = interpret(&ue2, e.e2, istate);
 4565             if (exceptionOrCant(result))
 4566                 return;
 4567             if (result.op == TOK.voidExpression)
 4568             {
 4569                 assert(e.type.ty == Tvoid);
 4570                 result = null;
 4571                 return;
 4572             }
 4573             if (result.isBool(false))
 4574                 res = false;
 4575             else if (isTrueBool(result))
 4576                 res = true;
 4577             else
 4578             {
 4579                 e.error("`%s` does not evaluate to a `bool`", result.toChars());
 4580                 result = CTFEExp.cantexp;
 4581                 return;
 4582             }
 4583         }
 4584         else
 4585         {
 4586             e.error("`%s` cannot be interpreted as a `bool`", result.toChars());
 4587             result = CTFEExp.cantexp;
 4588             return;
 4589         }
 4590         incUsageCtfe(istate, e.e2.loc);
 4591 
 4592         if (goal != CTFEGoal.Nothing)
 4593         {
 4594             if (e.type.equals(Type.tbool))
 4595                 result = IntegerExp.createBool(res);
 4596             else
 4597             {
 4598                 emplaceExp!(IntegerExp)(pue, e.loc, res, e.type);
 4599                 result = pue.exp();
 4600             }
 4601         }
 4602     }
 4603 
 4604 
 4605     // Print a stack trace, starting from callingExp which called fd.
 4606     // To shorten the stack trace, try to detect recursion.
 4607     private void showCtfeBackTrace(CallExp callingExp, FuncDeclaration fd)
 4608     {
 4609         if (ctfeGlobals.stackTraceCallsToSuppress > 0)
 4610         {
 4611             --ctfeGlobals.stackTraceCallsToSuppress;
 4612             return;
 4613         }
 4614         errorSupplemental(callingExp.loc, "called from here: `%s`", callingExp.toChars());
 4615         // Quit if it's not worth trying to compress the stack trace
 4616         if (ctfeGlobals.callDepth < 6 || global.params.verbose)
 4617             return;
 4618         // Recursion happens if the current function already exists in the call stack.
 4619         int numToSuppress = 0;
 4620         int recurseCount = 0;
 4621         int depthSoFar = 0;
 4622         InterState* lastRecurse = istate;
 4623         for (InterState* cur = istate; cur; cur = cur.caller)
 4624         {
 4625             if (cur.fd == fd)
 4626             {
 4627                 ++recurseCount;
 4628                 numToSuppress = depthSoFar;
 4629                 lastRecurse = cur;
 4630             }
 4631             ++depthSoFar;
 4632         }
 4633         // We need at least three calls to the same function, to make compression worthwhile
 4634         if (recurseCount < 2)
 4635             return;
 4636         // We found a useful recursion.  Print all the calls involved in the recursion
 4637         errorSupplemental(fd.loc, "%d recursive calls to function `%s`", recurseCount, fd.toChars());
 4638         for (InterState* cur = istate; cur.fd != fd; cur = cur.caller)
 4639         {
 4640             errorSupplemental(cur.fd.loc, "recursively called from function `%s`", cur.fd.toChars());
 4641         }
 4642         // We probably didn't enter the recursion in this function.
 4643         // Go deeper to find the real beginning.
 4644         InterState* cur = istate;
 4645         while (lastRecurse.caller && cur.fd == lastRecurse.caller.fd)
 4646         {
 4647             cur = cur.caller;
 4648             lastRecurse = lastRecurse.caller;
 4649             ++numToSuppress;
 4650         }
 4651         ctfeGlobals.stackTraceCallsToSuppress = numToSuppress;
 4652     }
 4653 
 4654     override void visit(CallExp e)
 4655     {
 4656         debug (LOG)
 4657         {
 4658             printf("%s CallExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 4659         }
 4660         Expression pthis = null;
 4661         FuncDeclaration fd = null;
 4662 
 4663         Expression ecall = interpretRegion(e.e1, istate);
 4664         if (exceptionOrCant(ecall))
 4665             return;
 4666 
 4667         if (auto dve = ecall.isDotVarExp())
 4668         {
 4669             // Calling a member function
 4670             pthis = dve.e1;
 4671             fd = dve.var.isFuncDeclaration();
 4672             assert(fd);
 4673 
 4674             if (auto dte = pthis.isDotTypeExp())
 4675                 pthis = dte.e1;
 4676         }
 4677         else if (auto ve = ecall.isVarExp())
 4678         {
 4679             fd = ve.var.isFuncDeclaration();
 4680             assert(fd);
 4681 
 4682             // If `_d_HookTraceImpl` is found, resolve the underlying hook and replace `e` and `fd` with it.
 4683             removeHookTraceImpl(e, fd);
 4684 
 4685             if (fd.ident == Id.__ArrayPostblit || fd.ident == Id.__ArrayDtor)
 4686             {
 4687                 assert(e.arguments.dim == 1);
 4688                 Expression ea = (*e.arguments)[0];
 4689                 // printf("1 ea = %s %s\n", ea.type.toChars(), ea.toChars());
 4690                 if (auto se = ea.isSliceExp())
 4691                     ea = se.e1;
 4692                 if (auto ce = ea.isCastExp())
 4693                     ea = ce.e1;
 4694 
 4695                 // printf("2 ea = %s, %s %s\n", ea.type.toChars(), Token.toChars(ea.op), ea.toChars());
 4696                 if (ea.op == TOK.variable || ea.op == TOK.symbolOffset)
 4697                     result = getVarExp(e.loc, istate, (cast(SymbolExp)ea).var, CTFEGoal.RValue);
 4698                 else if (auto ae = ea.isAddrExp())
 4699                     result = interpretRegion(ae.e1, istate);
 4700 
 4701                 // https://issues.dlang.org/show_bug.cgi?id=18871
 4702                 // https://issues.dlang.org/show_bug.cgi?id=18819
 4703                 else if (auto ale = ea.isArrayLiteralExp())
 4704                     result = interpretRegion(ale, istate);
 4705 
 4706                 else
 4707                     assert(0);
 4708                 if (CTFEExp.isCantExp(result))
 4709                     return;
 4710 
 4711                 if (fd.ident == Id.__ArrayPostblit)
 4712                     result = evaluatePostblit(istate, result);
 4713                 else
 4714                     result = evaluateDtor(istate, result);
 4715                 if (!result)
 4716                     result = CTFEExp.voidexp;
 4717                 return;
 4718             }
 4719             else if (fd.ident == Id._d_arraysetlengthT)
 4720             {
 4721                 // In expressionsem.d `ea.length = eb;` got lowered to `_d_arraysetlengthT(ea, eb);`.
 4722                 // The following code will rewrite it back to `ea.length = eb` and then interpret that expression.
 4723                 assert(e.arguments.dim == 2);
 4724 
 4725                 Expression ea = (*e.arguments)[0];
 4726                 Expression eb = (*e.arguments)[1];
 4727 
 4728                 auto ale = ctfeEmplaceExp!ArrayLengthExp(e.loc, ea);
 4729                 ale.type = Type.tsize_t;
 4730                 AssignExp ae = ctfeEmplaceExp!AssignExp(e.loc, ale, eb);
 4731                 ae.type = ea.type;
 4732 
 4733                 // if (global.params.verbose)
 4734                 //     message("interpret  %s =>\n          %s", e.toChars(), ae.toChars());
 4735                 result = interpretRegion(ae, istate);
 4736                 return;
 4737             }
 4738         }
 4739         else if (auto soe = ecall.isSymOffExp())
 4740         {
 4741             fd = soe.var.isFuncDeclaration();
 4742             assert(fd && soe.offset == 0);
 4743         }
 4744         else if (auto de = ecall.isDelegateExp())
 4745         {
 4746             // Calling a delegate
 4747             fd = de.func;
 4748             pthis = de.e1;
 4749 
 4750             // Special handling for: &nestedfunc --> DelegateExp(VarExp(nestedfunc), nestedfunc)
 4751             if (auto ve = pthis.isVarExp())
 4752                 if (ve.var == fd)
 4753                     pthis = null; // context is not necessary for CTFE
 4754         }
 4755         else if (auto fe = ecall.isFuncExp())
 4756         {
 4757             // Calling a delegate literal
 4758             fd = fe.fd;
 4759         }
 4760         else
 4761         {
 4762             // delegate.funcptr()
 4763             // others
 4764             e.error("cannot call `%s` at compile time", e.toChars());
 4765             result = CTFEExp.cantexp;
 4766             return;
 4767         }
 4768         if (!fd)
 4769         {
 4770             e.error("CTFE internal error: cannot evaluate `%s` at compile time", e.toChars());
 4771             result = CTFEExp.cantexp;
 4772             return;
 4773         }
 4774         if (pthis)
 4775         {
 4776             // Member function call
 4777 
 4778             // Currently this is satisfied because closure is not yet supported.
 4779             assert(!fd.isNested() || fd.needThis());
 4780 
 4781             if (pthis.op == TOK.typeid_)
 4782             {
 4783                 pthis.error("static variable `%s` cannot be read at compile time", pthis.toChars());
 4784                 result = CTFEExp.cantexp;
 4785                 return;
 4786             }
 4787             assert(pthis);
 4788 
 4789             if (pthis.op == TOK.null_)
 4790             {
 4791                 assert(pthis.type.toBasetype().ty == Tclass);
 4792                 e.error("function call through null class reference `%s`", pthis.toChars());
 4793                 result = CTFEExp.cantexp;
 4794                 return;
 4795             }
 4796 
 4797             assert(pthis.op == TOK.structLiteral || pthis.op == TOK.classReference || pthis.op == TOK.type);
 4798 
 4799             if (fd.isVirtual() && !e.directcall)
 4800             {
 4801                 // Make a virtual function call.
 4802                 // Get the function from the vtable of the original class
 4803                 assert(pthis.op == TOK.classReference);
 4804                 ClassDeclaration cd = (cast(ClassReferenceExp)pthis).originalClass();
 4805 
 4806                 // We can't just use the vtable index to look it up, because
 4807                 // vtables for interfaces don't get populated until the glue layer.
 4808                 fd = cd.findFunc(fd.ident, cast(TypeFunction)fd.type);
 4809                 assert(fd);
 4810             }
 4811         }
 4812 
 4813         if (fd && fd.semanticRun >= PASS.semantic3done && fd.semantic3Errors)
 4814         {
 4815             e.error("CTFE failed because of previous errors in `%s`", fd.toChars());
 4816             result = CTFEExp.cantexp;
 4817             return;
 4818         }
 4819 
 4820         // Check for built-in functions
 4821         result = evaluateIfBuiltin(pue, istate, e.loc, fd, e.arguments, pthis);
 4822         if (result)
 4823             return;
 4824 
 4825         if (!fd.fbody)
 4826         {
 4827             e.error("`%s` cannot be interpreted at compile time, because it has no available source code", fd.toChars());
 4828             result = CTFEExp.showcontext;
 4829             return;
 4830         }
 4831 
 4832         result = interpretFunction(pue, fd, istate, e.arguments, pthis);
 4833         if (result.op == TOK.voidExpression)
 4834             return;
 4835         if (!exceptionOrCantInterpret(result))
 4836         {
 4837             if (goal != CTFEGoal.LValue) // Peel off CTFE reference if it's unnecessary
 4838             {
 4839                 if (result == pue.exp())
 4840                     result = pue.copy();
 4841                 result = interpret(pue, result, istate);
 4842             }
 4843         }
 4844         if (!exceptionOrCantInterpret(result))
 4845         {
 4846             result = paintTypeOntoLiteral(pue, e.type, result);
 4847             result.loc = e.loc;
 4848         }
 4849         else if (CTFEExp.isCantExp(result) && !global.gag)
 4850             showCtfeBackTrace(e, fd); // Print a stack trace.
 4851     }
 4852 
 4853     override void visit(CommaExp e)
 4854     {
 4855         debug (LOG)
 4856         {
 4857             printf("%s CommaExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 4858         }
 4859 
 4860         // If it creates a variable, and there's no context for
 4861         // the variable to be created in, we need to create one now.
 4862         InterState istateComma;
 4863         if (!istate && firstComma(e.e1).op == TOK.declaration)
 4864         {
 4865             ctfeGlobals.stack.startFrame(null);
 4866             istate = &istateComma;
 4867         }
 4868 
 4869         void endTempStackFrame()
 4870         {
 4871             // If we created a temporary stack frame, end it now.
 4872             if (istate == &istateComma)
 4873                 ctfeGlobals.stack.endFrame();
 4874         }
 4875 
 4876         result = CTFEExp.cantexp;
 4877 
 4878         // If the comma returns a temporary variable, it needs to be an lvalue
 4879         // (this is particularly important for struct constructors)
 4880         if (e.e1.op == TOK.declaration &&
 4881             e.e2.op == TOK.variable &&
 4882             (cast(DeclarationExp)e.e1).declaration == (cast(VarExp)e.e2).var &&
 4883             (cast(VarExp)e.e2).var.storage_class & STC.ctfe)
 4884         {
 4885             VarExp ve = cast(VarExp)e.e2;
 4886             VarDeclaration v = ve.var.isVarDeclaration();
 4887             ctfeGlobals.stack.push(v);
 4888             if (!v._init && !getValue(v))
 4889             {
 4890                 setValue(v, copyLiteral(v.type.defaultInitLiteral(e.loc)).copy());
 4891             }
 4892             if (!getValue(v))
 4893             {
 4894                 Expression newval = v._init.initializerToExpression();
 4895                 // Bug 4027. Copy constructors are a weird case where the
 4896                 // initializer is a void function (the variable is modified
 4897                 // through a reference parameter instead).
 4898                 newval = interpretRegion(newval, istate);
 4899                 if (exceptionOrCant(newval))
 4900                     return endTempStackFrame();
 4901                 if (newval.op != TOK.voidExpression)
 4902                 {
 4903                     // v isn't necessarily null.
 4904                     setValueWithoutChecking(v, copyLiteral(newval).copy());
 4905                 }
 4906             }
 4907         }
 4908         else
 4909         {
 4910             UnionExp ue = void;
 4911             auto e1 = interpret(&ue, e.e1, istate, CTFEGoal.Nothing);
 4912             if (exceptionOrCant(e1))
 4913                 return endTempStackFrame();
 4914         }
 4915         result = interpret(pue, e.e2, istate, goal);
 4916         return endTempStackFrame();
 4917     }
 4918 
 4919     override void visit(CondExp e)
 4920     {
 4921         debug (LOG)
 4922         {
 4923             printf("%s CondExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 4924         }
 4925         UnionExp uecond = void;
 4926         Expression econd;
 4927         econd = interpret(&uecond, e.econd, istate);
 4928         if (exceptionOrCant(econd))
 4929             return;
 4930 
 4931         if (isPointer(e.econd.type))
 4932         {
 4933             if (econd.op != TOK.null_)
 4934             {
 4935                 econd = IntegerExp.createBool(true);
 4936             }
 4937         }
 4938 
 4939         if (isTrueBool(econd))
 4940         {
 4941             result = interpret(pue, e.e1, istate, goal);
 4942             incUsageCtfe(istate, e.e1.loc);
 4943         }
 4944         else if (econd.isBool(false))
 4945         {
 4946             result = interpret(pue, e.e2, istate, goal);
 4947             incUsageCtfe(istate, e.e2.loc);
 4948         }
 4949         else
 4950         {
 4951             e.error("`%s` does not evaluate to boolean result at compile time", e.econd.toChars());
 4952             result = CTFEExp.cantexp;
 4953         }
 4954     }
 4955 
 4956     override void visit(ArrayLengthExp e)
 4957     {
 4958         debug (LOG)
 4959         {
 4960             printf("%s ArrayLengthExp::interpret() %s\n", e.loc.toChars(), e.toChars());
 4961         }
 4962         UnionExp ue1;
 4963         Expression e1 = interpret(&ue1, e.e1, istate);
 4964         assert(e1);
 4965         if (exceptionOrCant(e1))
 4966             return;
 4967         if (e1.op != TOK.string_ && e1.op != TOK.arrayLiteral && e1.op != TOK.slice && e1.op != TOK.null_)
 4968         {
 4969             e.error("`%s` cannot be evaluated at compile time", e.toChars());
 4970             result = CTFEExp.cantexp;
 4971             return;
 4972         }
 4973         emplaceExp!(IntegerExp)(pue, e.loc, resolveArrayLength(e1), e.type);
 4974         result = pue.exp();
 4975     }
 4976 
 4977     /**
 4978      * Interpret the vector expression as an array literal.
 4979      * Params:
 4980      *    pue = non-null pointer to temporary storage that can be used to store the return value
 4981      *    e = Expression to interpret
 4982      * Returns:
 4983      *    resulting array literal or 'e' if unable to interpret
 4984      */
 4985     static Expression interpretVectorToArray(UnionExp* pue, VectorExp e)
 4986     {
 4987         if (auto ale = e.e1.isArrayLiteralExp())
 4988             return ale;
 4989         if (e.e1.op == TOK.int64 || e.e1.op == TOK.float64)
 4990         {
 4991             // Convert literal __vector(int) -> __vector([array])
 4992             auto elements = new Expressions(e.dim);
 4993             foreach (ref element; *elements)
 4994                 element = copyLiteral(e.e1).copy();
 4995             auto type = (e.type.ty ==<