2 * Semantic analysis of initializers.
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
14 import core
.stdc
.stdio
;
15 import core
.checkedint
;
19 import dmd
.arraytypes
;
22 import dmd
.declaration
;
28 import dmd
.expression
;
29 import dmd
.expressionsem
;
34 import dmd
.identifier
;
45 /********************************
46 * If possible, convert array initializer to associative array initializer.
49 * ai = array initializer to be converted
52 * The converted associative array initializer or ErrorExp if `ai`
53 * is not an associative array initializer.
55 Expression
toAssocArrayLiteral(ArrayInitializer ai
)
57 //printf("ArrayInitializer::toAssocArrayInitializer(%s)\n", ai.toChars());
58 //static int i; if (++i == 2) assert(0);
59 const dim
= ai
.value
.length
;
62 error(ai
.loc
, "invalid associative array initializer `%s`, use `null` instead",
64 return ErrorExp
.get();
66 auto no(const char* format
, Initializer i
)
68 error(i
.loc
, format
, toChars(i
));
69 return ErrorExp
.get();
72 auto keys
= new Expressions(dim
);
73 auto values
= new Expressions(dim
);
74 for (size_t i
= 0; i
< dim
; i
++)
76 Initializer iz
= ai
.value
[i
];
78 e
= iz
.initializerToExpression();
80 return no("invalid value `%s` in initializer", iz
);
84 return no("missing key for value `%s` in initializer", iz
);
87 e
= new AssocArrayLiteralExp(ai
.loc
, keys
, values
);
91 /******************************************
92 * Perform semantic analysis on init.
94 * init = Initializer AST node
96 * tx = type that the initializer needs to become. If tx is an incomplete
97 * type and the initializer completes it, it is updated to be the
98 * complete type. ImportC has incomplete types
99 * needInterpret = if CTFE needs to be run on this,
100 * such as if it is the initializer for a const declaration
102 * `Initializer` with completed semantic analysis, `ErrorInitializer` if errors
105 extern(C
++) Initializer
initializerSemantic(Initializer init
, Scope
* sc
, ref Type tx
, NeedInterpret needInterpret
)
109 static Initializer
err()
111 return new ErrorInitializer();
114 Initializer
visitVoid(VoidInitializer i
)
120 Initializer
visitError(ErrorInitializer i
)
125 Initializer
visitStruct(StructInitializer i
)
127 //printf("StructInitializer::semantic(t = %s) %s\n", t.toChars(), i.toChars());
128 /* This works by replacing the StructInitializer with an ExpInitializer.
131 if (t
.ty
== Tsarray
&& t
.nextOf().toBasetype().ty
== Tstruct
)
132 t
= t
.nextOf().toBasetype();
133 if (auto ts
= t
.isTypeStruct())
135 StructDeclaration sd
= ts
.sym
;
136 // check if the sd has a regular ctor (user defined non-copy ctor)
137 // that is not disabled.
138 if (sd
.hasRegularCtor(true))
140 error(i
.loc
, "%s `%s` has constructors, cannot use `{ initializers }`, use `%s( initializers )` instead", sd
.kind(), sd
.toChars(), sd
.toChars());
144 if (sd
.sizeok
!= Sizeok
.done
)
147 Expression
getExp(size_t j
, Type fieldType
)
149 // Convert initializer to Expression `ex`
150 auto tm
= fieldType
.addMod(t
.mod
);
151 auto iz
= i
.value
[j
].initializerSemantic(sc
, tm
, needInterpret
);
152 auto ex
= iz
.initializerToExpression(null, (sc
.flags
& SCOPE
.Cfile
) != 0);
153 if (ex
.op
!= EXP
.error
)
157 auto elements
= resolveStructLiteralNamedArgs(sd
, t
, sc
, i
.loc
, i
.field
[], &getExp
, (size_t j
) => i
.value
[j
].loc
);
161 // Make a StructLiteralExp out of elements[]
162 auto sle
= new StructLiteralExp(i
.loc
, sd
, elements
, t
);
163 if (!sd
.fill(i
.loc
, *elements
, false))
166 auto ie
= new ExpInitializer(i
.loc
, sle
);
167 return ie
.initializerSemantic(sc
, t
, needInterpret
);
169 else if ((t
.ty
== Tdelegate || t
.isPtrToFunction()) && i
.value
.length
== 0)
171 const tok
= (t
.ty
== Tdelegate
) ? TOK
.delegate_
: TOK
.function_
;
172 /* Rewrite as empty delegate literal { }
174 Type tf
= new TypeFunction(ParameterList(), null, LINK
.d
);
175 auto fd
= new FuncLiteralDeclaration(i
.loc
, Loc
.initial
, tf
, tok
, null);
176 fd
.fbody
= new CompoundStatement(i
.loc
, new Statements());
178 Expression e
= new FuncExp(i
.loc
, fd
);
179 auto ie
= new ExpInitializer(i
.loc
, e
);
180 return ie
.initializerSemantic(sc
, t
, needInterpret
);
183 error(i
.loc
, "a struct is not a valid initializer for a `%s`", t
.toChars());
187 Initializer
visitArray(ArrayInitializer i
)
190 const(uint) amax
= 0x80000000;
192 //printf("ArrayInitializer::semantic(%s), ai: %s %p\n", t.toChars(), i.toChars(), i);
193 if (i
.sem
) // if semantic() already run
205 t
= t
.isTypeVector().basetype
;
208 case Tstruct
: // consider implicit constructor call
211 // note: MyStruct foo = [1:2, 3:4] is correct code if MyStruct has a this(int[int])
212 if (t
.ty
== Taarray || i
.isAssociativeArray())
213 e
= i
.toAssocArrayLiteral();
215 e
= i
.initializerToExpression();
219 error(i
.loc
, "cannot use array to initialize `%s`", t
.toChars());
222 auto ei
= new ExpInitializer(e
.loc
, e
);
223 return ei
.initializerSemantic(sc
, t
, needInterpret
);
226 if (t
.nextOf().ty
!= Tfunction
)
230 error(i
.loc
, "cannot use array to initialize `%s`", t
.toChars());
235 for (size_t j
= 0; j
< i
.index
.length
; j
++)
237 Expression idx
= i
.index
[j
];
241 idx
= idx
.expressionSemantic(sc
);
243 idx
= idx
.ctfeInterpret();
245 const uinteger_t idxvalue
= idx
.toInteger();
246 if (idxvalue
>= amax
)
248 error(i
.loc
, "array index %llu overflow", idxvalue
);
251 length
= cast(uint)idxvalue
;
252 if (idx
.op
== EXP
.error
)
255 Initializer val
= i
.value
[j
];
256 ExpInitializer ei
= val
.isExpInitializer();
258 ei
.expandTuples
= true;
259 auto tn
= t
.nextOf();
260 val
= val
.initializerSemantic(sc
, tn
, needInterpret
);
261 if (val
.isErrorInitializer())
263 ei
= val
.isExpInitializer();
264 // found a tuple, expand it
265 if (ei
&& ei
.exp
.op
== EXP
.tuple
)
267 TupleExp te
= ei
.exp
.isTupleExp();
270 for (size_t k
= 0; k
< te
.exps
.length
; ++k
)
272 Expression e
= (*te
.exps
)[k
];
273 i
.index
.insert(j
+ k
, cast(Expression
)null);
274 i
.value
.insert(j
+ k
, new ExpInitializer(e
.loc
, e
));
286 error(i
.loc
, "array dimension overflow");
292 if (auto tsa
= t
.isTypeSArray())
294 if (sc
.flags
& SCOPE
.Cfile
&& tsa
.isIncomplete())
296 // Change to array of known length
297 auto tn
= tsa
.next
.toBasetype();
298 tsa
= new TypeSArray(tn
, new IntegerExp(Loc
.initial
, i
.dim
, Type
.tsize_t
));
299 tx
= tsa
; // rewrite caller's type
300 i
.type
= tsa
; // remember for later passes
304 uinteger_t edim
= tsa
.dim
.toInteger();
307 error(i
.loc
, "array initializer has %u elements, but array length is %llu", i
.dim
, edim
);
315 const sz
= t
.nextOf().size();
316 if (sz
== SIZE_INVALID
)
319 const max
= mulu(i
.dim
, sz
, overflow
);
320 if (overflow || max
>= amax
)
322 error(i
.loc
, "array dimension %llu exceeds max of %llu", ulong(i
.dim
), ulong(amax
/ sz
));
325 //printf("returns ai: %s\n", i.toChars());
329 Initializer
visitExp(ExpInitializer i
)
331 //printf("ExpInitializer::semantic(%s), type = %s\n", i.exp.toChars(), t.toChars());
334 i
.exp
= i
.exp
.expressionSemantic(sc
);
335 i
.exp
= resolveProperties(sc
, i
.exp
);
338 if (i
.exp
.op
== EXP
.error
)
340 uint olderrors
= global
.errors
;
342 /* ImportC: convert arrays to pointers, functions to pointers to functions
344 Type tb
= t
.toBasetype();
345 if (tb
.isTypePointer())
346 i
.exp
= i
.exp
.arrayFuncConv(sc
);
348 /* Save the expression before ctfe
349 * Otherwise the error message would contain for example "&[0][0]" instead of "new int"
350 * Regression: https://issues.dlang.org/show_bug.cgi?id=21687
352 Expression currExp
= i
.exp
;
355 // If the result will be implicitly cast, move the cast into CTFE
356 // to avoid premature truncation of polysemous types.
357 // eg real [] x = [1.1, 2.2]; should use real precision.
358 if (i
.exp
.implicitConvTo(t
) && !(sc
.flags
& SCOPE
.Cfile
))
360 i
.exp
= i
.exp
.implicitCastTo(sc
, t
);
362 if (!global
.gag
&& olderrors
!= global
.errors
)
366 if (sc
.flags
& SCOPE
.Cfile
)
368 /* the interpreter turns (char*)"string" into &"string"[0] which then
369 * it cannot interpret. Resolve that case by doing optimize() first
371 i
.exp
= i
.exp
.optimize(WANTvalue
);
372 if (i
.exp
.isSymOffExp())
374 /* `static variable cannot be read at compile time`
375 * https://issues.dlang.org/show_bug.cgi?id=22513
376 * Maybe this would be better addressed in ctfeInterpret()?
378 needInterpret
= NeedInterpret
.INITnointerpret
;
382 i
.exp
= i
.exp
.ctfeInterpret();
383 if (i
.exp
.op
== EXP
.voidExpression
)
384 error(i
.loc
, "variables cannot be initialized with an expression of type `void`. Use `void` initialization instead.");
388 i
.exp
= i
.exp
.optimize(WANTvalue
);
391 if (!global
.gag
&& olderrors
!= global
.errors
)
393 return i
; // Failed, suppress duplicate error messages
395 if (i
.exp
.type
.isTypeTuple() && i
.exp
.type
.isTypeTuple().arguments
.length
== 0)
397 Type et
= i
.exp
.type
;
398 i
.exp
= new TupleExp(i
.exp
.loc
, new Expressions());
401 if (i
.exp
.op
== EXP
.type
)
403 error(i
.exp
.loc
, "initializer must be an expression, not `%s`", i
.exp
.toChars());
406 // Make sure all pointers are constants
407 if (needInterpret
&& hasNonConstPointers(i
.exp
))
409 error(i
.exp
.loc
, "cannot use non-constant CTFE pointer in an initializer `%s`", currExp
.toChars());
412 Type ti
= i
.exp
.type
.toBasetype();
413 if (i
.exp
.op
== EXP
.tuple
&& i
.expandTuples
&& !i
.exp
.implicitConvTo(t
))
415 return new ExpInitializer(i
.loc
, i
.exp
);
417 /* Look for case of initializing a static array with a too-short
418 * string literal, such as:
419 * char[5] foo = "abc";
420 * Allow this by doing an explicit cast, which will lengthen the string
423 if (i
.exp
.op
== EXP
.string_
&& tb
.ty
== Tsarray
)
425 StringExp se
= i
.exp
.isStringExp();
426 Type typeb
= se
.type
.toBasetype();
427 TY tynto
= tb
.nextOf().ty
;
429 (typeb
.ty
== Tarray || typeb
.ty
== Tsarray
) && tynto
.isSomeChar
&&
430 se
.numberOfCodeUnits(tynto
) < tb
.isTypeSArray().dim
.toInteger())
432 i
.exp
= se
.castTo(sc
, t
);
436 /* Lop off terminating 0 of initializer for:
437 * static char s[5] = "hello";
439 if (sc
.flags
& SCOPE
.Cfile
&&
440 typeb
.ty
== Tsarray
&&
442 tb
.isTypeSArray().dim
.toInteger() + 1 == typeb
.isTypeSArray().dim
.toInteger())
444 i
.exp
= se
.castTo(sc
, t
);
449 * Initialize an array of unknown size with a string.
450 * Change to static array of known size
452 if (sc
.flags
& SCOPE
.Cfile
&& i
.exp
.isStringExp() &&
453 tb
.isTypeSArray() && tb
.isTypeSArray().isIncomplete())
455 StringExp se
= i
.exp
.isStringExp();
456 auto ts
= new TypeSArray(tb
.nextOf(), new IntegerExp(Loc
.initial
, se
.len
+ 1, Type
.tsize_t
));
457 t
= typeSemantic(ts
, Loc
.initial
, sc
);
462 // Look for implicit constructor call
463 if (tb
.ty
== Tstruct
&& !(ti
.ty
== Tstruct
&& tb
.toDsymbol(sc
) == ti
.toDsymbol(sc
)) && !i
.exp
.implicitConvTo(t
))
465 StructDeclaration sd
= tb
.isTypeStruct().sym
;
468 // Rewrite as S().ctor(exp)
470 e
= new StructLiteralExp(i
.loc
, sd
, null);
471 e
= new DotIdExp(i
.loc
, e
, Id
.ctor
);
472 e
= new CallExp(i
.loc
, e
, i
.exp
);
473 e
= e
.expressionSemantic(sc
);
475 i
.exp
= e
.ctfeInterpret();
477 i
.exp
= e
.optimize(WANTvalue
);
479 else if (search_function(sd
, Id
.call))
481 /* https://issues.dlang.org/show_bug.cgi?id=1547
483 * Look for static opCall
486 * i.exp = typeof(sd).opCall(arguments)
489 Expression e
= typeDotIdExp(i
.loc
, sd
.type
, Id
.call);
490 e
= new CallExp(i
.loc
, e
, i
.exp
);
491 e
= e
.expressionSemantic(sc
);
492 e
= resolveProperties(sc
, e
);
494 i
.exp
= e
.ctfeInterpret();
496 i
.exp
= e
.optimize(WANTvalue
);
500 // Look for the case of statically initializing an array with a single member.
501 // Recursively strip static array / enum layers until a compatible element is found,
502 // and return an `ArrayLiteralExp` repeating the initializer, or `null` if no match found
503 // int[2][3] = 7 => [[7, 7], [7, 7], [7, 7]]
504 // int[2] = new Object => null
505 Expression
sarrayRepeat(Type tb
)
507 auto tsa
= tb
.isTypeSArray();
511 // printf("i.exp = %s, tsa = %s\n", i.exp.toChars(), tsa.toChars());
512 Expression elem
= null;
513 if (i
.exp
.implicitConvTo(tb
.nextOf()))
514 elem
= i
.exp
.implicitCastTo(sc
, tb
.nextOf());
515 else if (auto ae
= sarrayRepeat(tb
.nextOf().toBasetype()))
520 auto arrayElements
= new Expressions(cast(size_t
) tsa
.dim
.toInteger());
521 foreach (ref e
; *arrayElements
)
523 return new ArrayLiteralExp(i
.exp
.loc
, tb
, elem
, arrayElements
);
526 if (auto sa
= sarrayRepeat(tb
))
528 // printf("sa = %s\n", sa.toChars());
533 auto tta
= t
.isTypeSArray();
534 if (i
.exp
.implicitConvTo(t
))
536 i
.exp
= i
.exp
.implicitCastTo(sc
, t
);
538 else if (sc
.flags
& SCOPE
.Cfile
&& i
.exp
.isStringExp() &&
539 tta
&& (tta
.next
.ty
== Tint8 || tta
.next
.ty
== Tuns8
) &&
540 ti
.ty
== Tsarray
&& ti
.nextOf().ty
== Tchar
)
542 /* unsigned char bbb[1] = "";
543 * signed char ccc[1] = "";
545 i
.exp
= i
.exp
.castTo(sc
, t
);
549 auto tba
= tb
.isTypeSArray();
550 // Look for mismatch of compile-time known length to emit
551 // better diagnostic message, as same as AssignExp::semantic.
552 if (tba
&& i
.exp
.implicitConvTo(tba
.next
.arrayOf()) > MATCH
.nomatch
)
554 uinteger_t dim1
= tba
.dim
.toInteger();
555 uinteger_t dim2
= dim1
;
556 if (auto ale
= i
.exp
.isArrayLiteralExp())
558 dim2
= ale
.elements ? ale
.elements
.length
: 0;
560 else if (auto se
= i
.exp
.isSliceExp())
562 if (Type tx
= toStaticArrayType(se
))
563 dim2
= tx
.isTypeSArray().dim
.toInteger();
567 error(i
.exp
.loc
, "mismatched array lengths, %d and %d", cast(int)dim1
, cast(int)dim2
);
568 i
.exp
= ErrorExp
.get();
571 Type et
= i
.exp
.type
;
572 const errors
= global
.startGagging();
573 i
.exp
= i
.exp
.implicitCastTo(sc
, t
);
574 if (global
.endGagging(errors
))
575 error(currExp
.loc
, "cannot implicitly convert expression `%s` of type `%s` to `%s`", currExp
.toChars(), et
.toChars(), t
.toChars());
579 if (i
.exp
.op
== EXP
.error
)
584 i
.exp
= i
.exp
.ctfeInterpret();
586 i
.exp
= i
.exp
.optimize(WANTvalue
);
587 //printf("-ExpInitializer::semantic(): "); i.exp.print();
591 Initializer
visitC(CInitializer ci
)
593 //printf("CInitializer::semantic() tx: %s t: %s ci: %s\n", (tx ? tx.toChars() : "".ptr), t.toChars(), ci.toChars());
594 /* Rewrite CInitializer into ExpInitializer, ArrayInitializer, or StructInitializer
598 if (auto tv
= t
.isTypeVector())
601 /* If `{ expression }` return the expression initializer
603 ExpInitializer
isBraceExpression()
605 auto dil
= ci
.initializerList
[];
606 return (dil
.length
== 1 && !dil
[0].designatorList
)
607 ? dil
[0].initializer
.isExpInitializer()
611 /********************************
613 bool overlaps(VarDeclaration field
, VarDeclaration
[] fields
, StructInitializer si
)
615 foreach (fld; fields
)
617 if (field
.isOverlappedWith(fld))
619 // look for initializer corresponding with fld
620 foreach (i
, ident
; si
.field
[])
622 if (ident
== fld.ident
&& si
.value
[i
])
623 return true; // already an initializer for `field`
630 /* Run semantic on ExpInitializer, see if it represents entire struct ts
632 bool representsStruct(ExpInitializer ei
, TypeStruct ts
)
636 ei
.exp
= ei
.exp
.expressionSemantic(sc
);
637 ei
.exp
= resolveProperties(sc
, ei
.exp
);
640 return ei
.exp
.implicitConvTo(ts
) != MATCH
.nomatch
; // initializer represents the entire struct
643 /* If { } are omitted from substructs, use recursion to reconstruct where
646 * ts = substruct to initialize
647 * index = index into ci.initializer, updated
648 * Returns: struct initializer for this substruct
650 Initializer
subStruct()(TypeStruct ts
, ref size_t index
)
652 //printf("subStruct(ts: %s, index %d)\n", ts.toChars(), cast(int)index);
654 auto si
= new StructInitializer(ci
.loc
);
655 StructDeclaration sd
= ts
.sym
;
657 if (sd
.sizeok
!= Sizeok
.done
)
659 index
= ci
.initializerList
.length
;
662 const nfields
= sd
.fields
.length
;
664 foreach (fieldi
; 0 .. nfields
)
666 if (index
>= ci
.initializerList
.length
)
667 break; // ran out of initializers
668 auto di = ci
.initializerList
[index
];
669 if (di.designatorList
&& fieldi
!= 0)
670 break; // back to top level
673 VarDeclaration field
;
674 while (1) // skip field if it overlaps with previously seen fields
676 field
= sd
.fields
[fieldi
];
678 if (!overlaps(field
, sd
.fields
[], si
))
680 if (fieldi
== nfields
)
683 auto tn
= field
.type
.toBasetype();
684 auto tnsa
= tn
.isTypeSArray();
685 auto tns
= tn
.isTypeStruct();
686 auto ix
= di.initializer
;
687 if (tnsa
&& ix
.isExpInitializer())
689 ExpInitializer ei
= ix
.isExpInitializer();
690 if (ei
.exp
.isStringExp() && tnsa
.nextOf().isintegral())
692 si
.addInit(field
.ident
, ei
);
696 si
.addInit(field
.ident
, subArray(tnsa
, index
)); // fwd ref of subArray is why subStruct is a template
698 else if (tns
&& ix
.isExpInitializer())
700 /* Disambiguate between an exp representing the entire
701 * struct, and an exp representing the first field of the struct
703 if (representsStruct(ix
.isExpInitializer(), tns
)) // initializer represents the entire struct
705 si
.addInit(field
.ident
, initializerSemantic(ix
, sc
, tn
, needInterpret
));
708 else // field initializers for struct
709 si
.addInit(field
.ident
, subStruct(tns
, index
)); // the first field
713 si
.addInit(field
.ident
, ix
);
718 //printf("subStruct() returns ai: %s, index: %d\n", si.toChars(), cast(int)index);
722 /* If { } are omitted from subarrays, use recursion to reconstruct where
725 * tsa = subarray to initialize
726 * index = index into ci.initializer, updated
727 * Returns: array initializer for this subarray
729 Initializer
subArray(TypeSArray tsa
, ref size_t index
)
731 //printf("array(tsa: %s, index %d)\n", tsa.toChars(), cast(int)index);
732 if (tsa
.isIncomplete())
734 // C11 6.2.5-20 "element type shall be complete whenever the array type is specified"
735 assert(0); // should have been detected by parser
738 auto tnsa
= tsa
.nextOf().toBasetype().isTypeSArray();
740 auto ai
= new ArrayInitializer(ci
.loc
);
743 foreach (n
; 0 .. cast(size_t
)tsa
.dim
.toInteger())
745 if (index
>= ci
.initializerList
.length
)
746 break; // ran out of initializers
747 auto di = ci
.initializerList
[index
];
748 if (di.designatorList
)
749 break; // back to top level
750 else if (tnsa
&& di.initializer
.isExpInitializer())
752 ExpInitializer ei
= di.initializer
.isExpInitializer();
753 if (ei
.exp
.isStringExp() && tnsa
.nextOf().isintegral())
755 ai
.addInit(null, ei
);
759 ai
.addInit(null, subArray(tnsa
, index
));
763 ai
.addInit(null, di.initializer
);
767 //printf("array() returns ai: %s, index: %d\n", ai.toChars(), cast(int)index);
771 if (auto ts
= t
.isTypeStruct())
773 auto si
= new StructInitializer(ci
.loc
);
774 StructDeclaration sd
= ts
.sym
;
775 sd
.size(ci
.loc
); // run semantic() on sd to get fields
776 if (sd
.sizeok
!= Sizeok
.done
)
780 const nfields
= sd
.fields
.length
;
784 for (size_t index
= 0; index
< ci
.initializerList
.length
; )
788 DesigInit
di = ci
.initializerList
[index
];
789 Designators
* dlist
= di.designatorList
;
792 const length
= (*dlist
).length
;
793 if (length
== 0 ||
!(*dlist
)[0].ident
)
795 error(ci
.loc
, "`.identifier` expected for C struct field initializer `%s`", toChars(ci
));
800 error(ci
.loc
, "only 1 designator currently allowed for C struct field initializer `%s`", toChars(ci
));
803 auto id
= (*dlist
)[0].ident
;
804 foreach (k
, f
; sd
.fields
[]) // linear search for now
809 si
.addInit(id
, di.initializer
);
817 /* The peeling didn't work, so unpeel it
820 di = ci
.initializerList
[index
];
823 error(ci
.loc
, "`.%s` is not a field of `%s`\n", id
.toChars(), sd
.toChars());
828 if (fieldi
== nfields
)
830 if (index
== 0 && ci
.initializerList
.length
== 1 && di.initializer
.isCInitializer())
832 /* Try peeling off this set of { } and see if it works
835 ci
= di.initializer
.isCInitializer();
840 VarDeclaration field
;
841 while (1) // skip field if it overlaps with previously seen fields
843 field
= sd
.fields
[fieldi
];
845 if (!overlaps(field
, sd
.fields
[], si
))
847 if (fieldi
== nfields
)
850 auto tn
= field
.type
.toBasetype();
851 auto tnsa
= tn
.isTypeSArray();
852 auto tns
= tn
.isTypeStruct();
853 auto ix
= di.initializer
;
854 if (tnsa
&& ix
.isExpInitializer())
856 ExpInitializer ei
= ix
.isExpInitializer();
857 if (ei
.exp
.isStringExp() && tnsa
.nextOf().isintegral())
859 si
.addInit(field
.ident
, ei
);
863 si
.addInit(field
.ident
, subArray(tnsa
, index
));
865 else if (tns
&& ix
.isExpInitializer())
867 /* Disambiguate between an exp representing the entire
868 * struct, and an exp representing the first field of the struct
870 if (representsStruct(ix
.isExpInitializer(), tns
)) // initializer represents the entire struct
872 si
.addInit(field
.ident
, initializerSemantic(ix
, sc
, tn
, needInterpret
));
875 else // field initializers for struct
876 si
.addInit(field
.ident
, subStruct(tns
, index
)); // the first field
880 si
.addInit(field
.ident
, di.initializer
);
885 return initializerSemantic(si
, sc
, t
, needInterpret
);
887 else if (auto ta
= t
.isTypeSArray())
889 auto tn
= t
.nextOf().toBasetype(); // element type of array
891 /* If it's an array of integral being initialized by `{ string }`
892 * replace with `string`
896 if (ExpInitializer ei
= isBraceExpression())
898 if (ei
.exp
.isStringExp())
899 return ei
.initializerSemantic(sc
, t
, needInterpret
);
903 auto tnsa
= tn
.isTypeSArray(); // array of array
904 auto tns
= tn
.isTypeStruct(); // array of struct
906 auto ai
= new ArrayInitializer(ci
.loc
);
908 for (size_t index
= 0; index
< ci
.initializerList
.length
; )
910 auto di = ci
.initializerList
[index
];
911 if (auto dlist
= di.designatorList
)
913 const length
= (*dlist
).length
;
914 if (length
== 0 ||
!(*dlist
)[0].exp
)
916 error(ci
.loc
, "`[ constant-expression ]` expected for C array element initializer `%s`", toChars(ci
));
921 error(ci
.loc
, "only 1 designator currently allowed for C array element initializer `%s`", toChars(ci
));
924 //printf("tn: %s, di.initializer: %s\n", tn.toChars(), di.initializer.toChars());
925 auto ix
= di.initializer
;
926 if (tnsa
&& ix
.isExpInitializer())
928 // Wrap initializer in [ ]
929 auto ain
= new ArrayInitializer(ci
.loc
);
930 ain
.addInit(null, di.initializer
);
932 ai
.addInit((*dlist
)[0].exp
, initializerSemantic(ix
, sc
, tn
, needInterpret
));
935 else if (tns
&& ix
.isExpInitializer())
937 /* Disambiguate between an exp representing the entire
938 * struct, and an exp representing the first field of the struct
940 if (representsStruct(ix
.isExpInitializer(), tns
)) // initializer represents the entire struct
942 ai
.addInit((*dlist
)[0].exp
, initializerSemantic(ix
, sc
, tn
, needInterpret
));
945 else // field initializers for struct
946 ai
.addInit((*dlist
)[0].exp
, subStruct(tns
, index
)); // the first field
950 ai
.addInit((*dlist
)[0].exp
, initializerSemantic(ix
, sc
, tn
, needInterpret
));
954 else if (tnsa
&& di.initializer
.isExpInitializer())
956 ExpInitializer ei
= di.initializer
.isExpInitializer();
957 if (ei
.exp
.isStringExp() && tnsa
.nextOf().isintegral())
959 ai
.addInit(null, ei
);
963 ai
.addInit(null, subArray(tnsa
, index
));
965 else if (tns
&& di.initializer
.isExpInitializer())
967 /* Disambiguate between an exp representing the entire
968 * struct, and an exp representing the first field of the struct
970 if (representsStruct(di.initializer
.isExpInitializer(), tns
)) // initializer represents the entire struct
972 ai
.addInit(null, initializerSemantic(di.initializer
, sc
, tn
, needInterpret
));
975 else // field initializers for struct
976 ai
.addInit(null, subStruct(tns
, index
)); // the first field
980 ai
.addInit(null, initializerSemantic(di.initializer
, sc
, tn
, needInterpret
));
984 return initializerSemantic(ai
, sc
, tx
, needInterpret
);
986 else if (ExpInitializer ei
= isBraceExpression())
992 error(ci
.loc
, "unrecognized C initializer `%s`", toChars(ci
));
997 mixin VisitInitializer
!Initializer visit
;
998 auto result
= visit
.VisitInitializer(init
);
999 return (result
!is null) ? result
: new ErrorInitializer();
1002 /***********************
1003 * Translate init to an `Expression` in order to infer the type.
1005 * init = `Initializer` AST node
1008 * an equivalent `ExpInitializer` if successful, or `ErrorInitializer` if it cannot be translated
1010 Initializer
inferType(Initializer init
, Scope
* sc
)
1012 Initializer
visitVoid(VoidInitializer i
)
1014 error(i
.loc
, "cannot infer type from void initializer");
1015 return new ErrorInitializer();
1018 Initializer
visitError(ErrorInitializer i
)
1023 Initializer
visitStruct(StructInitializer i
)
1025 error(i
.loc
, "cannot infer type from struct initializer");
1026 return new ErrorInitializer();
1029 Initializer
visitArray(ArrayInitializer init
)
1031 //printf("ArrayInitializer::inferType() %s\n", toChars());
1032 Expressions
* keys
= null;
1033 Expressions
* values
;
1034 if (init
.isAssociativeArray())
1036 keys
= new Expressions(init
.value
.length
);
1037 values
= new Expressions(init
.value
.length
);
1038 for (size_t i
= 0; i
< init
.value
.length
; i
++)
1040 Expression e
= init
.index
[i
];
1044 Initializer iz
= init
.value
[i
];
1047 iz
= iz
.inferType(sc
);
1048 if (iz
.isErrorInitializer())
1052 (*values
)[i
] = iz
.isExpInitializer().exp
;
1053 assert(!(*values
)[i
].isErrorExp());
1055 Expression e
= new AssocArrayLiteralExp(init
.loc
, keys
, values
);
1056 auto ei
= new ExpInitializer(init
.loc
, e
);
1057 return ei
.inferType(sc
);
1061 auto elements
= new Expressions(init
.value
.length
);
1063 for (size_t i
= 0; i
< init
.value
.length
; i
++)
1065 assert(!init
.index
[i
]); // already asserted by isAssociativeArray()
1066 Initializer iz
= init
.value
[i
];
1069 iz
= iz
.inferType(sc
);
1070 if (iz
.isErrorInitializer())
1074 (*elements
)[i
] = iz
.isExpInitializer().exp
;
1075 assert(!(*elements
)[i
].isErrorExp());
1077 Expression e
= new ArrayLiteralExp(init
.loc
, null, elements
);
1078 auto ei
= new ExpInitializer(init
.loc
, e
);
1079 return ei
.inferType(sc
);
1084 error(init
.loc
, "not an associative array initializer");
1088 error(init
.loc
, "cannot infer type from array initializer");
1090 return new ErrorInitializer();
1093 Initializer
visitExp(ExpInitializer init
)
1095 //printf("ExpInitializer::inferType() %s\n", init.toChars());
1096 init
.exp
= init
.exp
.expressionSemantic(sc
);
1098 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
1099 if (init
.exp
.op
== EXP
.type
)
1100 init
.exp
= resolveAliasThis(sc
, init
.exp
);
1102 init
.exp
= resolveProperties(sc
, init
.exp
);
1103 if (auto se
= init
.exp
.isScopeExp())
1105 TemplateInstance ti
= se
.sds
.isTemplateInstance();
1106 if (ti
&& ti
.semanticRun
== PASS
.semantic
&& !ti
.aliasdecl
)
1107 error(se
.loc
, "cannot infer type from %s `%s`, possible circular dependency", se
.sds
.kind(), se
.toChars());
1109 error(se
.loc
, "cannot infer type from %s `%s`", se
.sds
.kind(), se
.toChars());
1110 return new ErrorInitializer();
1113 // Give error for overloaded function addresses
1115 if (auto f
= isFuncAddress(init
.exp
, &hasOverloads
))
1117 if (f
.checkForwardRef(init
.loc
))
1119 return new ErrorInitializer();
1121 if (hasOverloads
&& !f
.isUnique())
1123 error(init
.exp
.loc
, "cannot infer type from overloaded function symbol `%s`", init
.exp
.toChars());
1124 return new ErrorInitializer();
1127 if (auto ae
= init
.exp
.isAddrExp())
1129 if (ae
.e1
.op
== EXP
.overloadSet
)
1131 error(init
.exp
.loc
, "cannot infer type from overloaded function symbol `%s`", init
.exp
.toChars());
1132 return new ErrorInitializer();
1135 if (init
.exp
.isErrorExp())
1137 return new ErrorInitializer();
1141 return new ErrorInitializer();
1146 Initializer
visitC(CInitializer i
)
1148 //printf("CInitializer.inferType()\n");
1149 error(i
.loc
, "TODO C inferType initializers not supported yet");
1150 return new ErrorInitializer();
1153 mixin VisitInitializer
!Initializer visit
;
1154 auto result
= visit
.VisitInitializer(init
);
1155 return (result
!is null) ? result
: new ErrorInitializer();
1158 /***********************
1159 * Translate init to an `Expression`.
1161 * init = `Initializer` AST node
1162 * itype = if not `null`, type to coerce expression to
1163 * isCfile = default initializers are different with C
1165 * `Expression` created, `null` if cannot, `ErrorExp` for other errors
1167 extern (C
++) Expression
initializerToExpression(Initializer init
, Type itype
= null, const bool isCfile
= false)
1169 //printf("initializerToExpression() isCfile: %d\n", isCfile);
1171 Expression
visitVoid(VoidInitializer
)
1176 Expression
visitError(ErrorInitializer
)
1178 return ErrorExp
.get();
1181 /***************************************
1182 * This works by transforming a struct initializer into
1183 * a struct literal. In the future, the two should be the
1186 Expression
visitStruct(StructInitializer
)
1188 // cannot convert to an expression without target 'ad'
1192 /********************************
1193 * If possible, convert array initializer to array literal.
1194 * Otherwise return NULL.
1196 Expression
visitArray(ArrayInitializer init
)
1198 //printf("ArrayInitializer::toExpression(), dim = %d\n", dim);
1199 //static int i; if (++i == 2) assert(0);
1200 uint edim
; // the length of the resulting array literal
1201 const(uint) amax
= 0x80000000;
1202 Type t
= null; // type of the array literal being initialized
1205 if (init
.type
== Type
.terror
)
1207 return ErrorExp
.get();
1209 t
= init
.type
.toBasetype();
1213 t
= t
.isTypeVector().basetype
;
1217 uinteger_t adim
= t
.isTypeSArray().dim
.toInteger();
1220 edim
= cast(uint)adim
;
1234 /* Calculate the length of the array literal
1236 edim
= cast(uint)init
.value
.length
;
1238 foreach (i
; 0 .. init
.value
.length
)
1240 if (auto e
= init
.index
[i
])
1242 if (e
.op
== EXP
.int64
)
1244 const uinteger_t idxval
= e
.toInteger();
1247 j
= cast(size_t
)idxval
;
1258 auto elements
= new Expressions(edim
);
1261 foreach (i
; 0 .. init
.value
.length
)
1263 if (auto e
= init
.index
[i
])
1264 j
= cast(size_t
)e
.toInteger();
1266 if (Initializer iz
= init
.value
[i
])
1268 if (Expression ex
= iz
.initializerToExpression(null, isCfile
))
1270 (*elements
)[j
] = ex
;
1280 /* Fill in any missing elements with the default initializer
1282 Expression defaultInit
= null; // lazily create it
1283 foreach (ref element
; (*elements
)[0 .. edim
])
1287 if (!init
.type
) // don't know what type to use
1290 defaultInit
= (cast(TypeNext
)t
).next
.defaultInit(Loc
.initial
, isCfile
);
1291 element
= defaultInit
;
1295 /* Expand any static array initializers that are a single expression
1296 * into an array of them
1297 * e => [e, e, ..., e, e]
1301 Type tn
= t
.nextOf().toBasetype();
1302 if (tn
.ty
== Tsarray
)
1304 const dim
= cast(size_t
)(cast(TypeSArray
)tn
).dim
.toInteger();
1305 Type te
= tn
.nextOf().toBasetype();
1306 foreach (ref e
; *elements
)
1308 if (te
.equals(e
.type
))
1310 auto elements2
= new Expressions(dim
);
1311 foreach (ref e2
; *elements2
)
1313 e
= new ArrayLiteralExp(e
.loc
, tn
, elements2
);
1319 /* If any elements are errors, then the whole thing is an error
1321 foreach (e
; (*elements
)[0 .. edim
])
1323 if (e
.op
== EXP
.error
)
1329 Expression e
= new ArrayLiteralExp(init
.loc
, init
.type
, elements
);
1333 Expression
visitExp(ExpInitializer i
)
1337 //printf("ExpInitializer::toExpression(t = %s) exp = %s\n", itype.toChars(), i.exp.toChars());
1338 Type tb
= itype
.toBasetype();
1339 Expression e
= (i
.exp
.op
== EXP
.construct || i
.exp
.op
== EXP
.blit
) ?
(cast(AssignExp
)i
.exp
).e2
: i
.exp
;
1340 if (tb
.ty
== Tsarray
&& e
.implicitConvTo(tb
.nextOf()))
1342 TypeSArray tsa
= cast(TypeSArray
)tb
;
1343 size_t d
= cast(size_t
)tsa
.dim
.toInteger();
1344 auto elements
= new Expressions(d
);
1345 for (size_t j
= 0; j
< d
; j
++)
1347 auto ae
= new ArrayLiteralExp(e
.loc
, itype
, elements
);
1354 Expression
visitC(CInitializer i
)
1356 //printf("CInitializer.initializerToExpression(null, true)\n");
1360 mixin VisitInitializer
!Expression visit
;
1361 return visit
.VisitInitializer(init
);
1365 /**************************************
1366 * Determine if expression has non-constant pointers, or more precisely,
1367 * a pointer that CTFE cannot handle.
1369 * e = expression to check
1371 * true if it has non-constant pointers
1373 private bool hasNonConstPointers(Expression e
)
1375 static bool checkArray(Expressions
* elems
)
1379 if (e
&& hasNonConstPointers(e
))
1385 if (e
.type
.ty
== Terror
)
1387 if (e
.op
== EXP
.null_
)
1389 if (auto se
= e
.isStructLiteralExp())
1391 return checkArray(se
.elements
);
1393 if (auto ae
= e
.isArrayLiteralExp())
1395 if (!ae
.type
.nextOf().hasPointers())
1397 return checkArray(ae
.elements
);
1399 if (auto ae
= e
.isAssocArrayLiteralExp())
1401 if (ae
.type
.nextOf().hasPointers() && checkArray(ae
.values
))
1403 if (ae
.type
.isTypeAArray().index
.hasPointers())
1404 return checkArray(ae
.keys
);
1407 if (auto ae
= e
.isAddrExp())
1409 if (ae
.type
.nextOf().isImmutable() || ae
.type
.nextOf().isConst())
1413 if (auto se
= ae
.e1
.isStructLiteralExp())
1415 if (!(se
.stageflags
& stageSearchPointers
))
1417 const old
= se
.stageflags
;
1418 se
.stageflags |
= stageSearchPointers
;
1419 bool ret = checkArray(se
.elements
);
1420 se
.stageflags
= old
;
1430 if (e
.type
.ty
== Tpointer
&& !e
.type
.isPtrToFunction())
1432 if (e
.op
== EXP
.symbolOffset
) // address of a global is OK
1434 if (e
.op
== EXP
.int64
) // cast(void *)int is OK
1436 if (e
.op
== EXP
.string_
) // "abc".ptr is OK
1444 Given the names and values of a `StructInitializer` or `CallExp`,
1445 resolve it to a list of expressions to construct a `StructLiteralExp`.
1449 t = type of struct (potentially including qualifiers such as `const` or `immutable`)
1450 sc = scope of the expression initializing the struct
1451 iloc = location of expression initializing the struct
1452 names = identifiers passed in argument list, `null` entries for positional arguments
1453 getExp = function that, given an index into `names` and destination type, returns the initializing expression
1454 getLoc = function that, given an index into `names`, returns a location for error messages
1456 Returns: list of expressions ordered to the struct's fields, or `null` on error
1458 Expressions
* resolveStructLiteralNamedArgs(StructDeclaration sd
, Type t
, Scope
* sc
,
1459 Loc iloc
, Identifier
[] names
, scope Expression
delegate(size_t i
, Type fieldType
) getExp
,
1460 scope Loc
delegate(size_t i
) getLoc
1463 //expandTuples for non-identity arguments?
1464 const nfields
= sd
.nonHiddenFields();
1465 auto elements
= new Expressions(nfields
);
1466 auto elems
= (*elements
)[];
1467 foreach (ref elem
; elems
)
1470 // Run semantic for explicitly given initializers
1471 // TODO: this part is slightly different from StructLiteralExp::semantic.
1472 bool errors
= false;
1474 foreach (j
, id
; names
)
1476 const argLoc
= getLoc(j
);
1479 // Determine `fieldi` that `id` matches
1480 Dsymbol s
= sd
.search(iloc
, id
);
1483 s
= sd
.search_correct(id
);
1485 error(argLoc
, "`%s` is not a member of `%s`, did you mean %s `%s`?", id
.toChars(), sd
.toChars(), s
.kind(), s
.toChars());
1487 error(argLoc
, "`%s` is not a member of `%s`", id
.toChars(), sd
.toChars());
1490 s
.checkDeprecated(iloc
, sc
);
1493 // Find out which field index `s` is
1494 for (fieldi
= 0; 1; fieldi
++)
1496 if (fieldi
>= nfields
)
1498 error(iloc
, "`%s.%s` is not a per-instance initializable field", sd
.toChars(), s
.toChars());
1501 if (s
== sd
.fields
[fieldi
])
1507 error(argLoc
, "initializer provided for struct `%s` with no fields", sd
.toChars());
1512 error(argLoc
, "too many initializers for `%s` with %d field%s", sd
.toChars(),
1513 cast(int) nfields
, nfields
!= 1 ?
"s".ptr
: "".ptr
);
1517 VarDeclaration vd
= sd
.fields
[fieldi
];
1520 error(argLoc
, "duplicate initializer for field `%s`", vd
.toChars());
1522 elems
[fieldi
] = ErrorExp
.get(); // for better diagnostics on multiple errors
1527 // Check for @safe violations
1528 if (vd
.type
.hasPointers
)
1530 if ((!t
.alignment
.isDefault() && t
.alignment
.get() < target
.ptrsize ||
1531 (vd
.offset
& (target
.ptrsize
- 1))))
1533 if (sc
.setUnsafe(false, argLoc
,
1534 "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd
, vd
))
1537 elems
[fieldi
] = ErrorExp
.get(); // for better diagnostics on multiple errors
1544 // Check for overlapping initializations (can happen with unions)
1545 foreach (k
, v2
; sd
.fields
[0 .. nfields
])
1547 if (vd
.isOverlappedWith(v2
) && elems
[k
])
1549 error(elems
[k
].loc
, "overlapping initialization for field `%s` and `%s`", v2
.toChars(), vd
.toChars());
1550 enum errorMsg
= "`struct` initializers that contain anonymous unions" ~
1551 " must initialize only the first member of a `union`. All subsequent" ~
1552 " non-overlapping fields are default initialized";
1553 if (!sd
.isUnionDeclaration())
1554 .errorSupplemental(elems
[k
].loc
, errorMsg
);
1562 auto ex
= getExp(j
, vd
.type
);
1564 if (ex
.op
== EXP
.error
)
1567 elems
[fieldi
] = ErrorExp
.get(); // for better diagnostics on multiple errors
1572 elems
[fieldi
] = doCopyOrMove(sc
, ex
);