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