2 * Semantic analysis of initializers.
4 * Copyright: Copyright (C) 1999-2024 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
;
37 import dmd
.identifier
;
49 /********************************
50 * If possible, convert array initializer to associative array initializer.
53 * ai = array initializer to be converted
56 * The converted associative array initializer or ErrorExp if `ai`
57 * is not an associative array initializer.
59 Expression
toAssocArrayLiteral(ArrayInitializer ai
)
61 //printf("ArrayInitializer::toAssocArrayInitializer(%s)\n", ai.toChars());
62 //static int i; if (++i == 2) assert(0);
64 auto no(const char* format
, Initializer i
)
66 error(i
.loc
, format
, toChars(i
));
67 return ErrorExp
.get();
70 const dim
= ai
.value
.length
;
72 return no("invalid associative array initializer `%s`, use `null` instead", ai
);
74 auto keys
= new Expressions(dim
);
75 auto values
= new Expressions(dim
);
76 foreach (i
, iz
; ai
.value
[])
79 auto ev
= iz
.initializerToExpression();
81 return no("invalid value `%s` in initializer", iz
);
84 auto ei
= ai
.index
[i
];
86 return no("missing key for value `%s` in initializer", iz
);
89 return new AssocArrayLiteralExp(ai
.loc
, keys
, values
);
92 /******************************************
93 * Perform semantic analysis on init.
95 * init = Initializer AST node
97 * tx = type that the initializer needs to become. If tx is an incomplete
98 * type and the initializer completes it, it is updated to be the
99 * complete type. ImportC has incomplete types
100 * needInterpret = if CTFE needs to be run on this,
101 * such as if it is the initializer for a const declaration
103 * `Initializer` with completed semantic analysis, `ErrorInitializer` if errors
106 Initializer
initializerSemantic(Initializer init
, Scope
* sc
, ref Type tx
, NeedInterpret needInterpret
)
108 //printf("initializerSemantic() tx: %p %s\n", tx, tx.toChars());
111 static Initializer
err()
113 return new ErrorInitializer();
116 Initializer
visitVoid(VoidInitializer i
)
122 Initializer
visitDefault(DefaultInitializer i
)
128 Initializer
visitError(ErrorInitializer i
)
133 Initializer
visitStruct(StructInitializer i
)
135 //printf("StructInitializer::semantic(t = %s) %s\n", t.toChars(), i.toChars());
136 /* This works by replacing the StructInitializer with an ExpInitializer.
139 if (auto tsa
= t
.isTypeSArray())
141 auto ts
= tsa
.nextOf().toBasetype().isTypeStruct();
145 if (auto ts
= t
.isTypeStruct())
147 StructDeclaration sd
= ts
.sym
;
148 // check if the sd has a regular ctor (user defined non-copy ctor)
149 // that is not disabled.
150 if (sd
.hasRegularCtor(true))
152 error(i
.loc
, "%s `%s` has constructors, cannot use `{ initializers }`, use `%s( initializers )` instead", sd
.kind(), sd
.toChars(), sd
.toChars());
156 if (sd
.sizeok
!= Sizeok
.done
)
159 Expression
getExp(size_t j
, Type fieldType
)
161 // Convert initializer to Expression `ex`
162 auto tm
= fieldType
.addMod(t
.mod
);
163 auto iz
= i
.value
[j
].initializerSemantic(sc
, tm
, needInterpret
);
164 auto ex
= iz
.initializerToExpression(null, (sc
.flags
& SCOPE
.Cfile
) != 0);
165 if (ex
.op
!= EXP
.error
)
170 auto elements
= resolveStructLiteralNamedArgs(sd
, t
, sc
, i
.loc
, i
.field
[], &getExp
, (size_t j
) => i
.value
[j
].loc
);
174 // Make a StructLiteralExp out of elements[]
175 auto sle
= new StructLiteralExp(i
.loc
, sd
, elements
, t
);
176 if (!sd
.fill(i
.loc
, *elements
, false))
179 auto ie
= new ExpInitializer(i
.loc
, sle
);
180 return ie
.initializerSemantic(sc
, t
, needInterpret
);
182 else if ((t
.ty
== Tdelegate || t
.isPtrToFunction()) && i
.value
.length
== 0)
184 const tok
= (t
.ty
== Tdelegate
) ? TOK
.delegate_
: TOK
.function_
;
185 /* Rewrite as empty delegate literal { }
187 Type tf
= new TypeFunction(ParameterList(), null, LINK
.d
);
188 auto fd
= new FuncLiteralDeclaration(i
.loc
, Loc
.initial
, tf
, tok
, null);
189 fd
.fbody
= new CompoundStatement(i
.loc
, new Statements());
191 Expression e
= new FuncExp(i
.loc
, fd
);
192 auto ie
= new ExpInitializer(i
.loc
, e
);
193 return ie
.initializerSemantic(sc
, t
, needInterpret
);
196 error(i
.loc
, "a struct is not a valid initializer for a `%s`", t
.toChars());
200 Initializer
visitArray(ArrayInitializer i
)
203 const(uint) amax
= 0x80000000;
205 //printf("ArrayInitializer::semantic(%s), ai: %s\n", t.toChars(), toChars(i));
206 if (i
.sem
) // if semantic() already run
218 t
= t
.isTypeVector().basetype
;
221 case Tstruct
: // consider implicit constructor call
224 // note: MyStruct foo = [1:2, 3:4] is correct code if MyStruct has a this(int[int])
225 if (t
.ty
== Taarray || i
.isAssociativeArray())
226 e
= i
.toAssocArrayLiteral();
228 e
= i
.initializerToExpression();
232 error(i
.loc
, "cannot use array to initialize `%s`", t
.toChars());
235 auto ei
= new ExpInitializer(e
.loc
, e
);
236 return ei
.initializerSemantic(sc
, t
, needInterpret
);
240 if (t
.nextOf().isTypeFunction())
245 error(i
.loc
, "cannot use array to initialize `%s`", t
.toChars());
250 for (size_t j
= 0; j
< i
.index
.length
; j
++) // don't replace with foreach; j is modified
252 Expression idx
= i
.index
[j
];
256 idx
= idx
.expressionSemantic(sc
);
258 idx
= idx
.ctfeInterpret();
260 const uinteger_t idxvalue
= idx
.toInteger();
261 if (idxvalue
>= amax
)
263 error(i
.loc
, "array index %llu overflow", idxvalue
);
266 length
= cast(uint)idxvalue
;
267 if (idx
.op
== EXP
.error
)
270 Initializer val
= i
.value
[j
];
271 ExpInitializer ei
= val
.isExpInitializer();
273 ei
.expandTuples
= true;
274 auto tn
= t
.nextOf();
275 val
= val
.initializerSemantic(sc
, tn
, needInterpret
);
276 if (val
.isErrorInitializer())
278 ei
= val
.isExpInitializer();
279 // found a tuple, expand it
280 if (ei
&& ei
.exp
.op
== EXP
.tuple
)
282 TupleExp te
= ei
.exp
.isTupleExp();
285 foreach (k
, e
; (*te
.exps
)[])
287 i
.index
.insert(j
+ k
, cast(Expression
)null);
288 i
.value
.insert(j
+ k
, new ExpInitializer(e
.loc
, e
));
300 error(i
.loc
, "array dimension overflow");
306 if (auto tsa
= t
.isTypeSArray())
308 if (sc
.flags
& SCOPE
.Cfile
&& tsa
.isIncomplete())
310 // Change to array of known length
311 auto tn
= tsa
.next
.toBasetype();
312 tsa
= new TypeSArray(tn
, new IntegerExp(Loc
.initial
, i
.dim
, Type
.tsize_t
));
313 tx
= tsa
; // rewrite caller's type
314 i
.type
= tsa
; // remember for later passes
318 ulong edim
= tsa
.dim
.toInteger();
321 error(i
.loc
, "array initializer has %u elements, but array length is %llu", i
.dim
, edim
);
329 const sz
= t
.nextOf().size();
330 if (sz
== SIZE_INVALID
)
333 const max
= mulu(i
.dim
, sz
, overflow
);
334 if (overflow || max
>= amax
)
336 error(i
.loc
, "array dimension %llu exceeds max of %llu", ulong(i
.dim
), ulong(amax
/ sz
));
339 //printf("returns ai: %s\n", i.toChars());
343 Initializer
visitExp(ExpInitializer i
)
345 //printf("ExpInitializer::semantic(%s), type = %s\n", i.exp.toChars(), t.toChars());
348 i
.exp
= i
.exp
.expressionSemantic(sc
);
349 i
.exp
= resolveProperties(sc
, i
.exp
);
352 if (i
.exp
.op
== EXP
.error
)
354 const olderrors
= global
.errors
;
356 /* ImportC: convert arrays to pointers, functions to pointers to functions
358 Type tb
= t
.toBasetype();
359 if (tb
.isTypePointer())
360 i
.exp
= i
.exp
.arrayFuncConv(sc
);
362 /* Save the expression before ctfe
363 * Otherwise the error message would contain for example "&[0][0]" instead of "new int"
364 * Regression: https://issues.dlang.org/show_bug.cgi?id=21687
366 Expression currExp
= i
.exp
;
369 // If the result will be implicitly cast, move the cast into CTFE
370 // to avoid premature truncation of polysemous types.
371 // eg real [] x = [1.1, 2.2]; should use real precision.
372 if (i
.exp
.implicitConvTo(t
) && !(sc
.flags
& SCOPE
.Cfile
))
374 i
.exp
= i
.exp
.implicitCastTo(sc
, t
);
376 if (!global
.gag
&& olderrors
!= global
.errors
)
380 if (sc
.flags
& SCOPE
.Cfile
)
382 /* the interpreter turns (char*)"string" into &"string"[0] which then
383 * it cannot interpret. Resolve that case by doing optimize() first
385 i
.exp
= i
.exp
.optimize(WANTvalue
);
386 if (i
.exp
.isSymOffExp())
388 /* `static variable cannot be read at compile time`
389 * https://issues.dlang.org/show_bug.cgi?id=22513
390 * Maybe this would be better addressed in ctfeInterpret()?
392 needInterpret
= NeedInterpret
.INITnointerpret
;
396 i
.exp
= i
.exp
.ctfeInterpret();
397 if (i
.exp
.op
== EXP
.voidExpression
)
398 error(i
.loc
, "variables cannot be initialized with an expression of type `void`. Use `void` initialization instead.");
402 i
.exp
= i
.exp
.optimize(WANTvalue
);
405 if (!global
.gag
&& olderrors
!= global
.errors
)
407 return i
; // Failed, suppress duplicate error messages
409 if (i
.exp
.type
.isTypeTuple() && i
.exp
.type
.isTypeTuple().arguments
.length
== 0)
411 Type et
= i
.exp
.type
;
412 i
.exp
= new TupleExp(i
.exp
.loc
, new Expressions());
415 if (i
.exp
.op
== EXP
.type
)
417 error(i
.exp
.loc
, "initializer must be an expression, not `%s`", i
.exp
.toChars());
420 // Make sure all pointers are constants
421 if (needInterpret
&& hasNonConstPointers(i
.exp
))
423 error(i
.exp
.loc
, "cannot use non-constant CTFE pointer in an initializer `%s`", currExp
.toChars());
426 Type ti
= i
.exp
.type
.toBasetype();
427 if (i
.exp
.op
== EXP
.tuple
&& i
.expandTuples
&& !i
.exp
.implicitConvTo(t
))
429 return new ExpInitializer(i
.loc
, i
.exp
);
431 /* Look for case of initializing a static array with a too-short
432 * string literal, such as:
433 * char[5] foo = "abc";
434 * Allow this by doing an explicit cast, which will lengthen the string
437 if (i
.exp
.op
== EXP
.string_
&& tb
.ty
== Tsarray
)
439 StringExp se
= i
.exp
.isStringExp();
440 Type typeb
= se
.type
.toBasetype();
441 TY tynto
= tb
.nextOf().ty
;
443 (typeb
.ty
== Tarray || typeb
.ty
== Tsarray
) && tynto
.isSomeChar
&&
444 se
.numberOfCodeUnits(tynto
) < tb
.isTypeSArray().dim
.toInteger())
446 i
.exp
= se
.castTo(sc
, t
);
450 /* Lop off terminating 0 of initializer for:
451 * static char s[5] = "hello";
453 if (sc
.flags
& SCOPE
.Cfile
&&
454 typeb
.ty
== Tsarray
&&
456 tb
.isTypeSArray().dim
.toInteger() + 1 == typeb
.isTypeSArray().dim
.toInteger())
458 i
.exp
= se
.castTo(sc
, t
);
463 * Initialize an array of unknown size with a string.
464 * Change to static array of known size
466 if (sc
.flags
& SCOPE
.Cfile
&& i
.exp
.isStringExp() &&
467 tb
.isTypeSArray() && tb
.isTypeSArray().isIncomplete())
469 StringExp se
= i
.exp
.isStringExp();
470 auto ts
= new TypeSArray(tb
.nextOf(), new IntegerExp(Loc
.initial
, se
.len
+ 1, Type
.tsize_t
));
471 t
= typeSemantic(ts
, Loc
.initial
, sc
);
476 // Look for implicit constructor call
477 if (tb
.ty
== Tstruct
&& !(ti
.ty
== Tstruct
&& tb
.toDsymbol(sc
) == ti
.toDsymbol(sc
)) && !i
.exp
.implicitConvTo(t
))
479 StructDeclaration sd
= tb
.isTypeStruct().sym
;
482 // Rewrite as S().ctor(exp)
484 e
= new StructLiteralExp(i
.loc
, sd
, null);
485 e
= new DotIdExp(i
.loc
, e
, Id
.ctor
);
486 e
= new CallExp(i
.loc
, e
, i
.exp
);
487 e
= e
.expressionSemantic(sc
);
489 i
.exp
= e
.ctfeInterpret();
491 i
.exp
= e
.optimize(WANTvalue
);
493 else if (search_function(sd
, Id
.call))
495 /* https://issues.dlang.org/show_bug.cgi?id=1547
497 * Look for static opCall
500 * i.exp = typeof(sd).opCall(arguments)
503 Expression e
= typeDotIdExp(i
.loc
, sd
.type
, Id
.call);
504 e
= new CallExp(i
.loc
, e
, i
.exp
);
505 e
= e
.expressionSemantic(sc
);
506 e
= resolveProperties(sc
, e
);
508 i
.exp
= e
.ctfeInterpret();
510 i
.exp
= e
.optimize(WANTvalue
);
514 // Look for the case of statically initializing an array with a single member.
515 // Recursively strip static array / enum layers until a compatible element is found,
516 // and return an `ArrayLiteralExp` repeating the initializer, or `null` if no match found
517 // int[2][3] = 7 => [[7, 7], [7, 7], [7, 7]]
518 // int[2] = new Object => null
519 Expression
sarrayRepeat(Type tb
)
521 auto tsa
= tb
.isTypeSArray();
525 // printf("i.exp = %s, tsa = %s\n", i.exp.toChars(), tsa.toChars());
526 Expression elem
= null;
527 if (i
.exp
.implicitConvTo(tb
.nextOf()))
528 elem
= i
.exp
.implicitCastTo(sc
, tb
.nextOf());
529 else if (auto ae
= sarrayRepeat(tb
.nextOf().toBasetype()))
534 auto arrayElements
= new Expressions(cast(size_t
) tsa
.dim
.toInteger());
535 foreach (ref e
; *arrayElements
)
537 return new ArrayLiteralExp(i
.exp
.loc
, tb
, elem
, arrayElements
);
540 if (auto sa
= sarrayRepeat(tb
))
542 // printf("sa = %s\n", sa.toChars());
547 auto tta
= t
.isTypeSArray();
548 if (i
.exp
.implicitConvTo(t
))
550 i
.exp
= i
.exp
.implicitCastTo(sc
, t
);
552 else if (sc
.flags
& SCOPE
.Cfile
&& i
.exp
.isStringExp() &&
553 tta
&& (tta
.next
.ty
== Tint8 || tta
.next
.ty
== Tuns8
) &&
554 ti
.ty
== Tsarray
&& ti
.nextOf().ty
== Tchar
)
556 /* unsigned char bbb[1] = "";
557 * signed char ccc[1] = "";
559 i
.exp
= i
.exp
.castTo(sc
, t
);
563 auto tba
= tb
.isTypeSArray();
564 // Look for mismatch of compile-time known length to emit
565 // better diagnostic message, as same as AssignExp::semantic.
566 if (tba
&& i
.exp
.implicitConvTo(tba
.next
.arrayOf()) > MATCH
.nomatch
)
568 uinteger_t dim1
= tba
.dim
.toInteger();
569 uinteger_t dim2
= dim1
;
570 if (auto ale
= i
.exp
.isArrayLiteralExp())
572 dim2
= ale
.elements ? ale
.elements
.length
: 0;
574 else if (auto se
= i
.exp
.isSliceExp())
576 if (Type tx
= toStaticArrayType(se
))
577 dim2
= tx
.isTypeSArray().dim
.toInteger();
581 error(i
.exp
.loc
, "mismatched array lengths, %d and %d", cast(int)dim1
, cast(int)dim2
);
582 i
.exp
= ErrorExp
.get();
585 Type et
= i
.exp
.type
;
586 const errors
= global
.startGagging();
587 i
.exp
= i
.exp
.implicitCastTo(sc
, t
);
588 if (global
.endGagging(errors
))
589 error(currExp
.loc
, "cannot implicitly convert expression `%s` of type `%s` to `%s`", currExp
.toChars(), et
.toChars(), t
.toChars());
593 if (i
.exp
.op
== EXP
.error
)
598 i
.exp
= i
.exp
.ctfeInterpret();
600 i
.exp
= i
.exp
.optimize(WANTvalue
);
601 //printf("-ExpInitializer::semantic(): "); i.exp.print();
605 Initializer
visitC(CInitializer ci
)
607 //printf("CInitializer::semantic() tx: %s t: %s ci: %s\n", (tx ? tx.toChars() : "".ptr), t.toChars(), toChars(ci));
609 if (auto ts
= tx
.isTypeStruct())
611 import dmd
.common
.outbuffer
;
614 toCBuffer(ts
.sym
, buf
, hgs
);
615 printf("%s\n", buf
.peekChars());
618 /* Rewrite CInitializer into ExpInitializer, ArrayInitializer, or StructInitializer
622 if (auto tv
= t
.isTypeVector())
625 /* If `{ expression }` return the expression initializer
627 ExpInitializer
isBraceExpression()
629 auto dil
= ci
.initializerList
[];
630 return (dil
.length
== 1 && !dil
[0].designatorList
)
631 ? dil
[0].initializer
.isExpInitializer()
635 /********************************
637 bool overlaps(VarDeclaration field
, VarDeclaration
[] fields
, StructInitializer si
)
639 foreach (fld; fields
)
641 if (field
.isOverlappedWith(fld))
643 // look for initializer corresponding with fld
644 foreach (i
, ident
; si
.field
[])
646 if (ident
== fld.ident
&& si
.value
[i
])
647 return true; // already an initializer for `field`
654 /* Run semantic on ExpInitializer, see if it represents entire struct ts
656 bool representsStruct(ExpInitializer ei
, TypeStruct ts
)
660 ei
.exp
= ei
.exp
.expressionSemantic(sc
);
661 ei
.exp
= resolveProperties(sc
, ei
.exp
);
664 return ei
.exp
.implicitConvTo(ts
) != MATCH
.nomatch
; // initializer represents the entire struct
667 /* If { } are omitted from substructs, use recursion to reconstruct where
670 * ts = substruct to initialize
671 * index = index into ci.initializer, updated
672 * Returns: struct initializer for this substruct
674 Initializer
subStruct()(TypeStruct ts
, ref size_t index
)
676 //printf("subStruct(ts: %s, index %d)\n", ts.toChars(), cast(int)index);
678 auto si
= new StructInitializer(ci
.loc
);
679 StructDeclaration sd
= ts
.sym
;
681 if (sd
.sizeok
!= Sizeok
.done
)
683 index
= ci
.initializerList
.length
;
686 const nfields
= sd
.fields
.length
;
688 foreach (fieldi
; 0 .. nfields
)
690 if (index
>= ci
.initializerList
.length
)
691 break; // ran out of initializers
692 auto di = ci
.initializerList
[index
];
693 if (di.designatorList
&& fieldi
!= 0)
694 break; // back to top level
697 VarDeclaration field
;
698 while (1) // skip field if it overlaps with previously seen fields
700 field
= sd
.fields
[fieldi
];
702 if (!overlaps(field
, sd
.fields
[], si
))
704 if (fieldi
== nfields
)
707 auto tn
= field
.type
.toBasetype();
708 auto tnsa
= tn
.isTypeSArray();
709 auto tns
= tn
.isTypeStruct();
710 auto ix
= di.initializer
;
711 if (tnsa
&& ix
.isExpInitializer())
713 ExpInitializer ei
= ix
.isExpInitializer();
714 if (ei
.exp
.isStringExp() && tnsa
.nextOf().isintegral())
716 si
.addInit(field
.ident
, ei
);
720 si
.addInit(field
.ident
, subArray(tnsa
, index
)); // fwd ref of subArray is why subStruct is a template
722 else if (tns
&& ix
.isExpInitializer())
724 /* Disambiguate between an exp representing the entire
725 * struct, and an exp representing the first field of the struct
727 if (representsStruct(ix
.isExpInitializer(), tns
)) // initializer represents the entire struct
729 si
.addInit(field
.ident
, initializerSemantic(ix
, sc
, tn
, needInterpret
));
732 else // field initializers for struct
733 si
.addInit(field
.ident
, subStruct(tns
, index
)); // the first field
737 si
.addInit(field
.ident
, ix
);
742 //printf("subStruct() returns ai: %s, index: %d\n", si.toChars(), cast(int)index);
746 /* If { } are omitted from subarrays, use recursion to reconstruct where
749 * tsa = subarray to initialize
750 * index = index into ci.initializer, updated
751 * Returns: array initializer for this subarray
753 Initializer
subArray(TypeSArray tsa
, ref size_t index
)
755 //printf("array(tsa: %s, index %d)\n", tsa.toChars(), cast(int)index);
756 if (tsa
.isIncomplete())
758 // C11 6.2.5-20 "element type shall be complete whenever the array type is specified"
759 assert(0); // should have been detected by parser
762 auto tnsa
= tsa
.nextOf().toBasetype().isTypeSArray();
764 auto ai
= new ArrayInitializer(ci
.loc
);
767 foreach (n
; 0 .. cast(size_t
)tsa
.dim
.toInteger())
769 if (index
>= ci
.initializerList
.length
)
770 break; // ran out of initializers
771 auto di = ci
.initializerList
[index
];
772 if (di.designatorList
)
773 break; // back to top level
774 else if (tnsa
&& di.initializer
.isExpInitializer())
776 ExpInitializer ei
= di.initializer
.isExpInitializer();
777 if (ei
.exp
.isStringExp() && tnsa
.nextOf().isintegral())
779 ai
.addInit(null, ei
);
783 ai
.addInit(null, subArray(tnsa
, index
));
787 ai
.addInit(null, di.initializer
);
791 //printf("array() returns ai: %s, index: %d\n", ai.toChars(), cast(int)index);
795 if (auto ts
= t
.isTypeStruct())
797 auto si
= new StructInitializer(ci
.loc
);
798 StructDeclaration sd
= ts
.sym
;
799 sd
.size(ci
.loc
); // run semantic() on sd to get fields
800 if (sd
.sizeok
!= Sizeok
.done
)
804 const nfields
= sd
.fields
.length
;
808 for (size_t index
= 0; index
< ci
.initializerList
.length
; )
810 DesigInit
di = ci
.initializerList
[index
];
811 Designators
* dlist
= di.designatorList
;
814 const length
= (*dlist
).length
;
815 if (length
== 0 ||
!(*dlist
)[0].ident
)
817 error(ci
.loc
, "`.identifier` expected for C struct field initializer `%s`", toChars(ci
));
822 error(ci
.loc
, "only 1 designator currently allowed for C struct field initializer `%s`", toChars(ci
));
825 auto id
= (*dlist
)[0].ident
;
826 foreach (k
, f
; sd
.fields
[]) // linear search for now
831 si
.addInit(id
, di.initializer
);
837 error(ci
.loc
, "`.%s` is not a field of `%s`\n", id
.toChars(), sd
.toChars());
842 if (fieldi
== nfields
)
845 auto ix
= di.initializer
;
847 /* If a C initializer is wrapped in a C initializer, with no designators,
848 * peel off the outer one
850 if (ix
.isCInitializer())
852 CInitializer cix
= ix
.isCInitializer();
853 if (cix
.initializerList
.length
== 1)
855 DesigInit dix
= cix
.initializerList
[0];
856 if (!dix
.designatorList
)
858 Initializer inix
= dix
.initializer
;
859 if (inix
.isCInitializer())
865 if (auto cix
= ix
.isCInitializer())
867 /* ImportC loses the structure from anonymous structs, but this is retained
868 * by the initializer syntax. if a CInitializer has a Designator, it is probably
869 * a nested anonymous struct
871 if (cix
.initializerList
.length
)
873 DesigInit dix
= cix
.initializerList
[0];
874 Designators
* dlistx
= dix
.designatorList
;
875 if (dlistx
&& (*dlistx
).length
== 1 && (*dlistx
)[0].ident
)
877 auto id
= (*dlistx
)[0].ident
;
878 foreach (k
, f
; sd
.fields
[]) // linear search for now
883 si
.addInit(id
, dix
.initializer
);
893 VarDeclaration field
;
894 while (1) // skip field if it overlaps with previously seen fields
896 field
= sd
.fields
[fieldi
];
898 if (!overlaps(field
, sd
.fields
[], si
))
900 if (fieldi
== nfields
)
904 auto tn
= field
.type
.toBasetype();
905 auto tnsa
= tn
.isTypeSArray();
906 auto tns
= tn
.isTypeStruct();
908 if (tnsa
&& ix
.isExpInitializer())
910 ExpInitializer ei
= ix
.isExpInitializer();
911 if (ei
.exp
.isStringExp() && tnsa
.nextOf().isintegral())
913 si
.addInit(field
.ident
, ei
);
917 si
.addInit(field
.ident
, subArray(tnsa
, index
));
919 else if (tns
&& ix
.isExpInitializer())
921 /* Disambiguate between an exp representing the entire
922 * struct, and an exp representing the first field of the struct
924 if (representsStruct(ix
.isExpInitializer(), tns
)) // initializer represents the entire struct
926 si
.addInit(field
.ident
, initializerSemantic(ix
, sc
, tn
, needInterpret
));
929 else // field initializers for struct
930 si
.addInit(field
.ident
, subStruct(tns
, index
)); // the first field
934 si
.addInit(field
.ident
, di.initializer
);
939 return initializerSemantic(si
, sc
, t
, needInterpret
);
941 else if (auto ta
= t
.isTypeSArray())
943 auto tn
= t
.nextOf().toBasetype(); // element type of array
945 /* If it's an array of integral being initialized by `{ string }`
946 * replace with `string`
950 if (ExpInitializer ei
= isBraceExpression())
952 if (ei
.exp
.isStringExp())
953 return ei
.initializerSemantic(sc
, t
, needInterpret
);
957 auto tnsa
= tn
.isTypeSArray(); // array of array
958 auto tns
= tn
.isTypeStruct(); // array of struct
960 auto ai
= new ArrayInitializer(ci
.loc
);
962 for (size_t index
= 0; index
< ci
.initializerList
.length
; )
964 auto di = ci
.initializerList
[index
];
965 if (auto dlist
= di.designatorList
)
967 const length
= (*dlist
).length
;
968 if (length
== 0 ||
!(*dlist
)[0].exp
)
970 error(ci
.loc
, "`[ constant-expression ]` expected for C array element initializer `%s`", toChars(ci
));
975 error(ci
.loc
, "only 1 designator currently allowed for C array element initializer `%s`", toChars(ci
));
978 //printf("tn: %s, di.initializer: %s\n", tn.toChars(), di.initializer.toChars());
979 auto ix
= di.initializer
;
980 if (tnsa
&& ix
.isExpInitializer())
982 // Wrap initializer in [ ]
983 auto ain
= new ArrayInitializer(ci
.loc
);
984 ain
.addInit(null, di.initializer
);
986 ai
.addInit((*dlist
)[0].exp
, initializerSemantic(ix
, sc
, tn
, needInterpret
));
989 else if (tns
&& ix
.isExpInitializer())
991 /* Disambiguate between an exp representing the entire
992 * struct, and an exp representing the first field of the struct
994 if (representsStruct(ix
.isExpInitializer(), tns
)) // initializer represents the entire struct
996 ai
.addInit((*dlist
)[0].exp
, initializerSemantic(ix
, sc
, tn
, needInterpret
));
999 else // field initializers for struct
1000 ai
.addInit((*dlist
)[0].exp
, subStruct(tns
, index
)); // the first field
1004 ai
.addInit((*dlist
)[0].exp
, initializerSemantic(ix
, sc
, tn
, needInterpret
));
1008 else if (tnsa
&& di.initializer
.isExpInitializer())
1010 ExpInitializer ei
= di.initializer
.isExpInitializer();
1011 if (ei
.exp
.isStringExp() && tnsa
.nextOf().isintegral())
1013 ai
.addInit(null, ei
);
1017 ai
.addInit(null, subArray(tnsa
, index
));
1019 else if (tns
&& di.initializer
.isExpInitializer())
1021 /* Disambiguate between an exp representing the entire
1022 * struct, and an exp representing the first field of the struct
1024 if (representsStruct(di.initializer
.isExpInitializer(), tns
)) // initializer represents the entire struct
1026 ai
.addInit(null, initializerSemantic(di.initializer
, sc
, tn
, needInterpret
));
1029 else // field initializers for struct
1030 ai
.addInit(null, subStruct(tns
, index
)); // the first field
1034 ai
.addInit(null, initializerSemantic(di.initializer
, sc
, tn
, needInterpret
));
1038 return initializerSemantic(ai
, sc
, tx
, needInterpret
);
1040 else if (ExpInitializer ei
= isBraceExpression())
1042 return visitExp(ei
);
1046 error(ci
.loc
, "unrecognized C initializer `%s` for type `%s`", toChars(ci
), t
.toChars());
1051 mixin VisitInitializer
!Initializer visit
;
1052 auto result
= visit
.VisitInitializer(init
);
1053 return (result
!is null) ? result
: new ErrorInitializer();
1056 /***********************
1057 * Translate init to an `Expression` in order to infer the type.
1059 * init = `Initializer` AST node
1062 * an equivalent `ExpInitializer` if successful, or `ErrorInitializer` if it cannot be translated
1064 Initializer
inferType(Initializer init
, Scope
* sc
)
1066 Initializer
visitVoid(VoidInitializer i
)
1068 error(i
.loc
, "cannot infer type from void initializer");
1069 return new ErrorInitializer();
1072 Initializer
visitDefault(DefaultInitializer i
)
1074 error(i
.loc
, "cannot infer type from default initializer");
1075 return new ErrorInitializer();
1078 Initializer
visitError(ErrorInitializer i
)
1083 Initializer
visitStruct(StructInitializer i
)
1085 error(i
.loc
, "cannot infer type from struct initializer");
1086 return new ErrorInitializer();
1089 Initializer
visitArray(ArrayInitializer init
)
1091 //printf("ArrayInitializer::inferType() %s\n", toChars());
1092 Expressions
* keys
= null;
1093 Expressions
* values
;
1094 if (init
.isAssociativeArray())
1096 keys
= new Expressions(init
.value
.length
);
1097 values
= new Expressions(init
.value
.length
);
1098 for (size_t i
= 0; i
< init
.value
.length
; i
++)
1100 Expression e
= init
.index
[i
];
1104 Initializer iz
= init
.value
[i
];
1107 iz
= iz
.inferType(sc
);
1108 if (iz
.isErrorInitializer())
1112 (*values
)[i
] = iz
.isExpInitializer().exp
;
1113 assert(!(*values
)[i
].isErrorExp());
1115 Expression e
= new AssocArrayLiteralExp(init
.loc
, keys
, values
);
1116 auto ei
= new ExpInitializer(init
.loc
, e
);
1117 return ei
.inferType(sc
);
1121 auto elements
= new Expressions(init
.value
.length
);
1123 for (size_t i
= 0; i
< init
.value
.length
; i
++)
1125 assert(!init
.index
[i
]); // already asserted by isAssociativeArray()
1126 Initializer iz
= init
.value
[i
];
1129 iz
= iz
.inferType(sc
);
1130 if (iz
.isErrorInitializer())
1134 (*elements
)[i
] = iz
.isExpInitializer().exp
;
1135 assert(!(*elements
)[i
].isErrorExp());
1137 Expression e
= new ArrayLiteralExp(init
.loc
, null, elements
);
1138 auto ei
= new ExpInitializer(init
.loc
, e
);
1139 return ei
.inferType(sc
);
1144 error(init
.loc
, "not an associative array initializer");
1148 error(init
.loc
, "cannot infer type from array initializer");
1150 return new ErrorInitializer();
1153 Initializer
visitExp(ExpInitializer init
)
1155 //printf("ExpInitializer::inferType() %s\n", init.toChars());
1156 init
.exp
= init
.exp
.expressionSemantic(sc
);
1158 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
1159 if (init
.exp
.op
== EXP
.type
)
1160 init
.exp
= resolveAliasThis(sc
, init
.exp
);
1162 init
.exp
= resolveProperties(sc
, init
.exp
);
1163 if (auto se
= init
.exp
.isScopeExp())
1165 TemplateInstance ti
= se
.sds
.isTemplateInstance();
1166 if (ti
&& ti
.semanticRun
== PASS
.semantic
&& !ti
.aliasdecl
)
1167 error(se
.loc
, "cannot infer type from %s `%s`, possible circular dependency", se
.sds
.kind(), se
.toChars());
1169 error(se
.loc
, "cannot infer type from %s `%s`", se
.sds
.kind(), se
.toChars());
1170 return new ErrorInitializer();
1173 // Give error for overloaded function addresses
1175 if (auto f
= isFuncAddress(init
.exp
, &hasOverloads
))
1177 if (checkForwardRef(f
, init
.loc
))
1179 return new ErrorInitializer();
1181 if (hasOverloads
&& !f
.isUnique())
1183 error(init
.exp
.loc
, "cannot infer type from overloaded function symbol `%s`", init
.exp
.toChars());
1184 return new ErrorInitializer();
1187 if (auto ae
= init
.exp
.isAddrExp())
1189 if (ae
.e1
.op
== EXP
.overloadSet
)
1191 error(init
.exp
.loc
, "cannot infer type from overloaded function symbol `%s`", init
.exp
.toChars());
1192 return new ErrorInitializer();
1195 if (init
.exp
.isErrorExp())
1197 return new ErrorInitializer();
1201 return new ErrorInitializer();
1206 Initializer
visitC(CInitializer i
)
1208 //printf("CInitializer.inferType()\n");
1209 error(i
.loc
, "TODO C inferType initializers not supported yet");
1210 return new ErrorInitializer();
1213 mixin VisitInitializer
!Initializer visit
;
1214 auto result
= visit
.VisitInitializer(init
);
1215 return (result
!is null) ? result
: new ErrorInitializer();
1218 /***********************
1219 * Translate init to an `Expression`.
1221 * init = `Initializer` AST node
1222 * itype = if not `null`, type to coerce expression to
1223 * isCfile = default initializers are different with C
1225 * `Expression` created, `null` if cannot, `ErrorExp` for other errors
1227 Expression
initializerToExpression(Initializer init
, Type itype
= null, const bool isCfile
= false)
1229 //printf("initializerToExpression() isCfile: %d\n", isCfile);
1231 Expression
visitVoid(VoidInitializer
)
1236 Expression
visitDefault(DefaultInitializer
di)
1238 return di.type ?
di.type
.defaultInit(Loc
.initial
, isCfile
) : null;
1241 Expression
visitError(ErrorInitializer
)
1243 return ErrorExp
.get();
1246 /***************************************
1247 * This works by transforming a struct initializer into
1248 * a struct literal. In the future, the two should be the
1251 Expression
visitStruct(StructInitializer
)
1253 // cannot convert to an expression without target 'ad'
1257 /********************************
1258 * If possible, convert array initializer to array literal.
1259 * Otherwise return NULL.
1261 Expression
visitArray(ArrayInitializer init
)
1263 //printf("ArrayInitializer::toExpression(), dim = %d\n", dim);
1264 //static int i; if (++i == 2) assert(0);
1265 uint edim
; // the length of the resulting array literal
1266 const(uint) amax
= 0x80000000;
1267 Type t
= null; // type of the array literal being initialized
1270 if (init
.type
== Type
.terror
)
1272 return ErrorExp
.get();
1274 t
= init
.type
.toBasetype();
1278 t
= t
.isTypeVector().basetype
;
1282 uinteger_t adim
= t
.isTypeSArray().dim
.toInteger();
1285 edim
= cast(uint)adim
;
1299 /* Calculate the length of the array literal
1301 edim
= cast(uint)init
.value
.length
;
1303 foreach (i
; 0 .. init
.value
.length
)
1305 if (auto e
= init
.index
[i
])
1307 if (e
.op
== EXP
.int64
)
1309 const uinteger_t idxval
= e
.toInteger();
1312 j
= cast(size_t
)idxval
;
1323 auto elements
= new Expressions(edim
);
1326 foreach (i
; 0 .. init
.value
.length
)
1328 if (auto e
= init
.index
[i
])
1329 j
= cast(size_t
)e
.toInteger();
1331 if (Initializer iz
= init
.value
[i
])
1333 if (Expression ex
= iz
.initializerToExpression(null, isCfile
))
1335 (*elements
)[j
] = ex
;
1345 /* Fill in any missing elements with the default initializer
1347 Expression defaultInit
= null; // lazily create it
1348 foreach (ref element
; (*elements
)[0 .. edim
])
1352 if (!init
.type
) // don't know what type to use
1355 defaultInit
= (cast(TypeNext
)t
).next
.defaultInit(Loc
.initial
, isCfile
);
1356 element
= defaultInit
;
1360 /* Expand any static array initializers that are a single expression
1361 * into an array of them
1362 * e => [e, e, ..., e, e]
1366 Type tn
= t
.nextOf().toBasetype();
1367 if (tn
.ty
== Tsarray
)
1369 const dim
= cast(size_t
)(cast(TypeSArray
)tn
).dim
.toInteger();
1370 Type te
= tn
.nextOf().toBasetype();
1371 foreach (ref e
; *elements
)
1373 if (te
.equals(e
.type
))
1375 auto elements2
= new Expressions(dim
);
1376 foreach (ref e2
; *elements2
)
1378 e
= new ArrayLiteralExp(e
.loc
, tn
, elements2
);
1384 /* If any elements are errors, then the whole thing is an error
1386 foreach (e
; (*elements
)[0 .. edim
])
1388 if (e
.op
== EXP
.error
)
1394 Expression e
= new ArrayLiteralExp(init
.loc
, init
.type
, elements
);
1398 Expression
visitExp(ExpInitializer i
)
1402 //printf("ExpInitializer::toExpression(t = %s) exp = %s\n", itype.toChars(), i.exp.toChars());
1403 Type tb
= itype
.toBasetype();
1404 Expression e
= (i
.exp
.op
== EXP
.construct || i
.exp
.op
== EXP
.blit
) ?
(cast(AssignExp
)i
.exp
).e2
: i
.exp
;
1405 if (tb
.ty
== Tsarray
&& e
.implicitConvTo(tb
.nextOf()))
1407 TypeSArray tsa
= cast(TypeSArray
)tb
;
1408 size_t d
= cast(size_t
)tsa
.dim
.toInteger();
1409 auto elements
= new Expressions(d
);
1410 for (size_t j
= 0; j
< d
; j
++)
1412 auto ae
= new ArrayLiteralExp(e
.loc
, itype
, elements
);
1419 Expression
visitC(CInitializer i
)
1421 //printf("CInitializer.initializerToExpression(null, true)\n");
1425 mixin VisitInitializer
!Expression visit
;
1426 return visit
.VisitInitializer(init
);
1430 /**************************************
1431 * Determine if expression has non-constant pointers, or more precisely,
1432 * a pointer that CTFE cannot handle.
1434 * e = expression to check
1436 * true if it has non-constant pointers
1438 private bool hasNonConstPointers(Expression e
)
1440 static bool checkArray(Expressions
* elems
)
1444 if (e
&& hasNonConstPointers(e
))
1450 if (e
.type
.ty
== Terror
)
1452 if (e
.op
== EXP
.null_
)
1454 if (auto se
= e
.isStructLiteralExp())
1456 return checkArray(se
.elements
);
1458 if (auto ae
= e
.isArrayLiteralExp())
1460 if (!ae
.type
.nextOf().hasPointers())
1462 return checkArray(ae
.elements
);
1464 if (auto ae
= e
.isAssocArrayLiteralExp())
1466 if (ae
.type
.nextOf().hasPointers() && checkArray(ae
.values
))
1468 if (ae
.type
.isTypeAArray().index
.hasPointers())
1469 return checkArray(ae
.keys
);
1472 if (auto ae
= e
.isAddrExp())
1474 if (ae
.type
.nextOf().isImmutable() || ae
.type
.nextOf().isConst())
1478 if (auto se
= ae
.e1
.isStructLiteralExp())
1480 if (!(se
.stageflags
& stageSearchPointers
))
1482 const old
= se
.stageflags
;
1483 se
.stageflags |
= stageSearchPointers
;
1484 bool ret = checkArray(se
.elements
);
1485 se
.stageflags
= old
;
1495 if (e
.type
.ty
== Tpointer
&& !e
.type
.isPtrToFunction())
1497 if (e
.op
== EXP
.symbolOffset
) // address of a global is OK
1499 if (e
.op
== EXP
.int64
) // cast(void *)int is OK
1501 if (e
.op
== EXP
.string_
) // "abc".ptr is OK
1509 Given the names and values of a `StructInitializer` or `CallExp`,
1510 resolve it to a list of expressions to construct a `StructLiteralExp`.
1514 t = type of struct (potentially including qualifiers such as `const` or `immutable`)
1515 sc = scope of the expression initializing the struct
1516 iloc = location of expression initializing the struct
1517 names = identifiers passed in argument list, `null` entries for positional arguments
1518 getExp = function that, given an index into `names` and destination type, returns the initializing expression
1519 getLoc = function that, given an index into `names`, returns a location for error messages
1521 Returns: list of expressions ordered to the struct's fields, or `null` on error
1523 Expressions
* resolveStructLiteralNamedArgs(StructDeclaration sd
, Type t
, Scope
* sc
,
1524 Loc iloc
, Identifier
[] names
, scope Expression
delegate(size_t i
, Type fieldType
) getExp
,
1525 scope Loc
delegate(size_t i
) getLoc
1528 //expandTuples for non-identity arguments?
1529 const nfields
= sd
.nonHiddenFields();
1530 auto elements
= new Expressions(nfields
);
1531 auto elems
= (*elements
)[];
1532 foreach (ref elem
; elems
)
1535 // Run semantic for explicitly given initializers
1536 // TODO: this part is slightly different from StructLiteralExp::semantic.
1537 bool errors
= false;
1539 foreach (j
, id
; names
)
1541 const argLoc
= getLoc(j
);
1544 // Determine `fieldi` that `id` matches
1545 Dsymbol s
= sd
.search(iloc
, id
);
1548 s
= sd
.search_correct(id
);
1550 error(argLoc
, "`%s` is not a member of `%s`, did you mean %s `%s`?", id
.toChars(), sd
.toChars(), s
.kind(), s
.toChars());
1552 error(argLoc
, "`%s` is not a member of `%s`", id
.toChars(), sd
.toChars());
1555 s
.checkDeprecated(iloc
, sc
);
1558 // Find out which field index `s` is
1559 for (fieldi
= 0; 1; fieldi
++)
1561 if (fieldi
>= nfields
)
1563 error(iloc
, "`%s.%s` is not a per-instance initializable field", sd
.toChars(), s
.toChars());
1566 if (s
== sd
.fields
[fieldi
])
1572 error(argLoc
, "initializer provided for struct `%s` with no fields", sd
.toChars());
1577 error(argLoc
, "too many initializers for `%s` with %d field%s", sd
.toChars(),
1578 cast(int) nfields
, nfields
!= 1 ?
"s".ptr
: "".ptr
);
1581 if (fieldi
>= nfields
)
1583 error(argLoc
, "trying to initialize past the last field `%s` of `%s`", sd
.fields
[nfields
- 1].toChars(), sd
.toChars());
1587 VarDeclaration vd
= sd
.fields
[fieldi
];
1590 error(argLoc
, "duplicate initializer for field `%s`", vd
.toChars());
1592 elems
[fieldi
] = ErrorExp
.get(); // for better diagnostics on multiple errors
1597 // Check for @safe violations
1598 if (vd
.type
.hasPointers
)
1600 if ((!t
.alignment
.isDefault() && t
.alignment
.get() < target
.ptrsize ||
1601 (vd
.offset
& (target
.ptrsize
- 1))))
1603 if (sc
.setUnsafe(false, argLoc
,
1604 "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd
, vd
))
1607 elems
[fieldi
] = ErrorExp
.get(); // for better diagnostics on multiple errors
1614 // Check for overlapping initializations (can happen with unions)
1615 foreach (k
, v2
; sd
.fields
[0 .. nfields
])
1617 if (vd
.isOverlappedWith(v2
) && elems
[k
])
1619 error(elems
[k
].loc
, "overlapping initialization for field `%s` and `%s`", v2
.toChars(), vd
.toChars());
1620 enum errorMsg
= "`struct` initializers that contain anonymous unions" ~
1621 " must initialize only the first member of a `union`. All subsequent" ~
1622 " non-overlapping fields are default initialized";
1623 if (!sd
.isUnionDeclaration())
1624 .errorSupplemental(elems
[k
].loc
, errorMsg
);
1632 auto ex
= getExp(j
, vd
.type
);
1634 if (ex
.op
== EXP
.error
)
1637 elems
[fieldi
] = ErrorExp
.get(); // for better diagnostics on multiple errors
1642 elems
[fieldi
] = doCopyOrMove(sc
, ex
);