Home | History | Annotate | Line # | Download | only in dmd
      1  1.1  mrg /**
      2  1.1  mrg  * CTFE for expressions involving pointers, slices, array concatenation etc.
      3  1.1  mrg  *
      4  1.1  mrg  * Copyright:   Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
      5  1.1  mrg  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
      6  1.1  mrg  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
      7  1.1  mrg  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ctfeexpr.d, _ctfeexpr.d)
      8  1.1  mrg  * Documentation:  https://dlang.org/phobos/dmd_ctfeexpr.html
      9  1.1  mrg  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/ctfeexpr.d
     10  1.1  mrg  */
     11  1.1  mrg 
     12  1.1  mrg module dmd.ctfeexpr;
     13  1.1  mrg 
     14  1.1  mrg import core.stdc.stdio;
     15  1.1  mrg import core.stdc.stdlib;
     16  1.1  mrg import core.stdc.string;
     17  1.1  mrg import dmd.arraytypes;
     18  1.1  mrg import dmd.astenums;
     19  1.1  mrg import dmd.constfold;
     20  1.1  mrg import dmd.compiler;
     21  1.1  mrg import dmd.dclass;
     22  1.1  mrg import dmd.declaration;
     23  1.1  mrg import dmd.dinterpret;
     24  1.1  mrg import dmd.dstruct;
     25  1.1  mrg import dmd.dtemplate;
     26  1.1  mrg import dmd.errors;
     27  1.1  mrg import dmd.expression;
     28  1.1  mrg import dmd.func;
     29  1.1  mrg import dmd.globals;
     30  1.1  mrg import dmd.mtype;
     31  1.1  mrg import dmd.root.complex;
     32  1.1  mrg import dmd.root.ctfloat;
     33  1.1  mrg import dmd.root.port;
     34  1.1  mrg import dmd.root.rmem;
     35  1.1  mrg import dmd.tokens;
     36  1.1  mrg import dmd.visitor;
     37  1.1  mrg 
     38  1.1  mrg 
     39  1.1  mrg /***********************************************************
     40  1.1  mrg  * A reference to a class, or an interface. We need this when we
     41  1.1  mrg  * point to a base class (we must record what the type is).
     42  1.1  mrg  */
     43  1.1  mrg extern (C++) final class ClassReferenceExp : Expression
     44  1.1  mrg {
     45  1.1  mrg     StructLiteralExp value;
     46  1.1  mrg 
     47  1.1  mrg     extern (D) this(const ref Loc loc, StructLiteralExp lit, Type type)
     48  1.1  mrg     {
     49  1.1  mrg         super(loc, EXP.classReference, __traits(classInstanceSize, ClassReferenceExp));
     50  1.1  mrg         assert(lit && lit.sd && lit.sd.isClassDeclaration());
     51  1.1  mrg         this.value = lit;
     52  1.1  mrg         this.type = type;
     53  1.1  mrg     }
     54  1.1  mrg 
     55  1.1  mrg     ClassDeclaration originalClass()
     56  1.1  mrg     {
     57  1.1  mrg         return value.sd.isClassDeclaration();
     58  1.1  mrg     }
     59  1.1  mrg 
     60  1.1  mrg     // Return index of the field, or -1 if not found
     61  1.1  mrg     private int getFieldIndex(Type fieldtype, uint fieldoffset)
     62  1.1  mrg     {
     63  1.1  mrg         ClassDeclaration cd = originalClass();
     64  1.1  mrg         uint fieldsSoFar = 0;
     65  1.1  mrg         for (size_t j = 0; j < value.elements.dim; j++)
     66  1.1  mrg         {
     67  1.1  mrg             while (j - fieldsSoFar >= cd.fields.dim)
     68  1.1  mrg             {
     69  1.1  mrg                 fieldsSoFar += cd.fields.dim;
     70  1.1  mrg                 cd = cd.baseClass;
     71  1.1  mrg             }
     72  1.1  mrg             VarDeclaration v2 = cd.fields[j - fieldsSoFar];
     73  1.1  mrg             if (fieldoffset == v2.offset && fieldtype.size() == v2.type.size())
     74  1.1  mrg             {
     75  1.1  mrg                 return cast(int)(value.elements.dim - fieldsSoFar - cd.fields.dim + (j - fieldsSoFar));
     76  1.1  mrg             }
     77  1.1  mrg         }
     78  1.1  mrg         return -1;
     79  1.1  mrg     }
     80  1.1  mrg 
     81  1.1  mrg     // Return index of the field, or -1 if not found
     82  1.1  mrg     // Same as getFieldIndex, but checks for a direct match with the VarDeclaration
     83  1.1  mrg     int findFieldIndexByName(VarDeclaration v)
     84  1.1  mrg     {
     85  1.1  mrg         ClassDeclaration cd = originalClass();
     86  1.1  mrg         size_t fieldsSoFar = 0;
     87  1.1  mrg         for (size_t j = 0; j < value.elements.dim; j++)
     88  1.1  mrg         {
     89  1.1  mrg             while (j - fieldsSoFar >= cd.fields.dim)
     90  1.1  mrg             {
     91  1.1  mrg                 fieldsSoFar += cd.fields.dim;
     92  1.1  mrg                 cd = cd.baseClass;
     93  1.1  mrg             }
     94  1.1  mrg             VarDeclaration v2 = cd.fields[j - fieldsSoFar];
     95  1.1  mrg             if (v == v2)
     96  1.1  mrg             {
     97  1.1  mrg                 return cast(int)(value.elements.dim - fieldsSoFar - cd.fields.dim + (j - fieldsSoFar));
     98  1.1  mrg             }
     99  1.1  mrg         }
    100  1.1  mrg         return -1;
    101  1.1  mrg     }
    102  1.1  mrg 
    103  1.1  mrg     override void accept(Visitor v)
    104  1.1  mrg     {
    105  1.1  mrg         v.visit(this);
    106  1.1  mrg     }
    107  1.1  mrg }
    108  1.1  mrg 
    109  1.1  mrg /*************************
    110  1.1  mrg  * Same as getFieldIndex, but checks for a direct match with the VarDeclaration
    111  1.1  mrg  * Returns:
    112  1.1  mrg  *    index of the field, or -1 if not found
    113  1.1  mrg  */
    114  1.1  mrg int findFieldIndexByName(const StructDeclaration sd, const VarDeclaration v) pure
    115  1.1  mrg {
    116  1.1  mrg     foreach (i, field; sd.fields)
    117  1.1  mrg     {
    118  1.1  mrg         if (field == v)
    119  1.1  mrg             return cast(int)i;
    120  1.1  mrg     }
    121  1.1  mrg     return -1;
    122  1.1  mrg }
    123  1.1  mrg 
    124  1.1  mrg /***********************************************************
    125  1.1  mrg  * Fake class which holds the thrown exception.
    126  1.1  mrg  * Used for implementing exception handling.
    127  1.1  mrg  */
    128  1.1  mrg extern (C++) final class ThrownExceptionExp : Expression
    129  1.1  mrg {
    130  1.1  mrg     ClassReferenceExp thrown;   // the thing being tossed
    131  1.1  mrg 
    132  1.1  mrg     extern (D) this(const ref Loc loc, ClassReferenceExp victim)
    133  1.1  mrg     {
    134  1.1  mrg         super(loc, EXP.thrownException, __traits(classInstanceSize, ThrownExceptionExp));
    135  1.1  mrg         this.thrown = victim;
    136  1.1  mrg         this.type = victim.type;
    137  1.1  mrg     }
    138  1.1  mrg 
    139  1.1  mrg     override const(char)* toChars() const
    140  1.1  mrg     {
    141  1.1  mrg         return "CTFE ThrownException";
    142  1.1  mrg     }
    143  1.1  mrg 
    144  1.1  mrg     // Generate an error message when this exception is not caught
    145  1.1  mrg     extern (D) void generateUncaughtError()
    146  1.1  mrg     {
    147  1.1  mrg         UnionExp ue = void;
    148  1.1  mrg         Expression e = resolveSlice((*thrown.value.elements)[0], &ue);
    149  1.1  mrg         StringExp se = e.toStringExp();
    150  1.1  mrg         thrown.error("uncaught CTFE exception `%s(%s)`", thrown.type.toChars(), se ? se.toChars() : e.toChars());
    151  1.1  mrg         /* Also give the line where the throw statement was. We won't have it
    152  1.1  mrg          * in the case where the ThrowStatement is generated internally
    153  1.1  mrg          * (eg, in ScopeStatement)
    154  1.1  mrg          */
    155  1.1  mrg         if (loc.isValid() && !loc.equals(thrown.loc))
    156  1.1  mrg             .errorSupplemental(loc, "thrown from here");
    157  1.1  mrg     }
    158  1.1  mrg 
    159  1.1  mrg     override void accept(Visitor v)
    160  1.1  mrg     {
    161  1.1  mrg         v.visit(this);
    162  1.1  mrg     }
    163  1.1  mrg }
    164  1.1  mrg 
    165  1.1  mrg /***********************************************************
    166  1.1  mrg  * This type is only used by the interpreter.
    167  1.1  mrg  */
    168  1.1  mrg extern (C++) final class CTFEExp : Expression
    169  1.1  mrg {
    170  1.1  mrg     extern (D) this(EXP tok)
    171  1.1  mrg     {
    172  1.1  mrg         super(Loc.initial, tok, __traits(classInstanceSize, CTFEExp));
    173  1.1  mrg         type = Type.tvoid;
    174  1.1  mrg     }
    175  1.1  mrg 
    176  1.1  mrg     override const(char)* toChars() const
    177  1.1  mrg     {
    178  1.1  mrg         switch (op)
    179  1.1  mrg         {
    180  1.1  mrg         case EXP.cantExpression:
    181  1.1  mrg             return "<cant>";
    182  1.1  mrg         case EXP.voidExpression:
    183  1.1  mrg             return "cast(void)0";
    184  1.1  mrg         case EXP.showCtfeContext:
    185  1.1  mrg             return "<error>";
    186  1.1  mrg         case EXP.break_:
    187  1.1  mrg             return "<break>";
    188  1.1  mrg         case EXP.continue_:
    189  1.1  mrg             return "<continue>";
    190  1.1  mrg         case EXP.goto_:
    191  1.1  mrg             return "<goto>";
    192  1.1  mrg         default:
    193  1.1  mrg             assert(0);
    194  1.1  mrg         }
    195  1.1  mrg     }
    196  1.1  mrg 
    197  1.1  mrg     extern (D) __gshared CTFEExp cantexp;
    198  1.1  mrg     extern (D) __gshared CTFEExp voidexp;
    199  1.1  mrg     extern (D) __gshared CTFEExp breakexp;
    200  1.1  mrg     extern (D) __gshared CTFEExp continueexp;
    201  1.1  mrg     extern (D) __gshared CTFEExp gotoexp;
    202  1.1  mrg     /* Used when additional information is needed regarding
    203  1.1  mrg      * a ctfe error.
    204  1.1  mrg      */
    205  1.1  mrg     extern (D) __gshared CTFEExp showcontext;
    206  1.1  mrg 
    207  1.1  mrg     extern (D) static bool isCantExp(const Expression e)
    208  1.1  mrg     {
    209  1.1  mrg         return e && e.op == EXP.cantExpression;
    210  1.1  mrg     }
    211  1.1  mrg 
    212  1.1  mrg     extern (D) static bool isGotoExp(const Expression e)
    213  1.1  mrg     {
    214  1.1  mrg         return e && e.op == EXP.goto_;
    215  1.1  mrg     }
    216  1.1  mrg }
    217  1.1  mrg 
    218  1.1  mrg // True if 'e' is CTFEExp::cantexp, or an exception
    219  1.1  mrg bool exceptionOrCantInterpret(const Expression e)
    220  1.1  mrg {
    221  1.1  mrg     return e && (e.op == EXP.cantExpression || e.op == EXP.thrownException || e.op == EXP.showCtfeContext);
    222  1.1  mrg }
    223  1.1  mrg 
    224  1.1  mrg /************** Aggregate literals (AA/string/array/struct) ******************/
    225  1.1  mrg // Given expr, which evaluates to an array/AA/string literal,
    226  1.1  mrg // return true if it needs to be copied
    227  1.1  mrg bool needToCopyLiteral(const Expression expr)
    228  1.1  mrg {
    229  1.1  mrg     Expression e = cast()expr;
    230  1.1  mrg     for (;;)
    231  1.1  mrg     {
    232  1.1  mrg         switch (e.op)
    233  1.1  mrg         {
    234  1.1  mrg         case EXP.arrayLiteral:
    235  1.1  mrg             return e.isArrayLiteralExp().ownedByCtfe == OwnedBy.code;
    236  1.1  mrg         case EXP.assocArrayLiteral:
    237  1.1  mrg             return e.isAssocArrayLiteralExp().ownedByCtfe == OwnedBy.code;
    238  1.1  mrg         case EXP.structLiteral:
    239  1.1  mrg             return e.isStructLiteralExp().ownedByCtfe == OwnedBy.code;
    240  1.1  mrg         case EXP.string_:
    241  1.1  mrg         case EXP.this_:
    242  1.1  mrg         case EXP.variable:
    243  1.1  mrg             return false;
    244  1.1  mrg         case EXP.assign:
    245  1.1  mrg             return false;
    246  1.1  mrg         case EXP.index:
    247  1.1  mrg         case EXP.dotVariable:
    248  1.1  mrg         case EXP.slice:
    249  1.1  mrg         case EXP.cast_:
    250  1.1  mrg             e = e.isUnaExp().e1;
    251  1.1  mrg             continue;
    252  1.1  mrg         case EXP.concatenate:
    253  1.1  mrg             return needToCopyLiteral(e.isBinExp().e1) || needToCopyLiteral(e.isBinExp().e2);
    254  1.1  mrg         case EXP.concatenateAssign:
    255  1.1  mrg         case EXP.concatenateElemAssign:
    256  1.1  mrg         case EXP.concatenateDcharAssign:
    257  1.1  mrg             e = e.isBinExp().e2;
    258  1.1  mrg             continue;
    259  1.1  mrg         default:
    260  1.1  mrg             return false;
    261  1.1  mrg         }
    262  1.1  mrg     }
    263  1.1  mrg }
    264  1.1  mrg 
    265  1.1  mrg private Expressions* copyLiteralArray(Expressions* oldelems, Expression basis = null)
    266  1.1  mrg {
    267  1.1  mrg     if (!oldelems)
    268  1.1  mrg         return oldelems;
    269  1.1  mrg     incArrayAllocs();
    270  1.1  mrg     auto newelems = new Expressions(oldelems.dim);
    271  1.1  mrg     foreach (i, el; *oldelems)
    272  1.1  mrg     {
    273  1.1  mrg         (*newelems)[i] = copyLiteral(el ? el : basis).copy();
    274  1.1  mrg     }
    275  1.1  mrg     return newelems;
    276  1.1  mrg }
    277  1.1  mrg 
    278  1.1  mrg // Make a copy of the ArrayLiteral, AALiteral, String, or StructLiteral.
    279  1.1  mrg // This value will be used for in-place modification.
    280  1.1  mrg UnionExp copyLiteral(Expression e)
    281  1.1  mrg {
    282  1.1  mrg     UnionExp ue = void;
    283  1.1  mrg     if (auto se = e.isStringExp()) // syntaxCopy doesn't make a copy for StringExp!
    284  1.1  mrg     {
    285  1.1  mrg         char* s = cast(char*)mem.xcalloc(se.len + 1, se.sz);
    286  1.1  mrg         const slice = se.peekData();
    287  1.1  mrg         memcpy(s, slice.ptr, slice.length);
    288  1.1  mrg         emplaceExp!(StringExp)(&ue, se.loc, s[0 .. se.len * se.sz], se.len, se.sz);
    289  1.1  mrg         StringExp se2 = ue.exp().isStringExp();
    290  1.1  mrg         se2.committed = se.committed;
    291  1.1  mrg         se2.postfix = se.postfix;
    292  1.1  mrg         se2.type = se.type;
    293  1.1  mrg         se2.ownedByCtfe = OwnedBy.ctfe;
    294  1.1  mrg         return ue;
    295  1.1  mrg     }
    296  1.1  mrg     if (auto ale = e.isArrayLiteralExp())
    297  1.1  mrg     {
    298  1.1  mrg         auto elements = copyLiteralArray(ale.elements, ale.basis);
    299  1.1  mrg 
    300  1.1  mrg         emplaceExp!(ArrayLiteralExp)(&ue, e.loc, e.type, elements);
    301  1.1  mrg 
    302  1.1  mrg         ArrayLiteralExp r = ue.exp().isArrayLiteralExp();
    303  1.1  mrg         r.ownedByCtfe = OwnedBy.ctfe;
    304  1.1  mrg         return ue;
    305  1.1  mrg     }
    306  1.1  mrg     if (auto aae = e.isAssocArrayLiteralExp())
    307  1.1  mrg     {
    308  1.1  mrg         emplaceExp!(AssocArrayLiteralExp)(&ue, e.loc, copyLiteralArray(aae.keys), copyLiteralArray(aae.values));
    309  1.1  mrg         AssocArrayLiteralExp r = ue.exp().isAssocArrayLiteralExp();
    310  1.1  mrg         r.type = e.type;
    311  1.1  mrg         r.ownedByCtfe = OwnedBy.ctfe;
    312  1.1  mrg         return ue;
    313  1.1  mrg     }
    314  1.1  mrg     if (auto sle = e.isStructLiteralExp())
    315  1.1  mrg     {
    316  1.1  mrg         /* syntaxCopy doesn't work for struct literals, because of a nasty special
    317  1.1  mrg          * case: block assignment is permitted inside struct literals, eg,
    318  1.1  mrg          * an int[4] array can be initialized with a single int.
    319  1.1  mrg          */
    320  1.1  mrg         auto oldelems = sle.elements;
    321  1.1  mrg         auto newelems = new Expressions(oldelems.dim);
    322  1.1  mrg         foreach (i, ref el; *newelems)
    323  1.1  mrg         {
    324  1.1  mrg             // We need the struct definition to detect block assignment
    325  1.1  mrg             auto v = sle.sd.fields[i];
    326  1.1  mrg             auto m = (*oldelems)[i];
    327  1.1  mrg 
    328  1.1  mrg             // If it is a void assignment, use the default initializer
    329  1.1  mrg             if (!m)
    330  1.1  mrg                 m = voidInitLiteral(v.type, v).copy();
    331  1.1  mrg 
    332  1.1  mrg             if (v.type.ty == Tarray || v.type.ty == Taarray)
    333  1.1  mrg             {
    334  1.1  mrg                 // Don't have to copy array references
    335  1.1  mrg             }
    336  1.1  mrg             else
    337  1.1  mrg             {
    338  1.1  mrg                 // Buzilla 15681: Copy the source element always.
    339  1.1  mrg                 m = copyLiteral(m).copy();
    340  1.1  mrg 
    341  1.1  mrg                 // Block assignment from inside struct literals
    342  1.1  mrg                 if (v.type.ty != m.type.ty && v.type.ty == Tsarray)
    343  1.1  mrg                 {
    344  1.1  mrg                     auto tsa = v.type.isTypeSArray();
    345  1.1  mrg                     auto len = cast(size_t)tsa.dim.toInteger();
    346  1.1  mrg                     m = createBlockDuplicatedArrayLiteral(&ue, e.loc, v.type, m, len);
    347  1.1  mrg                     if (m == ue.exp())
    348  1.1  mrg                         m = ue.copy();
    349  1.1  mrg                 }
    350  1.1  mrg             }
    351  1.1  mrg             el = m;
    352  1.1  mrg         }
    353  1.1  mrg         emplaceExp!(StructLiteralExp)(&ue, e.loc, sle.sd, newelems, sle.stype);
    354  1.1  mrg         auto r = ue.exp().isStructLiteralExp();
    355  1.1  mrg         r.type = e.type;
    356  1.1  mrg         r.ownedByCtfe = OwnedBy.ctfe;
    357  1.1  mrg         r.origin = sle.origin;
    358  1.1  mrg         return ue;
    359  1.1  mrg     }
    360  1.1  mrg     if (e.op == EXP.function_ || e.op == EXP.delegate_ || e.op == EXP.symbolOffset || e.op == EXP.null_ || e.op == EXP.variable || e.op == EXP.dotVariable || e.op == EXP.int64 || e.op == EXP.float64 || e.op == EXP.char_ || e.op == EXP.complex80 || e.op == EXP.void_ || e.op == EXP.vector || e.op == EXP.typeid_)
    361  1.1  mrg     {
    362  1.1  mrg         // Simple value types
    363  1.1  mrg         // Keep e1 for DelegateExp and DotVarExp
    364  1.1  mrg         emplaceExp!(UnionExp)(&ue, e);
    365  1.1  mrg         Expression r = ue.exp();
    366  1.1  mrg         r.type = e.type;
    367  1.1  mrg         return ue;
    368  1.1  mrg     }
    369  1.1  mrg     if (auto se = e.isSliceExp())
    370  1.1  mrg     {
    371  1.1  mrg         if (se.type.toBasetype().ty == Tsarray)
    372  1.1  mrg         {
    373  1.1  mrg             // same with resolveSlice()
    374  1.1  mrg             if (se.e1.op == EXP.null_)
    375  1.1  mrg             {
    376  1.1  mrg                 emplaceExp!(NullExp)(&ue, se.loc, se.type);
    377  1.1  mrg                 return ue;
    378  1.1  mrg             }
    379  1.1  mrg             ue = Slice(se.type, se.e1, se.lwr, se.upr);
    380  1.1  mrg             auto r = ue.exp().isArrayLiteralExp();
    381  1.1  mrg             r.elements = copyLiteralArray(r.elements);
    382  1.1  mrg             r.ownedByCtfe = OwnedBy.ctfe;
    383  1.1  mrg             return ue;
    384  1.1  mrg         }
    385  1.1  mrg         else
    386  1.1  mrg         {
    387  1.1  mrg             // Array slices only do a shallow copy
    388  1.1  mrg             emplaceExp!(SliceExp)(&ue, e.loc, se.e1, se.lwr, se.upr);
    389  1.1  mrg             Expression r = ue.exp();
    390  1.1  mrg             r.type = e.type;
    391  1.1  mrg             return ue;
    392  1.1  mrg         }
    393  1.1  mrg     }
    394  1.1  mrg     if (isPointer(e.type))
    395  1.1  mrg     {
    396  1.1  mrg         // For pointers, we only do a shallow copy.
    397  1.1  mrg         if (auto ae = e.isAddrExp())
    398  1.1  mrg             emplaceExp!(AddrExp)(&ue, e.loc, ae.e1);
    399  1.1  mrg         else if (auto ie = e.isIndexExp())
    400  1.1  mrg             emplaceExp!(IndexExp)(&ue, e.loc, ie.e1, ie.e2);
    401  1.1  mrg         else if (auto dve = e.isDotVarExp())
    402  1.1  mrg         {
    403  1.1  mrg             emplaceExp!(DotVarExp)(&ue, e.loc, dve.e1, dve.var, dve.hasOverloads);
    404  1.1  mrg         }
    405  1.1  mrg         else
    406  1.1  mrg             assert(0);
    407  1.1  mrg 
    408  1.1  mrg         Expression r = ue.exp();
    409  1.1  mrg         r.type = e.type;
    410  1.1  mrg         return ue;
    411  1.1  mrg     }
    412  1.1  mrg     if (auto cre = e.isClassReferenceExp())
    413  1.1  mrg     {
    414  1.1  mrg         emplaceExp!(ClassReferenceExp)(&ue, e.loc, cre.value, e.type);
    415  1.1  mrg         return ue;
    416  1.1  mrg     }
    417  1.1  mrg     if (e.op == EXP.error)
    418  1.1  mrg     {
    419  1.1  mrg         emplaceExp!(UnionExp)(&ue, e);
    420  1.1  mrg         return ue;
    421  1.1  mrg     }
    422  1.1  mrg     e.error("CTFE internal error: literal `%s`", e.toChars());
    423  1.1  mrg     assert(0);
    424  1.1  mrg }
    425  1.1  mrg 
    426  1.1  mrg /* Deal with type painting.
    427  1.1  mrg  * Type painting is a major nuisance: we can't just set
    428  1.1  mrg  * e.type = type, because that would change the original literal.
    429  1.1  mrg  * But, we can't simply copy the literal either, because that would change
    430  1.1  mrg  * the values of any pointers.
    431  1.1  mrg  */
    432  1.1  mrg Expression paintTypeOntoLiteral(Type type, Expression lit)
    433  1.1  mrg {
    434  1.1  mrg     if (lit.type.equals(type))
    435  1.1  mrg         return lit;
    436  1.1  mrg     return paintTypeOntoLiteralCopy(type, lit).copy();
    437  1.1  mrg }
    438  1.1  mrg 
    439  1.1  mrg Expression paintTypeOntoLiteral(UnionExp* pue, Type type, Expression lit)
    440  1.1  mrg {
    441  1.1  mrg     if (lit.type.equals(type))
    442  1.1  mrg         return lit;
    443  1.1  mrg     *pue = paintTypeOntoLiteralCopy(type, lit);
    444  1.1  mrg     return pue.exp();
    445  1.1  mrg }
    446  1.1  mrg 
    447  1.1  mrg private UnionExp paintTypeOntoLiteralCopy(Type type, Expression lit)
    448  1.1  mrg {
    449  1.1  mrg     UnionExp ue;
    450  1.1  mrg     if (lit.type.equals(type))
    451  1.1  mrg     {
    452  1.1  mrg         emplaceExp!(UnionExp)(&ue, lit);
    453  1.1  mrg         return ue;
    454  1.1  mrg     }
    455  1.1  mrg     // If it is a cast to inout, retain the original type of the referenced part.
    456  1.1  mrg     if (type.hasWild())
    457  1.1  mrg     {
    458  1.1  mrg         emplaceExp!(UnionExp)(&ue, lit);
    459  1.1  mrg         ue.exp().type = type;
    460  1.1  mrg         return ue;
    461  1.1  mrg     }
    462  1.1  mrg     if (auto se = lit.isSliceExp())
    463  1.1  mrg     {
    464  1.1  mrg         emplaceExp!(SliceExp)(&ue, lit.loc, se.e1, se.lwr, se.upr);
    465  1.1  mrg     }
    466  1.1  mrg     else if (auto ie = lit.isIndexExp())
    467  1.1  mrg     {
    468  1.1  mrg         emplaceExp!(IndexExp)(&ue, lit.loc, ie.e1, ie.e2);
    469  1.1  mrg     }
    470  1.1  mrg     else if (lit.op == EXP.arrayLiteral)
    471  1.1  mrg     {
    472  1.1  mrg         emplaceExp!(SliceExp)(&ue, lit.loc, lit, ctfeEmplaceExp!IntegerExp(Loc.initial, 0, Type.tsize_t), ArrayLength(Type.tsize_t, lit).copy());
    473  1.1  mrg     }
    474  1.1  mrg     else if (lit.op == EXP.string_)
    475  1.1  mrg     {
    476  1.1  mrg         // For strings, we need to introduce another level of indirection
    477  1.1  mrg         emplaceExp!(SliceExp)(&ue, lit.loc, lit, ctfeEmplaceExp!IntegerExp(Loc.initial, 0, Type.tsize_t), ArrayLength(Type.tsize_t, lit).copy());
    478  1.1  mrg     }
    479  1.1  mrg     else if (auto aae = lit.isAssocArrayLiteralExp())
    480  1.1  mrg     {
    481  1.1  mrg         // TODO: we should be creating a reference to this AAExp, not
    482  1.1  mrg         // just a ref to the keys and values.
    483  1.1  mrg         OwnedBy wasOwned = aae.ownedByCtfe;
    484  1.1  mrg         emplaceExp!(AssocArrayLiteralExp)(&ue, lit.loc, aae.keys, aae.values);
    485  1.1  mrg         aae = ue.exp().isAssocArrayLiteralExp();
    486  1.1  mrg         aae.ownedByCtfe = wasOwned;
    487  1.1  mrg     }
    488  1.1  mrg     else
    489  1.1  mrg     {
    490  1.1  mrg         // Can't type paint from struct to struct*; this needs another
    491  1.1  mrg         // level of indirection
    492  1.1  mrg         if (lit.op == EXP.structLiteral && isPointer(type))
    493  1.1  mrg             lit.error("CTFE internal error: painting `%s`", type.toChars());
    494  1.1  mrg         ue = copyLiteral(lit);
    495  1.1  mrg     }
    496  1.1  mrg     ue.exp().type = type;
    497  1.1  mrg     return ue;
    498  1.1  mrg }
    499  1.1  mrg 
    500  1.1  mrg /*************************************
    501  1.1  mrg  * If e is a SliceExp, constant fold it.
    502  1.1  mrg  * Params:
    503  1.1  mrg  *      e = expression to resolve
    504  1.1  mrg  *      pue = if not null, store resulting expression here
    505  1.1  mrg  * Returns:
    506  1.1  mrg  *      resulting expression
    507  1.1  mrg  */
    508  1.1  mrg Expression resolveSlice(Expression e, UnionExp* pue = null)
    509  1.1  mrg {
    510  1.1  mrg     SliceExp se = e.isSliceExp();
    511  1.1  mrg     if (!se)
    512  1.1  mrg         return e;
    513  1.1  mrg     if (se.e1.op == EXP.null_)
    514  1.1  mrg         return se.e1;
    515  1.1  mrg     if (pue)
    516  1.1  mrg     {
    517  1.1  mrg         *pue = Slice(e.type, se.e1, se.lwr, se.upr);
    518  1.1  mrg         return pue.exp();
    519  1.1  mrg     }
    520  1.1  mrg     else
    521  1.1  mrg         return Slice(e.type, se.e1, se.lwr, se.upr).copy();
    522  1.1  mrg }
    523  1.1  mrg 
    524  1.1  mrg /* Determine the array length, without interpreting it.
    525  1.1  mrg  * e must be an array literal, or a slice
    526  1.1  mrg  * It's very wasteful to resolve the slice when we only
    527  1.1  mrg  * need the length.
    528  1.1  mrg  */
    529  1.1  mrg uinteger_t resolveArrayLength(Expression e)
    530  1.1  mrg {
    531  1.1  mrg     switch (e.op)
    532  1.1  mrg     {
    533  1.1  mrg         case EXP.vector:
    534  1.1  mrg             return e.isVectorExp().dim;
    535  1.1  mrg 
    536  1.1  mrg         case EXP.null_:
    537  1.1  mrg             return 0;
    538  1.1  mrg 
    539  1.1  mrg         case EXP.slice:
    540  1.1  mrg         {
    541  1.1  mrg             auto se = e.isSliceExp();
    542  1.1  mrg             const ilo = se.lwr.toInteger();
    543  1.1  mrg             const iup = se.upr.toInteger();
    544  1.1  mrg             return iup - ilo;
    545  1.1  mrg         }
    546  1.1  mrg 
    547  1.1  mrg         case EXP.string_:
    548  1.1  mrg             return e.isStringExp().len;
    549  1.1  mrg 
    550  1.1  mrg         case EXP.arrayLiteral:
    551  1.1  mrg         {
    552  1.1  mrg             const ale = e.isArrayLiteralExp();
    553  1.1  mrg             return ale.elements ? ale.elements.dim : 0;
    554  1.1  mrg         }
    555  1.1  mrg 
    556  1.1  mrg         case EXP.assocArrayLiteral:
    557  1.1  mrg         {
    558  1.1  mrg             return e.isAssocArrayLiteralExp().keys.dim;
    559  1.1  mrg         }
    560  1.1  mrg 
    561  1.1  mrg         default:
    562  1.1  mrg             assert(0);
    563  1.1  mrg     }
    564  1.1  mrg }
    565  1.1  mrg 
    566  1.1  mrg /******************************
    567  1.1  mrg  * Helper for NewExp
    568  1.1  mrg  * Create an array literal consisting of 'elem' duplicated 'dim' times.
    569  1.1  mrg  * Params:
    570  1.1  mrg  *      pue = where to store result
    571  1.1  mrg  *      loc = source location where the interpretation occurs
    572  1.1  mrg  *      type = target type of the result
    573  1.1  mrg  *      elem = the source of array element, it will be owned by the result
    574  1.1  mrg  *      dim = element number of the result
    575  1.1  mrg  * Returns:
    576  1.1  mrg  *      Constructed ArrayLiteralExp
    577  1.1  mrg  */
    578  1.1  mrg ArrayLiteralExp createBlockDuplicatedArrayLiteral(UnionExp* pue, const ref Loc loc, Type type, Expression elem, size_t dim)
    579  1.1  mrg {
    580  1.1  mrg     if (type.ty == Tsarray && type.nextOf().ty == Tsarray && elem.type.ty != Tsarray)
    581  1.1  mrg     {
    582  1.1  mrg         // If it is a multidimensional array literal, do it recursively
    583  1.1  mrg         auto tsa = type.nextOf().isTypeSArray();
    584  1.1  mrg         const len = cast(size_t)tsa.dim.toInteger();
    585  1.1  mrg         elem = createBlockDuplicatedArrayLiteral(pue, loc, type.nextOf(), elem, len);
    586  1.1  mrg         if (elem == pue.exp())
    587  1.1  mrg             elem = pue.copy();
    588  1.1  mrg     }
    589  1.1  mrg 
    590  1.1  mrg     // Buzilla 15681
    591  1.1  mrg     const tb = elem.type.toBasetype();
    592  1.1  mrg     const mustCopy = tb.ty == Tstruct || tb.ty == Tsarray;
    593  1.1  mrg 
    594  1.1  mrg     auto elements = new Expressions(dim);
    595  1.1  mrg     foreach (i, ref el; *elements)
    596  1.1  mrg     {
    597  1.1  mrg         el = mustCopy && i ? copyLiteral(elem).copy() : elem;
    598  1.1  mrg     }
    599  1.1  mrg     emplaceExp!(ArrayLiteralExp)(pue, loc, type, elements);
    600  1.1  mrg     auto ale = pue.exp().isArrayLiteralExp();
    601  1.1  mrg     ale.ownedByCtfe = OwnedBy.ctfe;
    602  1.1  mrg     return ale;
    603  1.1  mrg }
    604  1.1  mrg 
    605  1.1  mrg /******************************
    606  1.1  mrg  * Helper for NewExp
    607  1.1  mrg  * Create a string literal consisting of 'value' duplicated 'dim' times.
    608  1.1  mrg  */
    609  1.1  mrg StringExp createBlockDuplicatedStringLiteral(UnionExp* pue, const ref Loc loc, Type type, dchar value, size_t dim, ubyte sz)
    610  1.1  mrg {
    611  1.1  mrg     auto s = cast(char*)mem.xcalloc(dim, sz);
    612  1.1  mrg     foreach (elemi; 0 .. dim)
    613  1.1  mrg     {
    614  1.1  mrg         switch (sz)
    615  1.1  mrg         {
    616  1.1  mrg         case 1:
    617  1.1  mrg             s[elemi] = cast(char)value;
    618  1.1  mrg             break;
    619  1.1  mrg         case 2:
    620  1.1  mrg             (cast(wchar*)s)[elemi] = cast(wchar)value;
    621  1.1  mrg             break;
    622  1.1  mrg         case 4:
    623  1.1  mrg             (cast(dchar*)s)[elemi] = value;
    624  1.1  mrg             break;
    625  1.1  mrg         default:
    626  1.1  mrg             assert(0);
    627  1.1  mrg         }
    628  1.1  mrg     }
    629  1.1  mrg     emplaceExp!(StringExp)(pue, loc, s[0 .. dim * sz], dim, sz);
    630  1.1  mrg     auto se = pue.exp().isStringExp();
    631  1.1  mrg     se.type = type;
    632  1.1  mrg     se.committed = true;
    633  1.1  mrg     se.ownedByCtfe = OwnedBy.ctfe;
    634  1.1  mrg     return se;
    635  1.1  mrg }
    636  1.1  mrg 
    637  1.1  mrg // Return true if t is an AA
    638  1.1  mrg bool isAssocArray(Type t)
    639  1.1  mrg {
    640  1.1  mrg     return t.toBasetype().isTypeAArray() !is null;
    641  1.1  mrg }
    642  1.1  mrg 
    643  1.1  mrg // Given a template AA type, extract the corresponding built-in AA type
    644  1.1  mrg TypeAArray toBuiltinAAType(Type t)
    645  1.1  mrg {
    646  1.1  mrg     return t.toBasetype().isTypeAArray();
    647  1.1  mrg }
    648  1.1  mrg 
    649  1.1  mrg /************** TypeInfo operations ************************************/
    650  1.1  mrg // Return true if type is TypeInfo_Class
    651  1.1  mrg bool isTypeInfo_Class(const Type type)
    652  1.1  mrg {
    653  1.1  mrg     auto tc = cast()type.isTypeClass();
    654  1.1  mrg     return tc && (Type.dtypeinfo == tc.sym || Type.dtypeinfo.isBaseOf(tc.sym, null));
    655  1.1  mrg }
    656  1.1  mrg 
    657  1.1  mrg /************** Pointer operations ************************************/
    658  1.1  mrg // Return true if t is a pointer (not a function pointer)
    659  1.1  mrg bool isPointer(Type t)
    660  1.1  mrg {
    661  1.1  mrg     Type tb = t.toBasetype();
    662  1.1  mrg     return tb.ty == Tpointer && tb.nextOf().ty != Tfunction;
    663  1.1  mrg }
    664  1.1  mrg 
    665  1.1  mrg // For CTFE only. Returns true if 'e' is true or a non-null pointer.
    666  1.1  mrg bool isTrueBool(Expression e)
    667  1.1  mrg {
    668  1.1  mrg     return e.toBool().hasValue(true) || ((e.type.ty == Tpointer || e.type.ty == Tclass) && e.op != EXP.null_);
    669  1.1  mrg }
    670  1.1  mrg 
    671  1.1  mrg /* Is it safe to convert from srcPointee* to destPointee* ?
    672  1.1  mrg  * srcPointee is the genuine type (never void).
    673  1.1  mrg  * destPointee may be void.
    674  1.1  mrg  */
    675  1.1  mrg bool isSafePointerCast(Type srcPointee, Type destPointee)
    676  1.1  mrg {
    677  1.1  mrg     // It's safe to cast S** to D** if it's OK to cast S* to D*
    678  1.1  mrg     while (srcPointee.ty == Tpointer && destPointee.ty == Tpointer)
    679  1.1  mrg     {
    680  1.1  mrg         srcPointee = srcPointee.nextOf();
    681  1.1  mrg         destPointee = destPointee.nextOf();
    682  1.1  mrg     }
    683  1.1  mrg     // It's OK if both are the same (modulo const)
    684  1.1  mrg     if (srcPointee.constConv(destPointee))
    685  1.1  mrg         return true;
    686  1.1  mrg 
    687  1.1  mrg     // It's ok to cast from/to shared because CTFE is single threaded anyways
    688  1.1  mrg     if (srcPointee.unSharedOf() == destPointee.unSharedOf())
    689  1.1  mrg         return true;
    690  1.1  mrg 
    691  1.1  mrg     // It's OK if function pointers differ only in safe/pure/nothrow
    692  1.1  mrg     if (srcPointee.ty == Tfunction && destPointee.ty == Tfunction)
    693  1.1  mrg         return srcPointee.covariant(destPointee) == Covariant.yes ||
    694  1.1  mrg             destPointee.covariant(srcPointee) == Covariant.yes;
    695  1.1  mrg     // it's OK to cast to void*
    696  1.1  mrg     if (destPointee.ty == Tvoid)
    697  1.1  mrg         return true;
    698  1.1  mrg     // It's OK to cast from V[K] to void*
    699  1.1  mrg     if (srcPointee.ty == Taarray && destPointee == Type.tvoidptr)
    700  1.1  mrg         return true;
    701  1.1  mrg     // It's OK if they are the same size (static array of) integers, eg:
    702  1.1  mrg     //     int*     --> uint*
    703  1.1  mrg     //     int[5][] --> uint[5][]
    704  1.1  mrg     if (srcPointee.ty == Tsarray && destPointee.ty == Tsarray)
    705  1.1  mrg     {
    706  1.1  mrg         if (srcPointee.size() != destPointee.size())
    707  1.1  mrg             return false;
    708  1.1  mrg         srcPointee = srcPointee.baseElemOf();
    709  1.1  mrg         destPointee = destPointee.baseElemOf();
    710  1.1  mrg     }
    711  1.1  mrg     return srcPointee.isintegral() && destPointee.isintegral() && srcPointee.size() == destPointee.size();
    712  1.1  mrg }
    713  1.1  mrg 
    714  1.1  mrg Expression getAggregateFromPointer(Expression e, dinteger_t* ofs)
    715  1.1  mrg {
    716  1.1  mrg     *ofs = 0;
    717  1.1  mrg     if (auto ae = e.isAddrExp())
    718  1.1  mrg         e = ae.e1;
    719  1.1  mrg     if (auto soe = e.isSymOffExp())
    720  1.1  mrg         *ofs = soe.offset;
    721  1.1  mrg     if (auto dve = e.isDotVarExp())
    722  1.1  mrg     {
    723  1.1  mrg         auto ex = dve.e1;
    724  1.1  mrg         const v = dve.var.isVarDeclaration();
    725  1.1  mrg         assert(v);
    726  1.1  mrg         StructLiteralExp se = (ex.op == EXP.classReference)
    727  1.1  mrg             ? ex.isClassReferenceExp().value
    728  1.1  mrg             : ex.isStructLiteralExp();
    729  1.1  mrg 
    730  1.1  mrg         // We can't use getField, because it makes a copy
    731  1.1  mrg         const i = (ex.op == EXP.classReference)
    732  1.1  mrg             ? ex.isClassReferenceExp().getFieldIndex(e.type, v.offset)
    733  1.1  mrg             : se.getFieldIndex(e.type, v.offset);
    734  1.1  mrg         e = (*se.elements)[i];
    735  1.1  mrg     }
    736  1.1  mrg     if (auto ie = e.isIndexExp())
    737  1.1  mrg     {
    738  1.1  mrg         // Note that each AA element is part of its own memory block
    739  1.1  mrg         if ((ie.e1.type.ty == Tarray || ie.e1.type.ty == Tsarray || ie.e1.op == EXP.string_ || ie.e1.op == EXP.arrayLiteral) && ie.e2.op == EXP.int64)
    740  1.1  mrg         {
    741  1.1  mrg             *ofs = ie.e2.toInteger();
    742  1.1  mrg             return ie.e1;
    743  1.1  mrg         }
    744  1.1  mrg     }
    745  1.1  mrg     if (auto se = e.isSliceExp())
    746  1.1  mrg     {
    747  1.1  mrg         if (se && e.type.toBasetype().ty == Tsarray &&
    748  1.1  mrg            (se.e1.type.ty == Tarray || se.e1.type.ty == Tsarray || se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral) && se.lwr.op == EXP.int64)
    749  1.1  mrg         {
    750  1.1  mrg             *ofs = se.lwr.toInteger();
    751  1.1  mrg             return se.e1;
    752  1.1  mrg         }
    753  1.1  mrg     }
    754  1.1  mrg 
    755  1.1  mrg     // It can be a `null` disguised as a cast, e.g. `cast(void*)0`.
    756  1.1  mrg     if (auto ie = e.isIntegerExp())
    757  1.1  mrg         if (ie.type.ty == Tpointer && ie.getInteger() == 0)
    758  1.1  mrg             return new NullExp(ie.loc, e.type.nextOf());
    759  1.1  mrg     // Those casts are invalid, but let the rest of the code handle it,
    760  1.1  mrg     // as it could be something like `x !is null`, which doesn't need
    761  1.1  mrg     // to dereference the pointer, even if the pointer is `cast(void*)420`.
    762  1.1  mrg 
    763  1.1  mrg     return e;
    764  1.1  mrg }
    765  1.1  mrg 
    766  1.1  mrg /** Return true if agg1 and agg2 are pointers to the same memory block
    767  1.1  mrg  */
    768  1.1  mrg bool pointToSameMemoryBlock(Expression agg1, Expression agg2)
    769  1.1  mrg {
    770  1.1  mrg     if (agg1 == agg2)
    771  1.1  mrg         return true;
    772  1.1  mrg     // For integers cast to pointers, we regard them as non-comparable
    773  1.1  mrg     // unless they are identical. (This may be overly strict).
    774  1.1  mrg     if (agg1.op == EXP.int64 && agg2.op == EXP.int64 && agg1.toInteger() == agg2.toInteger())
    775  1.1  mrg     {
    776  1.1  mrg         return true;
    777  1.1  mrg     }
    778  1.1  mrg     // Note that type painting can occur with VarExp, so we
    779  1.1  mrg     // must compare the variables being pointed to.
    780  1.1  mrg     if (agg1.op == EXP.variable && agg2.op == EXP.variable && agg1.isVarExp().var == agg2.isVarExp().var)
    781  1.1  mrg     {
    782  1.1  mrg         return true;
    783  1.1  mrg     }
    784  1.1  mrg     if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset && agg1.isSymOffExp().var == agg2.isSymOffExp().var)
    785  1.1  mrg     {
    786  1.1  mrg         return true;
    787  1.1  mrg     }
    788  1.1  mrg     return false;
    789  1.1  mrg }
    790  1.1  mrg 
    791  1.1  mrg // return e1 - e2 as an integer, or error if not possible
    792  1.1  mrg Expression pointerDifference(UnionExp* pue, const ref Loc loc, Type type, Expression e1, Expression e2)
    793  1.1  mrg {
    794  1.1  mrg     dinteger_t ofs1, ofs2;
    795  1.1  mrg     Expression agg1 = getAggregateFromPointer(e1, &ofs1);
    796  1.1  mrg     Expression agg2 = getAggregateFromPointer(e2, &ofs2);
    797  1.1  mrg     if (agg1 == agg2)
    798  1.1  mrg     {
    799  1.1  mrg         Type pointee = (cast(TypePointer)agg1.type).next;
    800  1.1  mrg         const sz = pointee.size();
    801  1.1  mrg         emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type);
    802  1.1  mrg     }
    803  1.1  mrg     else if (agg1.op == EXP.string_ && agg2.op == EXP.string_ &&
    804  1.1  mrg              agg1.isStringExp().peekString().ptr == agg2.isStringExp().peekString().ptr)
    805  1.1  mrg     {
    806  1.1  mrg         Type pointee = (cast(TypePointer)agg1.type).next;
    807  1.1  mrg         const sz = pointee.size();
    808  1.1  mrg         emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type);
    809  1.1  mrg     }
    810  1.1  mrg     else if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset &&
    811  1.1  mrg              agg1.isSymOffExp().var == agg2.isSymOffExp().var)
    812  1.1  mrg     {
    813  1.1  mrg         emplaceExp!(IntegerExp)(pue, loc, ofs1 - ofs2, type);
    814  1.1  mrg     }
    815  1.1  mrg     else
    816  1.1  mrg     {
    817  1.1  mrg         error(loc, "`%s - %s` cannot be interpreted at compile time: cannot subtract pointers to two different memory blocks", e1.toChars(), e2.toChars());
    818  1.1  mrg         emplaceExp!(CTFEExp)(pue, EXP.cantExpression);
    819  1.1  mrg     }
    820  1.1  mrg     return pue.exp();
    821  1.1  mrg }
    822  1.1  mrg 
    823  1.1  mrg // Return eptr op e2, where eptr is a pointer, e2 is an integer,
    824  1.1  mrg // and op is EXP.add or EXP.min
    825  1.1  mrg Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type, Expression eptr, Expression e2)
    826  1.1  mrg {
    827  1.1  mrg     if (eptr.type.nextOf().ty == Tvoid)
    828  1.1  mrg     {
    829  1.1  mrg         error(loc, "cannot perform arithmetic on `void*` pointers at compile time");
    830  1.1  mrg     Lcant:
    831  1.1  mrg         emplaceExp!(CTFEExp)(pue, EXP.cantExpression);
    832  1.1  mrg         return pue.exp();
    833  1.1  mrg     }
    834  1.1  mrg     if (eptr.op == EXP.address)
    835  1.1  mrg         eptr = eptr.isAddrExp().e1;
    836  1.1  mrg     dinteger_t ofs1;
    837  1.1  mrg     Expression agg1 = getAggregateFromPointer(eptr, &ofs1);
    838  1.1  mrg     if (agg1.op == EXP.symbolOffset)
    839  1.1  mrg     {
    840  1.1  mrg         if (agg1.isSymOffExp().var.type.ty != Tsarray)
    841  1.1  mrg         {
    842  1.1  mrg             error(loc, "cannot perform pointer arithmetic on arrays of unknown length at compile time");
    843  1.1  mrg             goto Lcant;
    844  1.1  mrg         }
    845  1.1  mrg     }
    846  1.1  mrg     else if (agg1.op != EXP.string_ && agg1.op != EXP.arrayLiteral)
    847  1.1  mrg     {
    848  1.1  mrg         error(loc, "cannot perform pointer arithmetic on non-arrays at compile time");
    849  1.1  mrg         goto Lcant;
    850  1.1  mrg     }
    851  1.1  mrg     dinteger_t ofs2 = e2.toInteger();
    852  1.1  mrg     Type pointee = (cast(TypeNext)agg1.type.toBasetype()).next;
    853  1.1  mrg     dinteger_t sz = pointee.size();
    854  1.1  mrg     sinteger_t indx;
    855  1.1  mrg     dinteger_t len;
    856  1.1  mrg     if (agg1.op == EXP.symbolOffset)
    857  1.1  mrg     {
    858  1.1  mrg         indx = ofs1 / sz;
    859  1.1  mrg         len = (cast(TypeSArray)agg1.isSymOffExp().var.type).dim.toInteger();
    860  1.1  mrg     }
    861  1.1  mrg     else
    862  1.1  mrg     {
    863  1.1  mrg         Expression dollar = ArrayLength(Type.tsize_t, agg1).copy();
    864  1.1  mrg         assert(!CTFEExp.isCantExp(dollar));
    865  1.1  mrg         indx = ofs1;
    866  1.1  mrg         len = dollar.toInteger();
    867  1.1  mrg     }
    868  1.1  mrg     if (op == EXP.add || op == EXP.addAssign || op == EXP.plusPlus)
    869  1.1  mrg         indx += ofs2 / sz;
    870  1.1  mrg     else if (op == EXP.min || op == EXP.minAssign || op == EXP.minusMinus)
    871  1.1  mrg         indx -= ofs2 / sz;
    872  1.1  mrg     else
    873  1.1  mrg     {
    874  1.1  mrg         error(loc, "CTFE internal error: bad pointer operation");
    875  1.1  mrg         goto Lcant;
    876  1.1  mrg     }
    877  1.1  mrg     if (indx < 0 || len < indx)
    878  1.1  mrg     {
    879  1.1  mrg         error(loc, "cannot assign pointer to index %lld inside memory block `[0..%lld]`", indx, len);
    880  1.1  mrg         goto Lcant;
    881  1.1  mrg     }
    882  1.1  mrg     if (agg1.op == EXP.symbolOffset)
    883  1.1  mrg     {
    884  1.1  mrg         emplaceExp!(SymOffExp)(pue, loc, agg1.isSymOffExp().var, indx * sz);
    885  1.1  mrg         SymOffExp se = pue.exp().isSymOffExp();
    886  1.1  mrg         se.type = type;
    887  1.1  mrg         return pue.exp();
    888  1.1  mrg     }
    889  1.1  mrg     if (agg1.op != EXP.arrayLiteral && agg1.op != EXP.string_)
    890  1.1  mrg     {
    891  1.1  mrg         error(loc, "CTFE internal error: pointer arithmetic `%s`", agg1.toChars());
    892  1.1  mrg         goto Lcant;
    893  1.1  mrg     }
    894  1.1  mrg     if (eptr.type.toBasetype().ty == Tsarray)
    895  1.1  mrg     {
    896  1.1  mrg         dinteger_t dim = (cast(TypeSArray)eptr.type.toBasetype()).dim.toInteger();
    897  1.1  mrg         // Create a CTFE pointer &agg1[indx .. indx+dim]
    898  1.1  mrg         auto se = ctfeEmplaceExp!SliceExp(loc, agg1,
    899  1.1  mrg                 ctfeEmplaceExp!IntegerExp(loc, indx, Type.tsize_t),
    900  1.1  mrg                 ctfeEmplaceExp!IntegerExp(loc, indx + dim, Type.tsize_t));
    901  1.1  mrg         se.type = type.toBasetype().nextOf();
    902  1.1  mrg         emplaceExp!(AddrExp)(pue, loc, se);
    903  1.1  mrg         pue.exp().type = type;
    904  1.1  mrg         return pue.exp();
    905  1.1  mrg     }
    906  1.1  mrg     // Create a CTFE pointer &agg1[indx]
    907  1.1  mrg     auto ofs = ctfeEmplaceExp!IntegerExp(loc, indx, Type.tsize_t);
    908  1.1  mrg     Expression ie = ctfeEmplaceExp!IndexExp(loc, agg1, ofs);
    909  1.1  mrg     ie.type = type.toBasetype().nextOf(); // https://issues.dlang.org/show_bug.cgi?id=13992
    910  1.1  mrg     emplaceExp!(AddrExp)(pue, loc, ie);
    911  1.1  mrg     pue.exp().type = type;
    912  1.1  mrg     return pue.exp();
    913  1.1  mrg }
    914  1.1  mrg 
    915  1.1  mrg // Return 1 if true, 0 if false
    916  1.1  mrg // -1 if comparison is illegal because they point to non-comparable memory blocks
    917  1.1  mrg int comparePointers(EXP op, Expression agg1, dinteger_t ofs1, Expression agg2, dinteger_t ofs2)
    918  1.1  mrg {
    919  1.1  mrg     if (pointToSameMemoryBlock(agg1, agg2))
    920  1.1  mrg     {
    921  1.1  mrg         int n;
    922  1.1  mrg         switch (op)
    923  1.1  mrg         {
    924  1.1  mrg         case EXP.lessThan:
    925  1.1  mrg             n = (ofs1 < ofs2);
    926  1.1  mrg             break;
    927  1.1  mrg         case EXP.lessOrEqual:
    928  1.1  mrg             n = (ofs1 <= ofs2);
    929  1.1  mrg             break;
    930  1.1  mrg         case EXP.greaterThan:
    931  1.1  mrg             n = (ofs1 > ofs2);
    932  1.1  mrg             break;
    933  1.1  mrg         case EXP.greaterOrEqual:
    934  1.1  mrg             n = (ofs1 >= ofs2);
    935  1.1  mrg             break;
    936  1.1  mrg         case EXP.identity:
    937  1.1  mrg         case EXP.equal:
    938  1.1  mrg             n = (ofs1 == ofs2);
    939  1.1  mrg             break;
    940  1.1  mrg         case EXP.notIdentity:
    941  1.1  mrg         case EXP.notEqual:
    942  1.1  mrg             n = (ofs1 != ofs2);
    943  1.1  mrg             break;
    944  1.1  mrg         default:
    945  1.1  mrg             assert(0);
    946  1.1  mrg         }
    947  1.1  mrg         return n;
    948  1.1  mrg     }
    949  1.1  mrg     const null1 = (agg1.op == EXP.null_);
    950  1.1  mrg     const null2 = (agg2.op == EXP.null_);
    951  1.1  mrg     int cmp;
    952  1.1  mrg     if (null1 || null2)
    953  1.1  mrg     {
    954  1.1  mrg         switch (op)
    955  1.1  mrg         {
    956  1.1  mrg         case EXP.lessThan:
    957  1.1  mrg             cmp = null1 && !null2;
    958  1.1  mrg             break;
    959  1.1  mrg         case EXP.greaterThan:
    960  1.1  mrg             cmp = !null1 && null2;
    961  1.1  mrg             break;
    962  1.1  mrg         case EXP.lessOrEqual:
    963  1.1  mrg             cmp = null1;
    964  1.1  mrg             break;
    965  1.1  mrg         case EXP.greaterOrEqual:
    966  1.1  mrg             cmp = null2;
    967  1.1  mrg             break;
    968  1.1  mrg         case EXP.identity:
    969  1.1  mrg         case EXP.equal:
    970  1.1  mrg         case EXP.notIdentity: // 'cmp' gets inverted below
    971  1.1  mrg         case EXP.notEqual:
    972  1.1  mrg             cmp = (null1 == null2);
    973  1.1  mrg             break;
    974  1.1  mrg         default:
    975  1.1  mrg             assert(0);
    976  1.1  mrg         }
    977  1.1  mrg     }
    978  1.1  mrg     else
    979  1.1  mrg     {
    980  1.1  mrg         switch (op)
    981  1.1  mrg         {
    982  1.1  mrg         case EXP.identity:
    983  1.1  mrg         case EXP.equal:
    984  1.1  mrg         case EXP.notIdentity: // 'cmp' gets inverted below
    985  1.1  mrg         case EXP.notEqual:
    986  1.1  mrg             cmp = 0;
    987  1.1  mrg             break;
    988  1.1  mrg         default:
    989  1.1  mrg             return -1; // memory blocks are different
    990  1.1  mrg         }
    991  1.1  mrg     }
    992  1.1  mrg     if (op == EXP.notIdentity || op == EXP.notEqual)
    993  1.1  mrg         cmp ^= 1;
    994  1.1  mrg     return cmp;
    995  1.1  mrg }
    996  1.1  mrg 
    997  1.1  mrg // True if conversion from type 'from' to 'to' involves a reinterpret_cast
    998  1.1  mrg // floating point -> integer or integer -> floating point
    999  1.1  mrg bool isFloatIntPaint(Type to, Type from)
   1000  1.1  mrg {
   1001  1.1  mrg     return from.size() == to.size() && (from.isintegral() && to.isfloating() || from.isfloating() && to.isintegral());
   1002  1.1  mrg }
   1003  1.1  mrg 
   1004  1.1  mrg // Reinterpret float/int value 'fromVal' as a float/integer of type 'to'.
   1005  1.1  mrg Expression paintFloatInt(UnionExp* pue, Expression fromVal, Type to)
   1006  1.1  mrg {
   1007  1.1  mrg     if (exceptionOrCantInterpret(fromVal))
   1008  1.1  mrg         return fromVal;
   1009  1.1  mrg     assert(to.size() == 4 || to.size() == 8);
   1010  1.1  mrg     return Compiler.paintAsType(pue, fromVal, to);
   1011  1.1  mrg }
   1012  1.1  mrg 
   1013  1.1  mrg /******** Constant folding, with support for CTFE ***************************/
   1014  1.1  mrg /// Return true if non-pointer expression e can be compared
   1015  1.1  mrg /// with >,is, ==, etc, using ctfeCmp, ctfeEqual, ctfeIdentity
   1016  1.1  mrg bool isCtfeComparable(Expression e)
   1017  1.1  mrg {
   1018  1.1  mrg     if (e.op == EXP.slice)
   1019  1.1  mrg         e = e.isSliceExp().e1;
   1020  1.1  mrg     if (e.isConst() != 1)
   1021  1.1  mrg     {
   1022  1.1  mrg         if (e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP.function_ || e.op == EXP.delegate_ || e.op == EXP.arrayLiteral || e.op == EXP.structLiteral || e.op == EXP.assocArrayLiteral || e.op == EXP.classReference)
   1023  1.1  mrg         {
   1024  1.1  mrg             return true;
   1025  1.1  mrg         }
   1026  1.1  mrg         // https://issues.dlang.org/show_bug.cgi?id=14123
   1027  1.1  mrg         // TypeInfo object is comparable in CTFE
   1028  1.1  mrg         if (e.op == EXP.typeid_)
   1029  1.1  mrg             return true;
   1030  1.1  mrg         return false;
   1031  1.1  mrg     }
   1032  1.1  mrg     return true;
   1033  1.1  mrg }
   1034  1.1  mrg 
   1035  1.1  mrg /// Map EXP comparison ops
   1036  1.1  mrg private bool numCmp(N)(EXP op, N n1, N n2)
   1037  1.1  mrg {
   1038  1.1  mrg     switch (op)
   1039  1.1  mrg     {
   1040  1.1  mrg     case EXP.lessThan:
   1041  1.1  mrg         return n1 < n2;
   1042  1.1  mrg     case EXP.lessOrEqual:
   1043  1.1  mrg         return n1 <= n2;
   1044  1.1  mrg     case EXP.greaterThan:
   1045  1.1  mrg         return n1 > n2;
   1046  1.1  mrg     case EXP.greaterOrEqual:
   1047  1.1  mrg         return n1 >= n2;
   1048  1.1  mrg 
   1049  1.1  mrg     default:
   1050  1.1  mrg         assert(0);
   1051  1.1  mrg     }
   1052  1.1  mrg }
   1053  1.1  mrg 
   1054  1.1  mrg /// Returns cmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1
   1055  1.1  mrg bool specificCmp(EXP op, int rawCmp)
   1056  1.1  mrg {
   1057  1.1  mrg     return numCmp!int(op, rawCmp, 0);
   1058  1.1  mrg }
   1059  1.1  mrg 
   1060  1.1  mrg /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
   1061  1.1  mrg bool intUnsignedCmp(EXP op, dinteger_t n1, dinteger_t n2)
   1062  1.1  mrg {
   1063  1.1  mrg     return numCmp!dinteger_t(op, n1, n2);
   1064  1.1  mrg }
   1065  1.1  mrg 
   1066  1.1  mrg /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
   1067  1.1  mrg bool intSignedCmp(EXP op, sinteger_t n1, sinteger_t n2)
   1068  1.1  mrg {
   1069  1.1  mrg     return numCmp!sinteger_t(op, n1, n2);
   1070  1.1  mrg }
   1071  1.1  mrg 
   1072  1.1  mrg /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
   1073  1.1  mrg bool realCmp(EXP op, real_t r1, real_t r2)
   1074  1.1  mrg {
   1075  1.1  mrg     // Don't rely on compiler, handle NAN arguments separately
   1076  1.1  mrg     if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
   1077  1.1  mrg     {
   1078  1.1  mrg         switch (op)
   1079  1.1  mrg         {
   1080  1.1  mrg         case EXP.lessThan:
   1081  1.1  mrg         case EXP.lessOrEqual:
   1082  1.1  mrg         case EXP.greaterThan:
   1083  1.1  mrg         case EXP.greaterOrEqual:
   1084  1.1  mrg             return false;
   1085  1.1  mrg 
   1086  1.1  mrg         default:
   1087  1.1  mrg             assert(0);
   1088  1.1  mrg         }
   1089  1.1  mrg     }
   1090  1.1  mrg     else
   1091  1.1  mrg     {
   1092  1.1  mrg         return numCmp!real_t(op, r1, r2);
   1093  1.1  mrg     }
   1094  1.1  mrg }
   1095  1.1  mrg 
   1096  1.1  mrg /* Conceptually the same as memcmp(e1, e2).
   1097  1.1  mrg  * e1 and e2 may be strings, arrayliterals, or slices.
   1098  1.1  mrg  * For string types, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2.
   1099  1.1  mrg  * For all other types, return 0 if e1 == e2, !=0 if e1 != e2.
   1100  1.1  mrg  * Returns:
   1101  1.1  mrg  *      -1,0,1
   1102  1.1  mrg  */
   1103  1.1  mrg private int ctfeCmpArrays(const ref Loc loc, Expression e1, Expression e2, uinteger_t len)
   1104  1.1  mrg {
   1105  1.1  mrg     // Resolve slices, if necessary
   1106  1.1  mrg     uinteger_t lo1 = 0;
   1107  1.1  mrg     uinteger_t lo2 = 0;
   1108  1.1  mrg 
   1109  1.1  mrg     Expression x1 = e1;
   1110  1.1  mrg     if (auto sle1 = x1.isSliceExp())
   1111  1.1  mrg     {
   1112  1.1  mrg         lo1 = sle1.lwr.toInteger();
   1113  1.1  mrg         x1 = sle1.e1;
   1114  1.1  mrg     }
   1115  1.1  mrg     auto se1 = x1.isStringExp();
   1116  1.1  mrg     auto ae1 = x1.isArrayLiteralExp();
   1117  1.1  mrg 
   1118  1.1  mrg     Expression x2 = e2;
   1119  1.1  mrg     if (auto sle2 = x2.isSliceExp())
   1120  1.1  mrg     {
   1121  1.1  mrg         lo2 = sle2.lwr.toInteger();
   1122  1.1  mrg         x2 = sle2.e1;
   1123  1.1  mrg     }
   1124  1.1  mrg     auto se2 = x2.isStringExp();
   1125  1.1  mrg     auto ae2 = x2.isArrayLiteralExp();
   1126  1.1  mrg 
   1127  1.1  mrg     // Now both must be either EXP.arrayLiteral or EXP.string_
   1128  1.1  mrg     if (se1 && se2)
   1129  1.1  mrg         return sliceCmpStringWithString(se1, se2, cast(size_t)lo1, cast(size_t)lo2, cast(size_t)len);
   1130  1.1  mrg     if (se1 && ae2)
   1131  1.1  mrg         return sliceCmpStringWithArray(se1, ae2, cast(size_t)lo1, cast(size_t)lo2, cast(size_t)len);
   1132  1.1  mrg     if (se2 && ae1)
   1133  1.1  mrg         return -sliceCmpStringWithArray(se2, ae1, cast(size_t)lo2, cast(size_t)lo1, cast(size_t)len);
   1134  1.1  mrg     assert(ae1 && ae2);
   1135  1.1  mrg     // Comparing two array literals. This case is potentially recursive.
   1136  1.1  mrg     // If they aren't strings, we just need an equality check rather than
   1137  1.1  mrg     // a full cmp.
   1138  1.1  mrg     const bool needCmp = ae1.type.nextOf().isintegral();
   1139  1.1  mrg     foreach (size_t i; 0 .. cast(size_t)len)
   1140  1.1  mrg     {
   1141  1.1  mrg         Expression ee1 = (*ae1.elements)[cast(size_t)(lo1 + i)];
   1142  1.1  mrg         Expression ee2 = (*ae2.elements)[cast(size_t)(lo2 + i)];
   1143  1.1  mrg         if (needCmp)
   1144  1.1  mrg         {
   1145  1.1  mrg             const sinteger_t c = ee1.toInteger() - ee2.toInteger();
   1146  1.1  mrg             if (c > 0)
   1147  1.1  mrg                 return 1;
   1148  1.1  mrg             if (c < 0)
   1149  1.1  mrg                 return -1;
   1150  1.1  mrg         }
   1151  1.1  mrg         else
   1152  1.1  mrg         {
   1153  1.1  mrg             if (ctfeRawCmp(loc, ee1, ee2))
   1154  1.1  mrg                 return 1;
   1155  1.1  mrg         }
   1156  1.1  mrg     }
   1157  1.1  mrg     return 0;
   1158  1.1  mrg }
   1159  1.1  mrg 
   1160  1.1  mrg /* Given a delegate expression e, return .funcptr.
   1161  1.1  mrg  * If e is NullExp, return NULL.
   1162  1.1  mrg  */
   1163  1.1  mrg private FuncDeclaration funcptrOf(Expression e)
   1164  1.1  mrg {
   1165  1.1  mrg     assert(e.type.ty == Tdelegate);
   1166  1.1  mrg     if (auto de = e.isDelegateExp())
   1167  1.1  mrg         return de.func;
   1168  1.1  mrg     if (auto fe = e.isFuncExp())
   1169  1.1  mrg         return fe.fd;
   1170  1.1  mrg     assert(e.op == EXP.null_);
   1171  1.1  mrg     return null;
   1172  1.1  mrg }
   1173  1.1  mrg 
   1174  1.1  mrg private bool isArray(const Expression e)
   1175  1.1  mrg {
   1176  1.1  mrg     return e.op == EXP.arrayLiteral || e.op == EXP.string_ || e.op == EXP.slice || e.op == EXP.null_;
   1177  1.1  mrg }
   1178  1.1  mrg 
   1179  1.1  mrg /*****
   1180  1.1  mrg  * Params:
   1181  1.1  mrg  *      loc = source file location
   1182  1.1  mrg  *      e1 = left operand
   1183  1.1  mrg  *      e2 = right operand
   1184  1.1  mrg  *      identity = true for `is` identity comparisons
   1185  1.1  mrg  * Returns:
   1186  1.1  mrg  * For strings, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2.
   1187  1.1  mrg  * For all other types, return 0 if e1 == e2, !=0 if e1 != e2.
   1188  1.1  mrg  */
   1189  1.1  mrg private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool identity = false)
   1190  1.1  mrg {
   1191  1.1  mrg     if (e1.op == EXP.classReference || e2.op == EXP.classReference)
   1192  1.1  mrg     {
   1193  1.1  mrg         if (e1.op == EXP.classReference && e2.op == EXP.classReference &&
   1194  1.1  mrg             e1.isClassReferenceExp().value == e2.isClassReferenceExp().value)
   1195  1.1  mrg             return 0;
   1196  1.1  mrg         return 1;
   1197  1.1  mrg     }
   1198  1.1  mrg     if (e1.op == EXP.typeid_ && e2.op == EXP.typeid_)
   1199  1.1  mrg     {
   1200  1.1  mrg         // printf("e1: %s\n", e1.toChars());
   1201  1.1  mrg         // printf("e2: %s\n", e2.toChars());
   1202  1.1  mrg         Type t1 = isType(e1.isTypeidExp().obj);
   1203  1.1  mrg         Type t2 = isType(e2.isTypeidExp().obj);
   1204  1.1  mrg         assert(t1);
   1205  1.1  mrg         assert(t2);
   1206  1.1  mrg         return t1 != t2;
   1207  1.1  mrg     }
   1208  1.1  mrg     // null == null, regardless of type
   1209  1.1  mrg     if (e1.op == EXP.null_ && e2.op == EXP.null_)
   1210  1.1  mrg         return 0;
   1211  1.1  mrg     if (e1.type.ty == Tpointer && e2.type.ty == Tpointer)
   1212  1.1  mrg     {
   1213  1.1  mrg         // Can only be an equality test.
   1214  1.1  mrg         dinteger_t ofs1, ofs2;
   1215  1.1  mrg         Expression agg1 = getAggregateFromPointer(e1, &ofs1);
   1216  1.1  mrg         Expression agg2 = getAggregateFromPointer(e2, &ofs2);
   1217  1.1  mrg         if ((agg1 == agg2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && agg1.isVarExp().var == agg2.isVarExp().var))
   1218  1.1  mrg         {
   1219  1.1  mrg             if (ofs1 == ofs2)
   1220  1.1  mrg                 return 0;
   1221  1.1  mrg         }
   1222  1.1  mrg         return 1;
   1223  1.1  mrg     }
   1224  1.1  mrg     if (e1.type.ty == Tdelegate && e2.type.ty == Tdelegate)
   1225  1.1  mrg     {
   1226  1.1  mrg         // If .funcptr isn't the same, they are not equal
   1227  1.1  mrg         if (funcptrOf(e1) != funcptrOf(e2))
   1228  1.1  mrg             return 1;
   1229  1.1  mrg         // If both are delegate literals, assume they have the
   1230  1.1  mrg         // same closure pointer. TODO: We don't support closures yet!
   1231  1.1  mrg         if (e1.op == EXP.function_ && e2.op == EXP.function_)
   1232  1.1  mrg             return 0;
   1233  1.1  mrg         assert(e1.op == EXP.delegate_ && e2.op == EXP.delegate_);
   1234  1.1  mrg         // Same .funcptr. Do they have the same .ptr?
   1235  1.1  mrg         Expression ptr1 = e1.isDelegateExp().e1;
   1236  1.1  mrg         Expression ptr2 = e2.isDelegateExp().e1;
   1237  1.1  mrg         dinteger_t ofs1, ofs2;
   1238  1.1  mrg         Expression agg1 = getAggregateFromPointer(ptr1, &ofs1);
   1239  1.1  mrg         Expression agg2 = getAggregateFromPointer(ptr2, &ofs2);
   1240  1.1  mrg         // If they are EXP.variable, it means they are FuncDeclarations
   1241  1.1  mrg         if ((agg1 == agg2 && ofs1 == ofs2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && agg1.isVarExp().var == agg2.isVarExp().var))
   1242  1.1  mrg         {
   1243  1.1  mrg             return 0;
   1244  1.1  mrg         }
   1245  1.1  mrg         return 1;
   1246  1.1  mrg     }
   1247  1.1  mrg     if (isArray(e1) && isArray(e2))
   1248  1.1  mrg     {
   1249  1.1  mrg         const uinteger_t len1 = resolveArrayLength(e1);
   1250  1.1  mrg         const uinteger_t len2 = resolveArrayLength(e2);
   1251  1.1  mrg         // workaround for dmc optimizer bug calculating wrong len for
   1252  1.1  mrg         // uinteger_t len = (len1 < len2 ? len1 : len2);
   1253  1.1  mrg         // if (len == 0) ...
   1254  1.1  mrg         if (len1 > 0 && len2 > 0)
   1255  1.1  mrg         {
   1256  1.1  mrg             const uinteger_t len = (len1 < len2 ? len1 : len2);
   1257  1.1  mrg             const int res = ctfeCmpArrays(loc, e1, e2, len);
   1258  1.1  mrg             if (res != 0)
   1259  1.1  mrg                 return res;
   1260  1.1  mrg         }
   1261  1.1  mrg         return cast(int)(len1 - len2);
   1262  1.1  mrg     }
   1263  1.1  mrg     if (e1.type.isintegral())
   1264  1.1  mrg     {
   1265  1.1  mrg         return e1.toInteger() != e2.toInteger();
   1266  1.1  mrg     }
   1267  1.1  mrg     if (e1.type.isreal() || e1.type.isimaginary())
   1268  1.1  mrg     {
   1269  1.1  mrg         real_t r1 = e1.type.isreal() ? e1.toReal() : e1.toImaginary();
   1270  1.1  mrg         real_t r2 = e1.type.isreal() ? e2.toReal() : e2.toImaginary();
   1271  1.1  mrg         if (identity)
   1272  1.1  mrg             return !CTFloat.isIdentical(r1, r2);
   1273  1.1  mrg         if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
   1274  1.1  mrg         {
   1275  1.1  mrg             return 1;   // they are not equal
   1276  1.1  mrg         }
   1277  1.1  mrg         else
   1278  1.1  mrg         {
   1279  1.1  mrg             return (r1 != r2);
   1280  1.1  mrg         }
   1281  1.1  mrg     }
   1282  1.1  mrg     else if (e1.type.iscomplex())
   1283  1.1  mrg     {
   1284  1.1  mrg         auto c1 = e1.toComplex();
   1285  1.1  mrg         auto c2 = e2.toComplex();
   1286  1.1  mrg         if (identity)
   1287  1.1  mrg         {
   1288  1.1  mrg             return !RealIdentical(c1.re, c2.re) && !RealIdentical(c1.im, c2.im);
   1289  1.1  mrg         }
   1290  1.1  mrg         return c1 != c2;
   1291  1.1  mrg     }
   1292  1.1  mrg     if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral)
   1293  1.1  mrg     {
   1294  1.1  mrg         StructLiteralExp es1 = e1.isStructLiteralExp();
   1295  1.1  mrg         StructLiteralExp es2 = e2.isStructLiteralExp();
   1296  1.1  mrg         // For structs, we only need to return 0 or 1 (< and > aren't legal).
   1297  1.1  mrg         if (es1.sd != es2.sd)
   1298  1.1  mrg             return 1;
   1299  1.1  mrg         else if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim))
   1300  1.1  mrg             return 0; // both arrays are empty
   1301  1.1  mrg         else if (!es1.elements || !es2.elements)
   1302  1.1  mrg             return 1;
   1303  1.1  mrg         else if (es1.elements.dim != es2.elements.dim)
   1304  1.1  mrg             return 1;
   1305  1.1  mrg         else
   1306  1.1  mrg         {
   1307  1.1  mrg             foreach (size_t i; 0 .. es1.elements.dim)
   1308  1.1  mrg             {
   1309  1.1  mrg                 Expression ee1 = (*es1.elements)[i];
   1310  1.1  mrg                 Expression ee2 = (*es2.elements)[i];
   1311  1.1  mrg 
   1312  1.1  mrg                 // https://issues.dlang.org/show_bug.cgi?id=16284
   1313  1.1  mrg                 if (ee1.op == EXP.void_ && ee2.op == EXP.void_) // if both are VoidInitExp
   1314  1.1  mrg                     continue;
   1315  1.1  mrg 
   1316  1.1  mrg                 if (ee1 == ee2)
   1317  1.1  mrg                     continue;
   1318  1.1  mrg                 if (!ee1 || !ee2)
   1319  1.1  mrg                     return 1;
   1320  1.1  mrg                 const int cmp = ctfeRawCmp(loc, ee1, ee2, identity);
   1321  1.1  mrg                 if (cmp)
   1322  1.1  mrg                     return 1;
   1323  1.1  mrg             }
   1324  1.1  mrg             return 0; // All elements are equal
   1325  1.1  mrg         }
   1326  1.1  mrg     }
   1327  1.1  mrg     if (e1.op == EXP.assocArrayLiteral && e2.op == EXP.assocArrayLiteral)
   1328  1.1  mrg     {
   1329  1.1  mrg         AssocArrayLiteralExp es1 = e1.isAssocArrayLiteralExp();
   1330  1.1  mrg         AssocArrayLiteralExp es2 = e2.isAssocArrayLiteralExp();
   1331  1.1  mrg         size_t dim = es1.keys.dim;
   1332  1.1  mrg         if (es2.keys.dim != dim)
   1333  1.1  mrg             return 1;
   1334  1.1  mrg         bool* used = cast(bool*)mem.xmalloc(bool.sizeof * dim);
   1335  1.1  mrg         memset(used, 0, bool.sizeof * dim);
   1336  1.1  mrg         foreach (size_t i; 0 .. dim)
   1337  1.1  mrg         {
   1338  1.1  mrg             Expression k1 = (*es1.keys)[i];
   1339  1.1  mrg             Expression v1 = (*es1.values)[i];
   1340  1.1  mrg             Expression v2 = null;
   1341  1.1  mrg             foreach (size_t j; 0 .. dim)
   1342  1.1  mrg             {
   1343  1.1  mrg                 if (used[j])
   1344  1.1  mrg                     continue;
   1345  1.1  mrg                 Expression k2 = (*es2.keys)[j];
   1346  1.1  mrg                 if (ctfeRawCmp(loc, k1, k2, identity))
   1347  1.1  mrg                     continue;
   1348  1.1  mrg                 used[j] = true;
   1349  1.1  mrg                 v2 = (*es2.values)[j];
   1350  1.1  mrg                 break;
   1351  1.1  mrg             }
   1352  1.1  mrg             if (!v2 || ctfeRawCmp(loc, v1, v2, identity))
   1353  1.1  mrg             {
   1354  1.1  mrg                 mem.xfree(used);
   1355  1.1  mrg                 return 1;
   1356  1.1  mrg             }
   1357  1.1  mrg         }
   1358  1.1  mrg         mem.xfree(used);
   1359  1.1  mrg         return 0;
   1360  1.1  mrg     }
   1361  1.1  mrg     else if (e1.op == EXP.assocArrayLiteral && e2.op == EXP.null_)
   1362  1.1  mrg     {
   1363  1.1  mrg         return e1.isAssocArrayLiteralExp.keys.dim != 0;
   1364  1.1  mrg     }
   1365  1.1  mrg     else if (e1.op == EXP.null_ && e2.op == EXP.assocArrayLiteral)
   1366  1.1  mrg     {
   1367  1.1  mrg         return e2.isAssocArrayLiteralExp.keys.dim != 0;
   1368  1.1  mrg     }
   1369  1.1  mrg 
   1370  1.1  mrg     error(loc, "CTFE internal error: bad compare of `%s` and `%s`", e1.toChars(), e2.toChars());
   1371  1.1  mrg     assert(0);
   1372  1.1  mrg }
   1373  1.1  mrg 
   1374  1.1  mrg /// Evaluate ==, !=.  Resolves slices before comparing. Returns 0 or 1
   1375  1.1  mrg bool ctfeEqual(const ref Loc loc, EXP op, Expression e1, Expression e2)
   1376  1.1  mrg {
   1377  1.1  mrg     return !ctfeRawCmp(loc, e1, e2) ^ (op == EXP.notEqual);
   1378  1.1  mrg }
   1379  1.1  mrg 
   1380  1.1  mrg /// Evaluate is, !is.  Resolves slices before comparing. Returns 0 or 1
   1381  1.1  mrg bool ctfeIdentity(const ref Loc loc, EXP op, Expression e1, Expression e2)
   1382  1.1  mrg {
   1383  1.1  mrg     //printf("ctfeIdentity %s %s\n", e1.toChars(), e2.toChars());
   1384  1.1  mrg     //printf("ctfeIdentity op = '%s', e1 = %s %s, e2 = %s %s\n", EXPtoString(op).ptr,
   1385  1.1  mrg     //    EXPtoString(e1.op).ptr, e1.toChars(), EXPtoString(e2.op).ptr, e1.toChars());
   1386  1.1  mrg     bool cmp;
   1387  1.1  mrg     if (e1.op == EXP.null_)
   1388  1.1  mrg     {
   1389  1.1  mrg         cmp = (e2.op == EXP.null_);
   1390  1.1  mrg     }
   1391  1.1  mrg     else if (e2.op == EXP.null_)
   1392  1.1  mrg     {
   1393  1.1  mrg         cmp = false;
   1394  1.1  mrg     }
   1395  1.1  mrg     else if (e1.op == EXP.symbolOffset && e2.op == EXP.symbolOffset)
   1396  1.1  mrg     {
   1397  1.1  mrg         SymOffExp es1 = e1.isSymOffExp();
   1398  1.1  mrg         SymOffExp es2 = e2.isSymOffExp();
   1399  1.1  mrg         cmp = (es1.var == es2.var && es1.offset == es2.offset);
   1400  1.1  mrg     }
   1401  1.1  mrg     else if (e1.type.isreal())
   1402  1.1  mrg         cmp = CTFloat.isIdentical(e1.toReal(), e2.toReal());
   1403  1.1  mrg     else if (e1.type.isimaginary())
   1404  1.1  mrg         cmp = RealIdentical(e1.toImaginary(), e2.toImaginary());
   1405  1.1  mrg     else if (e1.type.iscomplex())
   1406  1.1  mrg     {
   1407  1.1  mrg         complex_t v1 = e1.toComplex();
   1408  1.1  mrg         complex_t v2 = e2.toComplex();
   1409  1.1  mrg         cmp = RealIdentical(creall(v1), creall(v2)) && RealIdentical(cimagl(v1), cimagl(v1));
   1410  1.1  mrg     }
   1411  1.1  mrg     else
   1412  1.1  mrg     {
   1413  1.1  mrg         cmp = !ctfeRawCmp(loc, e1, e2, true);
   1414  1.1  mrg     }
   1415  1.1  mrg     if (op == EXP.notIdentity || op == EXP.notEqual)
   1416  1.1  mrg         cmp ^= true;
   1417  1.1  mrg     return cmp;
   1418  1.1  mrg }
   1419  1.1  mrg 
   1420  1.1  mrg /// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1
   1421  1.1  mrg bool ctfeCmp(const ref Loc loc, EXP op, Expression e1, Expression e2)
   1422  1.1  mrg {
   1423  1.1  mrg     Type t1 = e1.type.toBasetype();
   1424  1.1  mrg     Type t2 = e2.type.toBasetype();
   1425  1.1  mrg 
   1426  1.1  mrg     if (t1.isString() && t2.isString())
   1427  1.1  mrg         return specificCmp(op, ctfeRawCmp(loc, e1, e2));
   1428  1.1  mrg     else if (t1.isreal())
   1429  1.1  mrg         return realCmp(op, e1.toReal(), e2.toReal());
   1430  1.1  mrg     else if (t1.isimaginary())
   1431  1.1  mrg         return realCmp(op, e1.toImaginary(), e2.toImaginary());
   1432  1.1  mrg     else if (t1.isunsigned() || t2.isunsigned())
   1433  1.1  mrg         return intUnsignedCmp(op, e1.toInteger(), e2.toInteger());
   1434  1.1  mrg     else
   1435  1.1  mrg         return intSignedCmp(op, e1.toInteger(), e2.toInteger());
   1436  1.1  mrg }
   1437  1.1  mrg 
   1438  1.1  mrg UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
   1439  1.1  mrg {
   1440  1.1  mrg     Type t1 = e1.type.toBasetype();
   1441  1.1  mrg     Type t2 = e2.type.toBasetype();
   1442  1.1  mrg     UnionExp ue;
   1443  1.1  mrg     if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral())
   1444  1.1  mrg     {
   1445  1.1  mrg         // [chars] ~ string => string (only valid for CTFE)
   1446  1.1  mrg         StringExp es1 = e2.isStringExp();
   1447  1.1  mrg         ArrayLiteralExp es2 = e1.isArrayLiteralExp();
   1448  1.1  mrg         const len = es1.len + es2.elements.dim;
   1449  1.1  mrg         const sz = es1.sz;
   1450  1.1  mrg         void* s = mem.xmalloc((len + 1) * sz);
   1451  1.1  mrg         const data1 = es1.peekData();
   1452  1.1  mrg         memcpy(cast(char*)s + sz * es2.elements.dim, data1.ptr, data1.length);
   1453  1.1  mrg         foreach (size_t i; 0 .. es2.elements.dim)
   1454  1.1  mrg         {
   1455  1.1  mrg             Expression es2e = (*es2.elements)[i];
   1456  1.1  mrg             if (es2e.op != EXP.int64)
   1457  1.1  mrg             {
   1458  1.1  mrg                 emplaceExp!(CTFEExp)(&ue, EXP.cantExpression);
   1459  1.1  mrg                 return ue;
   1460  1.1  mrg             }
   1461  1.1  mrg             dinteger_t v = es2e.toInteger();
   1462  1.1  mrg             Port.valcpy(cast(char*)s + i * sz, v, sz);
   1463  1.1  mrg         }
   1464  1.1  mrg         // Add terminating 0
   1465  1.1  mrg         memset(cast(char*)s + len * sz, 0, sz);
   1466  1.1  mrg         emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
   1467  1.1  mrg         StringExp es = ue.exp().isStringExp();
   1468  1.1  mrg         es.committed = 0;
   1469  1.1  mrg         es.type = type;
   1470  1.1  mrg         return ue;
   1471  1.1  mrg     }
   1472  1.1  mrg     if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral && t2.nextOf().isintegral())
   1473  1.1  mrg     {
   1474  1.1  mrg         // string ~ [chars] => string (only valid for CTFE)
   1475  1.1  mrg         // Concatenate the strings
   1476  1.1  mrg         StringExp es1 = e1.isStringExp();
   1477  1.1  mrg         ArrayLiteralExp es2 = e2.isArrayLiteralExp();
   1478  1.1  mrg         const len = es1.len + es2.elements.dim;
   1479  1.1  mrg         const sz = es1.sz;
   1480  1.1  mrg         void* s = mem.xmalloc((len + 1) * sz);
   1481  1.1  mrg         auto slice = es1.peekData();
   1482  1.1  mrg         memcpy(s, slice.ptr, slice.length);
   1483  1.1  mrg         foreach (size_t i; 0 .. es2.elements.dim)
   1484  1.1  mrg         {
   1485  1.1  mrg             Expression es2e = (*es2.elements)[i];
   1486  1.1  mrg             if (es2e.op != EXP.int64)
   1487  1.1  mrg             {
   1488  1.1  mrg                 emplaceExp!(CTFEExp)(&ue, EXP.cantExpression);
   1489  1.1  mrg                 return ue;
   1490  1.1  mrg             }
   1491  1.1  mrg             const v = es2e.toInteger();
   1492  1.1  mrg             Port.valcpy(cast(char*)s + (es1.len + i) * sz, v, sz);
   1493  1.1  mrg         }
   1494  1.1  mrg         // Add terminating 0
   1495  1.1  mrg         memset(cast(char*)s + len * sz, 0, sz);
   1496  1.1  mrg         emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
   1497  1.1  mrg         StringExp es = ue.exp().isStringExp();
   1498  1.1  mrg         es.sz = sz;
   1499  1.1  mrg         es.committed = 0; //es1.committed;
   1500  1.1  mrg         es.type = type;
   1501  1.1  mrg         return ue;
   1502  1.1  mrg     }
   1503  1.1  mrg     if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
   1504  1.1  mrg     {
   1505  1.1  mrg         //  [ e1 ] ~ [ e2 ] ---> [ e1, e2 ]
   1506  1.1  mrg         ArrayLiteralExp es1 = e1.isArrayLiteralExp();
   1507  1.1  mrg         ArrayLiteralExp es2 = e2.isArrayLiteralExp();
   1508  1.1  mrg         emplaceExp!(ArrayLiteralExp)(&ue, es1.loc, type, copyLiteralArray(es1.elements));
   1509  1.1  mrg         es1 = ue.exp().isArrayLiteralExp();
   1510  1.1  mrg         es1.elements.insert(es1.elements.dim, copyLiteralArray(es2.elements));
   1511  1.1  mrg         return ue;
   1512  1.1  mrg     }
   1513  1.1  mrg     if (e1.op == EXP.arrayLiteral && e2.op == EXP.null_ && t1.nextOf().equals(t2.nextOf()))
   1514  1.1  mrg     {
   1515  1.1  mrg         //  [ e1 ] ~ null ----> [ e1 ].dup
   1516  1.1  mrg         ue = paintTypeOntoLiteralCopy(type, copyLiteral(e1).copy());
   1517  1.1  mrg         return ue;
   1518  1.1  mrg     }
   1519  1.1  mrg     if (e1.op == EXP.null_ && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
   1520  1.1  mrg     {
   1521  1.1  mrg         //  null ~ [ e2 ] ----> [ e2 ].dup
   1522  1.1  mrg         ue = paintTypeOntoLiteralCopy(type, copyLiteral(e2).copy());
   1523  1.1  mrg         return ue;
   1524  1.1  mrg     }
   1525  1.1  mrg     ue = Cat(loc, type, e1, e2);
   1526  1.1  mrg     return ue;
   1527  1.1  mrg }
   1528  1.1  mrg 
   1529  1.1  mrg /*  Given an AA literal 'ae', and a key 'e2':
   1530  1.1  mrg  *  Return ae[e2] if present, or NULL if not found.
   1531  1.1  mrg  */
   1532  1.1  mrg Expression findKeyInAA(const ref Loc loc, AssocArrayLiteralExp ae, Expression e2)
   1533  1.1  mrg {
   1534  1.1  mrg     /* Search the keys backwards, in case there are duplicate keys
   1535  1.1  mrg      */
   1536  1.1  mrg     for (size_t i = ae.keys.dim; i;)
   1537  1.1  mrg     {
   1538  1.1  mrg         --i;
   1539  1.1  mrg         Expression ekey = (*ae.keys)[i];
   1540  1.1  mrg         const int eq = ctfeEqual(loc, EXP.equal, ekey, e2);
   1541  1.1  mrg         if (eq)
   1542  1.1  mrg         {
   1543  1.1  mrg             return (*ae.values)[i];
   1544  1.1  mrg         }
   1545  1.1  mrg     }
   1546  1.1  mrg     return null;
   1547  1.1  mrg }
   1548  1.1  mrg 
   1549  1.1  mrg /* Same as for constfold.Index, except that it only works for static arrays,
   1550  1.1  mrg  * dynamic arrays, and strings. We know that e1 is an
   1551  1.1  mrg  * interpreted CTFE expression, so it cannot have side-effects.
   1552  1.1  mrg  */
   1553  1.1  mrg Expression ctfeIndex(UnionExp* pue, const ref Loc loc, Type type, Expression e1, uinteger_t indx)
   1554  1.1  mrg {
   1555  1.1  mrg     //printf("ctfeIndex(e1 = %s)\n", e1.toChars());
   1556  1.1  mrg     assert(e1.type);
   1557  1.1  mrg     if (auto es1 = e1.isStringExp())
   1558  1.1  mrg     {
   1559  1.1  mrg         if (indx >= es1.len)
   1560  1.1  mrg         {
   1561  1.1  mrg             error(loc, "string index %llu is out of bounds `[0 .. %llu]`", indx, cast(ulong)es1.len);
   1562  1.1  mrg             return CTFEExp.cantexp;
   1563  1.1  mrg         }
   1564  1.1  mrg         emplaceExp!IntegerExp(pue, loc, es1.getCodeUnit(cast(size_t) indx), type);
   1565  1.1  mrg         return pue.exp();
   1566  1.1  mrg     }
   1567  1.1  mrg 
   1568  1.1  mrg     if (auto ale = e1.isArrayLiteralExp())
   1569  1.1  mrg     {
   1570  1.1  mrg         if (indx >= ale.elements.dim)
   1571  1.1  mrg         {
   1572  1.1  mrg             error(loc, "array index %llu is out of bounds `%s[0 .. %llu]`", indx, e1.toChars(), cast(ulong)ale.elements.dim);
   1573  1.1  mrg             return CTFEExp.cantexp;
   1574  1.1  mrg         }
   1575  1.1  mrg         Expression e = (*ale.elements)[cast(size_t)indx];
   1576  1.1  mrg         return paintTypeOntoLiteral(pue, type, e);
   1577  1.1  mrg     }
   1578  1.1  mrg 
   1579  1.1  mrg     assert(0);
   1580  1.1  mrg }
   1581  1.1  mrg 
   1582  1.1  mrg Expression ctfeCast(UnionExp* pue, const ref Loc loc, Type type, Type to, Expression e, bool explicitCast = false)
   1583  1.1  mrg {
   1584  1.1  mrg     Expression paint()
   1585  1.1  mrg     {
   1586  1.1  mrg         return paintTypeOntoLiteral(pue, to, e);
   1587  1.1  mrg     }
   1588  1.1  mrg 
   1589  1.1  mrg     if (e.op == EXP.null_)
   1590  1.1  mrg         return paint();
   1591  1.1  mrg 
   1592  1.1  mrg     if (e.op == EXP.classReference)
   1593  1.1  mrg     {
   1594  1.1  mrg         // Disallow reinterpreting class casts. Do this by ensuring that
   1595  1.1  mrg         // the original class can implicitly convert to the target class.
   1596  1.1  mrg         // Also do not check 'alias this' for explicit cast expressions.
   1597  1.1  mrg         auto tclass = e.isClassReferenceExp().originalClass().type.isTypeClass();
   1598  1.1  mrg         auto match = explicitCast ? tclass.implicitConvToWithoutAliasThis(to.mutableOf())
   1599  1.1  mrg                                   : tclass.implicitConvTo(to.mutableOf());
   1600  1.1  mrg         if (match)
   1601  1.1  mrg             return paint();
   1602  1.1  mrg         else
   1603  1.1  mrg         {
   1604  1.1  mrg             emplaceExp!(NullExp)(pue, loc, to);
   1605  1.1  mrg             return pue.exp();
   1606  1.1  mrg         }
   1607  1.1  mrg     }
   1608  1.1  mrg 
   1609  1.1  mrg     // Allow TypeInfo type painting
   1610  1.1  mrg     if (isTypeInfo_Class(e.type) && e.type.implicitConvTo(to))
   1611  1.1  mrg         return paint();
   1612  1.1  mrg 
   1613  1.1  mrg     // Allow casting away const for struct literals
   1614  1.1  mrg     if (e.op == EXP.structLiteral && e.type.toBasetype().castMod(0) == to.toBasetype().castMod(0))
   1615  1.1  mrg         return paint();
   1616  1.1  mrg 
   1617  1.1  mrg     Expression r;
   1618  1.1  mrg     if (e.type.equals(type) && type.equals(to))
   1619  1.1  mrg     {
   1620  1.1  mrg         // necessary not to change e's address for pointer comparisons
   1621  1.1  mrg         r = e;
   1622  1.1  mrg     }
   1623  1.1  mrg     else if (to.toBasetype().ty == Tarray &&
   1624  1.1  mrg              type.toBasetype().ty == Tarray &&
   1625  1.1  mrg              to.toBasetype().nextOf().size() == type.toBasetype().nextOf().size())
   1626  1.1  mrg     {
   1627  1.1  mrg         // https://issues.dlang.org/show_bug.cgi?id=12495
   1628  1.1  mrg         // Array reinterpret casts: eg. string to immutable(ubyte)[]
   1629  1.1  mrg         return paint();
   1630  1.1  mrg     }
   1631  1.1  mrg     else
   1632  1.1  mrg     {
   1633  1.1  mrg         *pue = Cast(loc, type, to, e);
   1634  1.1  mrg         r = pue.exp();
   1635  1.1  mrg     }
   1636  1.1  mrg 
   1637  1.1  mrg     if (CTFEExp.isCantExp(r))
   1638  1.1  mrg         error(loc, "cannot cast `%s` to `%s` at compile time", e.toChars(), to.toChars());
   1639  1.1  mrg 
   1640  1.1  mrg     if (auto ae = e.isArrayLiteralExp())
   1641  1.1  mrg         ae.ownedByCtfe = OwnedBy.ctfe;
   1642  1.1  mrg 
   1643  1.1  mrg     if (auto se = e.isStringExp())
   1644  1.1  mrg         se.ownedByCtfe = OwnedBy.ctfe;
   1645  1.1  mrg 
   1646  1.1  mrg     return r;
   1647  1.1  mrg }
   1648  1.1  mrg 
   1649  1.1  mrg /******** Assignment helper functions ***************************/
   1650  1.1  mrg /* Set dest = src, where both dest and src are container value literals
   1651  1.1  mrg  * (ie, struct literals, or static arrays (can be an array literal or a string))
   1652  1.1  mrg  * Assignment is recursively in-place.
   1653  1.1  mrg  * Purpose: any reference to a member of 'dest' will remain valid after the
   1654  1.1  mrg  * assignment.
   1655  1.1  mrg  */
   1656  1.1  mrg void assignInPlace(Expression dest, Expression src)
   1657  1.1  mrg {
   1658  1.1  mrg     if (!(dest.op == EXP.structLiteral || dest.op == EXP.arrayLiteral || dest.op == EXP.string_))
   1659  1.1  mrg     {
   1660  1.1  mrg         printf("invalid op %d %d\n", src.op, dest.op);
   1661  1.1  mrg         assert(0);
   1662  1.1  mrg     }
   1663  1.1  mrg     Expressions* oldelems;
   1664  1.1  mrg     Expressions* newelems;
   1665  1.1  mrg     if (dest.op == EXP.structLiteral)
   1666  1.1  mrg     {
   1667  1.1  mrg         assert(dest.op == src.op);
   1668  1.1  mrg         oldelems = dest.isStructLiteralExp().elements;
   1669  1.1  mrg         newelems = src.isStructLiteralExp().elements;
   1670  1.1  mrg         auto sd = dest.isStructLiteralExp().sd;
   1671  1.1  mrg         const nfields = sd.nonHiddenFields();
   1672  1.1  mrg         const nvthis = sd.fields.dim - nfields;
   1673  1.1  mrg         if (nvthis && oldelems.dim >= nfields && oldelems.dim < newelems.dim)
   1674  1.1  mrg             foreach (_; 0 .. newelems.dim - oldelems.dim)
   1675  1.1  mrg                 oldelems.push(null);
   1676  1.1  mrg     }
   1677  1.1  mrg     else if (dest.op == EXP.arrayLiteral && src.op == EXP.arrayLiteral)
   1678  1.1  mrg     {
   1679  1.1  mrg         oldelems = dest.isArrayLiteralExp().elements;
   1680  1.1  mrg         newelems = src.isArrayLiteralExp().elements;
   1681  1.1  mrg     }
   1682  1.1  mrg     else if (dest.op == EXP.string_ && src.op == EXP.string_)
   1683  1.1  mrg     {
   1684  1.1  mrg         sliceAssignStringFromString(dest.isStringExp(), src.isStringExp(), 0);
   1685  1.1  mrg         return;
   1686  1.1  mrg     }
   1687  1.1  mrg     else if (dest.op == EXP.arrayLiteral && src.op == EXP.string_)
   1688  1.1  mrg     {
   1689  1.1  mrg         sliceAssignArrayLiteralFromString(dest.isArrayLiteralExp(), src.isStringExp(), 0);
   1690  1.1  mrg         return;
   1691  1.1  mrg     }
   1692  1.1  mrg     else if (src.op == EXP.arrayLiteral && dest.op == EXP.string_)
   1693  1.1  mrg     {
   1694  1.1  mrg         sliceAssignStringFromArrayLiteral(dest.isStringExp(), src.isArrayLiteralExp(), 0);
   1695  1.1  mrg         return;
   1696  1.1  mrg     }
   1697  1.1  mrg     else
   1698  1.1  mrg     {
   1699  1.1  mrg         printf("invalid op %d %d\n", src.op, dest.op);
   1700  1.1  mrg         assert(0);
   1701  1.1  mrg     }
   1702  1.1  mrg     assert(oldelems.dim == newelems.dim);
   1703  1.1  mrg     foreach (size_t i; 0 .. oldelems.dim)
   1704  1.1  mrg     {
   1705  1.1  mrg         Expression e = (*newelems)[i];
   1706  1.1  mrg         Expression o = (*oldelems)[i];
   1707  1.1  mrg         if (e.op == EXP.structLiteral)
   1708  1.1  mrg         {
   1709  1.1  mrg             assert(o.op == e.op);
   1710  1.1  mrg             assignInPlace(o, e);
   1711  1.1  mrg         }
   1712  1.1  mrg         else if (e.type.ty == Tsarray && e.op != EXP.void_ && o.type.ty == Tsarray)
   1713  1.1  mrg         {
   1714  1.1  mrg             assignInPlace(o, e);
   1715  1.1  mrg         }
   1716  1.1  mrg         else
   1717  1.1  mrg         {
   1718  1.1  mrg             (*oldelems)[i] = (*newelems)[i];
   1719  1.1  mrg         }
   1720  1.1  mrg     }
   1721  1.1  mrg }
   1722  1.1  mrg 
   1723  1.1  mrg // Given an AA literal aae,  set aae[index] = newval and return newval.
   1724  1.1  mrg Expression assignAssocArrayElement(const ref Loc loc, AssocArrayLiteralExp aae, Expression index, Expression newval)
   1725  1.1  mrg {
   1726  1.1  mrg     /* Create new associative array literal reflecting updated key/value
   1727  1.1  mrg      */
   1728  1.1  mrg     Expressions* keysx = aae.keys;
   1729  1.1  mrg     Expressions* valuesx = aae.values;
   1730  1.1  mrg     int updated = 0;
   1731  1.1  mrg     for (size_t j = valuesx.dim; j;)
   1732  1.1  mrg     {
   1733  1.1  mrg         j--;
   1734  1.1  mrg         Expression ekey = (*aae.keys)[j];
   1735  1.1  mrg         int eq = ctfeEqual(loc, EXP.equal, ekey, index);
   1736  1.1  mrg         if (eq)
   1737  1.1  mrg         {
   1738  1.1  mrg             (*valuesx)[j] = newval;
   1739  1.1  mrg             updated = 1;
   1740  1.1  mrg         }
   1741  1.1  mrg     }
   1742  1.1  mrg     if (!updated)
   1743  1.1  mrg     {
   1744  1.1  mrg         // Append index/newval to keysx[]/valuesx[]
   1745  1.1  mrg         valuesx.push(newval);
   1746  1.1  mrg         keysx.push(index);
   1747  1.1  mrg     }
   1748  1.1  mrg     return newval;
   1749  1.1  mrg }
   1750  1.1  mrg 
   1751  1.1  mrg /// Given array literal oldval of type ArrayLiteralExp or StringExp, of length
   1752  1.1  mrg /// oldlen, change its length to newlen. If the newlen is longer than oldlen,
   1753  1.1  mrg /// all new elements will be set to the default initializer for the element type.
   1754  1.1  mrg Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray arrayType, Expression oldval, size_t oldlen, size_t newlen)
   1755  1.1  mrg {
   1756  1.1  mrg     Type elemType = arrayType.next;
   1757  1.1  mrg     assert(elemType);
   1758  1.1  mrg     Expression defaultElem = elemType.defaultInitLiteral(loc);
   1759  1.1  mrg     auto elements = new Expressions(newlen);
   1760  1.1  mrg     // Resolve slices
   1761  1.1  mrg     size_t indxlo = 0;
   1762  1.1  mrg     if (oldval.op == EXP.slice)
   1763  1.1  mrg     {
   1764  1.1  mrg         indxlo = cast(size_t)oldval.isSliceExp().lwr.toInteger();
   1765  1.1  mrg         oldval = oldval.isSliceExp().e1;
   1766  1.1  mrg     }
   1767  1.1  mrg     size_t copylen = oldlen < newlen ? oldlen : newlen;
   1768  1.1  mrg     if (oldval.op == EXP.string_)
   1769  1.1  mrg     {
   1770  1.1  mrg         StringExp oldse = oldval.isStringExp();
   1771  1.1  mrg         void* s = mem.xcalloc(newlen + 1, oldse.sz);
   1772  1.1  mrg         const data = oldse.peekData();
   1773  1.1  mrg         memcpy(s, data.ptr, copylen * oldse.sz);
   1774  1.1  mrg         const defaultValue = cast(uint)defaultElem.toInteger();
   1775  1.1  mrg         foreach (size_t elemi; copylen .. newlen)
   1776  1.1  mrg         {
   1777  1.1  mrg             switch (oldse.sz)
   1778  1.1  mrg             {
   1779  1.1  mrg             case 1:
   1780  1.1  mrg                 (cast(char*)s)[cast(size_t)(indxlo + elemi)] = cast(char)defaultValue;
   1781  1.1  mrg                 break;
   1782  1.1  mrg             case 2:
   1783  1.1  mrg                 (cast(wchar*)s)[cast(size_t)(indxlo + elemi)] = cast(wchar)defaultValue;
   1784  1.1  mrg                 break;
   1785  1.1  mrg             case 4:
   1786  1.1  mrg                 (cast(dchar*)s)[cast(size_t)(indxlo + elemi)] = cast(dchar)defaultValue;
   1787  1.1  mrg                 break;
   1788  1.1  mrg             default:
   1789  1.1  mrg                 assert(0);
   1790  1.1  mrg             }
   1791  1.1  mrg         }
   1792  1.1  mrg         emplaceExp!(StringExp)(pue, loc, s[0 .. newlen * oldse.sz], newlen, oldse.sz);
   1793  1.1  mrg         StringExp se = pue.exp().isStringExp();
   1794  1.1  mrg         se.type = arrayType;
   1795  1.1  mrg         se.sz = oldse.sz;
   1796  1.1  mrg         se.committed = oldse.committed;
   1797  1.1  mrg         se.ownedByCtfe = OwnedBy.ctfe;
   1798  1.1  mrg     }
   1799  1.1  mrg     else
   1800  1.1  mrg     {
   1801  1.1  mrg         if (oldlen != 0)
   1802  1.1  mrg         {
   1803  1.1  mrg             assert(oldval.op == EXP.arrayLiteral);
   1804  1.1  mrg             ArrayLiteralExp ae = oldval.isArrayLiteralExp();
   1805  1.1  mrg             foreach (size_t i; 0 .. copylen)
   1806  1.1  mrg                 (*elements)[i] = (*ae.elements)[indxlo + i];
   1807  1.1  mrg         }
   1808  1.1  mrg         if (elemType.ty == Tstruct || elemType.ty == Tsarray)
   1809  1.1  mrg         {
   1810  1.1  mrg             /* If it is an aggregate literal representing a value type,
   1811  1.1  mrg              * we need to create a unique copy for each element
   1812  1.1  mrg              */
   1813  1.1  mrg             foreach (size_t i; copylen .. newlen)
   1814  1.1  mrg                 (*elements)[i] = copyLiteral(defaultElem).copy();
   1815  1.1  mrg         }
   1816  1.1  mrg         else
   1817  1.1  mrg         {
   1818  1.1  mrg             foreach (size_t i; copylen .. newlen)
   1819  1.1  mrg                 (*elements)[i] = defaultElem;
   1820  1.1  mrg         }
   1821  1.1  mrg         emplaceExp!(ArrayLiteralExp)(pue, loc, arrayType, elements);
   1822  1.1  mrg         ArrayLiteralExp aae = pue.exp().isArrayLiteralExp();
   1823  1.1  mrg         aae.ownedByCtfe = OwnedBy.ctfe;
   1824  1.1  mrg     }
   1825  1.1  mrg     return pue.exp();
   1826  1.1  mrg }
   1827  1.1  mrg 
   1828  1.1  mrg /*************************** CTFE Sanity Checks ***************************/
   1829  1.1  mrg 
   1830  1.1  mrg bool isCtfeValueValid(Expression newval)
   1831  1.1  mrg {
   1832  1.1  mrg     Type tb = newval.type.toBasetype();
   1833  1.1  mrg     switch (newval.op)
   1834  1.1  mrg     {
   1835  1.1  mrg         case EXP.int64:
   1836  1.1  mrg         case EXP.float64:
   1837  1.1  mrg         case EXP.char_:
   1838  1.1  mrg         case EXP.complex80:
   1839  1.1  mrg             return tb.isscalar();
   1840  1.1  mrg 
   1841  1.1  mrg         case EXP.null_:
   1842  1.1  mrg             return tb.ty == Tnull    ||
   1843  1.1  mrg                    tb.ty == Tpointer ||
   1844  1.1  mrg                    tb.ty == Tarray   ||
   1845  1.1  mrg                    tb.ty == Taarray  ||
   1846  1.1  mrg                    tb.ty == Tclass   ||
   1847  1.1  mrg                    tb.ty == Tdelegate;
   1848  1.1  mrg 
   1849  1.1  mrg         case EXP.string_:
   1850  1.1  mrg             return true; // CTFE would directly use the StringExp in AST.
   1851  1.1  mrg 
   1852  1.1  mrg         case EXP.arrayLiteral:
   1853  1.1  mrg             return true; //((ArrayLiteralExp *)newval)->ownedByCtfe;
   1854  1.1  mrg 
   1855  1.1  mrg         case EXP.assocArrayLiteral:
   1856  1.1  mrg             return true; //((AssocArrayLiteralExp *)newval)->ownedByCtfe;
   1857  1.1  mrg 
   1858  1.1  mrg         case EXP.structLiteral:
   1859  1.1  mrg             return true; //((StructLiteralExp *)newval)->ownedByCtfe;
   1860  1.1  mrg 
   1861  1.1  mrg         case EXP.classReference:
   1862  1.1  mrg             return true;
   1863  1.1  mrg 
   1864  1.1  mrg         case EXP.type:
   1865  1.1  mrg             return true;
   1866  1.1  mrg 
   1867  1.1  mrg         case EXP.vector:
   1868  1.1  mrg             return true; // vector literal
   1869  1.1  mrg 
   1870  1.1  mrg         case EXP.function_:
   1871  1.1  mrg             return true; // function literal or delegate literal
   1872  1.1  mrg 
   1873  1.1  mrg         case EXP.delegate_:
   1874  1.1  mrg         {
   1875  1.1  mrg             // &struct.func or &clasinst.func
   1876  1.1  mrg             // &nestedfunc
   1877  1.1  mrg             Expression ethis = newval.isDelegateExp().e1;
   1878  1.1  mrg             return (ethis.op == EXP.structLiteral || ethis.op == EXP.classReference || ethis.op == EXP.variable && ethis.isVarExp().var == newval.isDelegateExp().func);
   1879  1.1  mrg         }
   1880  1.1  mrg 
   1881  1.1  mrg         case EXP.symbolOffset:
   1882  1.1  mrg         {
   1883  1.1  mrg             // function pointer, or pointer to static variable
   1884  1.1  mrg             Declaration d = newval.isSymOffExp().var;
   1885  1.1  mrg             return d.isFuncDeclaration() || d.isDataseg();
   1886  1.1  mrg         }
   1887  1.1  mrg 
   1888  1.1  mrg         case EXP.typeid_:
   1889  1.1  mrg         {
   1890  1.1  mrg             // always valid
   1891  1.1  mrg             return true;
   1892  1.1  mrg         }
   1893  1.1  mrg 
   1894  1.1  mrg         case EXP.address:
   1895  1.1  mrg         {
   1896  1.1  mrg             // e1 should be a CTFE reference
   1897  1.1  mrg             Expression e1 = newval.isAddrExp().e1;
   1898  1.1  mrg             return tb.ty == Tpointer &&
   1899  1.1  mrg             (
   1900  1.1  mrg                 (e1.op == EXP.structLiteral || e1.op == EXP.arrayLiteral) && isCtfeValueValid(e1) ||
   1901  1.1  mrg                  e1.op == EXP.variable ||
   1902  1.1  mrg                  e1.op == EXP.dotVariable && isCtfeReferenceValid(e1) ||
   1903  1.1  mrg                  e1.op == EXP.index && isCtfeReferenceValid(e1) ||
   1904  1.1  mrg                  e1.op == EXP.slice && e1.type.toBasetype().ty == Tsarray
   1905  1.1  mrg             );
   1906  1.1  mrg         }
   1907  1.1  mrg 
   1908  1.1  mrg         case EXP.slice:
   1909  1.1  mrg         {
   1910  1.1  mrg             // e1 should be an array aggregate
   1911  1.1  mrg             const SliceExp se = newval.isSliceExp();
   1912  1.1  mrg             assert(se.lwr && se.lwr.op == EXP.int64);
   1913  1.1  mrg             assert(se.upr && se.upr.op == EXP.int64);
   1914  1.1  mrg             return (tb.ty == Tarray || tb.ty == Tsarray) && (se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral);
   1915  1.1  mrg         }
   1916  1.1  mrg 
   1917  1.1  mrg         case EXP.void_:
   1918  1.1  mrg             return true; // uninitialized value
   1919  1.1  mrg 
   1920  1.1  mrg         default:
   1921  1.1  mrg             newval.error("CTFE internal error: illegal CTFE value `%s`", newval.toChars());
   1922  1.1  mrg             return false;
   1923  1.1  mrg     }
   1924  1.1  mrg }
   1925  1.1  mrg 
   1926  1.1  mrg bool isCtfeReferenceValid(Expression newval)
   1927  1.1  mrg {
   1928  1.1  mrg     switch (newval.op)
   1929  1.1  mrg     {
   1930  1.1  mrg         case EXP.this_:
   1931  1.1  mrg             return true;
   1932  1.1  mrg 
   1933  1.1  mrg         case EXP.variable:
   1934  1.1  mrg         {
   1935  1.1  mrg             const VarDeclaration v = newval.isVarExp().var.isVarDeclaration();
   1936  1.1  mrg             assert(v);
   1937  1.1  mrg             // Must not be a reference to a reference
   1938  1.1  mrg             return true;
   1939  1.1  mrg         }
   1940  1.1  mrg 
   1941  1.1  mrg         case EXP.index:
   1942  1.1  mrg         {
   1943  1.1  mrg             const Expression eagg = newval.isIndexExp().e1;
   1944  1.1  mrg             return eagg.op == EXP.string_ || eagg.op == EXP.arrayLiteral || eagg.op == EXP.assocArrayLiteral;
   1945  1.1  mrg         }
   1946  1.1  mrg 
   1947  1.1  mrg         case EXP.dotVariable:
   1948  1.1  mrg         {
   1949  1.1  mrg             Expression eagg = newval.isDotVarExp().e1;
   1950  1.1  mrg             return (eagg.op == EXP.structLiteral || eagg.op == EXP.classReference) && isCtfeValueValid(eagg);
   1951  1.1  mrg         }
   1952  1.1  mrg 
   1953  1.1  mrg         default:
   1954  1.1  mrg             // Internally a ref variable may directly point a stack memory.
   1955  1.1  mrg             // e.g. ref int v = 1;
   1956  1.1  mrg             return isCtfeValueValid(newval);
   1957  1.1  mrg     }
   1958  1.1  mrg }
   1959  1.1  mrg 
   1960  1.1  mrg // Used for debugging only
   1961  1.1  mrg void showCtfeExpr(Expression e, int level = 0)
   1962  1.1  mrg {
   1963  1.1  mrg     for (int i = level; i > 0; --i)
   1964  1.1  mrg         printf(" ");
   1965  1.1  mrg     Expressions* elements = null;
   1966  1.1  mrg     // We need the struct definition to detect block assignment
   1967  1.1  mrg     StructDeclaration sd = null;
   1968  1.1  mrg     ClassDeclaration cd = null;
   1969  1.1  mrg     if (e.op == EXP.structLiteral)
   1970  1.1  mrg     {
   1971  1.1  mrg         elements = e.isStructLiteralExp().elements;
   1972  1.1  mrg         sd = e.isStructLiteralExp().sd;
   1973  1.1  mrg         printf("STRUCT type = %s %p:\n", e.type.toChars(), e);
   1974  1.1  mrg     }
   1975  1.1  mrg     else if (e.op == EXP.classReference)
   1976  1.1  mrg     {
   1977  1.1  mrg         elements = e.isClassReferenceExp().value.elements;
   1978  1.1  mrg         cd = e.isClassReferenceExp().originalClass();
   1979  1.1  mrg         printf("CLASS type = %s %p:\n", e.type.toChars(), e.isClassReferenceExp().value);
   1980  1.1  mrg     }
   1981  1.1  mrg     else if (e.op == EXP.arrayLiteral)
   1982  1.1  mrg     {
   1983  1.1  mrg         elements = e.isArrayLiteralExp().elements;
   1984  1.1  mrg         printf("ARRAY LITERAL type=%s %p:\n", e.type.toChars(), e);
   1985  1.1  mrg     }
   1986  1.1  mrg     else if (e.op == EXP.assocArrayLiteral)
   1987  1.1  mrg     {
   1988  1.1  mrg         printf("AA LITERAL type=%s %p:\n", e.type.toChars(), e);
   1989  1.1  mrg     }
   1990  1.1  mrg     else if (e.op == EXP.string_)
   1991  1.1  mrg     {
   1992  1.1  mrg         printf("STRING %s %p\n", e.toChars(), e.isStringExp.peekString.ptr);
   1993  1.1  mrg     }
   1994  1.1  mrg     else if (e.op == EXP.slice)
   1995  1.1  mrg     {
   1996  1.1  mrg         printf("SLICE %p: %s\n", e, e.toChars());
   1997  1.1  mrg         showCtfeExpr(e.isSliceExp().e1, level + 1);
   1998  1.1  mrg     }
   1999  1.1  mrg     else if (e.op == EXP.variable)
   2000  1.1  mrg     {
   2001  1.1  mrg         printf("VAR %p %s\n", e, e.toChars());
   2002  1.1  mrg         VarDeclaration v = e.isVarExp().var.isVarDeclaration();
   2003  1.1  mrg         if (v && getValue(v))
   2004  1.1  mrg             showCtfeExpr(getValue(v), level + 1);
   2005  1.1  mrg     }
   2006  1.1  mrg     else if (e.op == EXP.address)
   2007  1.1  mrg     {
   2008  1.1  mrg         // This is potentially recursive. We mustn't try to print the thing we're pointing to.
   2009  1.1  mrg         printf("POINTER %p to %p: %s\n", e, e.isAddrExp().e1, e.toChars());
   2010  1.1  mrg     }
   2011  1.1  mrg     else
   2012  1.1  mrg         printf("VALUE %p: %s\n", e, e.toChars());
   2013  1.1  mrg     if (elements)
   2014  1.1  mrg     {
   2015  1.1  mrg         size_t fieldsSoFar = 0;
   2016  1.1  mrg         for (size_t i = 0; i < elements.dim; i++)
   2017  1.1  mrg         {
   2018  1.1  mrg             Expression z = null;
   2019  1.1  mrg             VarDeclaration v = null;
   2020  1.1  mrg             if (i > 15)
   2021  1.1  mrg             {
   2022  1.1  mrg                 printf("...(total %d elements)\n", cast(int)elements.dim);
   2023  1.1  mrg                 return;
   2024  1.1  mrg             }
   2025  1.1  mrg             if (sd)
   2026  1.1  mrg             {
   2027  1.1  mrg                 v = sd.fields[i];
   2028  1.1  mrg                 z = (*elements)[i];
   2029  1.1  mrg             }
   2030  1.1  mrg             else if (cd)
   2031  1.1  mrg             {
   2032  1.1  mrg                 while (i - fieldsSoFar >= cd.fields.dim)
   2033  1.1  mrg                 {
   2034  1.1  mrg                     fieldsSoFar += cd.fields.dim;
   2035  1.1  mrg                     cd = cd.baseClass;
   2036  1.1  mrg                     for (int j = level; j > 0; --j)
   2037  1.1  mrg                         printf(" ");
   2038  1.1  mrg                     printf(" BASE CLASS: %s\n", cd.toChars());
   2039  1.1  mrg                 }
   2040  1.1  mrg                 v = cd.fields[i - fieldsSoFar];
   2041  1.1  mrg                 assert((elements.dim + i) >= (fieldsSoFar + cd.fields.dim));
   2042  1.1  mrg                 size_t indx = (elements.dim - fieldsSoFar) - cd.fields.dim + i;
   2043  1.1  mrg                 assert(indx < elements.dim);
   2044  1.1  mrg                 z = (*elements)[indx];
   2045  1.1  mrg             }
   2046  1.1  mrg             if (!z)
   2047  1.1  mrg             {
   2048  1.1  mrg                 for (int j = level; j > 0; --j)
   2049  1.1  mrg                     printf(" ");
   2050  1.1  mrg                 printf(" void\n");
   2051  1.1  mrg                 continue;
   2052  1.1  mrg             }
   2053  1.1  mrg             if (v)
   2054  1.1  mrg             {
   2055  1.1  mrg                 // If it is a void assignment, use the default initializer
   2056  1.1  mrg                 if ((v.type.ty != z.type.ty) && v.type.ty == Tsarray)
   2057  1.1  mrg                 {
   2058  1.1  mrg                     for (int j = level; --j;)
   2059  1.1  mrg                         printf(" ");
   2060  1.1  mrg                     printf(" field: block initialized static array\n");
   2061  1.1  mrg                     continue;
   2062  1.1  mrg                 }
   2063  1.1  mrg             }
   2064  1.1  mrg             showCtfeExpr(z, level + 1);
   2065  1.1  mrg         }
   2066  1.1  mrg     }
   2067  1.1  mrg }
   2068  1.1  mrg 
   2069  1.1  mrg /*************************** Void initialization ***************************/
   2070  1.1  mrg UnionExp voidInitLiteral(Type t, VarDeclaration var)
   2071  1.1  mrg {
   2072  1.1  mrg     UnionExp ue;
   2073  1.1  mrg     if (t.ty == Tsarray)
   2074  1.1  mrg     {
   2075  1.1  mrg         TypeSArray tsa = cast(TypeSArray)t;
   2076  1.1  mrg         Expression elem = voidInitLiteral(tsa.next, var).copy();
   2077  1.1  mrg         // For aggregate value types (structs, static arrays) we must
   2078  1.1  mrg         // create an a separate copy for each element.
   2079  1.1  mrg         const mustCopy = (elem.op == EXP.arrayLiteral || elem.op == EXP.structLiteral);
   2080  1.1  mrg         const d = cast(size_t)tsa.dim.toInteger();
   2081  1.1  mrg         auto elements = new Expressions(d);
   2082  1.1  mrg         foreach (i; 0 .. d)
   2083  1.1  mrg         {
   2084  1.1  mrg             if (mustCopy && i > 0)
   2085  1.1  mrg                 elem = copyLiteral(elem).copy();
   2086  1.1  mrg             (*elements)[i] = elem;
   2087  1.1  mrg         }
   2088  1.1  mrg         emplaceExp!(ArrayLiteralExp)(&ue, var.loc, tsa, elements);
   2089  1.1  mrg         ArrayLiteralExp ae = ue.exp().isArrayLiteralExp();
   2090  1.1  mrg         ae.ownedByCtfe = OwnedBy.ctfe;
   2091  1.1  mrg     }
   2092  1.1  mrg     else if (t.ty == Tstruct)
   2093  1.1  mrg     {
   2094  1.1  mrg         TypeStruct ts = cast(TypeStruct)t;
   2095  1.1  mrg         auto exps = new Expressions(ts.sym.fields.dim);
   2096  1.1  mrg         foreach (size_t i;  0 .. ts.sym.fields.dim)
   2097  1.1  mrg         {
   2098  1.1  mrg             (*exps)[i] = voidInitLiteral(ts.sym.fields[i].type, ts.sym.fields[i]).copy();
   2099  1.1  mrg         }
   2100  1.1  mrg         emplaceExp!(StructLiteralExp)(&ue, var.loc, ts.sym, exps);
   2101  1.1  mrg         StructLiteralExp se = ue.exp().isStructLiteralExp();
   2102  1.1  mrg         se.type = ts;
   2103  1.1  mrg         se.ownedByCtfe = OwnedBy.ctfe;
   2104  1.1  mrg     }
   2105  1.1  mrg     else
   2106  1.1  mrg         emplaceExp!(VoidInitExp)(&ue, var);
   2107  1.1  mrg     return ue;
   2108  1.1  mrg }
   2109