Home | History | Annotate | Line # | Download | only in dmd
initsem.d revision 1.1.1.1
      1 /**
      2  * Semantic analysis of initializers.
      3  *
      4  * Copyright:   Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
      5  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
      6  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
      7  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/initsem.d, _initsem.d)
      8  * Documentation:  https://dlang.org/phobos/dmd_initsem.html
      9  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/initsem.d
     10  */
     11 
     12 module dmd.initsem;
     13 
     14 import core.stdc.stdio;
     15 import core.checkedint;
     16 
     17 import dmd.aggregate;
     18 import dmd.aliasthis;
     19 import dmd.arraytypes;
     20 import dmd.astenums;
     21 import dmd.dcast;
     22 import dmd.declaration;
     23 import dmd.dscope;
     24 import dmd.dstruct;
     25 import dmd.dsymbol;
     26 import dmd.dtemplate;
     27 import dmd.errors;
     28 import dmd.expression;
     29 import dmd.expressionsem;
     30 import dmd.func;
     31 import dmd.globals;
     32 import dmd.id;
     33 import dmd.identifier;
     34 import dmd.importc;
     35 import dmd.init;
     36 import dmd.mtype;
     37 import dmd.opover;
     38 import dmd.statement;
     39 import dmd.target;
     40 import dmd.tokens;
     41 import dmd.typesem;
     42 
     43 /********************************
     44  * If possible, convert array initializer to associative array initializer.
     45  *
     46  *  Params:
     47  *     ai = array initializer to be converted
     48  *
     49  *  Returns:
     50  *     The converted associative array initializer or ErrorExp if `ai`
     51  *     is not an associative array initializer.
     52  */
     53 Expression toAssocArrayLiteral(ArrayInitializer ai)
     54 {
     55     Expression e;
     56     //printf("ArrayInitializer::toAssocArrayInitializer()\n");
     57     //static int i; if (++i == 2) assert(0);
     58     const dim = ai.value.dim;
     59     auto keys = new Expressions(dim);
     60     auto values = new Expressions(dim);
     61     for (size_t i = 0; i < dim; i++)
     62     {
     63         e = ai.index[i];
     64         if (!e)
     65             goto Lno;
     66         (*keys)[i] = e;
     67         Initializer iz = ai.value[i];
     68         if (!iz)
     69             goto Lno;
     70         e = iz.initializerToExpression();
     71         if (!e)
     72             goto Lno;
     73         (*values)[i] = e;
     74     }
     75     e = new AssocArrayLiteralExp(ai.loc, keys, values);
     76     return e;
     77 Lno:
     78     error(ai.loc, "not an associative array initializer");
     79     return ErrorExp.get();
     80 }
     81 
     82 /******************************************
     83  * Perform semantic analysis on init.
     84  * Params:
     85  *      init = Initializer AST node
     86  *      sc = context
     87  *      tx = type that the initializer needs to become. If tx is an incomplete
     88  *           type and the initializer completes it, it is updated to be the
     89  *           complete type. ImportC has incomplete types
     90  *      needInterpret = if CTFE needs to be run on this,
     91  *                      such as if it is the initializer for a const declaration
     92  * Returns:
     93  *      `Initializer` with completed semantic analysis, `ErrorInitializer` if errors
     94  *      were encountered
     95  */
     96 extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedInterpret needInterpret)
     97 {
     98     Type t = tx;
     99 
    100     static Initializer err()
    101     {
    102         return new ErrorInitializer();
    103     }
    104 
    105     Initializer visitVoid(VoidInitializer i)
    106     {
    107         i.type = t;
    108         return i;
    109     }
    110 
    111     Initializer visitError(ErrorInitializer i)
    112     {
    113         return i;
    114     }
    115 
    116     Initializer visitStruct(StructInitializer i)
    117     {
    118         //printf("StructInitializer::semantic(t = %s) %s\n", t.toChars(), i.toChars());
    119         /* This works by replacing the StructInitializer with an ExpInitializer.
    120           */
    121         t = t.toBasetype();
    122         if (t.ty == Tsarray && t.nextOf().toBasetype().ty == Tstruct)
    123             t = t.nextOf().toBasetype();
    124         if (auto ts = t.isTypeStruct())
    125         {
    126             StructDeclaration sd = ts.sym;
    127             // check if the sd has a regular ctor (user defined non-copy ctor)
    128             // that is not disabled.
    129             if (sd.hasRegularCtor(true))
    130             {
    131                 error(i.loc, "%s `%s` has constructors, cannot use `{ initializers }`, use `%s( initializers )` instead", sd.kind(), sd.toChars(), sd.toChars());
    132                 return err();
    133             }
    134             sd.size(i.loc);
    135             if (sd.sizeok != Sizeok.done)
    136                 return err();
    137             const nfields = sd.nonHiddenFields();
    138             //expandTuples for non-identity arguments?
    139             auto elements = new Expressions(nfields);
    140             auto elems = (*elements)[];
    141             foreach (ref elem; elems)
    142                 elem = null;
    143 
    144             // Run semantic for explicitly given initializers
    145             // TODO: this part is slightly different from StructLiteralExp::semantic.
    146             bool errors = false;
    147             size_t fieldi = 0;
    148             foreach (j, id; i.field[])
    149             {
    150                 if (id)
    151                 {
    152                     /* Determine `fieldi` that `id` matches
    153                      */
    154                     Dsymbol s = sd.search(i.loc, id);
    155                     if (!s)
    156                     {
    157                         s = sd.search_correct(id);
    158                         const initLoc = i.value[j].loc;
    159                         if (s)
    160                             error(initLoc, "`%s` is not a member of `%s`, did you mean %s `%s`?", id.toChars(), sd.toChars(), s.kind(), s.toChars());
    161                         else
    162                             error(initLoc, "`%s` is not a member of `%s`", id.toChars(), sd.toChars());
    163                         return err();
    164                     }
    165                     s.checkDeprecated(i.loc, sc);
    166                     s = s.toAlias();
    167 
    168                     // Find out which field index `s` is
    169                     for (fieldi = 0; 1; fieldi++)
    170                     {
    171                         if (fieldi >= nfields)
    172                         {
    173                             error(i.loc, "`%s.%s` is not a per-instance initializable field", sd.toChars(), s.toChars());
    174                             return err();
    175                         }
    176                         if (s == sd.fields[fieldi])
    177                             break;
    178                     }
    179                 }
    180                 if (j >= nfields)
    181                 {
    182                     error(i.value[j].loc, "too many initializers for `%s`", sd.toChars());
    183                     return err();
    184                 }
    185 
    186                 VarDeclaration vd = sd.fields[fieldi];
    187                 if (elems[fieldi])
    188                 {
    189                     error(i.value[j].loc, "duplicate initializer for field `%s`", vd.toChars());
    190                     errors = true;
    191                     elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors
    192                     ++fieldi;
    193                     continue;
    194                 }
    195 
    196                 // Check for @safe violations
    197                 if (vd.type.hasPointers)
    198                 {
    199                     if ((!t.alignment.isDefault() && t.alignment.get() < target.ptrsize ||
    200                          (vd.offset & (target.ptrsize - 1))) &&
    201                         sc.func && sc.func.setUnsafe())
    202                     {
    203                         error(i.value[j].loc, "field `%s.%s` cannot assign to misaligned pointers in `@safe` code",
    204                             sd.toChars(), vd.toChars());
    205                         errors = true;
    206                         elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors
    207                         ++fieldi;
    208                         continue;
    209                     }
    210                 }
    211 
    212                 // Check for overlapping initializations (can happen with unions)
    213                 foreach (k, v2; sd.fields[0 .. nfields])
    214                 {
    215                     if (vd.isOverlappedWith(v2) && elems[k])
    216                     {
    217                         error(elems[k].loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
    218                         errors = true;
    219                         continue;
    220                     }
    221                 }
    222 
    223                 // Convert initializer to Expression `ex`
    224                 assert(sc);
    225                 auto tm = vd.type.addMod(t.mod);
    226                 auto iz = i.value[j].initializerSemantic(sc, tm, needInterpret);
    227                 auto ex = iz.initializerToExpression();
    228                 if (ex.op == EXP.error)
    229                 {
    230                     errors = true;
    231                     elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors
    232                     ++fieldi;
    233                     continue;
    234                 }
    235 
    236                 i.value[j] = iz;
    237                 elems[fieldi] = doCopyOrMove(sc, ex);
    238                 ++fieldi;
    239             }
    240             if (errors)
    241                 return err();
    242 
    243             // Make a StructLiteralExp out of elements[]
    244             auto sle = new StructLiteralExp(i.loc, sd, elements, t);
    245             if (!sd.fill(i.loc, elements, false))
    246                 return err();
    247             sle.type = t;
    248             auto ie = new ExpInitializer(i.loc, sle);
    249             return ie.initializerSemantic(sc, t, needInterpret);
    250         }
    251         else if ((t.ty == Tdelegate || t.isPtrToFunction()) && i.value.dim == 0)
    252         {
    253             const tok = (t.ty == Tdelegate) ? TOK.delegate_ : TOK.function_;
    254             /* Rewrite as empty delegate literal { }
    255              */
    256             Type tf = new TypeFunction(ParameterList(), null, LINK.d);
    257             auto fd = new FuncLiteralDeclaration(i.loc, Loc.initial, tf, tok, null);
    258             fd.fbody = new CompoundStatement(i.loc, new Statements());
    259             fd.endloc = i.loc;
    260             Expression e = new FuncExp(i.loc, fd);
    261             auto ie = new ExpInitializer(i.loc, e);
    262             return ie.initializerSemantic(sc, t, needInterpret);
    263         }
    264         if (t.ty != Terror)
    265             error(i.loc, "a struct is not a valid initializer for a `%s`", t.toChars());
    266         return err();
    267     }
    268 
    269     Initializer visitArray(ArrayInitializer i)
    270     {
    271         uint length;
    272         const(uint) amax = 0x80000000;
    273         bool errors = false;
    274         //printf("ArrayInitializer::semantic(%s)\n", t.toChars());
    275         if (i.sem) // if semantic() already run
    276         {
    277             return i;
    278         }
    279         i.sem = true;
    280         t = t.toBasetype();
    281         switch (t.ty)
    282         {
    283         case Tsarray:
    284         case Tarray:
    285             break;
    286         case Tvector:
    287             t = t.isTypeVector().basetype;
    288             break;
    289         case Taarray:
    290         case Tstruct: // consider implicit constructor call
    291             {
    292                 Expression e;
    293                 // note: MyStruct foo = [1:2, 3:4] is correct code if MyStruct has a this(int[int])
    294                 if (t.ty == Taarray || i.isAssociativeArray())
    295                     e = i.toAssocArrayLiteral();
    296                 else
    297                     e = i.initializerToExpression();
    298                 // Bugzilla 13987
    299                 if (!e)
    300                 {
    301                     error(i.loc, "cannot use array to initialize `%s`", t.toChars());
    302                     return err();
    303                 }
    304                 auto ei = new ExpInitializer(e.loc, e);
    305                 return ei.initializerSemantic(sc, t, needInterpret);
    306             }
    307         case Tpointer:
    308             if (t.nextOf().ty != Tfunction)
    309                 break;
    310             goto default;
    311         default:
    312             error(i.loc, "cannot use array to initialize `%s`", t.toChars());
    313             return err();
    314         }
    315         i.type = t;
    316         length = 0;
    317         for (size_t j = 0; j < i.index.dim; j++)
    318         {
    319             Expression idx = i.index[j];
    320             if (idx)
    321             {
    322                 sc = sc.startCTFE();
    323                 idx = idx.expressionSemantic(sc);
    324                 sc = sc.endCTFE();
    325                 idx = idx.ctfeInterpret();
    326                 i.index[j] = idx;
    327                 const uinteger_t idxvalue = idx.toInteger();
    328                 if (idxvalue >= amax)
    329                 {
    330                     error(i.loc, "array index %llu overflow", idxvalue);
    331                     errors = true;
    332                 }
    333                 length = cast(uint)idxvalue;
    334                 if (idx.op == EXP.error)
    335                     errors = true;
    336             }
    337             Initializer val = i.value[j];
    338             ExpInitializer ei = val.isExpInitializer();
    339             if (ei && !idx)
    340                 ei.expandTuples = true;
    341             auto tn = t.nextOf();
    342             val = val.initializerSemantic(sc, tn, needInterpret);
    343             if (val.isErrorInitializer())
    344                 errors = true;
    345             ei = val.isExpInitializer();
    346             // found a tuple, expand it
    347             if (ei && ei.exp.op == EXP.tuple)
    348             {
    349                 TupleExp te = ei.exp.isTupleExp();
    350                 i.index.remove(j);
    351                 i.value.remove(j);
    352                 for (size_t k = 0; k < te.exps.dim; ++k)
    353                 {
    354                     Expression e = (*te.exps)[k];
    355                     i.index.insert(j + k, cast(Expression)null);
    356                     i.value.insert(j + k, new ExpInitializer(e.loc, e));
    357                 }
    358                 j--;
    359                 continue;
    360             }
    361             else
    362             {
    363                 i.value[j] = val;
    364             }
    365             length++;
    366             if (length == 0)
    367             {
    368                 error(i.loc, "array dimension overflow");
    369                 return err();
    370             }
    371             if (length > i.dim)
    372                 i.dim = length;
    373         }
    374         if (auto tsa = t.isTypeSArray())
    375         {
    376             uinteger_t edim = tsa.dim.toInteger();
    377             if (i.dim > edim && !(tsa.isIncomplete() && (sc.flags & SCOPE.Cfile)))
    378             {
    379                 error(i.loc, "array initializer has %u elements, but array length is %llu", i.dim, edim);
    380                 return err();
    381             }
    382         }
    383         if (errors)
    384             return err();
    385 
    386         const sz = t.nextOf().size();
    387         if (sz == SIZE_INVALID)
    388             return err();
    389         bool overflow;
    390         const max = mulu(i.dim, sz, overflow);
    391         if (overflow || max >= amax)
    392         {
    393             error(i.loc, "array dimension %llu exceeds max of %llu", ulong(i.dim), ulong(amax / sz));
    394             return err();
    395         }
    396         return i;
    397     }
    398 
    399     Initializer visitExp(ExpInitializer i)
    400     {
    401         //printf("ExpInitializer::semantic(%s), type = %s\n", i.exp.toChars(), t.toChars());
    402         if (needInterpret)
    403             sc = sc.startCTFE();
    404         i.exp = i.exp.expressionSemantic(sc);
    405         i.exp = resolveProperties(sc, i.exp);
    406         if (needInterpret)
    407             sc = sc.endCTFE();
    408         if (i.exp.op == EXP.error)
    409             return err();
    410         uint olderrors = global.errors;
    411 
    412         /* ImportC: convert arrays to pointers, functions to pointers to functions
    413          */
    414         Type tb = t.toBasetype();
    415         if (tb.isTypePointer())
    416             i.exp = i.exp.arrayFuncConv(sc);
    417 
    418         /* Save the expression before ctfe
    419          * Otherwise the error message would contain for example "&[0][0]" instead of "new int"
    420          * Regression: https://issues.dlang.org/show_bug.cgi?id=21687
    421          */
    422         Expression currExp = i.exp;
    423         if (needInterpret)
    424         {
    425             // If the result will be implicitly cast, move the cast into CTFE
    426             // to avoid premature truncation of polysemous types.
    427             // eg real [] x = [1.1, 2.2]; should use real precision.
    428             if (i.exp.implicitConvTo(t) && !(sc.flags & SCOPE.Cfile))
    429             {
    430                 i.exp = i.exp.implicitCastTo(sc, t);
    431             }
    432             if (!global.gag && olderrors != global.errors)
    433             {
    434                 return i;
    435             }
    436             if (sc.flags & SCOPE.Cfile)
    437             {
    438                 /* the interpreter turns (char*)"string" into &"string"[0] which then
    439                  * it cannot interpret. Resolve that case by doing optimize() first
    440                  */
    441                 i.exp = i.exp.optimize(WANTvalue);
    442                 if (i.exp.isSymOffExp())
    443                 {
    444                     /* `static variable cannot be read at compile time`
    445                      * https://issues.dlang.org/show_bug.cgi?id=22513
    446                      * Maybe this would be better addressed in ctfeInterpret()?
    447                      */
    448                     needInterpret = NeedInterpret.INITnointerpret;
    449                 }
    450             }
    451             if (needInterpret)
    452                 i.exp = i.exp.ctfeInterpret();
    453             if (i.exp.op == EXP.voidExpression)
    454                 error(i.loc, "variables cannot be initialized with an expression of type `void`. Use `void` initialization instead.");
    455         }
    456         else
    457         {
    458             i.exp = i.exp.optimize(WANTvalue);
    459         }
    460 
    461         if (!global.gag && olderrors != global.errors)
    462         {
    463             return i; // Failed, suppress duplicate error messages
    464         }
    465         if (i.exp.type.isTypeTuple() && i.exp.type.isTypeTuple().arguments.dim == 0)
    466         {
    467             Type et = i.exp.type;
    468             i.exp = new TupleExp(i.exp.loc, new Expressions());
    469             i.exp.type = et;
    470         }
    471         if (i.exp.op == EXP.type)
    472         {
    473             i.exp.error("initializer must be an expression, not `%s`", i.exp.toChars());
    474             return err();
    475         }
    476         // Make sure all pointers are constants
    477         if (needInterpret && hasNonConstPointers(i.exp))
    478         {
    479             i.exp.error("cannot use non-constant CTFE pointer in an initializer `%s`", currExp.toChars());
    480             return err();
    481         }
    482         Type ti = i.exp.type.toBasetype();
    483         if (i.exp.op == EXP.tuple && i.expandTuples && !i.exp.implicitConvTo(t))
    484         {
    485             return new ExpInitializer(i.loc, i.exp);
    486         }
    487         /* Look for case of initializing a static array with a too-short
    488          * string literal, such as:
    489          *  char[5] foo = "abc";
    490          * Allow this by doing an explicit cast, which will lengthen the string
    491          * literal.
    492          */
    493         if (i.exp.op == EXP.string_ && tb.ty == Tsarray)
    494         {
    495             StringExp se = i.exp.isStringExp();
    496             Type typeb = se.type.toBasetype();
    497             TY tynto = tb.nextOf().ty;
    498             if (!se.committed &&
    499                 (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar &&
    500                 se.numberOfCodeUnits(tynto) < tb.isTypeSArray().dim.toInteger())
    501             {
    502                 i.exp = se.castTo(sc, t);
    503                 goto L1;
    504             }
    505 
    506             /* Lop off terminating 0 of initializer for:
    507              *  static char s[5] = "hello";
    508              */
    509             if (sc.flags & SCOPE.Cfile &&
    510                 typeb.ty == Tsarray &&
    511                 tynto.isSomeChar &&
    512                 tb.isTypeSArray().dim.toInteger() + 1 == typeb.isTypeSArray().dim.toInteger())
    513             {
    514                 i.exp = se.castTo(sc, t);
    515                 goto L1;
    516             }
    517         }
    518         /* C11 6.7.9-14..15
    519          * Initialize an array of unknown size with a string.
    520          * Change to static array of known size
    521          */
    522         if (sc.flags & SCOPE.Cfile && i.exp.isStringExp() &&
    523             tb.isTypeSArray() && tb.isTypeSArray().isIncomplete())
    524         {
    525             StringExp se = i.exp.isStringExp();
    526             auto ts = new TypeSArray(tb.nextOf(), new IntegerExp(Loc.initial, se.len + 1, Type.tsize_t));
    527             t = typeSemantic(ts, Loc.initial, sc);
    528             i.exp.type = t;
    529             tx = t;
    530         }
    531 
    532         // Look for implicit constructor call
    533         if (tb.ty == Tstruct && !(ti.ty == Tstruct && tb.toDsymbol(sc) == ti.toDsymbol(sc)) && !i.exp.implicitConvTo(t))
    534         {
    535             StructDeclaration sd = tb.isTypeStruct().sym;
    536             if (sd.ctor)
    537             {
    538                 // Rewrite as S().ctor(exp)
    539                 Expression e;
    540                 e = new StructLiteralExp(i.loc, sd, null);
    541                 e = new DotIdExp(i.loc, e, Id.ctor);
    542                 e = new CallExp(i.loc, e, i.exp);
    543                 e = e.expressionSemantic(sc);
    544                 if (needInterpret)
    545                     i.exp = e.ctfeInterpret();
    546                 else
    547                     i.exp = e.optimize(WANTvalue);
    548             }
    549             else if (search_function(sd, Id.call))
    550             {
    551                 /* https://issues.dlang.org/show_bug.cgi?id=1547
    552                  *
    553                  * Look for static opCall
    554                  *
    555                  * Rewrite as:
    556                  *  i.exp = typeof(sd).opCall(arguments)
    557                  */
    558 
    559                 Expression e = typeDotIdExp(i.loc, sd.type, Id.call);
    560                 e = new CallExp(i.loc, e, i.exp);
    561                 e = e.expressionSemantic(sc);
    562                 e = resolveProperties(sc, e);
    563                 if (needInterpret)
    564                     i.exp = e.ctfeInterpret();
    565                 else
    566                     i.exp = e.optimize(WANTvalue);
    567             }
    568         }
    569         {
    570         // Look for the case of statically initializing an array
    571         // with a single member.
    572         auto tba = tb.isTypeSArray();
    573         if (tba && !tba.next.equals(ti.toBasetype().nextOf()) && i.exp.implicitConvTo(tba.next))
    574         {
    575             /* If the variable is not actually used in compile time, array creation is
    576              * redundant. So delay it until invocation of toExpression() or toDt().
    577              */
    578             t = tb.nextOf();
    579         }
    580 
    581         auto tta = t.isTypeSArray();
    582         if (i.exp.implicitConvTo(t))
    583         {
    584             i.exp = i.exp.implicitCastTo(sc, t);
    585         }
    586         else if (sc.flags & SCOPE.Cfile && i.exp.isStringExp() &&
    587             tta && (tta.next.ty == Tint8 || tta.next.ty == Tuns8) &&
    588             ti.ty == Tpointer && ti.nextOf().ty == Tchar)
    589         {
    590             /* unsigned char bbb[1] = "";
    591              *   signed char ccc[1] = "";
    592              */
    593             i.exp = i.exp.castTo(sc, t);
    594         }
    595         else
    596         {
    597             // Look for mismatch of compile-time known length to emit
    598             // better diagnostic message, as same as AssignExp::semantic.
    599             if (tba && i.exp.implicitConvTo(tba.next.arrayOf()) > MATCH.nomatch)
    600             {
    601                 uinteger_t dim1 = tba.dim.toInteger();
    602                 uinteger_t dim2 = dim1;
    603                 if (auto ale = i.exp.isArrayLiteralExp())
    604                 {
    605                     dim2 = ale.elements ? ale.elements.dim : 0;
    606                 }
    607                 else if (auto se = i.exp.isSliceExp())
    608                 {
    609                     if (Type tx = toStaticArrayType(se))
    610                         dim2 = tx.isTypeSArray().dim.toInteger();
    611                 }
    612                 if (dim1 != dim2)
    613                 {
    614                     i.exp.error("mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2);
    615                     i.exp = ErrorExp.get();
    616                 }
    617             }
    618             Type et = i.exp.type;
    619             const errors = global.startGagging();
    620             i.exp = i.exp.implicitCastTo(sc, t);
    621             if (global.endGagging(errors))
    622                 currExp.error("cannot implicitly convert expression `%s` of type `%s` to `%s`", currExp.toChars(), et.toChars(), t.toChars());
    623         }
    624         }
    625     L1:
    626         if (i.exp.op == EXP.error)
    627         {
    628             return i;
    629         }
    630         if (needInterpret)
    631             i.exp = i.exp.ctfeInterpret();
    632         else
    633             i.exp = i.exp.optimize(WANTvalue);
    634         //printf("-ExpInitializer::semantic(): "); i.exp.print();
    635         return i;
    636     }
    637 
    638     Initializer visitC(CInitializer ci)
    639     {
    640         if (ci.sem) // if semantic() already run
    641             return ci;
    642         //printf("CInitializer::semantic() (%s) %s\n", t.toChars(), ci.toChars());
    643         ci.sem = true;
    644         t = t.toBasetype();
    645         ci.type = t;    // later passes will need this
    646 
    647         auto dil = ci.initializerList[];
    648         size_t i = 0;   // index into dil[]
    649         const uint amax = 0x8000_0000;
    650         bool errors;
    651 
    652         /* If `{ expression }` return the expression initializer
    653          */
    654         ExpInitializer isBraceExpression()
    655         {
    656             return (dil.length == 1 && !dil[0].designatorList)
    657                     ? dil[0].initializer.isExpInitializer()
    658                     : null;
    659         }
    660 
    661         /* Convert struct initializer into ExpInitializer
    662          */
    663         Initializer structs(TypeStruct ts)
    664         {
    665             //printf("structs %s\n", ts.toChars());
    666             StructDeclaration sd = ts.sym;
    667             sd.size(ci.loc);
    668             if (sd.sizeok != Sizeok.done)
    669             {
    670                 errors = true;
    671                 return err();
    672             }
    673             const nfields = sd.nonHiddenFields();
    674             auto elements = new Expressions(nfields);
    675             auto elems = (*elements)[];
    676             foreach (ref elem; elems)
    677                 elem = null;
    678 
    679           FieldLoop:
    680             for (size_t fieldi = 0; fieldi < nfields; ++fieldi)
    681             {
    682                 if (i == dil.length)
    683                     break;
    684 
    685                 auto di = dil[i];
    686                 if (di.designatorList)
    687                 {
    688                     error(ci.loc, "C designator-list not supported yet");
    689                     errors = true;
    690                     break;
    691                 }
    692 
    693                 VarDeclaration vd = sd.fields[fieldi];
    694 
    695                 // Check for overlapping initializations (can happen with unions)
    696                 foreach (k, v2; sd.fields[0 .. nfields])
    697                 {
    698                     if (vd.isOverlappedWith(v2) && elems[k])
    699                     {
    700                         continue FieldLoop;     // skip it
    701                     }
    702                 }
    703 
    704                 ++i;
    705 
    706                 // Convert initializer to Expression `ex`
    707                 assert(sc);
    708                 auto tm = vd.type.addMod(ts.mod);
    709                 auto iz = di.initializer.initializerSemantic(sc, tm, needInterpret);
    710                 auto ex = iz.initializerToExpression(null, true);
    711                 if (ex.op == EXP.error)
    712                 {
    713                     errors = true;
    714                     continue;
    715                 }
    716 
    717                 elems[fieldi] = ex;
    718             }
    719             if (errors)
    720                 return err();
    721 
    722             // Make a StructLiteralExp out of elements[]
    723             Type tx = ts;
    724             auto sle = new StructLiteralExp(ci.loc, sd, elements, tx);
    725             if (!sd.fill(ci.loc, elements, false))
    726                 return err();
    727             sle.type = tx;
    728             auto ie = new ExpInitializer(ci.loc, sle);
    729             return ie.initializerSemantic(sc, tx, needInterpret);
    730         }
    731 
    732         if (auto ts = t.isTypeStruct())
    733         {
    734             auto ei = structs(ts);
    735             if (errors)
    736                 return err();
    737             if (i < dil.length)
    738             {
    739                 error(ci.loc, "%d extra initializer(s) for `struct %s`", cast(int)(dil.length - i), ts.toChars());
    740                 return err();
    741             }
    742             return ei;
    743         }
    744 
    745         auto tsa = t.isTypeSArray();
    746         if (!tsa)
    747         {
    748             /* Not an array. See if it is `{ exp }` which can be
    749              * converted to an ExpInitializer
    750              */
    751             if (ExpInitializer ei = isBraceExpression())
    752             {
    753                 return ei.initializerSemantic(sc, t, needInterpret);
    754             }
    755 
    756             error(ci.loc, "C non-array initializer (%s) %s not supported yet", t.toChars(), ci.toChars());
    757             return err();
    758         }
    759 
    760         /* If it's an array of integral being initialized by `{ string }`
    761          * replace with `string`
    762          */
    763         auto tn = t.nextOf();
    764         if (tn.isintegral())
    765         {
    766             if (ExpInitializer ei = isBraceExpression())
    767             {
    768                 if (ei.exp.isStringExp())
    769                     return ei.initializerSemantic(sc, t, needInterpret);
    770             }
    771         }
    772 
    773         /* Support recursion to handle un-braced array initializers
    774          * Params:
    775          *    t = element type
    776          *    dim = max number of elements
    777          *    simple = true if array of simple elements
    778          * Returns:
    779          *    # of elements in array
    780          */
    781         size_t array(Type t, size_t dim, ref bool simple)
    782         {
    783             //printf(" type %s i %d dim %d dil.length = %d\n", t.toChars(), cast(int)i, cast(int)dim, cast(int)dil.length);
    784             auto tn = t.nextOf().toBasetype();
    785             auto tnsa = tn.isTypeSArray();
    786             if (tnsa && tnsa.isIncomplete())
    787             {
    788                 // C11 6.2.5-20 "element type shall be complete whenever the array type is specified"
    789                 error(ci.loc, "incomplete element type `%s` not allowed", tnsa.toChars());
    790                 errors = true;
    791                 return 1;
    792             }
    793             if (i == dil.length)
    794                 return 0;
    795             size_t n;
    796             const nelems = tnsa ? cast(size_t)tnsa.dim.toInteger() : 0;
    797 
    798             /* Run initializerSemantic on a single element.
    799              */
    800             Initializer elem(Initializer ie)
    801             {
    802                 ++i;
    803                 auto tnx = tn; // in case initializerSemantic tries to change it
    804                 ie = ie.initializerSemantic(sc, tnx, needInterpret);
    805                 if (ie.isErrorInitializer())
    806                     errors = true;
    807                 assert(tnx == tn); // sub-types should not be modified
    808                 return ie;
    809             }
    810 
    811             foreach (j; 0 .. dim)
    812             {
    813                 auto di = dil[i];
    814                 if (di.designatorList)
    815                 {
    816                     error(ci.loc, "C designator-list not supported yet");
    817                     errors = true;
    818                     break;
    819                 }
    820                 if (tnsa && di.initializer.isExpInitializer())
    821                 {
    822                     // no braces enclosing array initializer, so recurse
    823                     array(tnsa, nelems, simple);
    824                 }
    825                 else if (auto tns = tn.isTypeStruct())
    826                 {
    827                     if (auto ei = di.initializer.isExpInitializer())
    828                     {
    829                         // no braces enclosing struct initializer
    830 
    831                         /* Disambiguate between an exp representing the entire
    832                          * struct, and an exp representing the first field of the struct
    833                         */
    834                         if (needInterpret)
    835                             sc = sc.startCTFE();
    836                         ei.exp = ei.exp.expressionSemantic(sc);
    837                         ei.exp = resolveProperties(sc, ei.exp);
    838                         if (needInterpret)
    839                             sc = sc.endCTFE();
    840                         if (ei.exp.implicitConvTo(tn))
    841                             di.initializer = elem(di.initializer); // the whole struct
    842                         else
    843                         {
    844                             simple = false;
    845                             dil[n].initializer = structs(tns); // the first field
    846                         }
    847                     }
    848                     else
    849                         dil[n].initializer = elem(di.initializer);
    850                 }
    851                 else
    852                 {
    853                     di.initializer = elem(di.initializer);
    854                 }
    855                 ++n;
    856                 if (i == dil.length)
    857                     break;
    858             }
    859             //printf(" n: %d i: %d\n", cast(int)n, cast(int)i);
    860             return n;
    861         }
    862 
    863         size_t dim = tsa.isIncomplete() ? dil.length : cast(size_t)tsa.dim.toInteger();
    864         bool simple = true;
    865         auto newdim = array(t, dim, simple);
    866 
    867         if (errors)
    868             return err();
    869 
    870         if (tsa.isIncomplete()) // array of unknown length
    871         {
    872             // Change to array of known length
    873             tsa = new TypeSArray(tn, new IntegerExp(Loc.initial, newdim, Type.tsize_t));
    874             tx = tsa;       // rewrite caller's type
    875             ci.type = tsa;  // remember for later passes
    876         }
    877         const uinteger_t edim = tsa.dim.toInteger();
    878         if (i < dil.length)
    879         {
    880             error(ci.loc, "%d extra initializer(s) for static array length of %d", cast(int)(dil.length - i), cast(int)edim);
    881             return err();
    882         }
    883 
    884         const sz = tn.size(); // element size
    885         if (sz == SIZE_INVALID)
    886             return err();
    887         bool overflow;
    888         const max = mulu(edim, sz, overflow);
    889         if (overflow || max >= amax)
    890         {
    891             error(ci.loc, "array dimension %llu exceeds max of %llu", ulong(edim), ulong(amax / sz));
    892             return err();
    893         }
    894 
    895         /* If an array of simple elements, replace with an ArrayInitializer
    896          */
    897         auto tnb = tn.toBasetype();
    898         if (!tnb.isTypeSArray() && (!tnb.isTypeStruct() || simple))
    899         {
    900             auto ai = new ArrayInitializer(ci.loc);
    901             ai.dim = cast(uint) dil.length;
    902             ai.index.setDim(dil.length);
    903             ai.value.setDim(dil.length);
    904             foreach (const j; 0 .. dil.length)
    905             {
    906                 ai.index[j] = null;
    907                 ai.value[j] = dil[j].initializer;
    908             }
    909             auto ty = tx;
    910             return ai.initializerSemantic(sc, ty, needInterpret);
    911         }
    912 
    913         if (newdim < ci.initializerList.length && tnb.isTypeStruct())
    914         {
    915             // https://issues.dlang.org/show_bug.cgi?id=22375
    916             // initializerList can be bigger than the number of actual elements
    917             // to initialize for array of structs because it is not required
    918             // for values to have proper bracing.
    919             // i.e: These are all valid initializers for `struct{int a,b;}[3]`:
    920             //      {1,2,3,4}, {{1,2},3,4}, {1,2,{3,4}}, {{1,2},{3,4}}
    921             // In all examples above, the new length of the initializer list
    922             // has been shortened from four elements to two. This is important,
    923             // because `dil` is written back to directly, making the lowered
    924             // initializer `{{1,2},{3,4}}` and not `{{1,2},{3,4},3,4}`.
    925             ci.initializerList.length = newdim;
    926         }
    927 
    928         return ci;
    929     }
    930 
    931     final switch (init.kind)
    932     {
    933         case InitKind.void_:   return visitVoid  (init.isVoidInitializer());
    934         case InitKind.error:   return visitError (init.isErrorInitializer());
    935         case InitKind.struct_: return visitStruct(init.isStructInitializer());
    936         case InitKind.array:   return visitArray (init.isArrayInitializer());
    937         case InitKind.exp:     return visitExp   (init.isExpInitializer());
    938         case InitKind.C_:      return visitC     (init.isCInitializer());
    939     }
    940 }
    941 
    942 /***********************
    943  * Translate init to an `Expression` in order to infer the type.
    944  * Params:
    945  *      init = `Initializer` AST node
    946  *      sc = context
    947  * Returns:
    948  *      an equivalent `ExpInitializer` if successful, or `ErrorInitializer` if it cannot be translated
    949  */
    950 Initializer inferType(Initializer init, Scope* sc)
    951 {
    952     Initializer visitVoid(VoidInitializer i)
    953     {
    954         error(i.loc, "cannot infer type from void initializer");
    955         return new ErrorInitializer();
    956     }
    957 
    958     Initializer visitError(ErrorInitializer i)
    959     {
    960         return i;
    961     }
    962 
    963     Initializer visitStruct(StructInitializer i)
    964     {
    965         error(i.loc, "cannot infer type from struct initializer");
    966         return new ErrorInitializer();
    967     }
    968 
    969     Initializer visitArray(ArrayInitializer init)
    970     {
    971         //printf("ArrayInitializer::inferType() %s\n", toChars());
    972         Expressions* keys = null;
    973         Expressions* values;
    974         if (init.isAssociativeArray())
    975         {
    976             keys = new Expressions(init.value.dim);
    977             values = new Expressions(init.value.dim);
    978             for (size_t i = 0; i < init.value.dim; i++)
    979             {
    980                 Expression e = init.index[i];
    981                 if (!e)
    982                     goto Lno;
    983                 (*keys)[i] = e;
    984                 Initializer iz = init.value[i];
    985                 if (!iz)
    986                     goto Lno;
    987                 iz = iz.inferType(sc);
    988                 if (iz.isErrorInitializer())
    989                 {
    990                     return iz;
    991                 }
    992                 (*values)[i] = iz.isExpInitializer().exp;
    993                 assert(!(*values)[i].isErrorExp());
    994             }
    995             Expression e = new AssocArrayLiteralExp(init.loc, keys, values);
    996             auto ei = new ExpInitializer(init.loc, e);
    997             return ei.inferType(sc);
    998         }
    999         else
   1000         {
   1001             auto elements = new Expressions(init.value.dim);
   1002             elements.zero();
   1003             for (size_t i = 0; i < init.value.dim; i++)
   1004             {
   1005                 assert(!init.index[i]); // already asserted by isAssociativeArray()
   1006                 Initializer iz = init.value[i];
   1007                 if (!iz)
   1008                     goto Lno;
   1009                 iz = iz.inferType(sc);
   1010                 if (iz.isErrorInitializer())
   1011                 {
   1012                     return iz;
   1013                 }
   1014                 (*elements)[i] = iz.isExpInitializer().exp;
   1015                 assert(!(*elements)[i].isErrorExp());
   1016             }
   1017             Expression e = new ArrayLiteralExp(init.loc, null, elements);
   1018             auto ei = new ExpInitializer(init.loc, e);
   1019             return ei.inferType(sc);
   1020         }
   1021     Lno:
   1022         if (keys)
   1023         {
   1024             error(init.loc, "not an associative array initializer");
   1025         }
   1026         else
   1027         {
   1028             error(init.loc, "cannot infer type from array initializer");
   1029         }
   1030         return new ErrorInitializer();
   1031     }
   1032 
   1033     Initializer visitExp(ExpInitializer init)
   1034     {
   1035         //printf("ExpInitializer::inferType() %s\n", init.toChars());
   1036         init.exp = init.exp.expressionSemantic(sc);
   1037 
   1038         // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
   1039         if (init.exp.op == EXP.type)
   1040             init.exp = resolveAliasThis(sc, init.exp);
   1041 
   1042         init.exp = resolveProperties(sc, init.exp);
   1043         if (auto se = init.exp.isScopeExp())
   1044         {
   1045             TemplateInstance ti = se.sds.isTemplateInstance();
   1046             if (ti && ti.semanticRun == PASS.semantic && !ti.aliasdecl)
   1047                 se.error("cannot infer type from %s `%s`, possible circular dependency", se.sds.kind(), se.toChars());
   1048             else
   1049                 se.error("cannot infer type from %s `%s`", se.sds.kind(), se.toChars());
   1050             return new ErrorInitializer();
   1051         }
   1052 
   1053         // Give error for overloaded function addresses
   1054         bool hasOverloads;
   1055         if (auto f = isFuncAddress(init.exp, &hasOverloads))
   1056         {
   1057             if (f.checkForwardRef(init.loc))
   1058             {
   1059                 return new ErrorInitializer();
   1060             }
   1061             if (hasOverloads && !f.isUnique())
   1062             {
   1063                 init.exp.error("cannot infer type from overloaded function symbol `%s`", init.exp.toChars());
   1064                 return new ErrorInitializer();
   1065             }
   1066         }
   1067         if (auto ae = init.exp.isAddrExp())
   1068         {
   1069             if (ae.e1.op == EXP.overloadSet)
   1070             {
   1071                 init.exp.error("cannot infer type from overloaded function symbol `%s`", init.exp.toChars());
   1072                 return new ErrorInitializer();
   1073             }
   1074         }
   1075         if (init.exp.isErrorExp())
   1076         {
   1077             return new ErrorInitializer();
   1078         }
   1079         if (!init.exp.type)
   1080         {
   1081             return new ErrorInitializer();
   1082         }
   1083         return init;
   1084     }
   1085 
   1086     Initializer visitC(CInitializer i)
   1087     {
   1088         //printf("CInitializer.inferType()\n");
   1089         error(i.loc, "TODO C inferType initializers not supported yet");
   1090         return new ErrorInitializer();
   1091     }
   1092 
   1093     final switch (init.kind)
   1094     {
   1095         case InitKind.void_:   return visitVoid  (init.isVoidInitializer());
   1096         case InitKind.error:   return visitError (init.isErrorInitializer());
   1097         case InitKind.struct_: return visitStruct(init.isStructInitializer());
   1098         case InitKind.array:   return visitArray (init.isArrayInitializer());
   1099         case InitKind.exp:     return visitExp   (init.isExpInitializer());
   1100         case InitKind.C_:      return visitC     (init.isCInitializer());
   1101     }
   1102 }
   1103 
   1104 /***********************
   1105  * Translate init to an `Expression`.
   1106  * Params:
   1107  *      init = `Initializer` AST node
   1108  *      itype = if not `null`, type to coerce expression to
   1109  *      isCfile = default initializers are different with C
   1110  * Returns:
   1111  *      `Expression` created, `null` if cannot, `ErrorExp` for other errors
   1112  */
   1113 extern (C++) Expression initializerToExpression(Initializer init, Type itype = null, const bool isCfile = false)
   1114 {
   1115     //printf("initializerToExpression() isCfile: %d\n", isCfile);
   1116 
   1117     Expression visitVoid(VoidInitializer)
   1118     {
   1119         return null;
   1120     }
   1121 
   1122     Expression visitError(ErrorInitializer)
   1123     {
   1124         return ErrorExp.get();
   1125     }
   1126 
   1127     /***************************************
   1128      * This works by transforming a struct initializer into
   1129      * a struct literal. In the future, the two should be the
   1130      * same thing.
   1131      */
   1132     Expression visitStruct(StructInitializer)
   1133     {
   1134         // cannot convert to an expression without target 'ad'
   1135         return null;
   1136     }
   1137 
   1138     /********************************
   1139      * If possible, convert array initializer to array literal.
   1140      * Otherwise return NULL.
   1141      */
   1142     Expression visitArray(ArrayInitializer init)
   1143     {
   1144         //printf("ArrayInitializer::toExpression(), dim = %d\n", dim);
   1145         //static int i; if (++i == 2) assert(0);
   1146         uint edim;      // the length of the resulting array literal
   1147         const(uint) amax = 0x80000000;
   1148         Type t = null;  // type of the array literal being initialized
   1149         if (init.type)
   1150         {
   1151             if (init.type == Type.terror)
   1152             {
   1153                 return ErrorExp.get();
   1154             }
   1155             t = init.type.toBasetype();
   1156             switch (t.ty)
   1157             {
   1158             case Tvector:
   1159                 t = t.isTypeVector().basetype;
   1160                 goto case Tsarray;
   1161 
   1162             case Tsarray:
   1163                 uinteger_t adim = t.isTypeSArray().dim.toInteger();
   1164                 if (adim >= amax)
   1165                     return null;
   1166                 edim = cast(uint)adim;
   1167                 break;
   1168 
   1169             case Tpointer:
   1170             case Tarray:
   1171                 edim = init.dim;
   1172                 break;
   1173 
   1174             default:
   1175                 assert(0);
   1176             }
   1177         }
   1178         else
   1179         {
   1180             /* Calculate the length of the array literal
   1181              */
   1182             edim = cast(uint)init.value.dim;
   1183             size_t j = 0;
   1184             foreach (i; 0 .. init.value.dim)
   1185             {
   1186                 if (auto e = init.index[i])
   1187                 {
   1188                     if (e.op == EXP.int64)
   1189                     {
   1190                         const uinteger_t idxval = e.toInteger();
   1191                         if (idxval >= amax)
   1192                             return null;
   1193                         j = cast(size_t)idxval;
   1194                     }
   1195                     else
   1196                         return null;
   1197                 }
   1198                 ++j;
   1199                 if (j > edim)
   1200                     edim = cast(uint)j;
   1201             }
   1202         }
   1203 
   1204         auto elements = new Expressions(edim);
   1205         elements.zero();
   1206         size_t j = 0;
   1207         foreach (i; 0 .. init.value.dim)
   1208         {
   1209             if (auto e = init.index[i])
   1210                 j = cast(size_t)e.toInteger();
   1211             assert(j < edim);
   1212             if (Initializer iz = init.value[i])
   1213             {
   1214                 if (Expression ex = iz.initializerToExpression(null, isCfile))
   1215                 {
   1216                     (*elements)[j] = ex;
   1217                     ++j;
   1218                 }
   1219                 else
   1220                     return null;
   1221             }
   1222             else
   1223                 return null;
   1224         }
   1225 
   1226         /* Fill in any missing elements with the default initializer
   1227          */
   1228         Expression defaultInit = null;  // lazily create it
   1229         foreach (ref element; (*elements)[0 .. edim])
   1230         {
   1231             if (!element)
   1232             {
   1233                 if (!init.type) // don't know what type to use
   1234                     return null;
   1235                 if (!defaultInit)
   1236                     defaultInit = (cast(TypeNext)t).next.defaultInit(Loc.initial, isCfile);
   1237                 element = defaultInit;
   1238             }
   1239         }
   1240 
   1241         /* Expand any static array initializers that are a single expression
   1242          * into an array of them
   1243          *    e => [e, e, ..., e, e]
   1244          */
   1245         if (t)
   1246         {
   1247             Type tn = t.nextOf().toBasetype();
   1248             if (tn.ty == Tsarray)
   1249             {
   1250                 const dim = cast(size_t)(cast(TypeSArray)tn).dim.toInteger();
   1251                 Type te = tn.nextOf().toBasetype();
   1252                 foreach (ref e; *elements)
   1253                 {
   1254                     if (te.equals(e.type))
   1255                     {
   1256                         auto elements2 = new Expressions(dim);
   1257                         foreach (ref e2; *elements2)
   1258                             e2 = e;
   1259                         e = new ArrayLiteralExp(e.loc, tn, elements2);
   1260                     }
   1261                 }
   1262             }
   1263         }
   1264 
   1265         /* If any elements are errors, then the whole thing is an error
   1266          */
   1267         foreach (e; (*elements)[0 .. edim])
   1268         {
   1269             if (e.op == EXP.error)
   1270             {
   1271                 return e;
   1272             }
   1273         }
   1274 
   1275         Expression e = new ArrayLiteralExp(init.loc, init.type, elements);
   1276         return e;
   1277     }
   1278 
   1279     Expression visitExp(ExpInitializer i)
   1280     {
   1281         if (itype)
   1282         {
   1283             //printf("ExpInitializer::toExpression(t = %s) exp = %s\n", itype.toChars(), i.exp.toChars());
   1284             Type tb = itype.toBasetype();
   1285             Expression e = (i.exp.op == EXP.construct || i.exp.op == EXP.blit) ? (cast(AssignExp)i.exp).e2 : i.exp;
   1286             if (tb.ty == Tsarray && e.implicitConvTo(tb.nextOf()))
   1287             {
   1288                 TypeSArray tsa = cast(TypeSArray)tb;
   1289                 size_t d = cast(size_t)tsa.dim.toInteger();
   1290                 auto elements = new Expressions(d);
   1291                 for (size_t j = 0; j < d; j++)
   1292                     (*elements)[j] = e;
   1293                 auto ae = new ArrayLiteralExp(e.loc, itype, elements);
   1294                 return ae;
   1295             }
   1296         }
   1297         return i.exp;
   1298     }
   1299 
   1300     Expression visitC(CInitializer i)
   1301     {
   1302         //printf("CInitializer.initializerToExpression(null, true)\n");
   1303         return null;
   1304     }
   1305 
   1306     final switch (init.kind)
   1307     {
   1308         case InitKind.void_:   return visitVoid  (init.isVoidInitializer());
   1309         case InitKind.error:   return visitError (init.isErrorInitializer());
   1310         case InitKind.struct_: return visitStruct(init.isStructInitializer());
   1311         case InitKind.array:   return visitArray (init.isArrayInitializer());
   1312         case InitKind.exp:     return visitExp   (init.isExpInitializer());
   1313         case InitKind.C_:      return visitC     (init.isCInitializer());
   1314     }
   1315 }
   1316 
   1317 
   1318 /**************************************
   1319  * Determine if expression has non-constant pointers, or more precisely,
   1320  * a pointer that CTFE cannot handle.
   1321  * Params:
   1322  *    e = expression to check
   1323  * Returns:
   1324  *    true if it has non-constant pointers
   1325  */
   1326 private bool hasNonConstPointers(Expression e)
   1327 {
   1328     static bool checkArray(Expressions* elems)
   1329     {
   1330         foreach (e; *elems)
   1331         {
   1332             if (e && hasNonConstPointers(e))
   1333                 return true;
   1334         }
   1335         return false;
   1336     }
   1337 
   1338     if (e.type.ty == Terror)
   1339         return false;
   1340     if (e.op == EXP.null_)
   1341         return false;
   1342     if (auto se = e.isStructLiteralExp())
   1343     {
   1344         return checkArray(se.elements);
   1345     }
   1346     if (auto ae = e.isArrayLiteralExp())
   1347     {
   1348         if (!ae.type.nextOf().hasPointers())
   1349             return false;
   1350         return checkArray(ae.elements);
   1351     }
   1352     if (auto ae = e.isAssocArrayLiteralExp())
   1353     {
   1354         if (ae.type.nextOf().hasPointers() && checkArray(ae.values))
   1355             return true;
   1356         if (ae.type.isTypeAArray().index.hasPointers())
   1357             return checkArray(ae.keys);
   1358         return false;
   1359     }
   1360     if (auto ae = e.isAddrExp())
   1361     {
   1362         if (ae.type.nextOf().isImmutable() || ae.type.nextOf().isConst())
   1363         {
   1364             return false;
   1365         }
   1366         if (auto se = ae.e1.isStructLiteralExp())
   1367         {
   1368             if (!(se.stageflags & stageSearchPointers))
   1369             {
   1370                 const old = se.stageflags;
   1371                 se.stageflags |= stageSearchPointers;
   1372                 bool ret = checkArray(se.elements);
   1373                 se.stageflags = old;
   1374                 return ret;
   1375             }
   1376             else
   1377             {
   1378                 return false;
   1379             }
   1380         }
   1381         return true;
   1382     }
   1383     if (e.type.ty == Tpointer && !e.type.isPtrToFunction())
   1384     {
   1385         if (e.op == EXP.symbolOffset) // address of a global is OK
   1386             return false;
   1387         if (e.op == EXP.int64) // cast(void *)int is OK
   1388             return false;
   1389         if (e.op == EXP.string_) // "abc".ptr is OK
   1390             return false;
   1391         return true;
   1392     }
   1393     return false;
   1394 }
   1395