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
;
23 import dmd
.dinterpret
;
27 import dmd
.dsymbolsem
;
30 import dmd
.expression
;
31 import dmd
.expressionsem
;
36 import dmd
.identifier
;
48 /********************************
49 * If possible, convert array initializer to associative array initializer.
52 * ai = array initializer to be converted
55 * The converted associative array initializer or ErrorExp if `ai`
56 * is not an associative array initializer.
58 Expression
toAssocArrayLiteral(ArrayInitializer ai
)
60 //printf("ArrayInitializer::toAssocArrayInitializer(%s)\n", ai.toChars());
61 //static int i; if (++i == 2) assert(0);
62 const dim
= ai
.value
.length
;
65 error(ai
.loc
, "invalid associative array initializer `%s`, use `null` instead",
67 return ErrorExp
.get();
69 auto no(const char* format
, Initializer i
)
71 error(i
.loc
, format
, toChars(i
));
72 return ErrorExp
.get();
75 auto keys
= new Expressions(dim
);
76 auto values
= new Expressions(dim
);
77 for (size_t i
= 0; i
< dim
; i
++)
79 Initializer iz
= ai
.value
[i
];
81 e
= iz
.initializerToExpression();
83 return no("invalid value `%s` in initializer", iz
);
87 return no("missing key for value `%s` in initializer", iz
);
90 e
= new AssocArrayLiteralExp(ai
.loc
, keys
, values
);
94 /******************************************
95 * Perform semantic analysis on init.
97 * init = Initializer AST node
99 * tx = type that the initializer needs to become. If tx is an incomplete
100 * type and the initializer completes it, it is updated to be the
101 * complete type. ImportC has incomplete types
102 * needInterpret = if CTFE needs to be run on this,
103 * such as if it is the initializer for a const declaration
105 * `Initializer` with completed semantic analysis, `ErrorInitializer` if errors
108 extern(C
++) Initializer
initializerSemantic(Initializer init
, Scope
* sc
, ref Type tx
, NeedInterpret needInterpret
)
110 //printf("initializerSemantic() tx: %p %s\n", tx, tx.toChars());
113 static Initializer
err()
115 return new ErrorInitializer();
118 Initializer
visitVoid(VoidInitializer i
)
124 Initializer
visitDefault(DefaultInitializer i
)
130 Initializer
visitError(ErrorInitializer i
)
135 Initializer
visitStruct(StructInitializer i
)
137 //printf("StructInitializer::semantic(t = %s) %s\n", t.toChars(), i.toChars());
138 /* This works by replacing the StructInitializer with an ExpInitializer.
141 if (t
.ty
== Tsarray
&& t
.nextOf().toBasetype().ty
== Tstruct
)
142 t
= t
.nextOf().toBasetype();
143 if (auto ts
= t
.isTypeStruct())
145 StructDeclaration sd
= ts
.sym
;
146 // check if the sd has a regular ctor (user defined non-copy ctor)
147 // that is not disabled.
148 if (sd
.hasRegularCtor(true))
150 error(i
.loc
, "%s `%s` has constructors, cannot use `{ initializers }`, use `%s( initializers )` instead", sd
.kind(), sd
.toChars(), sd
.toChars());
154 if (sd
.sizeok
!= Sizeok
.done
)
157 Expression
getExp(size_t j
, Type fieldType
)
159 // Convert initializer to Expression `ex`
160 auto tm
= fieldType
.addMod(t
.mod
);
161 auto iz
= i
.value
[j
].initializerSemantic(sc
, tm
, needInterpret
);
162 auto ex
= iz
.initializerToExpression(null, (sc
.flags
& SCOPE
.Cfile
) != 0);
163 if (ex
.op
!= EXP
.error
)
167 auto elements
= resolveStructLiteralNamedArgs(sd
, t
, sc
, i
.loc
, i
.field
[], &getExp
, (size_t j
) => i
.value
[j
].loc
);
171 // Make a StructLiteralExp out of elements[]
172 auto sle
= new StructLiteralExp(i
.loc
, sd
, elements
, t
);
173 if (!sd
.fill(i
.loc
, *elements
, false))
176 auto ie
= new ExpInitializer(i
.loc
, sle
);
177 return ie
.initializerSemantic(sc
, t
, needInterpret
);
179 else if ((t
.ty
== Tdelegate || t
.isPtrToFunction()) && i
.value
.length
== 0)
181 const tok
= (t
.ty
== Tdelegate
) ? TOK
.delegate_
: TOK
.function_
;
182 /* Rewrite as empty delegate literal { }
184 Type tf
= new TypeFunction(ParameterList(), null, LINK
.d
);
185 auto fd
= new FuncLiteralDeclaration(i
.loc
, Loc
.initial
, tf
, tok
, null);
186 fd
.fbody
= new CompoundStatement(i
.loc
, new Statements());
188 Expression e
= new FuncExp(i
.loc
, fd
);
189 auto ie
= new ExpInitializer(i
.loc
, e
);
190 return ie
.initializerSemantic(sc
, t
, needInterpret
);
193 error(i
.loc
, "a struct is not a valid initializer for a `%s`", t
.toChars());
197 Initializer
visitArray(ArrayInitializer i
)
200 const(uint) amax
= 0x80000000;
202 //printf("ArrayInitializer::semantic(%s), ai: %s %p\n", t.toChars(), i.toChars(), i);
203 if (i
.sem
) // if semantic() already run
215 t
= t
.isTypeVector().basetype
;
218 case Tstruct
: // consider implicit constructor call
221 // note: MyStruct foo = [1:2, 3:4] is correct code if MyStruct has a this(int[int])
222 if (t
.ty
== Taarray || i
.isAssociativeArray())
223 e
= i
.toAssocArrayLiteral();
225 e
= i
.initializerToExpression();
229 error(i
.loc
, "cannot use array to initialize `%s`", t
.toChars());
232 auto ei
= new ExpInitializer(e
.loc
, e
);
233 return ei
.initializerSemantic(sc
, t
, needInterpret
);
236 if (t
.nextOf().ty
!= Tfunction
)
240 error(i
.loc
, "cannot use array to initialize `%s`", t
.toChars());
245 for (size_t j
= 0; j
< i
.index
.length
; j
++)
247 Expression idx
= i
.index
[j
];
251 idx
= idx
.expressionSemantic(sc
);
253 idx
= idx
.ctfeInterpret();
255 const uinteger_t idxvalue
= idx
.toInteger();
256 if (idxvalue
>= amax
)
258 error(i
.loc
, "array index %llu overflow", idxvalue
);
261 length
= cast(uint)idxvalue
;
262 if (idx
.op
== EXP
.error
)
265 Initializer val
= i
.value
[j
];
266 ExpInitializer ei
= val
.isExpInitializer();
268 ei
.expandTuples
= true;
269 auto tn
= t
.nextOf();
270 val
= val
.initializerSemantic(sc
, tn
, needInterpret
);
271 if (val
.isErrorInitializer())
273 ei
= val
.isExpInitializer();
274 // found a tuple, expand it
275 if (ei
&& ei
.exp
.op
== EXP
.tuple
)
277 TupleExp te
= ei
.exp
.isTupleExp();
280 for (size_t k
= 0; k
< te
.exps
.length
; ++k
)
282 Expression e
= (*te
.exps
)[k
];
283 i
.index
.insert(j
+ k
, cast(Expression
)null);
284 i
.value
.insert(j
+ k
, new ExpInitializer(e
.loc
, e
));
296 error(i
.loc
, "array dimension overflow");
302 if (auto tsa
= t
.isTypeSArray())
304 if (sc
.flags
& SCOPE
.Cfile
&& tsa
.isIncomplete())
306 // Change to array of known length
307 auto tn
= tsa
.next
.toBasetype();
308 tsa
= new TypeSArray(tn
, new IntegerExp(Loc
.initial
, i
.dim
, Type
.tsize_t
));
309 tx
= tsa
; // rewrite caller's type
310 i
.type
= tsa
; // remember for later passes
314 uinteger_t edim
= tsa
.dim
.toInteger();
317 error(i
.loc
, "array initializer has %u elements, but array length is %llu", i
.dim
, edim
);
325 const sz
= t
.nextOf().size();
326 if (sz
== SIZE_INVALID
)
329 const max
= mulu(i
.dim
, sz
, overflow
);
330 if (overflow || max
>= amax
)
332 error(i
.loc
, "array dimension %llu exceeds max of %llu", ulong(i
.dim
), ulong(amax
/ sz
));
335 //printf("returns ai: %s\n", i.toChars());
339 Initializer
visitExp(ExpInitializer i
)
341 //printf("ExpInitializer::semantic(%s), type = %s\n", i.exp.toChars(), t.toChars());
344 i
.exp
= i
.exp
.expressionSemantic(sc
);
345 i
.exp
= resolveProperties(sc
, i
.exp
);
348 if (i
.exp
.op
== EXP
.error
)
350 uint olderrors
= global
.errors
;
352 /* ImportC: convert arrays to pointers, functions to pointers to functions
354 Type tb
= t
.toBasetype();
355 if (tb
.isTypePointer())
356 i
.exp
= i
.exp
.arrayFuncConv(sc
);
358 /* Save the expression before ctfe
359 * Otherwise the error message would contain for example "&[0][0]" instead of "new int"
360 * Regression: https://issues.dlang.org/show_bug.cgi?id=21687
362 Expression currExp
= i
.exp
;
365 // If the result will be implicitly cast, move the cast into CTFE
366 // to avoid premature truncation of polysemous types.
367 // eg real [] x = [1.1, 2.2]; should use real precision.
368 if (i
.exp
.implicitConvTo(t
) && !(sc
.flags
& SCOPE
.Cfile
))
370 i
.exp
= i
.exp
.implicitCastTo(sc
, t
);
372 if (!global
.gag
&& olderrors
!= global
.errors
)
376 if (sc
.flags
& SCOPE
.Cfile
)
378 /* the interpreter turns (char*)"string" into &"string"[0] which then
379 * it cannot interpret. Resolve that case by doing optimize() first
381 i
.exp
= i
.exp
.optimize(WANTvalue
);
382 if (i
.exp
.isSymOffExp())
384 /* `static variable cannot be read at compile time`
385 * https://issues.dlang.org/show_bug.cgi?id=22513
386 * Maybe this would be better addressed in ctfeInterpret()?
388 needInterpret
= NeedInterpret
.INITnointerpret
;
392 i
.exp
= i
.exp
.ctfeInterpret();
393 if (i
.exp
.op
== EXP
.voidExpression
)
394 error(i
.loc
, "variables cannot be initialized with an expression of type `void`. Use `void` initialization instead.");
398 i
.exp
= i
.exp
.optimize(WANTvalue
);
401 if (!global
.gag
&& olderrors
!= global
.errors
)
403 return i
; // Failed, suppress duplicate error messages
405 if (i
.exp
.type
.isTypeTuple() && i
.exp
.type
.isTypeTuple().arguments
.length
== 0)
407 Type et
= i
.exp
.type
;
408 i
.exp
= new TupleExp(i
.exp
.loc
, new Expressions());
411 if (i
.exp
.op
== EXP
.type
)
413 error(i
.exp
.loc
, "initializer must be an expression, not `%s`", i
.exp
.toChars());
416 // Make sure all pointers are constants
417 if (needInterpret
&& hasNonConstPointers(i
.exp
))
419 error(i
.exp
.loc
, "cannot use non-constant CTFE pointer in an initializer `%s`", currExp
.toChars());
422 Type ti
= i
.exp
.type
.toBasetype();
423 if (i
.exp
.op
== EXP
.tuple
&& i
.expandTuples
&& !i
.exp
.implicitConvTo(t
))
425 return new ExpInitializer(i
.loc
, i
.exp
);
427 /* Look for case of initializing a static array with a too-short
428 * string literal, such as:
429 * char[5] foo = "abc";
430 * Allow this by doing an explicit cast, which will lengthen the string
433 if (i
.exp
.op
== EXP
.string_
&& tb
.ty
== Tsarray
)
435 StringExp se
= i
.exp
.isStringExp();
436 Type typeb
= se
.type
.toBasetype();
437 TY tynto
= tb
.nextOf().ty
;
439 (typeb
.ty
== Tarray || typeb
.ty
== Tsarray
) && tynto
.isSomeChar
&&
440 se
.numberOfCodeUnits(tynto
) < tb
.isTypeSArray().dim
.toInteger())
442 i
.exp
= se
.castTo(sc
, t
);
446 /* Lop off terminating 0 of initializer for:
447 * static char s[5] = "hello";
449 if (sc
.flags
& SCOPE
.Cfile
&&
450 typeb
.ty
== Tsarray
&&
452 tb
.isTypeSArray().dim
.toInteger() + 1 == typeb
.isTypeSArray().dim
.toInteger())
454 i
.exp
= se
.castTo(sc
, t
);
459 * Initialize an array of unknown size with a string.
460 * Change to static array of known size
462 if (sc
.flags
& SCOPE
.Cfile
&& i
.exp
.isStringExp() &&
463 tb
.isTypeSArray() && tb
.isTypeSArray().isIncomplete())
465 StringExp se
= i
.exp
.isStringExp();
466 auto ts
= new TypeSArray(tb
.nextOf(), new IntegerExp(Loc
.initial
, se
.len
+ 1, Type
.tsize_t
));
467 t
= typeSemantic(ts
, Loc
.initial
, sc
);
472 // Look for implicit constructor call
473 if (tb
.ty
== Tstruct
&& !(ti
.ty
== Tstruct
&& tb
.toDsymbol(sc
) == ti
.toDsymbol(sc
)) && !i
.exp
.implicitConvTo(t
))
475 StructDeclaration sd
= tb
.isTypeStruct().sym
;
478 // Rewrite as S().ctor(exp)
480 e
= new StructLiteralExp(i
.loc
, sd
, null);
481 e
= new DotIdExp(i
.loc
, e
, Id
.ctor
);
482 e
= new CallExp(i
.loc
, e
, i
.exp
);
483 e
= e
.expressionSemantic(sc
);
485 i
.exp
= e
.ctfeInterpret();
487 i
.exp
= e
.optimize(WANTvalue
);
489 else if (search_function(sd
, Id
.call))
491 /* https://issues.dlang.org/show_bug.cgi?id=1547
493 * Look for static opCall
496 * i.exp = typeof(sd).opCall(arguments)
499 Expression e
= typeDotIdExp(i
.loc
, sd
.type
, Id
.call);
500 e
= new CallExp(i
.loc
, e
, i
.exp
);
501 e
= e
.expressionSemantic(sc
);
502 e
= resolveProperties(sc
, e
);
504 i
.exp
= e
.ctfeInterpret();
506 i
.exp
= e
.optimize(WANTvalue
);
510 // Look for the case of statically initializing an array with a single member.
511 // Recursively strip static array / enum layers until a compatible element is found,
512 // and return an `ArrayLiteralExp` repeating the initializer, or `null` if no match found
513 // int[2][3] = 7 => [[7, 7], [7, 7], [7, 7]]
514 // int[2] = new Object => null
515 Expression
sarrayRepeat(Type tb
)
517 auto tsa
= tb
.isTypeSArray();
521 // printf("i.exp = %s, tsa = %s\n", i.exp.toChars(), tsa.toChars());
522 Expression elem
= null;
523 if (i
.exp
.implicitConvTo(tb
.nextOf()))
524 elem
= i
.exp
.implicitCastTo(sc
, tb
.nextOf());
525 else if (auto ae
= sarrayRepeat(tb
.nextOf().toBasetype()))
530 auto arrayElements
= new Expressions(cast(size_t
) tsa
.dim
.toInteger());
531 foreach (ref e
; *arrayElements
)
533 return new ArrayLiteralExp(i
.exp
.loc
, tb
, elem
, arrayElements
);
536 if (auto sa
= sarrayRepeat(tb
))
538 // printf("sa = %s\n", sa.toChars());
543 auto tta
= t
.isTypeSArray();
544 if (i
.exp
.implicitConvTo(t
))
546 i
.exp
= i
.exp
.implicitCastTo(sc
, t
);
548 else if (sc
.flags
& SCOPE
.Cfile
&& i
.exp
.isStringExp() &&
549 tta
&& (tta
.next
.ty
== Tint8 || tta
.next
.ty
== Tuns8
) &&
550 ti
.ty
== Tsarray
&& ti
.nextOf().ty
== Tchar
)
552 /* unsigned char bbb[1] = "";
553 * signed char ccc[1] = "";
555 i
.exp
= i
.exp
.castTo(sc
, t
);
559 auto tba
= tb
.isTypeSArray();
560 // Look for mismatch of compile-time known length to emit
561 // better diagnostic message, as same as AssignExp::semantic.
562 if (tba
&& i
.exp
.implicitConvTo(tba
.next
.arrayOf()) > MATCH
.nomatch
)
564 uinteger_t dim1
= tba
.dim
.toInteger();
565 uinteger_t dim2
= dim1
;
566 if (auto ale
= i
.exp
.isArrayLiteralExp())
568 dim2
= ale
.elements ? ale
.elements
.length
: 0;
570 else if (auto se
= i
.exp
.isSliceExp())
572 if (Type tx
= toStaticArrayType(se
))
573 dim2
= tx
.isTypeSArray().dim
.toInteger();
577 error(i
.exp
.loc
, "mismatched array lengths, %d and %d", cast(int)dim1
, cast(int)dim2
);
578 i
.exp
= ErrorExp
.get();
581 Type et
= i
.exp
.type
;
582 const errors
= global
.startGagging();
583 i
.exp
= i
.exp
.implicitCastTo(sc
, t
);
584 if (global
.endGagging(errors
))
585 error(currExp
.loc
, "cannot implicitly convert expression `%s` of type `%s` to `%s`", currExp
.toChars(), et
.toChars(), t
.toChars());
589 if (i
.exp
.op
== EXP
.error
)
594 i
.exp
= i
.exp
.ctfeInterpret();
596 i
.exp
= i
.exp
.optimize(WANTvalue
);
597 //printf("-ExpInitializer::semantic(): "); i.exp.print();
601 Initializer
visitC(CInitializer ci
)
603 //printf("CInitializer::semantic() tx: %s t: %s ci: %s\n", (tx ? tx.toChars() : "".ptr), t.toChars(), ci.toChars());
604 /* Rewrite CInitializer into ExpInitializer, ArrayInitializer, or StructInitializer
608 if (auto tv
= t
.isTypeVector())
611 /* If `{ expression }` return the expression initializer
613 ExpInitializer
isBraceExpression()
615 auto dil
= ci
.initializerList
[];
616 return (dil
.length
== 1 && !dil
[0].designatorList
)
617 ? dil
[0].initializer
.isExpInitializer()
621 /********************************
623 bool overlaps(VarDeclaration field
, VarDeclaration
[] fields
, StructInitializer si
)
625 foreach (fld; fields
)
627 if (field
.isOverlappedWith(fld))
629 // look for initializer corresponding with fld
630 foreach (i
, ident
; si
.field
[])
632 if (ident
== fld.ident
&& si
.value
[i
])
633 return true; // already an initializer for `field`
640 /* Run semantic on ExpInitializer, see if it represents entire struct ts
642 bool representsStruct(ExpInitializer ei
, TypeStruct ts
)
646 ei
.exp
= ei
.exp
.expressionSemantic(sc
);
647 ei
.exp
= resolveProperties(sc
, ei
.exp
);
650 return ei
.exp
.implicitConvTo(ts
) != MATCH
.nomatch
; // initializer represents the entire struct
653 /* If { } are omitted from substructs, use recursion to reconstruct where
656 * ts = substruct to initialize
657 * index = index into ci.initializer, updated
658 * Returns: struct initializer for this substruct
660 Initializer
subStruct()(TypeStruct ts
, ref size_t index
)
662 //printf("subStruct(ts: %s, index %d)\n", ts.toChars(), cast(int)index);
664 auto si
= new StructInitializer(ci
.loc
);
665 StructDeclaration sd
= ts
.sym
;
667 if (sd
.sizeok
!= Sizeok
.done
)
669 index
= ci
.initializerList
.length
;
672 const nfields
= sd
.fields
.length
;
674 foreach (fieldi
; 0 .. nfields
)
676 if (index
>= ci
.initializerList
.length
)
677 break; // ran out of initializers
678 auto di = ci
.initializerList
[index
];
679 if (di.designatorList
&& fieldi
!= 0)
680 break; // back to top level
683 VarDeclaration field
;
684 while (1) // skip field if it overlaps with previously seen fields
686 field
= sd
.fields
[fieldi
];
688 if (!overlaps(field
, sd
.fields
[], si
))
690 if (fieldi
== nfields
)
693 auto tn
= field
.type
.toBasetype();
694 auto tnsa
= tn
.isTypeSArray();
695 auto tns
= tn
.isTypeStruct();
696 auto ix
= di.initializer
;
697 if (tnsa
&& ix
.isExpInitializer())
699 ExpInitializer ei
= ix
.isExpInitializer();
700 if (ei
.exp
.isStringExp() && tnsa
.nextOf().isintegral())
702 si
.addInit(field
.ident
, ei
);
706 si
.addInit(field
.ident
, subArray(tnsa
, index
)); // fwd ref of subArray is why subStruct is a template
708 else if (tns
&& ix
.isExpInitializer())
710 /* Disambiguate between an exp representing the entire
711 * struct, and an exp representing the first field of the struct
713 if (representsStruct(ix
.isExpInitializer(), tns
)) // initializer represents the entire struct
715 si
.addInit(field
.ident
, initializerSemantic(ix
, sc
, tn
, needInterpret
));
718 else // field initializers for struct
719 si
.addInit(field
.ident
, subStruct(tns
, index
)); // the first field
723 si
.addInit(field
.ident
, ix
);
728 //printf("subStruct() returns ai: %s, index: %d\n", si.toChars(), cast(int)index);
732 /* If { } are omitted from subarrays, use recursion to reconstruct where
735 * tsa = subarray to initialize
736 * index = index into ci.initializer, updated
737 * Returns: array initializer for this subarray
739 Initializer
subArray(TypeSArray tsa
, ref size_t index
)
741 //printf("array(tsa: %s, index %d)\n", tsa.toChars(), cast(int)index);
742 if (tsa
.isIncomplete())
744 // C11 6.2.5-20 "element type shall be complete whenever the array type is specified"
745 assert(0); // should have been detected by parser
748 auto tnsa
= tsa
.nextOf().toBasetype().isTypeSArray();
750 auto ai
= new ArrayInitializer(ci
.loc
);
753 foreach (n
; 0 .. cast(size_t
)tsa
.dim
.toInteger())
755 if (index
>= ci
.initializerList
.length
)
756 break; // ran out of initializers
757 auto di = ci
.initializerList
[index
];
758 if (di.designatorList
)
759 break; // back to top level
760 else if (tnsa
&& di.initializer
.isExpInitializer())
762 ExpInitializer ei
= di.initializer
.isExpInitializer();
763 if (ei
.exp
.isStringExp() && tnsa
.nextOf().isintegral())
765 ai
.addInit(null, ei
);
769 ai
.addInit(null, subArray(tnsa
, index
));
773 ai
.addInit(null, di.initializer
);
777 //printf("array() returns ai: %s, index: %d\n", ai.toChars(), cast(int)index);
781 if (auto ts
= t
.isTypeStruct())
783 auto si
= new StructInitializer(ci
.loc
);
784 StructDeclaration sd
= ts
.sym
;
785 sd
.size(ci
.loc
); // run semantic() on sd to get fields
786 if (sd
.sizeok
!= Sizeok
.done
)
790 const nfields
= sd
.fields
.length
;
794 for (size_t index
= 0; index
< ci
.initializerList
.length
; )
798 DesigInit
di = ci
.initializerList
[index
];
799 Designators
* dlist
= di.designatorList
;
802 const length
= (*dlist
).length
;
803 if (length
== 0 ||
!(*dlist
)[0].ident
)
805 error(ci
.loc
, "`.identifier` expected for C struct field initializer `%s`", toChars(ci
));
810 error(ci
.loc
, "only 1 designator currently allowed for C struct field initializer `%s`", toChars(ci
));
813 auto id
= (*dlist
)[0].ident
;
814 foreach (k
, f
; sd
.fields
[]) // linear search for now
819 si
.addInit(id
, di.initializer
);
827 /* The peeling didn't work, so unpeel it
830 di = ci
.initializerList
[index
];
833 error(ci
.loc
, "`.%s` is not a field of `%s`\n", id
.toChars(), sd
.toChars());
838 if (fieldi
== nfields
)
840 if (index
== 0 && ci
.initializerList
.length
== 1 && di.initializer
.isCInitializer())
842 /* Try peeling off this set of { } and see if it works
845 ci
= di.initializer
.isCInitializer();
850 VarDeclaration field
;
851 while (1) // skip field if it overlaps with previously seen fields
853 field
= sd
.fields
[fieldi
];
855 if (!overlaps(field
, sd
.fields
[], si
))
857 if (fieldi
== nfields
)
860 auto tn
= field
.type
.toBasetype();
861 auto tnsa
= tn
.isTypeSArray();
862 auto tns
= tn
.isTypeStruct();
863 auto ix
= di.initializer
;
864 if (tnsa
&& ix
.isExpInitializer())
866 ExpInitializer ei
= ix
.isExpInitializer();
867 if (ei
.exp
.isStringExp() && tnsa
.nextOf().isintegral())
869 si
.addInit(field
.ident
, ei
);
873 si
.addInit(field
.ident
, subArray(tnsa
, index
));
875 else if (tns
&& ix
.isExpInitializer())
877 /* Disambiguate between an exp representing the entire
878 * struct, and an exp representing the first field of the struct
880 if (representsStruct(ix
.isExpInitializer(), tns
)) // initializer represents the entire struct
882 si
.addInit(field
.ident
, initializerSemantic(ix
, sc
, tn
, needInterpret
));
885 else // field initializers for struct
886 si
.addInit(field
.ident
, subStruct(tns
, index
)); // the first field
890 si
.addInit(field
.ident
, di.initializer
);
895 return initializerSemantic(si
, sc
, t
, needInterpret
);
897 else if (auto ta
= t
.isTypeSArray())
899 auto tn
= t
.nextOf().toBasetype(); // element type of array
901 /* If it's an array of integral being initialized by `{ string }`
902 * replace with `string`
906 if (ExpInitializer ei
= isBraceExpression())
908 if (ei
.exp
.isStringExp())
909 return ei
.initializerSemantic(sc
, t
, needInterpret
);
913 auto tnsa
= tn
.isTypeSArray(); // array of array
914 auto tns
= tn
.isTypeStruct(); // array of struct
916 auto ai
= new ArrayInitializer(ci
.loc
);
918 for (size_t index
= 0; index
< ci
.initializerList
.length
; )
920 auto di = ci
.initializerList
[index
];
921 if (auto dlist
= di.designatorList
)
923 const length
= (*dlist
).length
;
924 if (length
== 0 ||
!(*dlist
)[0].exp
)
926 error(ci
.loc
, "`[ constant-expression ]` expected for C array element initializer `%s`", toChars(ci
));
931 error(ci
.loc
, "only 1 designator currently allowed for C array element initializer `%s`", toChars(ci
));
934 //printf("tn: %s, di.initializer: %s\n", tn.toChars(), di.initializer.toChars());
935 auto ix
= di.initializer
;
936 if (tnsa
&& ix
.isExpInitializer())
938 // Wrap initializer in [ ]
939 auto ain
= new ArrayInitializer(ci
.loc
);
940 ain
.addInit(null, di.initializer
);
942 ai
.addInit((*dlist
)[0].exp
, initializerSemantic(ix
, sc
, tn
, needInterpret
));
945 else if (tns
&& ix
.isExpInitializer())
947 /* Disambiguate between an exp representing the entire
948 * struct, and an exp representing the first field of the struct
950 if (representsStruct(ix
.isExpInitializer(), tns
)) // initializer represents the entire struct
952 ai
.addInit((*dlist
)[0].exp
, initializerSemantic(ix
, sc
, tn
, needInterpret
));
955 else // field initializers for struct
956 ai
.addInit((*dlist
)[0].exp
, subStruct(tns
, index
)); // the first field
960 ai
.addInit((*dlist
)[0].exp
, initializerSemantic(ix
, sc
, tn
, needInterpret
));
964 else if (tnsa
&& di.initializer
.isExpInitializer())
966 ExpInitializer ei
= di.initializer
.isExpInitializer();
967 if (ei
.exp
.isStringExp() && tnsa
.nextOf().isintegral())
969 ai
.addInit(null, ei
);
973 ai
.addInit(null, subArray(tnsa
, index
));
975 else if (tns
&& di.initializer
.isExpInitializer())
977 /* Disambiguate between an exp representing the entire
978 * struct, and an exp representing the first field of the struct
980 if (representsStruct(di.initializer
.isExpInitializer(), tns
)) // initializer represents the entire struct
982 ai
.addInit(null, initializerSemantic(di.initializer
, sc
, tn
, needInterpret
));
985 else // field initializers for struct
986 ai
.addInit(null, subStruct(tns
, index
)); // the first field
990 ai
.addInit(null, initializerSemantic(di.initializer
, sc
, tn
, needInterpret
));
994 return initializerSemantic(ai
, sc
, tx
, needInterpret
);
996 else if (ExpInitializer ei
= isBraceExpression())
1002 error(ci
.loc
, "unrecognized C initializer `%s`", toChars(ci
));
1007 mixin VisitInitializer
!Initializer visit
;
1008 auto result
= visit
.VisitInitializer(init
);
1009 return (result
!is null) ? result
: new ErrorInitializer();
1012 /***********************
1013 * Translate init to an `Expression` in order to infer the type.
1015 * init = `Initializer` AST node
1018 * an equivalent `ExpInitializer` if successful, or `ErrorInitializer` if it cannot be translated
1020 Initializer
inferType(Initializer init
, Scope
* sc
)
1022 Initializer
visitVoid(VoidInitializer i
)
1024 error(i
.loc
, "cannot infer type from void initializer");
1025 return new ErrorInitializer();
1028 Initializer
visitDefault(DefaultInitializer i
)
1030 error(i
.loc
, "cannot infer type from default initializer");
1031 return new ErrorInitializer();
1034 Initializer
visitError(ErrorInitializer i
)
1039 Initializer
visitStruct(StructInitializer i
)
1041 error(i
.loc
, "cannot infer type from struct initializer");
1042 return new ErrorInitializer();
1045 Initializer
visitArray(ArrayInitializer init
)
1047 //printf("ArrayInitializer::inferType() %s\n", toChars());
1048 Expressions
* keys
= null;
1049 Expressions
* values
;
1050 if (init
.isAssociativeArray())
1052 keys
= new Expressions(init
.value
.length
);
1053 values
= new Expressions(init
.value
.length
);
1054 for (size_t i
= 0; i
< init
.value
.length
; i
++)
1056 Expression e
= init
.index
[i
];
1060 Initializer iz
= init
.value
[i
];
1063 iz
= iz
.inferType(sc
);
1064 if (iz
.isErrorInitializer())
1068 (*values
)[i
] = iz
.isExpInitializer().exp
;
1069 assert(!(*values
)[i
].isErrorExp());
1071 Expression e
= new AssocArrayLiteralExp(init
.loc
, keys
, values
);
1072 auto ei
= new ExpInitializer(init
.loc
, e
);
1073 return ei
.inferType(sc
);
1077 auto elements
= new Expressions(init
.value
.length
);
1079 for (size_t i
= 0; i
< init
.value
.length
; i
++)
1081 assert(!init
.index
[i
]); // already asserted by isAssociativeArray()
1082 Initializer iz
= init
.value
[i
];
1085 iz
= iz
.inferType(sc
);
1086 if (iz
.isErrorInitializer())
1090 (*elements
)[i
] = iz
.isExpInitializer().exp
;
1091 assert(!(*elements
)[i
].isErrorExp());
1093 Expression e
= new ArrayLiteralExp(init
.loc
, null, elements
);
1094 auto ei
= new ExpInitializer(init
.loc
, e
);
1095 return ei
.inferType(sc
);
1100 error(init
.loc
, "not an associative array initializer");
1104 error(init
.loc
, "cannot infer type from array initializer");
1106 return new ErrorInitializer();
1109 Initializer
visitExp(ExpInitializer init
)
1111 //printf("ExpInitializer::inferType() %s\n", init.toChars());
1112 init
.exp
= init
.exp
.expressionSemantic(sc
);
1114 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
1115 if (init
.exp
.op
== EXP
.type
)
1116 init
.exp
= resolveAliasThis(sc
, init
.exp
);
1118 init
.exp
= resolveProperties(sc
, init
.exp
);
1119 if (auto se
= init
.exp
.isScopeExp())
1121 TemplateInstance ti
= se
.sds
.isTemplateInstance();
1122 if (ti
&& ti
.semanticRun
== PASS
.semantic
&& !ti
.aliasdecl
)
1123 error(se
.loc
, "cannot infer type from %s `%s`, possible circular dependency", se
.sds
.kind(), se
.toChars());
1125 error(se
.loc
, "cannot infer type from %s `%s`", se
.sds
.kind(), se
.toChars());
1126 return new ErrorInitializer();
1129 // Give error for overloaded function addresses
1131 if (auto f
= isFuncAddress(init
.exp
, &hasOverloads
))
1133 if (f
.checkForwardRef(init
.loc
))
1135 return new ErrorInitializer();
1137 if (hasOverloads
&& !f
.isUnique())
1139 error(init
.exp
.loc
, "cannot infer type from overloaded function symbol `%s`", init
.exp
.toChars());
1140 return new ErrorInitializer();
1143 if (auto ae
= init
.exp
.isAddrExp())
1145 if (ae
.e1
.op
== EXP
.overloadSet
)
1147 error(init
.exp
.loc
, "cannot infer type from overloaded function symbol `%s`", init
.exp
.toChars());
1148 return new ErrorInitializer();
1151 if (init
.exp
.isErrorExp())
1153 return new ErrorInitializer();
1157 return new ErrorInitializer();
1162 Initializer
visitC(CInitializer i
)
1164 //printf("CInitializer.inferType()\n");
1165 error(i
.loc
, "TODO C inferType initializers not supported yet");
1166 return new ErrorInitializer();
1169 mixin VisitInitializer
!Initializer visit
;
1170 auto result
= visit
.VisitInitializer(init
);
1171 return (result
!is null) ? result
: new ErrorInitializer();
1174 /***********************
1175 * Translate init to an `Expression`.
1177 * init = `Initializer` AST node
1178 * itype = if not `null`, type to coerce expression to
1179 * isCfile = default initializers are different with C
1181 * `Expression` created, `null` if cannot, `ErrorExp` for other errors
1183 extern (C
++) Expression
initializerToExpression(Initializer init
, Type itype
= null, const bool isCfile
= false)
1185 //printf("initializerToExpression() isCfile: %d\n", isCfile);
1187 Expression
visitVoid(VoidInitializer
)
1192 Expression
visitDefault(DefaultInitializer
di)
1194 return di.type ?
di.type
.defaultInit(Loc
.initial
, isCfile
) : null;
1197 Expression
visitError(ErrorInitializer
)
1199 return ErrorExp
.get();
1202 /***************************************
1203 * This works by transforming a struct initializer into
1204 * a struct literal. In the future, the two should be the
1207 Expression
visitStruct(StructInitializer
)
1209 // cannot convert to an expression without target 'ad'
1213 /********************************
1214 * If possible, convert array initializer to array literal.
1215 * Otherwise return NULL.
1217 Expression
visitArray(ArrayInitializer init
)
1219 //printf("ArrayInitializer::toExpression(), dim = %d\n", dim);
1220 //static int i; if (++i == 2) assert(0);
1221 uint edim
; // the length of the resulting array literal
1222 const(uint) amax
= 0x80000000;
1223 Type t
= null; // type of the array literal being initialized
1226 if (init
.type
== Type
.terror
)
1228 return ErrorExp
.get();
1230 t
= init
.type
.toBasetype();
1234 t
= t
.isTypeVector().basetype
;
1238 uinteger_t adim
= t
.isTypeSArray().dim
.toInteger();
1241 edim
= cast(uint)adim
;
1255 /* Calculate the length of the array literal
1257 edim
= cast(uint)init
.value
.length
;
1259 foreach (i
; 0 .. init
.value
.length
)
1261 if (auto e
= init
.index
[i
])
1263 if (e
.op
== EXP
.int64
)
1265 const uinteger_t idxval
= e
.toInteger();
1268 j
= cast(size_t
)idxval
;
1279 auto elements
= new Expressions(edim
);
1282 foreach (i
; 0 .. init
.value
.length
)
1284 if (auto e
= init
.index
[i
])
1285 j
= cast(size_t
)e
.toInteger();
1287 if (Initializer iz
= init
.value
[i
])
1289 if (Expression ex
= iz
.initializerToExpression(null, isCfile
))
1291 (*elements
)[j
] = ex
;
1301 /* Fill in any missing elements with the default initializer
1303 Expression defaultInit
= null; // lazily create it
1304 foreach (ref element
; (*elements
)[0 .. edim
])
1308 if (!init
.type
) // don't know what type to use
1311 defaultInit
= (cast(TypeNext
)t
).next
.defaultInit(Loc
.initial
, isCfile
);
1312 element
= defaultInit
;
1316 /* Expand any static array initializers that are a single expression
1317 * into an array of them
1318 * e => [e, e, ..., e, e]
1322 Type tn
= t
.nextOf().toBasetype();
1323 if (tn
.ty
== Tsarray
)
1325 const dim
= cast(size_t
)(cast(TypeSArray
)tn
).dim
.toInteger();
1326 Type te
= tn
.nextOf().toBasetype();
1327 foreach (ref e
; *elements
)
1329 if (te
.equals(e
.type
))
1331 auto elements2
= new Expressions(dim
);
1332 foreach (ref e2
; *elements2
)
1334 e
= new ArrayLiteralExp(e
.loc
, tn
, elements2
);
1340 /* If any elements are errors, then the whole thing is an error
1342 foreach (e
; (*elements
)[0 .. edim
])
1344 if (e
.op
== EXP
.error
)
1350 Expression e
= new ArrayLiteralExp(init
.loc
, init
.type
, elements
);
1354 Expression
visitExp(ExpInitializer i
)
1358 //printf("ExpInitializer::toExpression(t = %s) exp = %s\n", itype.toChars(), i.exp.toChars());
1359 Type tb
= itype
.toBasetype();
1360 Expression e
= (i
.exp
.op
== EXP
.construct || i
.exp
.op
== EXP
.blit
) ?
(cast(AssignExp
)i
.exp
).e2
: i
.exp
;
1361 if (tb
.ty
== Tsarray
&& e
.implicitConvTo(tb
.nextOf()))
1363 TypeSArray tsa
= cast(TypeSArray
)tb
;
1364 size_t d
= cast(size_t
)tsa
.dim
.toInteger();
1365 auto elements
= new Expressions(d
);
1366 for (size_t j
= 0; j
< d
; j
++)
1368 auto ae
= new ArrayLiteralExp(e
.loc
, itype
, elements
);
1375 Expression
visitC(CInitializer i
)
1377 //printf("CInitializer.initializerToExpression(null, true)\n");
1381 mixin VisitInitializer
!Expression visit
;
1382 return visit
.VisitInitializer(init
);
1386 /**************************************
1387 * Determine if expression has non-constant pointers, or more precisely,
1388 * a pointer that CTFE cannot handle.
1390 * e = expression to check
1392 * true if it has non-constant pointers
1394 private bool hasNonConstPointers(Expression e
)
1396 static bool checkArray(Expressions
* elems
)
1400 if (e
&& hasNonConstPointers(e
))
1406 if (e
.type
.ty
== Terror
)
1408 if (e
.op
== EXP
.null_
)
1410 if (auto se
= e
.isStructLiteralExp())
1412 return checkArray(se
.elements
);
1414 if (auto ae
= e
.isArrayLiteralExp())
1416 if (!ae
.type
.nextOf().hasPointers())
1418 return checkArray(ae
.elements
);
1420 if (auto ae
= e
.isAssocArrayLiteralExp())
1422 if (ae
.type
.nextOf().hasPointers() && checkArray(ae
.values
))
1424 if (ae
.type
.isTypeAArray().index
.hasPointers())
1425 return checkArray(ae
.keys
);
1428 if (auto ae
= e
.isAddrExp())
1430 if (ae
.type
.nextOf().isImmutable() || ae
.type
.nextOf().isConst())
1434 if (auto se
= ae
.e1
.isStructLiteralExp())
1436 if (!(se
.stageflags
& stageSearchPointers
))
1438 const old
= se
.stageflags
;
1439 se
.stageflags |
= stageSearchPointers
;
1440 bool ret = checkArray(se
.elements
);
1441 se
.stageflags
= old
;
1451 if (e
.type
.ty
== Tpointer
&& !e
.type
.isPtrToFunction())
1453 if (e
.op
== EXP
.symbolOffset
) // address of a global is OK
1455 if (e
.op
== EXP
.int64
) // cast(void *)int is OK
1457 if (e
.op
== EXP
.string_
) // "abc".ptr is OK
1465 Given the names and values of a `StructInitializer` or `CallExp`,
1466 resolve it to a list of expressions to construct a `StructLiteralExp`.
1470 t = type of struct (potentially including qualifiers such as `const` or `immutable`)
1471 sc = scope of the expression initializing the struct
1472 iloc = location of expression initializing the struct
1473 names = identifiers passed in argument list, `null` entries for positional arguments
1474 getExp = function that, given an index into `names` and destination type, returns the initializing expression
1475 getLoc = function that, given an index into `names`, returns a location for error messages
1477 Returns: list of expressions ordered to the struct's fields, or `null` on error
1479 Expressions
* resolveStructLiteralNamedArgs(StructDeclaration sd
, Type t
, Scope
* sc
,
1480 Loc iloc
, Identifier
[] names
, scope Expression
delegate(size_t i
, Type fieldType
) getExp
,
1481 scope Loc
delegate(size_t i
) getLoc
1484 //expandTuples for non-identity arguments?
1485 const nfields
= sd
.nonHiddenFields();
1486 auto elements
= new Expressions(nfields
);
1487 auto elems
= (*elements
)[];
1488 foreach (ref elem
; elems
)
1491 // Run semantic for explicitly given initializers
1492 // TODO: this part is slightly different from StructLiteralExp::semantic.
1493 bool errors
= false;
1495 foreach (j
, id
; names
)
1497 const argLoc
= getLoc(j
);
1500 // Determine `fieldi` that `id` matches
1501 Dsymbol s
= sd
.search(iloc
, id
);
1504 s
= sd
.search_correct(id
);
1506 error(argLoc
, "`%s` is not a member of `%s`, did you mean %s `%s`?", id
.toChars(), sd
.toChars(), s
.kind(), s
.toChars());
1508 error(argLoc
, "`%s` is not a member of `%s`", id
.toChars(), sd
.toChars());
1511 s
.checkDeprecated(iloc
, sc
);
1514 // Find out which field index `s` is
1515 for (fieldi
= 0; 1; fieldi
++)
1517 if (fieldi
>= nfields
)
1519 error(iloc
, "`%s.%s` is not a per-instance initializable field", sd
.toChars(), s
.toChars());
1522 if (s
== sd
.fields
[fieldi
])
1528 error(argLoc
, "initializer provided for struct `%s` with no fields", sd
.toChars());
1533 error(argLoc
, "too many initializers for `%s` with %d field%s", sd
.toChars(),
1534 cast(int) nfields
, nfields
!= 1 ?
"s".ptr
: "".ptr
);
1538 VarDeclaration vd
= sd
.fields
[fieldi
];
1541 error(argLoc
, "duplicate initializer for field `%s`", vd
.toChars());
1543 elems
[fieldi
] = ErrorExp
.get(); // for better diagnostics on multiple errors
1548 // Check for @safe violations
1549 if (vd
.type
.hasPointers
)
1551 if ((!t
.alignment
.isDefault() && t
.alignment
.get() < target
.ptrsize ||
1552 (vd
.offset
& (target
.ptrsize
- 1))))
1554 if (sc
.setUnsafe(false, argLoc
,
1555 "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd
, vd
))
1558 elems
[fieldi
] = ErrorExp
.get(); // for better diagnostics on multiple errors
1565 // Check for overlapping initializations (can happen with unions)
1566 foreach (k
, v2
; sd
.fields
[0 .. nfields
])
1568 if (vd
.isOverlappedWith(v2
) && elems
[k
])
1570 error(elems
[k
].loc
, "overlapping initialization for field `%s` and `%s`", v2
.toChars(), vd
.toChars());
1571 enum errorMsg
= "`struct` initializers that contain anonymous unions" ~
1572 " must initialize only the first member of a `union`. All subsequent" ~
1573 " non-overlapping fields are default initialized";
1574 if (!sd
.isUnionDeclaration())
1575 .errorSupplemental(elems
[k
].loc
, errorMsg
);
1583 auto ex
= getExp(j
, vd
.type
);
1585 if (ex
.op
== EXP
.error
)
1588 elems
[fieldi
] = ErrorExp
.get(); // for better diagnostics on multiple errors
1593 elems
[fieldi
] = doCopyOrMove(sc
, ex
);