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