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