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