2 * Semantic analysis of expressions.
4 * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions)
6 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expressionsem.d, _expressionsem.d)
10 * Documentation: https://dlang.org/phobos/dmd_expressionsem.html
11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/expressionsem.d
14 module dmd
.expressionsem
;
16 import core
.stdc
.stdio
;
22 import dmd
.arraytypes
;
24 import dmd
.astcodegen
;
31 import dmd
.declaration
;
34 import dmd
.delegatize
;
37 import dmd
.dinterpret
;
41 import dmd
.dsymbolsem
;
46 import dmd
.expression
;
47 import dmd
.file_manager
;
52 import dmd
.identifier
;
68 import dmd
.postordervisitor
;
69 import dmd
.root
.array
;
70 import dmd
.root
.ctfloat
;
71 import dmd
.root
.filename
;
72 import dmd
.common
.outbuffer
;
73 import dmd
.rootobject
;
74 import dmd
.root
.string
;
78 import dmd
.sideeffect
;
88 enum LOGSEMANTIC
= false;
90 /***********************************
91 * Determine if a `this` is needed to access `d`.
94 * d = declaration to check
96 * true means a `this` is needed
98 private bool isNeedThisScope(Scope
* sc
, Declaration d
)
100 if (sc
.intypeof
== 1)
103 AggregateDeclaration ad
= d
.isThis();
106 //printf("d = %s, ad = %s\n", d.toChars(), ad.toChars());
108 for (Dsymbol s
= sc
.parent
; s
; s
= s
.toParentLocal())
110 //printf("\ts = %s %s, toParent2() = %p\n", s.kind(), s.toChars(), s.toParent2());
111 if (AggregateDeclaration ad2
= s
.isAggregateDeclaration())
115 else if (ad2
.isNested())
120 if (FuncDeclaration f
= s
.isFuncDeclaration())
122 if (f
.isMemberLocal())
130 /********************************************************
131 * Perform semantic analysis and CTFE on expressions to produce
134 * buf = append generated string to buffer
136 * exps = array of Expressions
140 bool expressionsToString(ref OutBuffer buf
, Scope
* sc
, Expressions
* exps
)
149 auto sc2
= sc
.startCTFE();
151 sc2
.minst
= null; // prevents emission of any instantiated templates to object file
152 auto e2
= ex
.expressionSemantic(sc2
);
153 auto e3
= resolveProperties(sc2
, e2
);
156 // allowed to contain types as well as expressions
157 auto e4
= ctfeInterpretForPragmaMsg(e3
);
158 if (!e4 || e4
.op
== EXP
.error
)
162 if (auto te
= e4
.isTupleExp())
164 if (expressionsToString(buf
, sc
, te
.exps
))
168 // char literals exp `.toStringExp` return `null` but we cant override it
169 // because in most contexts we don't want the conversion to succeed.
170 IntegerExp ie
= e4
.isIntegerExp();
171 const ty
= (ie
&& ie
.type
) ? ie
.type
.ty
: Terror
;
174 auto tsa
= new TypeSArray(ie
.type
, IntegerExp
.literal
!1);
175 e4
= new ArrayLiteralExp(ex
.loc
, tsa
, ie
);
178 if (StringExp se
= e4
.toStringExp())
179 buf
.writestring(se
.toUTF8(sc
).peekString());
181 buf
.writestring(e4
.toString());
186 /*****************************************
187 * Determine if `this` is available by walking up the enclosing
188 * scopes until a function is found.
191 * sc = where to start looking for the enclosing function
193 * Found function if it satisfies `isThis()`, otherwise `null`
195 FuncDeclaration
hasThis(Scope
* sc
)
197 //printf("hasThis()\n");
198 Dsymbol p
= sc
.parent
;
199 while (p
&& p
.isTemplateMixin())
201 FuncDeclaration fdthis
= p ? p
.isFuncDeclaration() : null;
202 //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis.toChars() : "");
204 // Go upwards until we find the enclosing member function
205 FuncDeclaration fd
= fdthis
;
212 if (!fd
.isNested() || fd
.isThis() ||
(fd
.hasDualContext() && fd
.isMember2()))
215 Dsymbol parent
= fd
.parent
;
220 TemplateInstance ti
= parent
.isTemplateInstance();
226 fd
= parent
.isFuncDeclaration();
229 if (!fd
.isThis() && !(fd
.hasDualContext() && fd
.isMember2()))
239 extern (D
) bool findTempDecl(DotTemplateInstanceExp exp
, Scope
* sc
)
243 static if (LOGSEMANTIC
)
245 printf("DotTemplateInstanceExp::findTempDecl('%s')\n", exp
.toChars());
250 Expression e
= new DotIdExp(exp
.loc
, e1
, ti
.name
);
251 e
= e
.expressionSemantic(sc
);
253 e
= (cast(DotExp
)e
).e2
;
258 case EXP
.overloadSet
:
259 s
= (cast(OverExp
)e
).vars
;
262 case EXP
.dotTemplateDeclaration
:
263 s
= (cast(DotTemplateExp
)e
).td
;
267 s
= (cast(ScopeExp
)e
).sds
;
270 case EXP
.dotVariable
:
271 s
= (cast(DotVarExp
)e
).var
;
275 s
= (cast(VarExp
)e
).var
;
281 return ti
.updateTempDecl(sc
, s
);
284 /***********************************************************
285 * Resolve `exp` as a compile-time known string.
288 * exp = Expression which expected as a string
289 * s = What the string is expected for, will be used in error diagnostic.
291 * String literal, or `null` if error happens.
293 StringExp
semanticString(Scope
*sc
, Expression exp
, const char* s
)
296 exp
= exp
.expressionSemantic(sc
);
297 exp
= resolveProperties(sc
, exp
);
300 if (exp
.op
== EXP
.error
)
304 if (exp
.type
.isString())
306 e
= e
.ctfeInterpret();
307 if (e
.op
== EXP
.error
)
311 auto se
= e
.toStringExp();
314 error(exp
.loc
, "`string` expected for %s, not `(%s)` of type `%s`",
315 s
, exp
.toChars(), exp
.type
.toChars());
321 /****************************************
322 * Convert string to char[].
324 StringExp
toUTF8(StringExp se
, Scope
* sc
)
328 // Convert to UTF-8 string
329 se
.committed
= false;
330 Expression e
= castTo(se
, sc
, Type
.tchar
.arrayOf());
331 e
= e
.optimize(WANTvalue
);
332 auto result
= e
.isStringExp();
333 assert(result
.sz
== 1);
339 private Expression
reorderSettingAAElem(BinExp exp
, Scope
* sc
)
343 auto ie
= be
.e1
.isIndexExp();
346 if (ie
.e1
.type
.toBasetype().ty
!= Taarray
)
349 /* Fix evaluation order of setting AA element
350 * https://issues.dlang.org/show_bug.cgi?id=3825
352 * aa[k1][k2][k3] op= val;
354 * auto ref __aatmp = aa;
355 * auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3;
356 * auto ref __aaval = val;
357 * __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval; // assignment
364 ie
.e2
= extractSideEffect(sc
, "__aakey", de, ie
.e2
);
365 e0
= Expression
.combine(de, e0
);
367 auto ie1
= ie
.e1
.isIndexExp();
369 ie1
.e1
.type
.toBasetype().ty
!= Taarray
)
375 assert(ie
.e1
.type
.toBasetype().ty
== Taarray
);
378 ie
.e1
= extractSideEffect(sc
, "__aatmp", de, ie
.e1
);
379 e0
= Expression
.combine(de, e0
);
381 be
.e2
= extractSideEffect(sc
, "__aaval", e0
, be
.e2
, true);
383 //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars());
384 return Expression
.combine(e0
, be
);
388 private Expression
checkOpAssignTypes(BinExp binExp
, Scope
* sc
)
393 auto type
= binExp
.type
;
394 auto loc
= binExp
.loc
;
396 // At that point t1 and t2 are the merged types. type is the original type of the lhs.
400 // T opAssign floating yields a floating. Prevent truncating conversions (float to int).
401 // See https://issues.dlang.org/show_bug.cgi?id=3841.
402 // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ?
403 if (op
== EXP
.addAssign || op
== EXP
.minAssign ||
404 op
== EXP
.mulAssign || op
== EXP
.divAssign || op
== EXP
.modAssign ||
407 if ((type
.isintegral() && t2
.isfloating()))
409 warning(loc
, "`%s %s %s` is performing truncating conversion", type
.toChars(), EXPtoString(op
).ptr
, t2
.toChars());
413 // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
414 if (op
== EXP
.mulAssign || op
== EXP
.divAssign || op
== EXP
.modAssign
)
416 // Any multiplication by an imaginary or complex number yields a complex result.
417 // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
418 const(char)* opstr
= EXPtoString(op
).ptr
;
419 if (t1
.isreal() && t2
.iscomplex())
421 error(loc
, "`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1
.toChars(), opstr
, t2
.toChars(), t1
.toChars(), opstr
, t2
.toChars());
422 return ErrorExp
.get();
424 else if (t1
.isimaginary() && t2
.iscomplex())
426 error(loc
, "`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1
.toChars(), opstr
, t2
.toChars(), t1
.toChars(), opstr
, t2
.toChars());
427 return ErrorExp
.get();
429 else if ((t1
.isreal() || t1
.isimaginary()) && t2
.isimaginary())
431 error(loc
, "`%s %s %s` is an undefined operation", t1
.toChars(), opstr
, t2
.toChars());
432 return ErrorExp
.get();
436 // generate an error if this is a nonsensical += or -=, eg real += imaginary
437 if (op
== EXP
.addAssign || op
== EXP
.minAssign
)
439 // Addition or subtraction of a real and an imaginary is a complex result.
440 // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
441 if ((t1
.isreal() && (t2
.isimaginary() || t2
.iscomplex())) ||
(t1
.isimaginary() && (t2
.isreal() || t2
.iscomplex())))
443 error(loc
, "`%s %s %s` is undefined (result is complex)", t1
.toChars(), EXPtoString(op
).ptr
, t2
.toChars());
444 return ErrorExp
.get();
446 if (type
.isreal() || type
.isimaginary())
448 assert(global
.errors || t2
.isfloating());
449 e2
= e2
.castTo(sc
, t1
);
452 if (op
== EXP
.mulAssign
)
458 if (t2
.isimaginary() || t2
.iscomplex())
460 e2
= e2
.castTo(sc
, t1
);
463 else if (t1
.isimaginary())
465 if (t2
.isimaginary() || t2
.iscomplex())
484 e2
= e2
.castTo(sc
, t2
);
489 else if (op
== EXP
.divAssign
)
491 if (t2
.isimaginary())
496 // Therefore, the result is 0
497 e2
= new CommaExp(loc
, e2
, new RealExp(loc
, CTFloat
.zero
, t1
));
499 Expression e
= new AssignExp(loc
, e1
, e2
);
503 else if (t1
.isimaginary())
523 e2
= e2
.castTo(sc
, t3
);
524 Expression e
= new AssignExp(loc
, e1
, e2
);
530 else if (op
== EXP
.modAssign
)
534 error(loc
, "cannot perform modulo complex arithmetic");
535 return ErrorExp
.get();
541 private Expression
extractOpDollarSideEffect(Scope
* sc
, UnaExp ue
)
544 Expression e1
= Expression
.extractLast(ue
.e1
, e0
);
545 // https://issues.dlang.org/show_bug.cgi?id=12585
546 // Extract the side effect part if ue.e1 is comma.
548 if ((sc
.flags
& SCOPE
.ctfe
) ?
hasSideEffect(e1
) : !isTrivialExp(e1
)) // match logic in extractSideEffect()
550 /* Even if opDollar is needed, 'e1' should be evaluate only once. So
552 * e1.opIndex( ... use of $ ... )
553 * e1.opSlice( ... use of $ ... )
555 * (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...)
556 * (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
558 e1
= extractSideEffect(sc
, "__dop", e0
, e1
, false);
559 assert(e1
.isVarExp());
560 e1
.isVarExp().var
.storage_class |
= STC
.exptemp
; // lifetime limited to expression
566 /**************************************
567 * Runs semantic on ae.arguments. Declares temporary variables
570 Expression
resolveOpDollar(Scope
* sc
, ArrayExp ae
, Expression
* pe0
)
572 assert(!ae
.lengthVar
);
574 AggregateDeclaration ad
= isAggregate(ae
.e1
.type
);
575 Dsymbol slice
= search_function(ad
, Id
.slice
);
576 //printf("slice = %s %s\n", slice.kind(), slice.toChars());
577 foreach (i
, e
; *ae
.arguments
)
580 *pe0
= extractOpDollarSideEffect(sc
, ae
);
582 if (e
.op
== EXP
.interval
&& !(slice
&& slice
.isTemplateDeclaration()))
585 if (ae
.arguments
.length
== 1)
587 error(ae
.loc
, "multi-dimensional slicing requires template `opSlice`");
588 return ErrorExp
.get();
590 //printf("[%d] e = %s\n", i, e.toChars());
592 // Create scope for '$' variable for this dimension
593 auto sym
= new ArrayScopeSymbol(sc
, ae
);
594 sym
.parent
= sc
.scopesym
;
596 ae
.lengthVar
= null; // Create it only if required
597 ae
.currentDimension
= i
; // Dimension for $, if required
599 e
= e
.expressionSemantic(sc
);
600 e
= resolveProperties(sc
, e
);
602 if (ae
.lengthVar
&& sc
.func
)
604 // If $ was used, declare it now
605 Expression
de = new DeclarationExp(ae
.loc
, ae
.lengthVar
);
606 de = de.expressionSemantic(sc
);
607 *pe0
= Expression
.combine(*pe0
, de);
611 if (auto ie
= e
.isIntervalExp())
613 auto tiargs
= new Objects();
614 Expression edim
= new IntegerExp(ae
.loc
, i
, Type
.tsize_t
);
615 edim
= edim
.expressionSemantic(sc
);
618 auto fargs
= new Expressions(2);
619 (*fargs
)[0] = ie
.lwr
;
620 (*fargs
)[1] = ie
.upr
;
622 uint xerrors
= global
.startGagging();
624 FuncDeclaration fslice
= resolveFuncCall(ae
.loc
, sc
, slice
, tiargs
, ae
.e1
.type
, ArgumentList(fargs
), FuncResolveFlag
.quiet
);
626 global
.endGagging(xerrors
);
630 e
= new DotTemplateInstanceExp(ae
.loc
, ae
.e1
, slice
.ident
, tiargs
);
631 e
= new CallExp(ae
.loc
, e
, fargs
);
632 e
= e
.expressionSemantic(sc
);
637 error(ae
.loc
, "`%s` has no value", e
.toChars());
640 if (e
.op
== EXP
.error
)
643 (*ae
.arguments
)[i
] = e
;
648 /**************************************
649 * Runs semantic on se.lwr and se.upr. Declares a temporary variable
652 * ae, or ErrorExp if errors occurred
654 Expression
resolveOpDollar(Scope
* sc
, ArrayExp ae
, IntervalExp ie
, Expression
* pe0
)
656 //assert(!ae.lengthVar);
660 VarDeclaration lengthVar
= ae
.lengthVar
;
663 // create scope for '$'
664 auto sym
= new ArrayScopeSymbol(sc
, ae
);
665 sym
.parent
= sc
.scopesym
;
668 Expression
sem(Expression e
)
670 e
= e
.expressionSemantic(sc
);
671 e
= resolveProperties(sc
, e
);
674 error(ae
.loc
, "`%s` has no value", e
.toChars());
680 ie
.lwr
= sem(ie
.lwr
);
681 ie
.upr
= sem(ie
.upr
);
683 if (ie
.lwr
.isErrorExp() || ie
.upr
.isErrorExp())
686 if (lengthVar
!= ae
.lengthVar
&& sc
.func
)
688 // If $ was used, declare it now
689 Expression
de = new DeclarationExp(ae
.loc
, ae
.lengthVar
);
690 de = de.expressionSemantic(sc
);
691 *pe0
= Expression
.combine(*pe0
, de);
696 return errors ? ErrorExp
.get() : ae
;
699 /******************************
700 * Perform semantic() on an array of Expressions.
702 extern(D
) bool arrayExpressionSemantic(
703 Expression
[] exps
, Scope
* sc
, bool preserveErrors
= false)
706 foreach (ref e
; exps
)
708 if (e
is null) continue;
709 auto e2
= e
.expressionSemantic(sc
);
710 if (e2
.op
== EXP
.error
)
712 if (preserveErrors || e2
.op
!= EXP
.error
)
718 /************************************************
719 * Handle the postblit call on lvalue, or the move of rvalue.
722 * sc = the scope where the expression is encountered
723 * e = the expression the needs to be moved or copied (source)
724 * t = if the struct defines a copy constructor, the type of the destination
727 * The expression that copy constructs or moves the value.
729 extern (D
) Expression
doCopyOrMove(Scope
*sc
, Expression e
, Type t
= null)
731 if (auto ce
= e
.isCondExp())
733 ce
.e1
= doCopyOrMove(sc
, ce
.e1
);
734 ce
.e2
= doCopyOrMove(sc
, ce
.e2
);
738 e
= e
.isLvalue() ?
callCpCtor(sc
, e
, t
) : valueNoDtor(e
);
743 /*********************************************
744 * If e is an instance of a struct, and that struct has a copy constructor,
748 * sc = just used to specify the scope of created temporary variable
749 * destinationType = the type of the object on which the copy constructor is called;
750 * may be null if the struct defines a postblit
752 private Expression
callCpCtor(Scope
* sc
, Expression e
, Type destinationType
)
754 if (auto ts
= e
.type
.baseElemOf().isTypeStruct())
756 StructDeclaration sd
= ts
.sym
;
757 if (sd
.postblit || sd
.hasCopyCtor
)
759 /* Create a variable tmp, and replace the argument e with:
761 * and let AssignExp() handle the construction.
762 * This is not the most efficient, ideally tmp would be constructed
763 * directly onto the stack.
765 auto tmp
= copyToTemp(STC
.rvalue
, "__copytmp", e
);
766 if (sd
.hasCopyCtor
&& destinationType
)
768 // https://issues.dlang.org/show_bug.cgi?id=22619
769 // If the destination type is inout we can preserve it
770 // only if inside an inout function; if we are not inside
771 // an inout function, then we will preserve the type of
773 if (destinationType
.hasWild
&& !(sc
.func
.storage_class
& STC
.wild
))
776 tmp
.type
= destinationType
;
778 tmp
.storage_class |
= STC
.nodtor
;
779 tmp
.dsymbolSemantic(sc
);
780 Expression
de = new DeclarationExp(e
.loc
, tmp
);
781 Expression ve
= new VarExp(e
.loc
, tmp
);
782 de.type
= Type
.tvoid
;
784 return Expression
.combine(de, ve
);
790 /************************************************
791 * If we want the value of this expression, but do not want to call
792 * the destructor on it.
794 Expression
valueNoDtor(Expression e
)
796 auto ex
= lastComma(e
);
798 if (auto ce
= ex
.isCallExp())
800 /* The struct value returned from the function is transferred
801 * so do not call the destructor on it.
803 * ((S _ctmp = S.init), _ctmp).this(...)
804 * and make sure the destructor is not called on _ctmp
805 * BUG: if ex is a CommaExp, we should go down the right side.
807 if (auto dve
= ce
.e1
.isDotVarExp())
809 if (dve
.var
.isCtorDeclaration())
811 // It's a constructor call
812 if (auto comma
= dve
.e1
.isCommaExp())
814 if (auto ve
= comma
.e2
.isVarExp())
816 VarDeclaration ctmp
= ve
.var
.isVarDeclaration();
819 ctmp
.storage_class |
= STC
.nodtor
;
820 assert(!ce
.isLvalue());
827 else if (auto ve
= ex
.isVarExp())
829 auto vtmp
= ve
.var
.isVarDeclaration();
830 if (vtmp
&& (vtmp
.storage_class
& STC
.rvalue
))
832 vtmp
.storage_class |
= STC
.nodtor
;
839 Checks if `exp` contains a direct access to a `noreturn`
840 variable. If that is the case, an `assert(0)` expression
841 is generated and returned. This function should be called
842 only after semantic analysis has been performed on `exp`.
845 exp = expression that is checked
848 An `assert(0)` expression if `exp` contains a `noreturn`
849 variable access, `exp` otherwise.
852 Expression
checkNoreturnVarAccess(Expression exp
)
856 Expression result
= exp
;
857 if (exp
.type
.isTypeNoreturn() && !exp
.isAssertExp() &&
858 !exp
.isThrowExp() && !exp
.isCallExp())
860 auto msg
= new StringExp(exp
.loc
, "Accessed expression of type `noreturn`");
861 msg
.type
= Type
.tstring
;
862 result
= new AssertExp(exp
.loc
, IntegerExp
.literal
!0, msg
);
863 result
.type
= exp
.type
;
869 /******************************
870 * Find symbol in accordance with the UFCS name look up rule
872 private Expression
searchUFCS(Scope
* sc
, UnaExp ue
, Identifier ident
)
874 //printf("searchUFCS(ident = %s)\n", ident.toChars());
877 // TODO: merge with Scope.search.searchScopes()
878 Dsymbol
searchScopes(int flags
)
881 for (Scope
* scx
= sc
; scx
; scx
= scx
.enclosing
)
885 if (scx
.scopesym
.isModule())
886 flags |
= SearchUnqualifiedModule
; // tell Module.search() that SearchLocalsOnly is to be obeyed
887 s
= scx
.scopesym
.search(loc
, ident
, flags
);
890 // overload set contains only module scope symbols.
891 if (s
.isOverloadSet())
893 // selective/renamed imports also be picked up
894 if (AliasDeclaration ad
= s
.isAliasDeclaration())
899 // See only module scope symbols for UFCS target.
900 Dsymbol p
= s
.toParent2();
901 if (p
&& p
.isModule())
906 // Stop when we hit a module, but keep going if that is not just under the global scope
907 if (scx
.scopesym
.isModule() && !(scx
.enclosing
&& !scx
.enclosing
.enclosing
))
916 if (sc
.flags
& SCOPE
.ignoresymbolvisibility
)
917 flags |
= IgnoreSymbolVisibility
;
919 // First look in local scopes
920 s
= searchScopes(flags | SearchLocalsOnly
);
923 // Second look in imported modules
924 s
= searchScopes(flags | SearchImportsOnly
);
928 return ue
.e1
.type
.getProperty(sc
, loc
, ident
, 0, ue
.e1
);
930 FuncDeclaration f
= s
.isFuncDeclaration();
933 TemplateDeclaration td
= getFuncTemplateDecl(f
);
942 if (auto dti
= ue
.isDotTemplateInstanceExp())
944 // https://issues.dlang.org/show_bug.cgi?id=23968
945 // Typically, deprecated alias declarations are caught
946 // when `TemplateInstance.findTempDecl` is called,
947 // however, in this case the tempdecl field is updated
948 // therefore `findTempDecl` will return immediately
949 // and not get the chance to issue the deprecation.
950 if (s
.isAliasDeclaration())
951 s
.checkDeprecated(ue
.loc
, sc
);
953 auto ti
= new TemplateInstance(loc
, s
.ident
, dti
.ti
.tiargs
);
954 if (!ti
.updateTempDecl(sc
, s
))
955 return ErrorExp
.get();
956 return new ScopeExp(loc
, ti
);
960 //printf("-searchUFCS() %s\n", s.toChars());
961 return new DsymbolExp(loc
, s
);
965 /******************************
966 * check e is exp.opDispatch!(tiargs) or not
967 * It's used to switch to UFCS the semantic analysis path
969 private bool isDotOpDispatch(Expression e
)
971 if (auto dtie
= e
.isDotTemplateInstanceExp())
972 return dtie
.ti
.name
== Id
.opDispatch
;
976 private void hookDtors(CondExp ce
, Scope
* sc
)
978 extern (C
++) final class DtorVisitor
: StoppableVisitor
980 alias visit
= typeof(super).visit
;
984 VarDeclaration vcond
;
987 extern (D
) this(Scope
* sc
, CondExp ce
) @safe
993 override void visit(Expression e
)
995 //printf("(e = %s)\n", e.toChars());
998 override void visit(DeclarationExp e
)
1000 auto v
= e
.declaration
.isVarDeclaration();
1001 if (v
&& !v
.isDataseg())
1005 if (auto ei
= v
._init
.isExpInitializer())
1006 walkPostorder(ei
.exp
, this);
1010 walkPostorder(v
.edtor
, this);
1012 if (v
.needsScopeDtor())
1016 vcond
= copyToTemp(STC
.volatile_ | STC
.const_
, "__cond", ce
.econd
);
1017 vcond
.dsymbolSemantic(sc
);
1019 Expression
de = new DeclarationExp(ce
.econd
.loc
, vcond
);
1020 de = de.expressionSemantic(sc
);
1022 Expression ve
= new VarExp(ce
.econd
.loc
, vcond
);
1023 ce
.econd
= Expression
.combine(de, ve
);
1026 //printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
1027 Expression ve
= new VarExp(vcond
.loc
, vcond
);
1029 v
.edtor
= new LogicalExp(v
.edtor
.loc
, EXP
.andAnd
, ve
, v
.edtor
);
1031 v
.edtor
= new LogicalExp(v
.edtor
.loc
, EXP
.orOr
, ve
, v
.edtor
);
1032 v
.edtor
= v
.edtor
.expressionSemantic(sc
);
1033 //printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
1039 scope DtorVisitor v
= new DtorVisitor(sc
, ce
);
1040 //printf("+%s\n", toChars());
1042 walkPostorder(ce
.e1
, v
);
1044 walkPostorder(ce
.e2
, v
);
1045 //printf("-%s\n", toChars());
1049 /******************************
1050 * Pull out callable entity with UFCS.
1052 private Expression
resolveUFCS(Scope
* sc
, CallExp ce
)
1058 if (auto die
= ce
.e1
.isDotIdExp())
1060 Identifier ident
= die
.ident
;
1062 Expression ex
= die
.dotIdSemanticPropX(sc
);
1070 Type t
= eleft
.type
.toBasetype();
1071 if (t
.ty
== Tarray || t
.ty
== Tsarray || t
.ty
== Tnull ||
(t
.isTypeBasic() && t
.ty
!= Tvoid
))
1073 /* Built-in types and arrays have no callable properties, so do shortcut.
1074 * It is necessary in: e.init()
1077 else if (t
.ty
== Taarray
)
1079 if (ident
== Id
.remove
)
1082 * aa.remove(arg) into delete aa[arg]
1084 if (!ce
.arguments || ce
.arguments
.length
!= 1)
1086 error(ce
.loc
, "expected key as argument to `aa.remove()`");
1087 return ErrorExp
.get();
1089 if (!eleft
.type
.isMutable())
1091 error(ce
.loc
, "cannot remove key from `%s` associative array `%s`", MODtoChars(t
.mod
), eleft
.toChars());
1092 return ErrorExp
.get();
1094 Expression key
= (*ce
.arguments
)[0];
1095 key
= key
.expressionSemantic(sc
);
1096 key
= resolveProperties(sc
, key
);
1098 TypeAArray taa
= t
.isTypeAArray();
1099 key
= key
.implicitCastTo(sc
, taa
.index
);
1101 if (key
.checkValue() || key
.checkSharedAccess(sc
))
1102 return ErrorExp
.get();
1104 semanticTypeInfo(sc
, taa
.index
);
1106 return new RemoveExp(loc
, eleft
, key
);
1111 if (Expression ey
= die
.dotIdSemanticProp(sc
, 1))
1113 if (ey
.op
== EXP
.error
)
1116 if (isDotOpDispatch(ey
))
1118 // even opDispatch and UFCS must have valid arguments,
1119 // so now that we've seen indication of a problem,
1120 // check them for issues.
1121 Expressions
* originalArguments
= Expression
.arraySyntaxCopy(ce
.arguments
);
1123 uint errors
= global
.startGagging();
1124 e
= ce
.expressionSemantic(sc
);
1125 if (!global
.endGagging(errors
))
1128 if (arrayExpressionSemantic(originalArguments
.peekSlice(), sc
))
1129 return ErrorExp
.get();
1131 /* fall down to UFCS */
1138 /* https://issues.dlang.org/show_bug.cgi?id=13953
1140 * If a struct has an alias this to an associative array
1141 * and remove is used on a struct instance, we have to
1142 * check first if there is a remove function that can be called
1143 * on the struct. If not we must check the alias this.
1157 const errors
= global
.startGagging();
1158 e
= searchUFCS(sc
, die
, ident
);
1159 // if there were any errors and the identifier was remove
1160 if (global
.endGagging(errors
))
1162 if (ident
== Id
.remove
)
1165 Expression alias_e
= resolveAliasThis(sc
, die
.e1
, 1);
1166 if (alias_e
&& alias_e
!= die
.e1
)
1169 CallExp ce2
= ce
.syntaxCopy();
1171 e
= ce2
.isCallExp().trySemantic(sc
);
1176 // if alias this did not work out, print the initial errors
1177 searchUFCS(sc
, die
, ident
);
1180 else if (auto dti
= ce
.e1
.isDotTemplateInstanceExp())
1182 if (Expression ey
= dti
.dotTemplateSemanticProp(sc
, DotExpFlag
.gag
))
1188 e
= searchUFCS(sc
, dti
, dti
.ti
.name
);
1196 ce
.arguments
= new Expressions();
1197 ce
.arguments
.shift(eleft
);
1199 ce
.names
= new Identifiers();
1200 ce
.names
.shift(null);
1201 ce
.isUfcsRewrite
= true;
1205 int expandAliasThisTuples(Expressions
* exps
, size_t starti
= 0)
1207 if (!exps || exps
.length
== 0)
1210 for (size_t u
= starti
; u
< exps
.length
; u
++)
1212 Expression exp
= (*exps
)[u
];
1213 if (TupleDeclaration td
= exp
.isAliasThisTuple
)
1219 auto d
= s
.isDeclaration();
1220 auto e
= new DotVarExp(exp
.loc
, exp
, d
);
1223 exps
.insert(u
+ i
, e
);
1228 printf("expansion ->\n");
1231 printf("\texps[%d] e = %s %s\n", i
, EXPtoString(e
.op
), e
.toChars());
1240 /******************************
1241 * Pull out property with UFCS.
1243 private Expression
resolveUFCSProperties(Scope
* sc
, Expression e1
, Expression e2
= null)
1249 if (auto die
= e1
.isDotIdExp())
1252 e
= searchUFCS(sc
, die
, die
.ident
);
1254 else if (auto dti
= e1
.isDotTemplateInstanceExp())
1257 e
= searchUFCS(sc
, dti
, dti
.ti
.name
);
1268 // run semantic without gagging
1269 e2
= e2
.expressionSemantic(sc
);
1273 Expression ex
= e
.copy();
1274 auto a1
= new Expressions(1);
1276 ex
= new CallExp(loc
, ex
, a1
);
1277 auto e1PassSemantic
= ex
.trySemantic(sc
);
1281 auto a2
= new Expressions(2);
1284 e
= new CallExp(loc
, e
, a2
);
1285 e
= e
.trySemantic(sc
);
1286 if (!e1PassSemantic
&& !e
)
1288 /* https://issues.dlang.org/show_bug.cgi?id=20448
1290 * If both versions have failed to pass semantic,
1291 * f(e1) = e2 gets priority in error printing
1292 * because f might be a templated function that
1293 * failed to instantiate and we have to print
1294 * the instantiation errors.
1296 return e1
.expressionSemantic(sc
);
1300 ex
= new AssignExp(loc
, ex
, e2
);
1301 return ex
.expressionSemantic(sc
);
1305 // strict setter prints errors if fails
1306 e
= e
.expressionSemantic(sc
);
1314 auto arguments
= new Expressions(1);
1315 (*arguments
)[0] = eleft
;
1316 e
= new CallExp(loc
, e
, arguments
);
1318 // https://issues.dlang.org/show_bug.cgi?id=24017
1319 if (sc
.flags
& SCOPE
.debug_
)
1320 e
.isCallExp().inDebugStatement
= true;
1322 e
= e
.expressionSemantic(sc
);
1327 /******************************
1328 * If e1 is a property function (template), resolve it.
1330 Expression
resolvePropertiesOnly(Scope
* sc
, Expression e1
)
1332 //printf("e1 = %s %s\n", Token.toChars(e1.op), e1.toChars());
1334 Expression
handleOverloadSet(OverloadSet os
)
1339 auto fd
= s
.isFuncDeclaration();
1340 auto td
= s
.isTemplateDeclaration();
1343 if (fd
.type
.isTypeFunction().isproperty
)
1344 return resolveProperties(sc
, e1
);
1346 else if (td
&& td
.onemember
&& (fd
= td
.onemember
.isFuncDeclaration()) !is null)
1348 if (fd
.type
.isTypeFunction().isproperty ||
1349 (fd
.storage_class2
& STC
.property
) ||
1350 (td
._scope
.stc & STC
.property
))
1351 return resolveProperties(sc
, e1
);
1357 Expression
handleTemplateDecl(TemplateDeclaration td
)
1362 if (auto fd
= td
.onemember
.isFuncDeclaration())
1364 if (fd
.type
.isTypeFunction().isproperty ||
1365 (fd
.storage_class2
& STC
.property
) ||
1366 (td
._scope
.stc & STC
.property
))
1367 return resolveProperties(sc
, e1
);
1373 Expression
handleFuncDecl(FuncDeclaration fd
)
1376 if (fd
.type
.isTypeFunction().isproperty
)
1377 return resolveProperties(sc
, e1
);
1381 if (auto de = e1
.isDotExp())
1383 if (auto os
= de.e2
.isOverExp())
1384 return handleOverloadSet(os
.vars
);
1386 else if (auto oe
= e1
.isOverExp())
1387 return handleOverloadSet(oe
.vars
);
1388 else if (auto dti
= e1
.isDotTemplateInstanceExp())
1390 if (dti
.ti
.tempdecl
)
1391 if (auto td
= dti
.ti
.tempdecl
.isTemplateDeclaration())
1392 return handleTemplateDecl(td
);
1394 else if (auto dte
= e1
.isDotTemplateExp())
1395 return handleTemplateDecl(dte
.td
);
1396 else if (auto se
= e1
.isScopeExp())
1399 TemplateInstance ti
= s
.isTemplateInstance();
1400 if (ti
&& !ti
.semanticRun
&& ti
.tempdecl
)
1401 if (auto td
= ti
.tempdecl
.isTemplateDeclaration())
1402 return handleTemplateDecl(td
);
1404 else if (auto et
= e1
.isTemplateExp())
1405 return handleTemplateDecl(et
.td
);
1406 else if (e1
.isDotVarExp() && e1
.type
.isTypeFunction())
1408 DotVarExp dve
= e1
.isDotVarExp();
1409 return handleFuncDecl(dve
.var
.isFuncDeclaration());
1411 else if (e1
.isVarExp() && e1
.type
&& e1
.type
.isTypeFunction() && (sc
.intypeof ||
!e1
.isVarExp().var
.needThis()))
1412 return handleFuncDecl(e1
.isVarExp().var
.isFuncDeclaration());
1416 /****************************************
1417 * Turn symbol `s` into the expression it represents.
1420 * s = symbol to resolve
1421 * loc = location of use of `s`
1423 * hasOverloads = applies if `s` represents a function.
1424 * true means it's overloaded and will be resolved later,
1425 * false means it's the exact function symbol.
1427 * `s` turned into an expression, `ErrorExp` if an error occurred
1429 Expression
symbolToExp(Dsymbol s
, const ref Loc loc
, Scope
*sc
, bool hasOverloads
)
1431 static if (LOGSEMANTIC
)
1433 printf("DsymbolExp::resolve(%s %s)\n", s
.kind(), s
.toChars());
1439 //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars());
1440 //printf("s = '%s', s.kind = '%s'\n", s.toChars(), s.kind());
1442 Declaration d
= s
.isDeclaration();
1443 if (d
&& (d
.storage_class
& STC
.templateparameter
))
1449 // functions are checked after overloading
1450 // templates are checked after matching constraints
1451 if (!s
.isFuncDeclaration() && !s
.isTemplateDeclaration())
1453 s
.checkDeprecated(loc
, sc
);
1455 d
.checkDisabled(loc
, sc
);
1458 // https://issues.dlang.org/show_bug.cgi?id=12023
1459 // if 's' is a tuple variable, the tuple is returned.
1462 //printf("s = '%s', s.kind = '%s', s.needThis() = %p\n", s.toChars(), s.kind(), s.needThis());
1463 if (s
!= olds
&& !s
.isFuncDeclaration() && !s
.isTemplateDeclaration())
1465 s
.checkDeprecated(loc
, sc
);
1467 d
.checkDisabled(loc
, sc
);
1470 if (auto sd
= s
.isDeclaration())
1474 if (sc
.setUnsafePreview(global
.params
.systemVariables
, false, loc
,
1475 "cannot access `@system` variable `%s` in @safe code", sd
))
1477 if (auto v
= sd
.isVarDeclaration())
1479 if (v
.systemInferred
)
1480 errorSupplemental(v
.loc
, "`%s` is inferred to be `@system` from its initializer here", v
.toChars());
1482 errorSupplemental(v
.loc
, "`%s` is declared here", v
.toChars());
1484 return ErrorExp
.get();
1490 if (auto em
= s
.isEnumMember())
1492 return em
.getVarExp(loc
, sc
);
1494 if (auto v
= s
.isVarDeclaration())
1496 //printf("Identifier '%s' is a variable, type '%s'\n", s.toChars(), v.type.toChars());
1497 if (sc
.intypeof
== 1 && !v
.inuse
)
1498 v
.dsymbolSemantic(sc
);
1499 if (!v
.type ||
// during variable type inference
1500 !v
.type
.deco
&& v
.inuse
) // during variable type semantic
1502 if (v
.inuse
) // variable type depends on the variable itself
1503 error(loc
, "circular reference to %s `%s`", v
.kind(), v
.toPrettyChars());
1504 else // variable type cannot be determined
1505 error(loc
, "forward reference to %s `%s`", v
.kind(), v
.toPrettyChars());
1506 return ErrorExp
.get();
1508 if (v
.type
.ty
== Terror
)
1509 return ErrorExp
.get();
1511 if ((v
.storage_class
& STC
.manifest
) && v
._init
)
1515 error(loc
, "circular initialization of %s `%s`", v
.kind(), v
.toPrettyChars());
1516 return ErrorExp
.get();
1518 e
= v
.expandInitializer(loc
);
1520 e
= e
.expressionSemantic(sc
);
1525 // We need to run semantics to correctly set 'STC.field' if it is a member variable
1526 // that could be forward referenced. This is needed for 'v.needThis()' to work
1528 v
.dsymbolSemantic(sc
);
1530 // Change the ancestor lambdas to delegate before hasThis(sc) call.
1531 if (v
.checkNestedReference(sc
, loc
))
1532 return ErrorExp
.get();
1534 if (v
.needThis() && hasThis(sc
))
1535 e
= new DotVarExp(loc
, new ThisExp(loc
), v
);
1537 e
= new VarExp(loc
, v
);
1538 e
= e
.expressionSemantic(sc
);
1541 if (auto fld = s
.isFuncLiteralDeclaration())
1543 //printf("'%s' is a function literal\n", fld.toChars());
1544 e
= new FuncExp(loc
, fld);
1545 return e
.expressionSemantic(sc
);
1547 if (auto f
= s
.isFuncDeclaration())
1549 f
= f
.toAliasFunc();
1550 if (!f
.functionSemantic())
1551 return ErrorExp
.get();
1553 if (!hasOverloads
&& f
.checkForwardRef(loc
))
1554 return ErrorExp
.get();
1556 auto fd
= s
.isFuncDeclaration();
1558 return new VarExp(loc
, fd
, hasOverloads
);
1560 if (OverDeclaration od
= s
.isOverDeclaration())
1562 e
= new VarExp(loc
, od
, true);
1563 e
.type
= Type
.tvoid
;
1566 if (OverloadSet o
= s
.isOverloadSet())
1568 //printf("'%s' is an overload set\n", o.toChars());
1569 return new OverExp(loc
, o
);
1572 if (Import imp
= s
.isImport())
1576 .error(loc
, "forward reference of import `%s`", imp
.toChars());
1577 return ErrorExp
.get();
1579 auto ie
= new ScopeExp(loc
, imp
.pkg
);
1580 return ie
.expressionSemantic(sc
);
1582 if (Package pkg
= s
.isPackage())
1584 auto ie
= new ScopeExp(loc
, pkg
);
1585 return ie
.expressionSemantic(sc
);
1587 if (Module mod
= s
.isModule())
1589 auto ie
= new ScopeExp(loc
, mod
);
1590 return ie
.expressionSemantic(sc
);
1592 if (Nspace ns
= s
.isNspace())
1594 auto ie
= new ScopeExp(loc
, ns
);
1595 return ie
.expressionSemantic(sc
);
1598 if (Type t
= s
.getType())
1600 return (new TypeExp(loc
, t
)).expressionSemantic(sc
);
1603 if (TupleDeclaration tup
= s
.isTupleDeclaration())
1605 if (tup
.needThis() && hasThis(sc
))
1606 e
= new DotVarExp(loc
, new ThisExp(loc
), tup
);
1608 e
= new TupleExp(loc
, tup
);
1609 e
= e
.expressionSemantic(sc
);
1613 if (TemplateInstance ti
= s
.isTemplateInstance())
1615 ti
.dsymbolSemantic(sc
);
1616 if (!ti
.inst || ti
.errors
)
1617 return ErrorExp
.get();
1619 if (!s
.isTemplateInstance())
1621 e
= new ScopeExp(loc
, ti
);
1622 e
= e
.expressionSemantic(sc
);
1625 if (TemplateDeclaration td
= s
.isTemplateDeclaration())
1627 Dsymbol p
= td
.toParentLocal();
1628 FuncDeclaration fdthis
= hasThis(sc
);
1629 AggregateDeclaration ad
= p ? p
.isAggregateDeclaration() : null;
1630 if (fdthis
&& ad
&& fdthis
.isMemberLocal() == ad
&& (td
._scope
.stc & STC
.static_
) == 0)
1632 e
= new DotTemplateExp(loc
, new ThisExp(loc
), td
);
1635 e
= new TemplateExp(loc
, td
);
1636 e
= e
.expressionSemantic(sc
);
1640 .error(loc
, "%s `%s` is not a variable", s
.kind(), s
.toChars());
1641 return ErrorExp
.get();
1644 /*************************************************************
1645 * Given var, get the
1646 * right `this` pointer if var is in an outer class, but our
1647 * existing `this` pointer is in an inner class.
1649 * loc = location to use for error messages
1651 * ad = struct or class we need the correct `this` for
1652 * e1 = existing `this`
1653 * var = the specific member of ad we're accessing
1654 * flag = if true, return `null` instead of throwing an error
1656 * Expression representing the `this` for the var
1658 private Expression
getRightThis(const ref Loc loc
, Scope
* sc
, AggregateDeclaration ad
, Expression e1
, Dsymbol var
, int flag
= 0)
1660 //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars());
1662 Type t
= e1
.type
.toBasetype();
1663 //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars());
1665 if (e1
.op
== EXP
.objcClassReference
)
1667 // We already have an Objective-C class reference, just use that as 'this'.
1670 else if (ad
&& ad
.isClassDeclaration
&& ad
.isClassDeclaration
.classKind
== ClassKind
.objc
&&
1671 var
.isFuncDeclaration
&& var
.isFuncDeclaration
.isStatic
&&
1672 var
.isFuncDeclaration
.objc
.selector
)
1674 auto cls
= ad
.isClassDeclaration();
1675 auto classObj
= new ObjcClassReferenceExp(e1
.loc
, cls
);
1676 classObj
.type
= objc
.getRuntimeMetaclass(cls
).getType();
1680 /* Access of a member which is a template parameter in dual-scope scenario
1681 * class A { inc(alias m)() { ++m; } } // `m` needs `this` of `B`
1682 * class B {int m; inc() { new A().inc!m(); } }
1684 if (e1
.op
== EXP
.this_
)
1686 FuncDeclaration f
= hasThis(sc
);
1687 if (f
&& f
.hasDualContext())
1689 if (f
.followInstantiationContext(ad
))
1691 e1
= new VarExp(loc
, f
.vthis
);
1692 e1
= new PtrExp(loc
, e1
);
1693 e1
= new IndexExp(loc
, e1
, IntegerExp
.literal
!1);
1694 e1
= getThisSkipNestedFuncs(loc
, sc
, f
.toParent2(), ad
, e1
, t
, var
);
1695 if (e1
.op
== EXP
.error
)
1702 /* If e1 is not the 'this' pointer for ad
1705 !(t
.isTypePointer() && t
.nextOf().isTypeStruct() && t
.nextOf().isTypeStruct().sym
== ad
) &&
1706 !(t
.isTypeStruct() && t
.isTypeStruct().sym
== ad
))
1708 ClassDeclaration cd
= ad
.isClassDeclaration();
1709 ClassDeclaration tcd
= t
.isClassHandle();
1711 /* e1 is the right this if ad is a base class of e1
1713 if (!cd ||
!tcd ||
!(tcd
== cd || cd
.isBaseOf(tcd
, null)))
1715 /* Only classes can be inner classes with an 'outer'
1716 * member pointing to the enclosing class instance
1718 if (tcd
&& tcd
.isNested())
1720 /* e1 is the 'this' pointer for an inner class: tcd.
1721 * Rewrite it as the 'this' pointer for the outer class.
1723 auto vthis
= tcd
.followInstantiationContext(ad
) ? tcd
.vthis2
: tcd
.vthis
;
1724 e1
= new DotVarExp(loc
, e1
, vthis
);
1725 e1
.type
= vthis
.type
;
1726 e1
.type
= e1
.type
.addMod(t
.mod
);
1727 // Do not call ensureStaticLinkTo()
1728 //e1 = e1.semantic(sc);
1730 // Skip up over nested functions, and get the enclosing
1732 e1
= getThisSkipNestedFuncs(loc
, sc
, tcd
.toParentP(ad
), ad
, e1
, t
, var
);
1733 if (e1
.op
== EXP
.error
)
1738 /* Can't find a path from e1 to ad
1742 error(e1
.loc
, "`this` for `%s` needs to be type `%s` not type `%s`", var
.toChars(), ad
.toChars(), t
.toChars());
1743 return ErrorExp
.get();
1750 * Check whether `outerFunc` and `calledFunc` have the same `this`.
1751 * If `calledFunc` is the member of a base class of the class that contains
1752 * `outerFunc` we consider that they have the same this.
1754 * This function is used to test whether `this` needs to be prepended to
1755 * a function call or function symbol. For example:
1771 * When `fun` is called, `outerfunc` = `sun` and `calledFunc = `fun`.
1772 * `sun` is a member of `A` and `fun` is also a member of `A`, therefore
1773 * `this` can be prepended to `fun`. When `gun` is called (it will result
1774 * in an error, but that is not relevant here), which is a member of `X`,
1775 * no `this` is needed because the outer function does not have the same
1779 * `true` if outerFunc and calledFunc may use the same `this` pointer.
1780 * `false` otherwise.
1782 private bool haveSameThis(FuncDeclaration outerFunc
, FuncDeclaration calledFunc
)
1784 // https://issues.dlang.org/show_bug.cgi?id=24013
1785 // traits(getOverloads) inserts an alias to select the overload.
1786 // When searching for the right this we need to use the aliased
1787 // overload/function, not the alias.
1788 outerFunc
= outerFunc
.toAliasFunc();
1789 calledFunc
= calledFunc
.toAliasFunc();
1791 auto thisAd
= outerFunc
.isMemberLocal();
1795 auto requiredAd
= calledFunc
.isMemberLocal();
1799 if (thisAd
== requiredAd
)
1802 // if outerfunc is the member of a nested aggregate, then let
1803 // getRightThis take care of this.
1804 if (thisAd
.isNested())
1807 // outerfunc is the member of a base class that contains calledFunc,
1808 // then we consider that they have the same this.
1809 auto cd
= requiredAd
.isClassDeclaration();
1813 if (cd
.isBaseOf2(thisAd
.isClassDeclaration()))
1819 /*********************************************
1820 * Calling function f.
1821 * Check the purity, i.e. if we're in a pure function
1822 * we can only call other pure functions.
1823 * Returns true if error occurs.
1825 private bool checkPurity(FuncDeclaration f
, const ref Loc loc
, Scope
* sc
)
1831 if (sc
.intypeof
== 1)
1833 if (sc
.flags
& (SCOPE
.ctfe | SCOPE
.debug_
))
1836 // If the call has a pure parent, then the called func must be pure.
1837 if (!f
.isPure() && checkImpure(sc
, loc
, null, f
))
1839 error(loc
, "`pure` %s `%s` cannot call impure %s `%s`",
1840 sc
.func
.kind(), sc
.func
.toPrettyChars(), f
.kind(),
1843 if (!f
.isDtorDeclaration())
1844 errorSupplementalInferredAttr(f
, /*max depth*/ 10, /*deprecation*/ false, STC
.pure_
);
1846 f
.checkOverriddenDtor(sc
, loc
, dd => dd.type
.toTypeFunction().purity
!= PURE
.impure
, "impure");
1853 * Checks whether `f` is a generated `DtorDeclaration` that hides a user-defined one
1854 * which passes `check` while `f` doesn't (e.g. when the user defined dtor is pure but
1855 * the generated dtor is not).
1856 * In that case the method will identify and print all members causing the attribute
1860 * f = potential `DtorDeclaration`
1863 * check = current check (e.g. whether it's pure)
1864 * checkName = the kind of check (e.g. `"pure"`)
1866 void checkOverriddenDtor(FuncDeclaration f
, Scope
* sc
, const ref Loc loc
,
1867 scope bool function(DtorDeclaration
) check
, const string checkName
)
1869 auto dd = f
.isDtorDeclaration();
1870 if (!dd ||
!dd.isGenerated())
1873 // DtorDeclaration without parents should fail at an earlier stage
1874 auto ad
= cast(AggregateDeclaration
) f
.toParent2();
1877 if (ad
.userDtors
.length
)
1879 if (!check(ad
.userDtors
[0])) // doesn't match check (e.g. is impure as well)
1883 assert(!check(ad
.fieldDtor
));
1886 dd.loc
.errorSupplemental("%s`%s.~this` is %.*s because of the following field's destructors:",
1887 dd.isGenerated() ?
"generated " : "".ptr
,
1889 cast(int) checkName
.length
, checkName
.ptr
);
1891 // Search for the offending fields
1892 foreach (field
; ad
.fields
)
1894 // Only structs may define automatically called destructors
1895 auto ts
= field
.type
.isTypeStruct();
1898 // But they might be part of a static array
1899 auto ta
= field
.type
.isTypeSArray();
1903 ts
= ta
.baseElemOf().isTypeStruct();
1908 auto fieldSym
= ts
.toDsymbol(sc
);
1909 assert(fieldSym
); // Resolving ts must succeed because missing defs. should error before
1911 auto fieldSd
= fieldSym
.isStructDeclaration();
1912 assert(fieldSd
); // ts is a TypeStruct, this would imply a malformed ASR
1914 if (fieldSd
.dtor
&& !check(fieldSd
.dtor
))
1916 field
.loc
.errorSupplemental(" - %s %s", field
.type
.toChars(), field
.toChars());
1918 if (fieldSd
.dtor
.isGenerated())
1919 fieldSd
.dtor
.checkOverriddenDtor(sc
, loc
, check
, checkName
);
1921 fieldSd
.dtor
.loc
.errorSupplemental(" %.*s `%s.~this` is declared here",
1922 cast(int) checkName
.length
, checkName
.ptr
, fieldSd
.toChars());
1927 /*******************************************
1928 * Accessing variable v.
1929 * Check for purity and safety violations.
1930 * Returns true if error occurs.
1932 private bool checkPurity(VarDeclaration v
, const ref Loc loc
, Scope
* sc
)
1934 //printf("v = %s %s\n", v.type.toChars(), v.toChars());
1935 /* Look for purity and safety violations when accessing variable v
1936 * from current function.
1940 if (sc
.intypeof
== 1)
1941 return false; // allow violations inside typeof(expression)
1942 if (sc
.flags
& (SCOPE
.ctfe | SCOPE
.debug_
))
1943 return false; // allow violations inside compile-time evaluated expressions and debug conditionals
1944 if (v
.ident
== Id
.ctfe
)
1945 return false; // magic variable never violates pure and safe
1946 if (v
.isImmutable())
1947 return false; // always safe and pure to access immutables...
1948 if (v
.isConst() && !v
.isReference() && (v
.isDataseg() || v
.isParameter()) && v
.type
.implicitConvTo(v
.type
.immutableOf()))
1949 return false; // or const global/parameter values which have no mutable indirections
1950 if (v
.storage_class
& STC
.manifest
)
1951 return false; // ...or manifest constants
1953 // accessing empty structs is pure
1954 // https://issues.dlang.org/show_bug.cgi?id=18694
1955 // https://issues.dlang.org/show_bug.cgi?id=21464
1956 // https://issues.dlang.org/show_bug.cgi?id=23589
1957 if (v
.type
.ty
== Tstruct
)
1959 StructDeclaration sd
= (cast(TypeStruct
)v
.type
).sym
;
1960 if (sd
.members
) // not opaque
1962 if (sd
.semanticRun
>= PASS
.semanticdone
)
1963 sd
.determineSize(v
.loc
);
1972 // https://issues.dlang.org/show_bug.cgi?id=7533
1973 // Accessing implicit generated __gate is pure.
1974 if (v
.ident
== Id
.gate
)
1977 if (checkImpure(sc
, loc
, "`pure` %s `%s` cannot access mutable static data `%s`", v
))
1979 error(loc
, "`pure` %s `%s` cannot access mutable static data `%s`",
1980 sc
.func
.kind(), sc
.func
.toPrettyChars(), v
.toChars());
1991 * /+pure+/ void h() {
1993 * /+pure+/ void i() { }
1997 * i() can modify hx and gx but not fx
2000 Dsymbol vparent
= v
.toParent2();
2001 for (Dsymbol s
= sc
.func
; !err
&& s
; s
= s
.toParentP(vparent
))
2006 if (AggregateDeclaration ad
= s
.isAggregateDeclaration())
2012 FuncDeclaration ff
= s
.isFuncDeclaration();
2015 if (ff
.isNested() || ff
.isThis())
2017 if (ff
.type
.isImmutable() ||
2018 ff
.type
.isShared() && !MODimplicitConv(ff
.type
.mod
, v
.type
.mod
))
2022 MODMatchToBuffer(&ffbuf
, ff
.type
.mod
, v
.type
.mod
);
2023 MODMatchToBuffer(&vbuf
, v
.type
.mod
, ff
.type
.mod
);
2024 error(loc
, "%s%s `%s` cannot access %sdata `%s`",
2025 ffbuf
.peekChars(), ff
.kind(), ff
.toPrettyChars(), vbuf
.peekChars(), v
.toChars());
2035 /* Do not allow safe functions to access __gshared data
2037 if (v
.storage_class
& STC
.gshared
)
2039 if (sc
.setUnsafe(false, loc
,
2040 "`@safe` function `%s` cannot access `__gshared` data `%s`", sc
.func
, v
))
2050 Check if sc.func is impure or can be made impure.
2051 Returns true on error, i.e. if sc.func is pure and cannot be made impure.
2053 private bool checkImpure(Scope
* sc
, Loc loc
, const(char)* fmt
, RootObject arg0
)
2055 return sc
.func
&& (isRootTraitsCompilesScope(sc
)
2056 ? sc
.func
.isPureBypassingInference() >= PURE
.weak
2057 : sc
.func
.setImpure(loc
, fmt
, arg0
));
2060 /*********************************************
2061 * Calling function f.
2062 * Check the safety, i.e. if we're in a @safe function
2063 * we can only call @safe or @trusted functions.
2064 * Returns true if error occurs.
2066 private bool checkSafety(FuncDeclaration f
, ref Loc loc
, Scope
* sc
)
2070 if (sc
.intypeof
== 1)
2072 if (sc
.flags
& SCOPE
.debug_
)
2074 if ((sc
.flags
& SCOPE
.ctfe
) && sc
.func
)
2079 if (sc
.varDecl
&& !f
.safetyInprocess
&& !f
.isSafe() && !f
.isTrusted())
2081 if (sc
.varDecl
.storage_class
& STC
.safe
)
2083 error(loc
, "`@safe` variable `%s` cannot be initialized by calling `@system` function `%s`",
2084 sc
.varDecl
.toChars(), f
.toChars());
2089 sc
.varDecl
.storage_class |
= STC
.system
;
2090 sc
.varDecl
.systemInferred
= true;
2096 if (!f
.isSafe() && !f
.isTrusted())
2098 if (isRootTraitsCompilesScope(sc
) ? sc
.func
.isSafeBypassingInference() : sc
.func
.setUnsafeCall(f
))
2100 if (!loc
.isValid()) // e.g. implicitly generated dtor
2103 const prettyChars
= f
.toPrettyChars();
2104 error(loc
, "`@safe` %s `%s` cannot call `@system` %s `%s`",
2105 sc
.func
.kind(), sc
.func
.toPrettyChars(), f
.kind(),
2107 if (!f
.isDtorDeclaration
)
2108 errorSupplementalInferredAttr(f
, /*max depth*/ 10, /*deprecation*/ false, STC
.safe
);
2109 .errorSupplemental(f
.loc
, "`%s` is declared here", prettyChars
);
2111 f
.checkOverriddenDtor(sc
, loc
, dd => dd.type
.toTypeFunction().trust
> TRUST
.system
, "@system");
2116 else if (f
.isSafe() && f
.safetyViolation
)
2118 // for dip1000 by default transition, print deprecations for calling functions that will become `@system`
2119 if (sc
.func
.isSafeBypassingInference())
2121 .deprecation(loc
, "`@safe` function `%s` calling `%s`", sc
.func
.toChars(), f
.toChars());
2122 errorSupplementalInferredAttr(f
, 10, true, STC
.safe
);
2124 else if (!sc
.func
.safetyViolation
)
2126 import dmd
.func
: AttributeViolation
;
2127 sc
.func
.safetyViolation
= new AttributeViolation(loc
, null, f
, null, null);
2133 /*********************************************
2134 * Calling function f.
2135 * Check the @nogc-ness, i.e. if we're in a @nogc function
2136 * we can only call other @nogc functions.
2137 * Returns true if error occurs.
2139 private bool checkNogc(FuncDeclaration f
, ref Loc loc
, Scope
* sc
)
2145 if (sc
.intypeof
== 1)
2147 if (sc
.flags
& (SCOPE
.ctfe | SCOPE
.debug_
))
2149 /* The original expressions (`new S(...)` or `new S[...]``) will be
2150 * verified instead. This is to keep errors related to the original code
2151 * and not the lowering.
2153 if (f
.ident
== Id
._d_newitemT || f
.ident
== Id
._d_newarrayT || f
.ident
== Id
._d_newarraymTX
)
2158 if (isRootTraitsCompilesScope(sc
) ? sc
.func
.isNogcBypassingInference() : sc
.func
.setGCCall(f
))
2160 if (loc
.linnum
== 0) // e.g. implicitly generated dtor
2163 // Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)),
2164 // so don't print anything to avoid double error messages.
2165 if (!(f
.ident
== Id
._d_HookTraceImpl || f
.ident
== Id
._d_arraysetlengthT
2166 || f
.ident
== Id
._d_arrayappendT || f
.ident
== Id
._d_arrayappendcTX
2167 || f
.ident
== Id
._d_arraycatnTX || f
.ident
== Id
._d_newclassT
))
2169 error(loc
, "`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
2170 sc
.func
.kind(), sc
.func
.toPrettyChars(), f
.kind(), f
.toPrettyChars());
2172 if (!f
.isDtorDeclaration
)
2173 f
.errorSupplementalInferredAttr(/*max depth*/ 10, /*deprecation*/ false, STC
.nogc
);
2176 f
.checkOverriddenDtor(sc
, loc
, dd => dd.type
.toTypeFunction().isnogc
, "non-@nogc");
2184 /********************************************
2185 * Check that the postblit is callable if t is an array of structs.
2186 * Returns true if error happens.
2188 private bool checkPostblit(Type t
, ref Loc loc
, Scope
* sc
)
2190 if (auto ts
= t
.baseElemOf().isTypeStruct())
2192 if (global
.params
.useTypeInfo
&& Type
.dtypeinfo
)
2194 // https://issues.dlang.org/show_bug.cgi?id=11395
2195 // Require TypeInfo generation for array concatenation
2196 semanticTypeInfo(sc
, t
);
2199 StructDeclaration sd
= ts
.sym
;
2202 if (sd
.postblit
.checkDisabled(loc
, sc
))
2205 //checkDeprecated(sc, sd.postblit); // necessary?
2206 sd
.postblit
.checkPurity(loc
, sc
);
2207 sd
.postblit
.checkSafety(loc
, sc
);
2208 sd
.postblit
.checkNogc(loc
, sc
);
2209 //checkAccess(sd, loc, sc, sd.postblit); // necessary?
2216 /***************************************
2217 * Pull out any properties.
2219 private Expression
resolvePropertiesX(Scope
* sc
, Expression e1
, Expression e2
= null, BinExp saveAtts
= null)
2221 //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null);
2228 if (auto de = e1
.isDotExp())
2230 if (auto oe
= de.e2
.isOverExp())
2238 else if (e1
.isOverExp())
2242 os
= e1
.isOverExp().vars
;
2245 FuncDeclaration fd
= null;
2248 e2
= e2
.expressionSemantic(sc
);
2249 if (e2
.op
== EXP
.error
)
2250 return ErrorExp
.get();
2251 e2
= resolveProperties(sc
, e2
);
2253 Expressions
* a
= new Expressions();
2256 for (size_t i
= 0; i
< os
.a
.length
; i
++)
2258 if (FuncDeclaration f
= resolveFuncCall(loc
, sc
, os
.a
[i
], tiargs
, tthis
, ArgumentList(a
), FuncResolveFlag
.quiet
))
2261 return ErrorExp
.get();
2263 assert(fd
.type
.ty
== Tfunction
);
2268 Expression e
= new CallExp(loc
, e1
, e2
);
2269 return e
.expressionSemantic(sc
);
2273 for (size_t i
= 0; i
< os
.a
.length
; i
++)
2275 if (FuncDeclaration f
= resolveFuncCall(loc
, sc
, os
.a
[i
], tiargs
, tthis
, ArgumentList(), FuncResolveFlag
.quiet
))
2278 return ErrorExp
.get();
2280 assert(fd
.type
.ty
== Tfunction
);
2281 auto tf
= fd
.type
.isTypeFunction();
2282 if (!tf
.isref
&& e2
)
2284 error(loc
, "%s is not an lvalue", e1
.toChars());
2285 return ErrorExp
.get();
2291 Expression e
= new CallExp(loc
, e1
);
2294 e
= new AssignExp(loc
, e
, e2
);
2297 (cast(BinExp
)e
).att1
= saveAtts
.att1
;
2298 (cast(BinExp
)e
).att2
= saveAtts
.att2
;
2301 return e
.expressionSemantic(sc
);
2307 else if (auto dti
= e1
.isDotTemplateInstanceExp())
2309 if (!dti
.findTempDecl(sc
))
2311 if (!dti
.ti
.semanticTiargs(sc
))
2313 tiargs
= dti
.ti
.tiargs
;
2314 tthis
= dti
.e1
.type
;
2315 if ((os
= dti
.ti
.tempdecl
.isOverloadSet()) !is null)
2317 if ((s
= dti
.ti
.tempdecl
) !is null)
2320 else if (auto dte
= e1
.isDotTemplateExp())
2324 tthis
= dte
.e1
.type
;
2327 else if (auto se
= e1
.isScopeExp())
2330 TemplateInstance ti
= s
.isTemplateInstance();
2331 if (ti
&& !ti
.semanticRun
&& ti
.tempdecl
)
2333 //assert(ti.needsTypeInference(sc));
2334 if (!ti
.semanticTiargs(sc
))
2338 if ((os
= ti
.tempdecl
.isOverloadSet()) !is null)
2340 if ((s
= ti
.tempdecl
) !is null)
2344 else if (auto te
= e1
.isTemplateExp())
2351 else if (e1
.isDotVarExp() && e1
.type
&& (e1
.type
.toBasetype().isTypeFunction() || e1
.isDotVarExp().var
.isOverDeclaration()))
2353 DotVarExp dve
= e1
.isDotVarExp();
2356 tthis
= dve
.e1
.type
;
2359 else if (sc
&& sc
.flags
& SCOPE
.Cfile
&& e1
.isVarExp() && !e2
)
2361 // ImportC: do not implicitly call function if no ( ) are present
2363 else if (e1
.isVarExp() && e1
.type
&& (e1
.type
.toBasetype().isTypeFunction() || e1
.isVarExp().var
.isOverDeclaration()))
2365 s
= e1
.isVarExp().var
;
2372 e2
= e2
.expressionSemantic(sc
);
2373 if (e2
.op
== EXP
.error
)
2374 return ErrorExp
.get();
2375 e2
= resolveProperties(sc
, e2
);
2377 Expressions
* a
= new Expressions();
2380 FuncDeclaration fd
= resolveFuncCall(loc
, sc
, s
, tiargs
, tthis
, ArgumentList(a
), FuncResolveFlag
.quiet
);
2384 return ErrorExp
.get();
2385 assert(fd
.type
.ty
== Tfunction
);
2386 Expression e
= new CallExp(loc
, e1
, e2
);
2387 return e
.expressionSemantic(sc
);
2391 FuncDeclaration fd
= resolveFuncCall(loc
, sc
, s
, tiargs
, tthis
, ArgumentList(), FuncResolveFlag
.quiet
);
2395 return ErrorExp
.get();
2396 TypeFunction tf
= fd
.type
.isTypeFunction();
2397 if (!e2 || tf
.isref
)
2399 Expression e
= new CallExp(loc
, e1
);
2402 e
= new AssignExp(loc
, e
, e2
);
2405 (cast(BinExp
)e
).att1
= saveAtts
.att1
;
2406 (cast(BinExp
)e
).att2
= saveAtts
.att2
;
2409 return e
.expressionSemantic(sc
);
2413 if (FuncDeclaration fd
= s
.isFuncDeclaration())
2415 // Keep better diagnostic message for invalid property usage of functions
2416 assert(fd
.type
.ty
== Tfunction
);
2417 Expression e
= new CallExp(loc
, e1
, e2
);
2418 return e
.expressionSemantic(sc
);
2423 if (auto ve
= e1
.isVarExp())
2425 if (auto v
= ve
.var
.isVarDeclaration())
2427 if (v
.checkPurity(ve
.loc
, sc
))
2428 return ErrorExp
.get();
2434 if (e1
.type
&& !e1
.isTypeExp()) // function type is not a property
2436 /* Look for e1 being a lazy parameter; rewrite as delegate call
2437 * only if the symbol wasn't already treated as a delegate
2439 auto ve
= e1
.isVarExp();
2440 if (ve
&& ve
.var
.storage_class
& STC
.lazy_
&& !ve
.delegateWasExtracted
)
2442 Expression e
= new CallExp(loc
, e1
);
2443 return e
.expressionSemantic(sc
);
2445 else if (e1
.isDotVarExp())
2447 // Check for reading overlapped pointer field in @safe code.
2448 if (checkUnsafeAccess(sc
, e1
, true, true))
2449 return ErrorExp
.get();
2451 else if (auto ce
= e1
.isCallExp())
2453 // Check for reading overlapped pointer field in @safe code.
2454 if (checkUnsafeAccess(sc
, ce
.e1
, true, true))
2455 return ErrorExp
.get();
2461 error(loc
, "cannot resolve type for %s", e1
.toChars());
2462 e1
= ErrorExp
.get();
2467 error(loc
, "not a property %s", e1
.toChars());
2468 return ErrorExp
.get();
2471 private bool checkRightThis(Expression e
, Scope
* sc
)
2473 if (e
.op
== EXP
.error
)
2475 if (e
.op
== EXP
.variable
&& e
.type
.ty
!= Terror
)
2477 VarExp ve
= cast(VarExp
)e
;
2478 if (isNeedThisScope(sc
, ve
.var
))
2480 //printf("checkRightThis sc.intypeof = %d, ad = %p, func = %p, fdthis = %p\n",
2481 // sc.intypeof, sc.getStructClassScope(), func, fdthis);
2482 auto t
= ve
.var
.isThis();
2484 error(e
.loc
, "accessing non-static variable `%s` requires an instance of `%s`", ve
.var
.toChars(), t
.toChars());
2491 extern (C
++) Expression
resolveProperties(Scope
* sc
, Expression e
)
2493 //printf("resolveProperties(%s)\n", e.toChars());
2494 e
= resolvePropertiesX(sc
, e
);
2495 if (e
.checkRightThis(sc
))
2496 return ErrorExp
.get();
2500 /****************************************
2501 * The common type is determined by applying ?: to each pair.
2503 * exps[] properties resolved, implicitly cast to common type, rewritten in place
2505 * The common type, or `null` if an error has occured
2507 private Type
arrayExpressionToCommonType(Scope
* sc
, ref Expressions exps
)
2509 /* Still have a problem with:
2510 * ubyte[][] = [ cast(ubyte[])"hello", [1]];
2511 * which works if the array literal is initialized top down with the ubyte[][]
2512 * type, but fails with this function doing bottom up typing.
2515 //printf("arrayExpressionToCommonType()\n");
2516 scope IntegerExp integerexp
= IntegerExp
.literal
!0;
2517 scope CondExp condexp
= new CondExp(Loc
.initial
, integerexp
, null, null);
2520 Expression e0
= null;
2523 for (size_t i
= 0; i
< exps
.length
; i
++)
2525 Expression e
= exps
[i
];
2529 e
= resolveProperties(sc
, e
);
2532 error(e
.loc
, "`%s` has no value", e
.toChars());
2536 if (e
.op
== EXP
.type
)
2538 foundType
= true; // do not break immediately, there might be more errors
2539 e
.checkValue(); // report an error "type T has no value"
2543 if (e
.type
.ty
== Tvoid
)
2545 // void expressions do not concur to the determination of the common
2549 if (checkNonAssignmentArrayOp(e
))
2555 e
= doCopyOrMove(sc
, e
);
2557 if (!foundType
&& t0
&& !t0
.equals(e
.type
))
2559 /* This applies ?: to merge the types. It's backwards;
2560 * ?: should call this function to merge types.
2562 condexp
.type
= null;
2565 condexp
.loc
= e
.loc
;
2566 Expression ex
= condexp
.expressionSemantic(sc
);
2567 if (ex
.op
== EXP
.error
)
2571 // Convert to common type
2572 exps
[i
] = condexp
.e1
.castTo(sc
, condexp
.type
);
2573 e
= condexp
.e2
.castTo(sc
, condexp
.type
);
2578 if (e
.op
!= EXP
.error
)
2582 // [] is typed as void[]
2586 // It's an error, don't do the cast
2587 if (t0
.ty
== Terror
)
2590 for (size_t i
= 0; i
< exps
.length
; i
++)
2592 Expression e
= exps
[i
];
2596 e
= e
.implicitCastTo(sc
, t0
);
2597 if (e
.op
== EXP
.error
)
2599 /* https://issues.dlang.org/show_bug.cgi?id=13024
2600 * a workaround for the bug in typeMerge -
2601 * it should paint e1 and e2 by deduced common type,
2602 * but doesn't in this particular case.
2611 private Expression
opAssignToOp(const ref Loc loc
, EXP op
, Expression e1
, Expression e2
) @safe
2617 e
= new AddExp(loc
, e1
, e2
);
2621 e
= new MinExp(loc
, e1
, e2
);
2625 e
= new MulExp(loc
, e1
, e2
);
2629 e
= new DivExp(loc
, e1
, e2
);
2633 e
= new ModExp(loc
, e1
, e2
);
2637 e
= new AndExp(loc
, e1
, e2
);
2641 e
= new OrExp(loc
, e1
, e2
);
2645 e
= new XorExp(loc
, e1
, e2
);
2648 case EXP
.leftShiftAssign
:
2649 e
= new ShlExp(loc
, e1
, e2
);
2652 case EXP
.rightShiftAssign
:
2653 e
= new ShrExp(loc
, e1
, e2
);
2656 case EXP
.unsignedRightShiftAssign
:
2657 e
= new UshrExp(loc
, e1
, e2
);
2666 /*********************
2668 * array.length op= e2
2670 private Expression
rewriteOpAssign(BinExp exp
)
2672 ArrayLengthExp ale
= exp
.e1
.isArrayLengthExp();
2673 if (ale
.e1
.isVarExp())
2675 // array.length = array.length op e2
2676 Expression e
= opAssignToOp(exp
.loc
, exp
.op
, ale
, exp
.e2
);
2677 e
= new AssignExp(exp
.loc
, ale
.syntaxCopy(), e
);
2682 // (ref tmp = array;), tmp.length = tmp.length op e2
2683 auto tmp
= copyToTemp(STC
.ref_
, "__arraylength", ale
.e1
);
2684 Expression e1
= new ArrayLengthExp(ale
.loc
, new VarExp(ale
.loc
, tmp
));
2685 Expression elvalue
= e1
.syntaxCopy();
2686 Expression e
= opAssignToOp(exp
.loc
, exp
.op
, e1
, exp
.e2
);
2687 e
= new AssignExp(exp
.loc
, elvalue
, e
);
2688 e
= new CommaExp(exp
.loc
, new DeclarationExp(ale
.loc
, tmp
), e
);
2693 /****************************************
2694 * Preprocess arguments to function.
2696 * Tuples in argumentList get expanded, properties resolved, rewritten in place
2700 * argumentList = arguments to function
2701 * reportErrors = whether or not to report errors here. Some callers are not
2702 * checking actual function params, so they'll do their own error reporting
2704 * `true` when a semantic error occurred
2706 private bool preFunctionParameters(Scope
* sc
, ArgumentList argumentList
, const bool reportErrors
= true)
2708 Expressions
* exps
= argumentList
.arguments
;
2712 expandTuples(exps
, argumentList
.names
);
2714 for (size_t i
= 0; i
< exps
.length
; i
++)
2716 Expression arg
= (*exps
)[i
];
2717 arg
= resolveProperties(sc
, arg
);
2718 arg
= arg
.arrayFuncConv(sc
);
2719 if (arg
.op
== EXP
.type
)
2721 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
2722 arg
= resolveAliasThis(sc
, arg
);
2724 if (arg
.op
== EXP
.type
)
2728 error(arg
.loc
, "cannot pass type `%s` as a function argument", arg
.toChars());
2729 arg
= ErrorExp
.get();
2734 else if (arg
.type
.toBasetype().ty
== Tfunction
)
2738 error(arg
.loc
, "cannot pass function `%s` as a function argument", arg
.toChars());
2739 arg
= ErrorExp
.get();
2743 else if (checkNonAssignmentArrayOp(arg
))
2745 arg
= ErrorExp
.get();
2754 /********************************************
2755 * Issue an error if default construction is disabled for type t.
2756 * Default construction is required for arrays and 'out' parameters.
2758 * true an error was issued
2760 private bool checkDefCtor(Loc loc
, Type t
)
2762 if (auto ts
= t
.baseElemOf().isTypeStruct())
2764 StructDeclaration sd
= ts
.sym
;
2765 if (sd
.noDefaultCtor
)
2767 .error(loc
, "%s `%s` default construction is disabled", sd
.kind
, sd
.toPrettyChars
);
2774 /****************************************
2775 * Now that we know the exact type of the function we're calling,
2776 * the arguments[] need to be adjusted:
2777 * 1. implicitly convert argument to the corresponding parameter type
2778 * 2. add default arguments for any missing arguments
2779 * 3. do default promotions on arguments corresponding to ...
2780 * 4. add hidden _arguments[] argument
2781 * 5. call copy constructor for struct value arguments
2783 * loc = location of function call
2785 * tf = type of the function
2786 * ethis = `this` argument, `null` if none or not known
2787 * tthis = type of `this` argument, `null` if no `this` argument
2788 * argumentsList = array of actual arguments to function call
2789 * fd = the function being called, `null` if called indirectly
2790 * prettype = set to return type of function
2791 * peprefix = set to expression to execute before `arguments[]` are evaluated, `null` if none
2793 * true errors happened
2795 private bool functionParameters(const ref Loc loc
, Scope
* sc
,
2796 TypeFunction tf
, Expression ethis
, Type tthis
, ArgumentList argumentList
, FuncDeclaration fd
,
2797 Type
* prettype
, Expression
* peprefix
)
2799 Expressions
* arguments
= argumentList
.arguments
;
2800 //printf("functionParameters() %s\n", fd ? fd.toChars() : "");
2802 assert(fd || tf
.next
);
2803 const size_t nparams
= tf
.parameterList
.length
;
2804 const olderrors
= global
.errors
;
2806 Expression eprefix
= null;
2809 if (argumentList
.names
)
2811 const(char)* msg
= null;
2812 auto resolvedArgs
= tf
.resolveNamedArgs(argumentList
, &msg
);
2815 // while errors are usually already caught by `tf.callMatch`,
2816 // this can happen when calling `typeof(freefunc)`
2818 error(loc
, "%s", msg
);
2821 // note: the argument list should be mutated with named arguments / default arguments,
2822 // so we can't simply change the pointer like `arguments = resolvedArgs;`
2823 arguments
.setDim(0);
2824 arguments
.pushSlice((*resolvedArgs
)[]);
2826 size_t nargs
= arguments ? arguments
.length
: 0;
2828 if (nargs
> nparams
&& tf
.parameterList
.varargs
== VarArg
.none
)
2830 error(loc
, "expected %llu arguments, not %llu for non-variadic function type `%s`", cast(ulong)nparams
, cast(ulong)nargs
, tf
.toChars());
2834 // If inferring return type, and semantic3() needs to be run if not already run
2835 if (!tf
.next
&& fd
.inferRetType
)
2837 fd
.functionSemantic();
2839 else if (fd
&& fd
.parent
)
2841 TemplateInstance ti
= fd
.parent
.isTemplateInstance();
2842 if (ti
&& ti
.tempdecl
)
2844 fd
.functionSemantic3();
2848 /* If calling a pragma(inline, true) function,
2849 * set flag to later scan for inlines.
2851 if (fd
&& fd
.inlining
== PINLINE
.always
)
2854 sc
._module
.hasAlwaysInlines
= true;
2856 sc
.func
.hasAlwaysInlines
= true;
2859 const isCtorCall
= fd
&& fd
.needThis() && fd
.isCtorDeclaration();
2861 const size_t n
= (nargs
> nparams
) ? nargs
: nparams
; // n = max(nargs, nparams)
2863 /* If the function return type has wildcards in it, we'll need to figure out the actual type
2864 * based on the actual argument types.
2865 * Start with the `this` argument, later on merge into wildmatch the mod bits of the rest
2868 MOD wildmatch
= (tthis
&& !isCtorCall
) ? tthis
.Type
.deduceWild(tf
, false) : 0;
2871 foreach (const i
; 0 .. n
)
2873 Expression arg
= (i
< nargs
) ?
(*arguments
)[i
] : null;
2879 error(loc
, "expected %llu function arguments, not %llu", cast(ulong)nparams
, cast(ulong)nargs
);
2883 Parameter p
= tf
.parameterList
[i
];
2889 if (tf
.parameterList
.varargs
== VarArg
.typesafe
&& i
+ 1 == nparams
)
2895 arg
= arg
.expressionSemantic(sc
);
2896 arg
= inlineCopy(arg
, sc
);
2897 // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
2898 arg
= arg
.resolveLoc(loc
, sc
);
2901 arguments
.push(arg
);
2905 (*arguments
)[i
] = arg
;
2909 if (arg
.isDefaultInitExp())
2911 arg
= arg
.resolveLoc(loc
, sc
);
2912 (*arguments
)[i
] = arg
;
2917 if (tf
.parameterList
.varargs
== VarArg
.typesafe
&& i
+ 1 == nparams
) // https://dlang.org/spec/function.html#variadic
2919 //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars());
2922 if ((m
= arg
.implicitConvTo(p
.type
)) > MATCH
.nomatch
)
2924 if (p
.type
.nextOf() && arg
.implicitConvTo(p
.type
.nextOf()) >= m
)
2926 else if (nargs
!= nparams
)
2932 Type tb
= p
.type
.toBasetype();
2938 /* Create a static array variable v of type arg.type:
2939 * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
2941 * The array literal in the initializer of the hidden variable
2943 * https://issues.dlang.org/show_bug.cgi?id=2356
2945 Type tbn
= (cast(TypeArray
)tb
).next
; // array element type
2946 Type tret
= p
.isLazyArray();
2948 auto elements
= new Expressions(nargs
- i
);
2949 foreach (u
; 0 .. elements
.length
)
2951 Expression a
= (*arguments
)[i
+ u
];
2952 if (tret
&& a
.implicitConvTo(tret
))
2954 // p is a lazy array of delegates, tret is return type of the delegates
2955 a
= a
.implicitCastTo(sc
, tret
)
2956 .optimize(WANTvalue
)
2957 .toDelegate(tret
, sc
);
2960 a
= a
.implicitCastTo(sc
, tbn
);
2961 a
= a
.addDtorHook(sc
);
2964 // https://issues.dlang.org/show_bug.cgi?id=14395
2965 // Convert to a static array literal, or its slice.
2966 arg
= new ArrayLiteralExp(loc
, tbn
.sarrayOf(nargs
- i
), elements
);
2967 if (tb
.ty
== Tarray
)
2969 arg
= new SliceExp(loc
, arg
, null, null);
2977 * new Tclass(arg0, arg1, ..., argn)
2979 auto args
= new Expressions(nargs
- i
);
2980 foreach (u
; i
.. nargs
)
2981 (*args
)[u
- i
] = (*arguments
)[u
];
2982 arg
= new NewExp(loc
, null, p
.type
, args
);
2988 error(loc
, "not enough arguments");
2993 arg
= arg
.expressionSemantic(sc
);
2994 //printf("\targ = '%s'\n", arg.toChars());
2995 arguments
.setDim(i
+ 1);
2996 (*arguments
)[i
] = arg
;
3002 if (!(p
.isLazy() && p
.type
.ty
== Tvoid
))
3004 if (ubyte wm
= arg
.type
.deduceWild(p
.type
, p
.isReference()))
3006 wildmatch
= wildmatch ?
MODmerge(wildmatch
, wm
) : wm
;
3007 //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p.type.toChars(), arg.type.toChars(), wm, wildmatch);
3014 if ((wildmatch
== MODFlags
.mutable || wildmatch
== MODFlags
.immutable_
) &&
3015 tf
.next
&& tf
.next
.hasWild() &&
3016 (tf
.isref ||
!tf
.next
.implicitConvTo(tf
.next
.immutableOf())))
3018 bool errorInout(MOD wildmatch
)
3020 const(char)* s
= wildmatch
== MODFlags
.mutable ?
"mutable" : MODtoChars(wildmatch
);
3021 error(loc
, "modify `inout` to `%s` is not allowed inside `inout` function", s
);
3027 /* If the called function may return the reference to
3028 * outer inout data, it should be rejected.
3030 * void foo(ref inout(int) x) {
3031 * ref inout(int) bar(inout(int)) { return x; }
3033 * ref inout(int) bar() inout { return x; }
3034 * ref inout(int) baz(alias a)() inout { return x; }
3036 * bar(int.init) = 1; // bad!
3037 * S().bar() = 1; // bad!
3042 * s.baz!a() = 1; // bad!
3046 bool checkEnclosingWild(Dsymbol s
)
3048 bool checkWild(Dsymbol s
)
3052 if (auto ad
= s
.isAggregateDeclaration())
3055 return checkEnclosingWild(s
);
3057 else if (auto ff
= s
.isFuncDeclaration())
3059 if (ff
.type
.isTypeFunction().iswild
)
3060 return errorInout(wildmatch
);
3062 if (ff
.isNested() || ff
.isThis())
3063 return checkEnclosingWild(s
);
3068 Dsymbol ctx0
= s
.toParent2();
3069 Dsymbol ctx1
= s
.toParentLocal();
3070 if (checkWild(ctx0
))
3073 return checkWild(ctx1
);
3076 if ((fd
.isThis() || fd
.isNested()) && checkEnclosingWild(fd
))
3079 else if (tf
.isWild())
3080 return errorInout(wildmatch
);
3083 Expression firstArg
= null;
3084 final switch (returnParamDest(tf
, tthis
))
3086 case ReturnParamDest
.returnVal
:
3088 case ReturnParamDest
.firstArg
:
3089 firstArg
= nargs
> 0 ?
(*arguments
)[0] : null;
3091 case ReturnParamDest
.this_
:
3096 assert(nargs
>= nparams
);
3097 foreach (const i
, arg
; (*arguments
)[0 .. nargs
])
3102 Parameter p
= tf
.parameterList
[i
];
3103 Type targ
= arg
.type
; // keep original type for isCopyable() because alias this
3104 // resolution may hide an uncopyable type
3106 if (!(p
.isLazy() && p
.type
.ty
== Tvoid
))
3108 Type tprm
= p
.type
.hasWild()
3109 ? p
.type
.substWildTo(wildmatch
)
3112 const hasCopyCtor
= arg
.type
.isTypeStruct() && arg
.type
.isTypeStruct().sym
.hasCopyCtor
;
3113 const typesMatch
= arg
.type
.mutableOf().unSharedOf().equals(tprm
.mutableOf().unSharedOf());
3114 if (!((hasCopyCtor
&& typesMatch
) || tprm
.equals(arg
.type
)))
3116 //printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars());
3117 arg
= arg
.implicitCastTo(sc
, tprm
);
3118 arg
= arg
.optimize(WANTvalue
, p
.isReference());
3122 // Support passing rvalue to `in` parameters
3123 if ((p
.storageClass
& (STC
.in_ | STC
.ref_
)) == (STC
.in_ | STC
.ref_
))
3125 if (!arg
.isLvalue())
3127 auto v
= copyToTemp(STC
.exptemp
, "__rvalue", arg
);
3128 Expression ev
= new DeclarationExp(arg
.loc
, v
);
3129 ev
= new CommaExp(arg
.loc
, ev
, new VarExp(arg
.loc
, v
));
3130 arg
= ev
.expressionSemantic(sc
);
3132 arg
= arg
.toLvalue(sc
, "create `in` parameter from");
3134 // Look for mutable misaligned pointer, etc., in @safe mode
3135 err |
= checkUnsafeAccess(sc
, arg
, false, true);
3137 else if (p
.storageClass
& STC
.ref_
)
3139 if (global
.params
.rvalueRefParam
== FeatureState
.enabled
&&
3142 { /* allow rvalues to be passed to ref parameters by copying
3143 * them to a temp, then pass the temp as the argument
3145 auto v
= copyToTemp(0, "__rvalue", arg
);
3146 Expression ev
= new DeclarationExp(arg
.loc
, v
);
3147 ev
= new CommaExp(arg
.loc
, ev
, new VarExp(arg
.loc
, v
));
3148 arg
= ev
.expressionSemantic(sc
);
3150 arg
= arg
.toLvalue(sc
, "create `ref` parameter from");
3152 // Look for mutable misaligned pointer, etc., in @safe mode
3153 err |
= checkUnsafeAccess(sc
, arg
, false, true);
3155 else if (p
.storageClass
& STC
.out_
)
3158 if (!t
.isMutable() ||
!t
.isAssignable()) // check blit assignable
3160 error(arg
.loc
, "cannot modify struct `%s` with immutable members", arg
.toChars());
3165 // Look for misaligned pointer, etc., in @safe mode
3166 err |
= checkUnsafeAccess(sc
, arg
, false, true);
3167 err |
= checkDefCtor(arg
.loc
, t
); // t must be default constructible
3169 arg
= arg
.toLvalue(sc
, "create `out` parameter from");
3171 else if (p
.isLazy())
3173 // Convert lazy argument to a delegate
3174 auto t
= (p
.type
.ty
== Tvoid
) ? p
.type
: arg
.type
;
3175 arg
= toDelegate(arg
, t
, sc
);
3177 //printf("arg: %s\n", arg.toChars());
3178 //printf("type: %s\n", arg.type.toChars());
3179 //printf("param: %s\n", p.toChars());
3181 const indirect
= (fd
is null) ||
(fd
.isVirtual() && !fd
.isFinal());
3182 const pStc
= tf
.parameterStorageClass(tthis
, p
, fd ?
&fd
.outerVars
: null, indirect
);
3184 if (firstArg
&& (pStc
& STC
.return_
))
3186 /* Argument value can be assigned to firstArg.
3187 * Check arg to see if it matters.
3189 err |
= checkParamArgumentReturn(sc
, firstArg
, arg
, p
, false);
3191 // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along
3192 // as lazy parameters to the next function, but that isn't escaping.
3193 // The arguments of `_d_arraycatnTX` are already handled in
3194 // expressionsem.d, via `checkNewEscape`. Without `-dip1000`, the
3195 // check does not return an error, so the lowering of `a ~ b` to
3196 // `_d_arraycatnTX(a, b)` still occurs.
3197 else if (!(pStc
& STC
.lazy_
) && (!fd || fd
.ident
!= Id
._d_arraycatnTX
))
3199 /* Argument value can escape from the called function.
3200 * Check arg to see if it matters.
3202 VarDeclaration vPar
= fd ?
(fd
.parameters ?
(*fd
.parameters
)[i
] : null) : null;
3203 err |
= checkParamArgumentEscape(sc
, fd
, p
.ident
, vPar
, cast(STC
) pStc
, arg
, false, false);
3206 // Turning heap allocations into stack allocations is dangerous without dip1000, since `scope` inference
3207 // may be unreliable when scope violations only manifest as deprecation warnings.
3208 // However, existing `@nogc` code may rely on it, so still do it when the parameter is explicitly marked `scope`
3209 const explicitScope
= p
.isLazy() ||
3210 ((p
.storageClass
& STC
.scope_
) && !(p
.storageClass
& STC
.scopeinferred
));
3211 if ((pStc
& (STC
.scope_ | STC
.lazy_
)) &&
3212 ((sc
.useDIP1000
== FeatureState
.enabled
) || explicitScope
) &&
3213 !(pStc
& STC
.return_
))
3215 /* Argument value cannot escape from the called function.
3218 if (auto ce
= a
.isCastExp())
3221 ArrayLiteralExp ale
;
3222 if (p
.type
.toBasetype().ty
== Tarray
&&
3223 (ale
= a
.isArrayLiteralExp()) !is null && ale
.elements
&& ale
.elements
.length
> 0)
3225 // allocate the array literal as temporary static array on the stack
3226 ale
.type
= ale
.type
.nextOf().sarrayOf(ale
.elements
.length
);
3227 auto tmp
= copyToTemp(0, "__arrayliteral_on_stack", ale
);
3228 tmp
.storage_class |
= STC
.exptemp
;
3229 auto declareTmp
= new DeclarationExp(ale
.loc
, tmp
);
3230 auto castToSlice
= new CastExp(ale
.loc
, new VarExp(ale
.loc
, tmp
),
3231 p
.type
.substWildTo(MODFlags
.mutable
));
3232 arg
= CommaExp
.combine(declareTmp
, castToSlice
);
3233 arg
= arg
.expressionSemantic(sc
);
3235 else if (auto fe
= a
.isFuncExp())
3237 /* Function literals can only appear once, so if this
3238 * appearance was scoped, there cannot be any others.
3240 fe
.fd
.tookAddressOf
= 0;
3242 else if (auto de = a
.isDelegateExp())
3244 /* For passing a delegate to a scoped parameter,
3245 * this doesn't count as taking the address of it.
3246 * We only worry about 'escaping' references to the function.
3248 if (auto ve
= de.e1
.isVarExp())
3250 if (auto f
= ve
.var
.isFuncDeclaration())
3252 if (f
.tookAddressOf
)
3254 //printf("--tookAddressOf = %d\n", f.tookAddressOf);
3259 if (!p
.isReference())
3260 err |
= arg
.checkSharedAccess(sc
);
3262 arg
= arg
.optimize(WANTvalue
, p
.isReference());
3266 // These will be the trailing ... arguments
3267 // If not D linkage, do promotions
3268 if (tf
.linkage
!= LINK
.d
)
3270 // Promote bytes, words, etc., to ints
3271 arg
= integralPromotions(arg
, sc
);
3273 // Promote floats to doubles
3274 switch (arg
.type
.ty
)
3277 arg
= arg
.castTo(sc
, Type
.tfloat64
);
3281 arg
= arg
.castTo(sc
, Type
.timaginary64
);
3287 if (tf
.parameterList
.varargs
== VarArg
.variadic ||
3288 tf
.parameterList
.varargs
== VarArg
.KRvariadic
)
3290 const(char)* p
= tf
.linkage
== LINK
.c ?
"extern(C)" : "extern(C++)";
3291 if (arg
.type
.ty
== Tarray
)
3293 error(arg
.loc
, "cannot pass dynamic arrays to `%s` vararg functions", p
);
3296 if (arg
.type
.ty
== Tsarray
)
3298 error(arg
.loc
, "cannot pass static arrays to `%s` vararg functions", p
);
3304 // Do not allow types that need destructors or copy constructors.
3305 if (arg
.type
.needsDestruction())
3307 error(arg
.loc
, "cannot pass types that need destruction as variadic arguments");
3310 if (arg
.type
.needsCopyOrPostblit())
3312 error(arg
.loc
, "cannot pass types with postblits or copy constructors as variadic arguments");
3316 // Convert static arrays to dynamic arrays
3317 // BUG: I don't think this is right for D2
3318 Type tb
= arg
.type
.toBasetype();
3319 if (auto ts
= tb
.isTypeSArray())
3321 Type ta
= ts
.next
.arrayOf();
3322 if (ts
.size(arg
.loc
) == 0)
3323 arg
= new NullExp(arg
.loc
, ta
);
3325 arg
= arg
.castTo(sc
, ta
);
3327 if (tb
.ty
== Tstruct
)
3329 //arg = callCpCtor(sc, arg);
3331 // Give error for overloaded function addresses
3332 if (auto se
= arg
.isSymOffExp())
3334 if (se
.hasOverloads
&& !se
.var
.isFuncDeclaration().isUnique())
3336 error(arg
.loc
, "function `%s` is overloaded", arg
.toChars());
3340 err |
= arg
.checkValue();
3341 err |
= arg
.checkSharedAccess(sc
);
3342 err |
= checkParamArgumentEscape(sc
, fd
, Id
.dotdotdot
, null, cast(STC
) tf
.parameterList
.stc, arg
, false, false);
3343 arg
= arg
.optimize(WANTvalue
);
3345 (*arguments
)[i
] = arg
;
3348 /* If calling C scanf(), printf(), or any variants, check the format string against the arguments
3350 const isVa_list
= tf
.parameterList
.varargs
== VarArg
.none
;
3351 if (fd
&& fd
.printf
)
3353 if (auto se
= (*arguments
)[nparams
- 1 - isVa_list
].isStringExp())
3355 checkPrintfFormat(se
.loc
, se
.peekString(), (*arguments
)[nparams
.. nargs
], isVa_list
, sc
.eSink
);
3358 else if (fd
&& fd
.scanf
)
3360 if (auto se
= (*arguments
)[nparams
- 1 - isVa_list
].isStringExp())
3362 checkScanfFormat(se
.loc
, se
.peekString(), (*arguments
)[nparams
.. nargs
], isVa_list
, sc
.eSink
);
3367 // TODO: not checking the "v" functions yet (for those, check format string only, not args)
3370 /* Remaining problems:
3371 * 1. value structs (or static arrays of them) that need to be copy constructed
3372 * 2. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
3373 * function gets called.
3374 * 3. value structs need to be destructed after the function call for platforms where the caller destroys the arguments.
3375 * Those are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
3376 * up properly. Pushing arguments on the stack then cannot fail.
3379 /* Does Problem (3) apply?
3381 const bool callerDestroysArgs
= !target
.isCalleeDestroyingArgs(tf
);
3383 /* Compute indices of last throwing argument and first arg needing destruction.
3384 * Used to not set up destructors unless an arg needs destruction on a throw
3385 * in a later argument.
3387 ptrdiff_t lastthrow
= -1; // last argument that may throw
3388 ptrdiff_t firstdtor
= -1; // first argument that needs destruction
3389 ptrdiff_t lastdtor
= -1; // last argument that needs destruction
3390 for (ptrdiff_t i
= 0; i
!= nargs
; i
++)
3392 Expression arg
= (*arguments
)[i
];
3393 if (canThrow(arg
, sc
.func
, null))
3395 if (arg
.type
.needsDestruction())
3397 Parameter p
= (i
>= nparams ?
null : tf
.parameterList
[i
]);
3398 if (!(p
&& (p
.isLazy() || p
.isReference())))
3400 if (firstdtor
== -1)
3407 /* Do we need 'eprefix' for problems 2 or 3?
3409 const bool needsPrefix
= callerDestroysArgs
3410 ? firstdtor
>= 0 // true if any argument needs destruction
3411 : firstdtor
>= 0 && lastthrow
>= 0 &&
3412 (lastthrow
- firstdtor
) > 0; // last throw after first destruction
3413 const ptrdiff_t lastPrefix
= callerDestroysArgs
3414 ? lastdtor
// up to last argument requiring destruction
3415 : lastthrow
; // up to last potentially throwing argument
3417 /* Problem 3: initialize 'eprefix' by declaring the gate
3419 VarDeclaration gate
;
3420 if (needsPrefix
&& !callerDestroysArgs
)
3422 // eprefix => bool __gate [= false]
3423 Identifier idtmp
= Identifier
.generateId("__gate");
3424 gate
= new VarDeclaration(loc
, Type
.tbool
, idtmp
, null);
3425 gate
.storage_class |
= STC
.temp | STC
.ctfe | STC
.volatile_
;
3426 gate
.dsymbolSemantic(sc
);
3428 auto ae
= new DeclarationExp(loc
, gate
);
3429 eprefix
= ae
.expressionSemantic(sc
);
3432 for (ptrdiff_t i
= 0; i
!= nargs
; i
++)
3434 Expression arg
= (*arguments
)[i
];
3435 //printf("arg[%d]: %s\n", cast(int)i, arg.toChars());
3437 Parameter parameter
= (i
>= nparams ?
null : tf
.parameterList
[i
]);
3438 const bool isRef
= parameter
&& parameter
.isReference();
3439 const bool isLazy
= parameter
&& parameter
.isLazy();
3441 /* Skip lazy parameters
3446 /* Do we have 'eprefix' and aren't past 'lastPrefix' yet?
3447 * Then declare a temporary variable for this arg and append that declaration
3448 * to 'eprefix', which will implicitly take care of potential problem 1) for
3450 * 'eprefix' will therefore finally contain all args up to and including 'lastPrefix',
3451 * excluding all lazy parameters.
3453 if (needsPrefix
&& (lastPrefix
- i
) >= 0)
3455 const bool needsDtor
= !isRef
&& arg
.type
.needsDestruction() &&
3456 // Problem 3: last throwing arg doesn't require dtor patching
3457 (callerDestroysArgs || i
!= lastPrefix
);
3459 /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
3461 auto tmp
= copyToTemp(
3462 (parameter ? parameter
.storageClass
: tf
.parameterList
.stc) & (STC
.scope_
),
3463 needsDtor ?
"__pfx" : "__pfy",
3464 !isRef ? arg
: arg
.addressOf());
3465 tmp
.dsymbolSemantic(sc
);
3467 if (callerDestroysArgs
)
3469 /* Problem 4: Normal temporary, destructed after the call
3472 tmp
.isArgDtorVar
= true; // mark it so that the backend passes it by ref to the function being called
3476 /* Problem 2: Modify the destructor so it only runs if gate==false,
3477 * i.e., only if there was a throw while constructing the args
3483 assert(i
== lastPrefix
);
3489 // edtor => (__gate || edtor)
3491 Expression e
= tmp
.edtor
;
3492 e
= new LogicalExp(e
.loc
, EXP
.orOr
, new VarExp(e
.loc
, gate
), e
);
3493 tmp
.edtor
= e
.expressionSemantic(sc
);
3494 //printf("edtor: %s\n", tmp.edtor.toChars());
3498 // eprefix => (eprefix, auto __pfx/y = arg)
3499 auto ae
= new DeclarationExp(loc
, tmp
);
3500 eprefix
= Expression
.combine(eprefix
, ae
.expressionSemantic(sc
));
3503 arg
= new VarExp(loc
, tmp
);
3504 arg
= arg
.expressionSemantic(sc
);
3507 arg
= new PtrExp(loc
, arg
);
3508 arg
= arg
.expressionSemantic(sc
);
3511 /* Problem 2: Last throwing arg?
3512 * Then finalize eprefix => (eprefix, gate = true), i.e., disable the
3513 * dtors right after constructing the last throwing arg.
3514 * From now on, the callee will take care of destructing the args because
3515 * the args are implicitly moved into function parameters.
3517 if (!callerDestroysArgs
&& i
== lastPrefix
)
3519 auto e
= new AssignExp(gate
.loc
, new VarExp(gate
.loc
, gate
), IntegerExp
.createBool(true));
3520 eprefix
= Expression
.combine(eprefix
, e
.expressionSemantic(sc
));
3523 else // not part of 'eprefix'
3525 /* Handle problem 1) by calling the copy constructor for value structs
3526 * (or static arrays of them) if appropriate.
3528 Type tv
= arg
.type
.baseElemOf();
3529 if (!isRef
&& tv
.ty
== Tstruct
)
3530 arg
= doCopyOrMove(sc
, arg
, parameter ? parameter
.type
: null);
3533 (*arguments
)[i
] = arg
;
3536 //if (eprefix) printf("eprefix: %s\n", eprefix.toChars());
3538 /* Test compliance with DIP1021 Argument Ownership and Function Calls
3540 if (global
.params
.useDIP1021
&& (tf
.trust
== TRUST
.safe || tf
.trust
== TRUST
.default_
) ||
3542 err |
= checkMutableArguments(sc
, fd
, tf
, ethis
, arguments
, false);
3544 // If D linkage and variadic, add _arguments[] as first argument
3545 if (tf
.isDstyleVariadic())
3547 assert(arguments
.length
>= nparams
);
3549 auto args
= new Parameters(arguments
.length
- nparams
);
3550 for (size_t i
= 0; i
< arguments
.length
- nparams
; i
++)
3552 Expression earg
= (*arguments
)[nparams
+ i
];
3553 auto arg
= new Parameter(earg
.loc
, STC
.in_
, earg
.type
, null, null, null);
3556 auto tup
= new TypeTuple(args
);
3557 Expression e
= (new TypeidExp(loc
, tup
)).expressionSemantic(sc
);
3558 arguments
.insert(0, e
);
3561 /* Determine function return type: tret
3563 Type tret
= tf
.next
;
3566 //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd.toChars(), fd.type.toChars(),
3567 // wildmatch, tf.isWild(), fd.isReturnIsolated());
3570 assert(sc
.intypeof || global
.errors
);
3571 tthis
= fd
.isThis().type
.addMod(fd
.type
.mod
);
3573 if (tf
.isWild() && !fd
.isReturnIsolated())
3576 tret
= tret
.substWildTo(wildmatch
);
3578 if (!tret
.implicitConvTo(tthis
) && !(MODimplicitConv(tret
.mod
, tthis
.mod
) && tret
.isBaseOf(tthis
, &offset
) && offset
== 0))
3580 const(char)* s1
= tret
.isNaked() ?
" mutable" : tret
.modToChars();
3581 const(char)* s2
= tthis
.isNaked() ?
" mutable" : tthis
.modToChars();
3582 .error(loc
, "`inout` constructor `%s` creates%s object, not%s", fd
.toPrettyChars(), s1
, s2
);
3588 else if (wildmatch
&& tret
)
3590 /* Adjust function return type based on wildmatch
3592 //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret.toChars());
3593 tret
= tret
.substWildTo(wildmatch
);
3597 *peprefix
= eprefix
;
3598 return (err || olderrors
!= global
.errors
);
3602 * Determines whether a symbol represents a module or package
3603 * (Used as a helper for is(type == module) and is(type == package))
3606 * sym = the symbol to be checked
3609 * the symbol which `sym` represents (or `null` if it doesn't represent a `Package`)
3611 Package
resolveIsPackage(Dsymbol sym
)
3614 if (Import imp
= sym
.isImport())
3616 if (imp
.pkg
is null)
3618 .error(sym
.loc
, "internal compiler error: unable to process forward-referenced import `%s`",
3624 else if (auto mod
= sym
.isModule())
3625 pkg
= mod
.isPackageFile ? mod
.pkg
: sym
.isPackage();
3627 pkg
= sym
.isPackage();
3629 pkg
.resolvePKGunknown();
3634 private extern (C
++) final class ExpressionSemanticVisitor
: Visitor
3636 alias visit
= Visitor
.visit
;
3641 this(Scope
* sc
) scope @safe
3646 private void setError()
3648 result
= ErrorExp
.get();
3651 private void needThisError(Loc loc
, FuncDeclaration f
)
3653 auto t
= f
.isThis();
3655 .error(loc
, "calling non-static function `%s` requires an instance of type `%s`", f
.toChars(), t
.toChars());
3659 /**************************
3660 * Semantically analyze Expression.
3661 * Determine types, fold constants, etc.
3663 override void visit(Expression e
)
3665 static if (LOGSEMANTIC
)
3667 printf("Expression::semantic() %s\n", e
.toChars());
3670 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
3672 e
.type
= Type
.tvoid
;
3676 override void visit(IntegerExp e
)
3679 if (e
.type
.ty
== Terror
)
3682 assert(e
.type
.deco
);
3683 e
.setInteger(e
.getInteger());
3687 override void visit(RealExp e
)
3690 e
.type
= Type
.tfloat64
;
3691 else if (e
.type
.isimaginary
&& sc
.flags
& SCOPE
.Cfile
)
3693 /* Convert to core.stdc.config.complex
3695 Type t
= getComplexLibraryType(e
.loc
, sc
, e
.type
.ty
);
3702 case Timaginary32
: tf
= Type
.tfloat32
; break;
3703 case Timaginary64
: tf
= Type
.tfloat64
; break;
3704 case Timaginary80
: tf
= Type
.tfloat80
; break;
3709 /* Construct ts{re : 0.0, im : e}
3711 TypeStruct ts
= t
.isTypeStruct
;
3712 Expressions
* elements
= new Expressions(2);
3713 (*elements
)[0] = new RealExp(e
.loc
, CTFloat
.zero
, tf
);
3714 (*elements
)[1] = new RealExp(e
.loc
, e
.toImaginary(), tf
);
3715 Expression sle
= new StructLiteralExp(e
.loc
, ts
.sym
, elements
);
3716 result
= sle
.expressionSemantic(sc
);
3720 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
3724 override void visit(ComplexExp e
)
3727 e
.type
= Type
.tcomplex80
;
3729 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
3733 override void visit(IdentifierExp exp
)
3735 static if (LOGSEMANTIC
)
3737 printf("IdentifierExp::semantic('%s')\n", exp
.ident
.toChars());
3739 if (exp
.type
) // This is used as the dummy expression
3746 Dsymbol s
= sc
.search(exp
.loc
, exp
.ident
, &scopesym
);
3754 /* See if the symbol was a member of an enclosing 'with'
3756 WithScopeSymbol withsym
= scopesym
.isWithScopeSymbol();
3757 if (withsym
&& withsym
.withstate
.wthis
&& symbolIsVisible(sc
, s
))
3759 /* Disallow shadowing
3761 // First find the scope of the with
3763 while (scwith
.scopesym
!= scopesym
)
3765 scwith
= scwith
.enclosing
;
3768 // Look at enclosing scopes for symbols with the same name,
3769 // in the same function
3770 for (Scope
* scx
= scwith
; scx
&& scx
.func
== scwith
.func
; scx
= scx
.enclosing
)
3773 if (scx
.scopesym
&& scx
.scopesym
.symtab
&& (s2
= scx
.scopesym
.symtab
.lookup(s
.ident
)) !is null && s
!= s2
)
3775 error(exp
.loc
, "with symbol `%s` is shadowing local symbol `%s`", s
.toPrettyChars(), s2
.toPrettyChars());
3781 // Same as wthis.ident
3782 // TODO: DotIdExp.semantic will find 'ident' from 'wthis' again.
3783 // The redudancy should be removed.
3784 e
= new VarExp(exp
.loc
, withsym
.withstate
.wthis
);
3785 e
= new DotIdExp(exp
.loc
, e
, exp
.ident
);
3786 e
= e
.expressionSemantic(sc
);
3792 if (withsym
.withstate
.exp
.type
.ty
!= Tvoid
)
3794 // 'with (exp)' is a type expression
3795 // or 's' is not visible there (for error message)
3796 e
= new TypeExp(exp
.loc
, withsym
.withstate
.exp
.type
);
3800 // 'with (exp)' is a Package/Module
3801 e
= withsym
.withstate
.exp
;
3803 e
= new DotIdExp(exp
.loc
, e
, exp
.ident
);
3804 result
= e
.expressionSemantic(sc
);
3808 /* If f is really a function template,
3809 * then replace f with the function template declaration.
3811 FuncDeclaration f
= s
.isFuncDeclaration();
3814 TemplateDeclaration td
= getFuncTemplateDecl(f
);
3817 if (td
.overroot
) // if not start of overloaded list of TemplateDeclaration's
3818 td
= td
.overroot
; // then get the start
3819 e
= new TemplateExp(exp
.loc
, td
, f
);
3820 e
= e
.expressionSemantic(sc
);
3826 if (global
.params
.fixAliasThis
)
3828 ExpressionDsymbol expDsym
= scopesym
.isExpressionDsymbol();
3831 //printf("expDsym = %s\n", expDsym.exp.toChars());
3832 result
= expDsym
.exp
.expressionSemantic(sc
);
3836 // Haven't done overload resolution yet, so pass 1
3837 e
= symbolToExp(s
, exp
.loc
, sc
, true);
3843 if (!global
.params
.fixAliasThis
&& hasThis(sc
))
3845 for (AggregateDeclaration ad
= sc
.getStructClassScope(); ad
;)
3850 e
= new ThisExp(exp
.loc
);
3851 e
= new DotIdExp(exp
.loc
, e
, ad
.aliasthis
.ident
);
3852 e
= new DotIdExp(exp
.loc
, e
, exp
.ident
);
3853 e
= e
.trySemantic(sc
);
3861 auto cd
= ad
.isClassDeclaration();
3862 if (cd
&& cd
.baseClass
&& cd
.baseClass
!= ClassDeclaration
.object
)
3871 if (exp
.ident
== Id
.ctfe
)
3873 if (sc
.flags
& SCOPE
.ctfe
)
3875 error(exp
.loc
, "variable `__ctfe` cannot be read at compile time");
3879 // Create the magic __ctfe bool variable
3880 auto vd
= new VarDeclaration(exp
.loc
, Type
.tbool
, Id
.ctfe
, null);
3881 vd
.storage_class |
= STC
.temp
;
3882 vd
.semanticRun
= PASS
.semanticdone
;
3883 Expression e
= new VarExp(exp
.loc
, vd
);
3884 e
= e
.expressionSemantic(sc
);
3889 // If we've reached this point and are inside a with() scope then we may
3890 // try one last attempt by checking whether the 'wthis' object supports
3891 // dynamic dispatching via opDispatch.
3892 // This is done by rewriting this expression as wthis.ident.
3893 // The innermost with() scope of the hierarchy to satisfy the condition
3895 // https://issues.dlang.org/show_bug.cgi?id=6400
3896 for (Scope
* sc2
= sc
; sc2
; sc2
= sc2
.enclosing
)
3901 if (auto ss
= sc2
.scopesym
.isWithScopeSymbol())
3903 if (ss
.withstate
.wthis
)
3906 e
= new VarExp(exp
.loc
, ss
.withstate
.wthis
);
3907 e
= new DotIdExp(exp
.loc
, e
, exp
.ident
);
3908 e
= e
.trySemantic(sc
);
3915 // Try Type.opDispatch (so the static version)
3916 else if (ss
.withstate
.exp
&& ss
.withstate
.exp
.op
== EXP
.type
)
3918 if (Type t
= ss
.withstate
.exp
.isTypeExp().type
)
3921 e
= new TypeExp(exp
.loc
, t
);
3922 e
= new DotIdExp(exp
.loc
, e
, exp
.ident
);
3923 e
= e
.trySemantic(sc
);
3934 /* Look for what user might have meant
3936 if (const n
= importHint(exp
.ident
.toString()))
3937 error(exp
.loc
, "`%s` is not defined, perhaps `import %.*s;` is needed?", exp
.ident
.toChars(), cast(int)n
.length
, n
.ptr
);
3938 else if (auto s2
= sc
.search_correct(exp
.ident
))
3939 error(exp
.loc
, "undefined identifier `%s`, did you mean %s `%s`?", exp
.ident
.toChars(), s2
.kind(), s2
.toChars());
3940 else if (const p
= Scope
.search_correct_C(exp
.ident
))
3941 error(exp
.loc
, "undefined identifier `%s`, did you mean `%s`?", exp
.ident
.toChars(), p
);
3942 else if (exp
.ident
== Id
.dollar
)
3943 error(exp
.loc
, "undefined identifier `$`");
3945 error(exp
.loc
, "undefined identifier `%s`", exp
.ident
.toChars());
3947 result
= ErrorExp
.get();
3950 override void visit(DsymbolExp e
)
3952 result
= symbolToExp(e
.s
, e
.loc
, sc
, e
.hasOverloads
);
3955 override void visit(ThisExp e
)
3957 static if (LOGSEMANTIC
)
3959 printf("ThisExp::semantic()\n");
3967 FuncDeclaration fd
= hasThis(sc
); // fd is the uplevel function with the 'this' variable
3968 AggregateDeclaration ad
;
3970 /* Special case for typeof(this) and typeof(super) since both
3971 * should work even if they are not inside a non-static member function
3973 if (!fd
&& sc
.intypeof
== 1)
3975 // Find enclosing struct or class
3976 for (Dsymbol s
= sc
.getStructClassScope(); 1; s
= s
.parent
)
3980 error(e
.loc
, "`%s` is not in a class or struct scope", e
.toChars());
3983 ClassDeclaration cd
= s
.isClassDeclaration();
3990 StructDeclaration sd
= s
.isStructDeclaration();
4001 error(e
.loc
, "`this` is only defined in non-static member functions, not `%s`", sc
.parent
.toChars());
4007 assert(e
.var
.parent
);
4008 ad
= fd
.isMemberLocal();
4010 ad
= fd
.isMember2();
4012 e
.type
= ad
.type
.addMod(e
.var
.type
.mod
);
4014 if (e
.var
.checkNestedReference(sc
, e
.loc
))
4020 override void visit(SuperExp e
)
4022 static if (LOGSEMANTIC
)
4024 printf("SuperExp::semantic('%s')\n", e
.toChars());
4032 FuncDeclaration fd
= hasThis(sc
);
4033 ClassDeclaration cd
;
4036 /* Special case for typeof(this) and typeof(super) since both
4037 * should work even if they are not inside a non-static member function
4039 if (!fd
&& sc
.intypeof
== 1)
4041 // Find enclosing class
4042 for (s
= sc
.getStructClassScope(); 1; s
= s
.parent
)
4046 error(e
.loc
, "`%s` is not in a class scope", e
.toChars());
4049 cd
= s
.isClassDeclaration();
4055 error(e
.loc
, "class `%s` has no `super`", s
.toChars());
4068 assert(e
.var
&& e
.var
.parent
);
4070 s
= fd
.toParentDecl();
4071 if (s
.isTemplateDeclaration()) // allow inside template constraint
4074 cd
= s
.isClassDeclaration();
4075 //printf("parent is %s %s\n", fd.toParent().kind(), fd.toParent().toChars());
4080 error(e
.loc
, "no base class for `%s`", cd
.toChars());
4081 e
.type
= cd
.type
.addMod(e
.var
.type
.mod
);
4085 e
.type
= cd
.baseClass
.type
;
4086 e
.type
= e
.type
.castMod(e
.var
.type
.mod
);
4089 if (e
.var
.checkNestedReference(sc
, e
.loc
))
4096 error(e
.loc
, "`super` is only allowed in non-static class member functions");
4097 result
= ErrorExp
.get();
4100 override void visit(NullExp e
)
4102 static if (LOGSEMANTIC
)
4104 printf("NullExp::semantic('%s')\n", e
.toChars());
4106 // NULL is the same as (void *)0
4112 e
.type
= Type
.tnull
;
4116 override void visit(StringExp e
)
4118 static if (LOGSEMANTIC
)
4120 printf("StringExp::semantic() %s\n", e
.toChars());
4136 for (u
= 0; u
< e
.len
;)
4138 if (const p
= utf_decodeChar(e
.peekString(), u
, c
))
4140 error(e
.loc
, "%.*s", cast(int)p
.length
, p
.ptr
);
4150 e
.setData(buffer
.extractData(), newlen
, 4);
4151 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
4152 e
.type
= Type
.tuns32
.sarrayOf(e
.len
+ 1);
4154 e
.type
= Type
.tdchar
.immutableOf().arrayOf();
4159 for (u
= 0; u
< e
.len
;)
4161 if (const p
= utf_decodeChar(e
.peekString(), u
, c
))
4163 error(e
.loc
, "%.*s", cast(int)p
.length
, p
.ptr
);
4168 buffer
.writeUTF16(c
);
4174 buffer
.writeUTF16(0);
4175 e
.setData(buffer
.extractData(), newlen
, 2);
4176 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
4177 e
.type
= Type
.tuns16
.sarrayOf(e
.len
+ 1);
4179 e
.type
= Type
.twchar
.immutableOf().arrayOf();
4188 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
4189 e
.type
= Type
.tchar
.sarrayOf(e
.len
+ 1);
4191 e
.type
= Type
.tchar
.immutableOf().arrayOf();
4194 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
4195 //type = type.immutableOf();
4196 //printf("type = %s\n", type.toChars());
4201 override void visit(TupleExp exp
)
4203 static if (LOGSEMANTIC
)
4205 printf("+TupleExp::semantic(%s)\n", exp
.toChars());
4214 exp
.e0
= exp
.e0
.expressionSemantic(sc
);
4216 // Run semantic() on each argument
4218 for (size_t i
= 0; i
< exp
.exps
.length
; i
++)
4220 Expression e
= (*exp
.exps
)[i
];
4221 e
= e
.expressionSemantic(sc
);
4224 error(exp
.loc
, "`%s` has no value", e
.toChars());
4227 else if (e
.op
== EXP
.error
)
4235 expandTuples(exp
.exps
);
4237 exp
.type
= new TypeTuple(exp
.exps
);
4238 exp
.type
= exp
.type
.typeSemantic(exp
.loc
, sc
);
4239 //printf("-TupleExp::semantic(%s)\n", toChars());
4243 override void visit(ArrayLiteralExp e
)
4245 static if (LOGSEMANTIC
)
4247 printf("ArrayLiteralExp::semantic('%s')\n", e
.toChars());
4255 /* Perhaps an empty array literal [ ] should be rewritten as null?
4259 e
.basis
= e
.basis
.expressionSemantic(sc
);
4260 if (arrayExpressionSemantic(e
.elements
.peekSlice(), sc
) ||
(e
.basis
&& e
.basis
.op
== EXP
.error
))
4263 expandTuples(e
.elements
);
4266 e
.elements
.push(e
.basis
);
4267 Type t0
= arrayExpressionToCommonType(sc
, *e
.elements
);
4269 e
.basis
= e
.elements
.pop();
4273 e
.type
= t0
.arrayOf();
4274 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
4276 /* Disallow array literals of type void being used.
4278 if (e
.elements
.length
> 0 && t0
.ty
== Tvoid
)
4280 error(e
.loc
, "`%s` of type `%s` has no value", e
.toChars(), e
.type
.toChars());
4284 if (global
.params
.useTypeInfo
&& Type
.dtypeinfo
)
4285 semanticTypeInfo(sc
, e
.type
);
4290 override void visit(AssocArrayLiteralExp e
)
4292 static if (LOGSEMANTIC
)
4294 printf("AssocArrayLiteralExp::semantic('%s')\n", e
.toChars());
4302 // Run semantic() on each element
4303 bool err_keys
= arrayExpressionSemantic(e
.keys
.peekSlice(), sc
);
4304 bool err_vals
= arrayExpressionSemantic(e
.values
.peekSlice(), sc
);
4305 if (err_keys || err_vals
)
4308 expandTuples(e
.keys
);
4309 expandTuples(e
.values
);
4310 if (e
.keys
.length
!= e
.values
.length
)
4312 error(e
.loc
, "number of keys is %llu, must match number of values %llu",
4313 cast(ulong) e
.keys
.length
, cast(ulong) e
.values
.length
);
4317 Type tkey
= arrayExpressionToCommonType(sc
, *e
.keys
);
4318 Type tvalue
= arrayExpressionToCommonType(sc
, *e
.values
);
4319 if (tkey
is null || tvalue
is null)
4322 e
.type
= new TypeAArray(tvalue
, tkey
);
4323 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
4325 semanticTypeInfo(sc
, e
.type
);
4327 if (checkAssocArrayLiteralEscape(sc
, e
, false))
4333 override void visit(StructLiteralExp e
)
4335 static if (LOGSEMANTIC
)
4337 printf("StructLiteralExp::semantic('%s')\n", e
.toChars());
4346 if (e
.sd
.sizeok
!= Sizeok
.done
)
4349 // run semantic() on each element
4350 if (arrayExpressionSemantic(e
.elements
.peekSlice(), sc
))
4353 expandTuples(e
.elements
);
4355 /* Fit elements[] to the corresponding type of field[].
4357 if (!e
.sd
.fit(e
.loc
, sc
, e
.elements
, e
.stype
))
4360 /* Fill out remainder of elements[] with default initializers for fields[]
4362 if (!e
.sd
.fill(e
.loc
, *e
.elements
, false))
4364 /* An error in the initializer needs to be recorded as an error
4365 * in the enclosing function or template, since the initializer
4366 * will be part of the stuct declaration.
4368 global
.increaseErrorCount();
4372 if (checkFrameAccess(e
.loc
, sc
, e
.sd
, e
.elements
.length
))
4375 e
.type
= e
.stype ? e
.stype
: e
.sd
.type
;
4379 override void visit(CompoundLiteralExp cle
)
4381 static if (LOGSEMANTIC
)
4383 printf("CompoundLiteralExp::semantic('%s')\n", cle
.toChars());
4385 Type t
= cle
.type
.typeSemantic(cle
.loc
, sc
);
4386 auto init
= initializerSemantic(cle
.initializer
, sc
, t
, INITnointerpret
);
4387 auto e
= initializerToExpression(init
, t
, (sc
.flags
& SCOPE
.Cfile
) != 0);
4390 error(cle
.loc
, "cannot convert initializer `%s` to expression", init
.toChars());
4397 override void visit(TypeExp exp
)
4399 if (exp
.type
.ty
== Terror
)
4402 //printf("TypeExp::semantic(%s)\n", exp.type.toChars());
4407 dmd
.typesem
.resolve(exp
.type
, exp
.loc
, sc
, e
, t
, s
, true);
4410 // `(Type)` is actually `(var)` so if `(var)` is a member requiring `this`
4411 // then rewrite as `(this.var)` in case it would be followed by a DotVar
4412 // to fix https://issues.dlang.org/show_bug.cgi?id=9490
4413 VarExp ve
= e
.isVarExp();
4414 if (ve
&& ve
.var
&& exp
.parens
&& !ve
.var
.isStatic() && !(sc
.stc & STC
.static_
) &&
4415 sc
.func
&& sc
.func
.needThis
&& ve
.var
.isMember2())
4417 // printf("apply fix for bugzilla issue 9490: add `this.` to `%s`...\n", e.toChars());
4418 e
= new DotVarExp(exp
.loc
, new ThisExp(exp
.loc
), ve
.var
, false);
4420 //printf("e = %s %s\n", Token.toChars(e.op), e.toChars());
4421 e
= e
.expressionSemantic(sc
);
4425 //printf("t = %d %s\n", t.ty, t.toChars());
4426 exp
.type
= t
.typeSemantic(exp
.loc
, sc
);
4431 //printf("s = %s %s\n", s.kind(), s.toChars());
4432 e
= symbolToExp(s
, exp
.loc
, sc
, true);
4437 exp
.type
.checkComplexTransition(exp
.loc
, sc
);
4442 override void visit(ScopeExp exp
)
4444 static if (LOGSEMANTIC
)
4446 printf("+ScopeExp::semantic(%p '%s')\n", exp
, exp
.toChars());
4454 ScopeDsymbol sds2
= exp
.sds
;
4455 TemplateInstance ti
= sds2
.isTemplateInstance();
4458 WithScopeSymbol withsym
;
4459 if (!ti
.findTempDecl(sc
, &withsym
) ||
!ti
.semanticTiargs(sc
))
4461 if (withsym
&& withsym
.withstate
.wthis
)
4463 Expression e
= new VarExp(exp
.loc
, withsym
.withstate
.wthis
);
4464 e
= new DotTemplateInstanceExp(exp
.loc
, e
, ti
);
4465 result
= e
.expressionSemantic(sc
);
4468 if (ti
.needsTypeInference(sc
))
4470 if (TemplateDeclaration td
= ti
.tempdecl
.isTemplateDeclaration())
4472 Dsymbol p
= td
.toParentLocal();
4473 FuncDeclaration fdthis
= hasThis(sc
);
4474 AggregateDeclaration ad
= p ? p
.isAggregateDeclaration() : null;
4475 if (fdthis
&& ad
&& fdthis
.isMemberLocal() == ad
&& (td
._scope
.stc & STC
.static_
) == 0)
4477 Expression e
= new DotTemplateInstanceExp(exp
.loc
, new ThisExp(exp
.loc
), ti
);
4478 result
= e
.expressionSemantic(sc
);
4482 else if (OverloadSet os
= ti
.tempdecl
.isOverloadSet())
4484 FuncDeclaration fdthis
= hasThis(sc
);
4485 AggregateDeclaration ad
= os
.parent
.isAggregateDeclaration();
4486 if (fdthis
&& ad
&& fdthis
.isMemberLocal() == ad
)
4488 Expression e
= new DotTemplateInstanceExp(exp
.loc
, new ThisExp(exp
.loc
), ti
);
4489 result
= e
.expressionSemantic(sc
);
4493 // ti is an instance which requires IFTI.
4495 exp
.type
= Type
.tvoid
;
4499 ti
.dsymbolSemantic(sc
);
4500 if (!ti
.inst || ti
.errors
)
4503 Dsymbol s
= ti
.toAlias();
4507 exp
.type
= Type
.tvoid
;
4511 sds2
= s
.isScopeDsymbol();
4514 ti
= sds2
.isTemplateInstance();
4515 //printf("+ sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
4519 if (auto v
= s
.isVarDeclaration())
4523 error(exp
.loc
, "forward reference of %s `%s`", v
.kind(), v
.toChars());
4526 if ((v
.storage_class
& STC
.manifest
) && v
._init
)
4528 /* When an instance that will be converted to a constant exists,
4529 * the instance representation "foo!tiargs" is treated like a
4530 * variable name, and its recursive appearance check (note that
4531 * it's equivalent with a recursive instantiation of foo) is done
4532 * separately from the circular initialization check for the
4533 * eponymous enum variable declaration.
4536 * enum bool foo = foo; // recursive definition check (v.inuse)
4539 * enum bool bar = bar!T; // recursive instantiation check (ti.inuse)
4544 error(exp
.loc
, "recursive expansion of %s `%s`", ti
.kind(), ti
.toPrettyChars());
4547 v
.checkDeprecated(exp
.loc
, sc
);
4548 auto e
= v
.expandInitializer(exp
.loc
);
4550 e
= e
.expressionSemantic(sc
);
4557 //printf("s = %s, '%s'\n", s.kind(), s.toChars());
4558 auto e
= symbolToExp(s
, exp
.loc
, sc
, true);
4559 //printf("-1ScopeExp::semantic()\n");
4564 //printf("sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
4565 //printf("\tparent = '%s'\n", sds2.parent.toChars());
4566 sds2
.dsymbolSemantic(sc
);
4568 // (Aggregate|Enum)Declaration
4569 if (auto t
= sds2
.getType())
4571 result
= (new TypeExp(exp
.loc
, t
)).expressionSemantic(sc
);
4575 if (auto td
= sds2
.isTemplateDeclaration())
4577 result
= (new TemplateExp(exp
.loc
, td
)).expressionSemantic(sc
);
4582 exp
.type
= Type
.tvoid
;
4583 //printf("-2ScopeExp::semantic() %s\n", toChars());
4588 * Sets the `lowering` field of a `NewExp` to a call to `_d_newitemT` unless
4589 * compiling with `-betterC` or within `__traits(compiles)`.
4592 * ne = the `NewExp` to lower
4594 private void tryLowerToNewItem(NewExp ne
)
4596 if (!global
.params
.useGC ||
!sc
.needsCodegen())
4599 auto hook
= global
.params
.tracegc ? Id
._d_newitemTTrace
: Id
._d_newitemT
;
4600 if (!verifyHookExist(ne
.loc
, *sc
, hook
, "new struct"))
4603 /* Lower the memory allocation and initialization of `new T()` to
4604 * `_d_newitemT!T()`.
4606 Expression id
= new IdentifierExp(ne
.loc
, Id
.empty
);
4607 id
= new DotIdExp(ne
.loc
, id
, Id
.object
);
4608 auto tiargs
= new Objects();
4610 * Remove `inout`, `const`, `immutable` and `shared` to reduce the
4611 * number of generated `_d_newitemT` instances.
4613 auto t
= ne
.type
.nextOf
.unqualify(MODFlags
.wild | MODFlags
.const_ |
4614 MODFlags
.immutable_ | MODFlags
.shared_
);
4616 id
= new DotTemplateInstanceExp(ne
.loc
, id
, hook
, tiargs
);
4618 auto arguments
= new Expressions();
4619 if (global
.params
.tracegc
)
4621 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ?
4622 sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
4623 arguments
.push(new StringExp(ne
.loc
, ne
.loc
.filename
.toDString()));
4624 arguments
.push(new IntegerExp(ne
.loc
, ne
.loc
.linnum
, Type
.tint32
));
4625 arguments
.push(new StringExp(ne
.loc
, funcname
.toDString()));
4627 id
= new CallExp(ne
.loc
, id
, arguments
);
4629 ne
.lowering
= id
.expressionSemantic(sc
);
4632 override void visit(NewExp exp
)
4634 static if (LOGSEMANTIC
)
4636 printf("NewExp::semantic() %s\n", exp
.toChars());
4638 printf("\tthisexp = %s\n", exp
.thisexp
.toChars());
4639 printf("\tnewtype: %s\n", exp
.newtype
.toChars());
4641 if (exp
.type
) // if semantic() already run
4647 //for error messages if the argument in [] is not convertible to size_t
4648 const originalNewtype
= exp
.newtype
;
4650 // https://issues.dlang.org/show_bug.cgi?id=11581
4651 // With the syntax `new T[edim]` or `thisexp.new T[edim]`,
4652 // T should be analyzed first and edim should go into arguments iff it's
4654 Expression edim
= null;
4655 if (!exp
.arguments
&& exp
.newtype
.isTypeSArray())
4657 auto ts
= exp
.newtype
.isTypeSArray();
4658 // check `new Value[Key]`
4659 ts
.dim
= ts
.dim
.expressionSemantic(sc
);
4660 if (ts
.dim
.op
== EXP
.type
)
4662 exp
.newtype
= new TypeAArray(ts
.next
, ts
.dim
.isTypeExp().type
);
4667 exp
.newtype
= ts
.next
;
4671 ClassDeclaration cdthis
= null;
4674 exp
.thisexp
= exp
.thisexp
.expressionSemantic(sc
);
4675 if (exp
.thisexp
.op
== EXP
.error
)
4678 cdthis
= exp
.thisexp
.type
.isClassHandle();
4681 error(exp
.loc
, "`this` for nested class must be a class type, not `%s`", exp
.thisexp
.type
.toChars());
4685 sc
= sc
.push(cdthis
);
4686 exp
.type
= exp
.newtype
.typeSemantic(exp
.loc
, sc
);
4691 exp
.type
= exp
.newtype
.typeSemantic(exp
.loc
, sc
);
4693 if (exp
.type
.ty
== Terror
)
4698 if (exp
.type
.toBasetype().ty
== Ttuple
)
4701 exp
.type
= new TypeSArray(exp
.type
, edim
);
4702 exp
.type
= exp
.type
.typeSemantic(exp
.loc
, sc
);
4703 if (exp
.type
.ty
== Terror
)
4708 // --> new T[](edim)
4709 exp
.arguments
= new Expressions();
4710 exp
.arguments
.push(edim
);
4711 exp
.type
= exp
.type
.arrayOf();
4715 exp
.newtype
= exp
.type
; // in case type gets cast to something else
4716 Type tb
= exp
.type
.toBasetype();
4717 //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco);
4718 if (arrayExpressionSemantic(exp
.arguments
.peekSlice(), sc
))
4722 if (preFunctionParameters(sc
, exp
.argumentList
))
4727 if (exp
.thisexp
&& tb
.ty
!= Tclass
)
4729 error(exp
.loc
, "`.new` is only for allocating nested classes, not `%s`", tb
.toChars());
4733 const size_t nargs
= exp
.arguments ? exp
.arguments
.length
: 0;
4734 Expression newprefix
= null;
4736 if (auto tc
= tb
.isTypeClass())
4742 if (cd
.sizeok
!= Sizeok
.done
)
4745 cd
.ctor
= cd
.searchCtor();
4746 if (cd
.noDefaultCtor
&& !nargs
&& !cd
.defaultCtor
)
4748 error(exp
.loc
, "default construction is disabled for type `%s`", cd
.type
.toChars());
4752 if (cd
.isInterfaceDeclaration())
4754 error(exp
.loc
, "cannot create instance of interface `%s`", cd
.toChars());
4758 if (cd
.isAbstract())
4760 error(exp
.loc
, "cannot create instance of abstract class `%s`", cd
.toChars());
4761 errorSupplemental(cd
.loc
, "class `%s` is declared here", cd
.toChars());
4762 for (size_t i
= 0; i
< cd
.vtbl
.length
; i
++)
4764 FuncDeclaration fd
= cd
.vtbl
[i
].isFuncDeclaration();
4765 if (fd
&& fd
.isAbstract())
4767 errorSupplemental(fd
.loc
, "function `%s` is not implemented",
4768 fd
.toFullSignature());
4773 // checkDeprecated() is already done in newtype.typeSemantic().
4777 /* We need a 'this' pointer for the nested class.
4778 * Ensure we have the right one.
4780 Dsymbol s
= cd
.toParentLocal();
4782 //printf("cd isNested, parent = %s '%s'\n", s.kind(), s.toPrettyChars());
4783 if (auto cdn
= s
.isClassDeclaration())
4787 void noReferenceToOuterClass()
4790 error(exp
.loc
, "cannot construct anonymous nested class because no implicit `this` reference to outer class is available");
4792 error(exp
.loc
, "cannot construct nested class `%s` because no implicit `this` reference to outer class `%s` is available",
4793 cd
.toChars(), cdn
.toChars());
4798 return noReferenceToOuterClass();
4800 // Supply an implicit 'this' and try again
4801 exp
.thisexp
= new ThisExp(exp
.loc
);
4802 for (Dsymbol sp
= sc
.parent
; 1; sp
= sp
.toParentLocal())
4805 return noReferenceToOuterClass();
4806 ClassDeclaration cdp
= sp
.isClassDeclaration();
4809 if (cdp
== cdn || cdn
.isBaseOf(cdp
, null))
4811 // Add a '.outer' and try again
4812 exp
.thisexp
= new DotIdExp(exp
.loc
, exp
.thisexp
, Id
.outer
);
4815 exp
.thisexp
= exp
.thisexp
.expressionSemantic(sc
);
4816 if (exp
.thisexp
.op
== EXP
.error
)
4818 cdthis
= exp
.thisexp
.type
.isClassHandle();
4820 if (cdthis
!= cdn
&& !cdn
.isBaseOf(cdthis
, null))
4822 //printf("cdthis = %s\n", cdthis.toChars());
4823 error(exp
.loc
, "`this` for nested class must be of type `%s`, not `%s`",
4824 cdn
.toChars(), exp
.thisexp
.type
.toChars());
4827 if (!MODimplicitConv(exp
.thisexp
.type
.mod
, exp
.newtype
.mod
))
4829 error(exp
.loc
, "nested type `%s` should have the same or weaker constancy as enclosing type `%s`",
4830 exp
.newtype
.toChars(), exp
.thisexp
.type
.toChars());
4834 else if (exp
.thisexp
)
4836 error(exp
.loc
, "`.new` is only for allocating nested classes");
4839 else if (auto fdn
= s
.isFuncDeclaration())
4841 // make sure the parent context fdn of cd is reachable from sc
4842 if (!ensureStaticLinkTo(sc
.parent
, fdn
))
4844 error(exp
.loc
, "outer function context of `%s` is needed to `new` nested class `%s`",
4845 fdn
.toPrettyChars(), cd
.toPrettyChars());
4852 else if (exp
.thisexp
)
4854 error(exp
.loc
, "`.new` is only for allocating nested classes");
4860 if (AggregateDeclaration ad2
= cd
.isMember2())
4862 Expression te
= new ThisExp(exp
.loc
).expressionSemantic(sc
);
4863 if (te
.op
!= EXP
.error
)
4864 te
= getRightThis(exp
.loc
, sc
, ad2
, te
, cd
);
4865 if (te
.op
== EXP
.error
)
4867 error(exp
.loc
, "need `this` of type `%s` needed to `new` nested class `%s`", ad2
.toChars(), cd
.toChars());
4873 if (cd
.disableNew
&& !exp
.onstack
)
4875 error(exp
.loc
, "cannot allocate `class %s` with `new` because it is annotated with `@disable new()`",
4876 originalNewtype
.toChars());
4882 FuncDeclaration f
= resolveFuncCall(exp
.loc
, sc
, cd
.ctor
, null, tb
, exp
.argumentList
, FuncResolveFlag
.standard
);
4886 checkFunctionAttributes(exp
, sc
, f
);
4887 checkAccess(cd
, exp
.loc
, sc
, f
);
4889 TypeFunction tf
= f
.type
.isTypeFunction();
4891 exp
.arguments
= new Expressions();
4892 if (functionParameters(exp
.loc
, sc
, tf
, null, exp
.type
, exp
.argumentList
, f
, &exp
.type
, &exp
.argprefix
))
4895 exp
.member
= f
.isCtorDeclaration();
4902 error(exp
.loc
, "no constructor for `%s`", cd
.toChars());
4906 // https://issues.dlang.org/show_bug.cgi?id=19941
4907 // Run semantic on all field initializers to resolve any forward
4908 // references. This is the same as done for structs in sd.fill().
4909 for (ClassDeclaration c
= cd
; c
; c
= c
.baseClass
)
4911 foreach (v
; c
.fields
)
4913 if (v
.inuse || v
._scope
is null || v
._init
is null ||
4914 v
._init
.isVoidInitializer() || v
.semanticRun
>= PASS
.semantic2done
)
4917 v
._init
= v
._init
.initializerSemantic(v
._scope
, v
.type
, INITinterpret
);
4918 import dmd
.semantic2
: lowerStaticAAs
;
4919 lowerStaticAAs(v
, sc
);
4925 // When using `@nogc` exception handling, lower `throw new E(args)` to
4926 // `throw (__tmp = _d_newThrowable!E(), __tmp.__ctor(args), __tmp)`.
4927 if (global
.params
.ehnogc
&& exp
.thrownew
&&
4928 !cd
.isCOMclass() && !cd
.isCPPclass())
4932 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
4933 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
4935 auto tiargs
= new Objects();
4936 tiargs
.push(exp
.newtype
);
4937 id
= new DotTemplateInstanceExp(exp
.loc
, id
, Id
._d_newThrowable
, tiargs
);
4938 id
= new CallExp(exp
.loc
, id
).expressionSemantic(sc
);
4941 Expression tmp
= extractSideEffect(sc
, "__tmpThrowable", idVal
, id
, true);
4942 // auto castTmp = new CastExp(exp.loc, tmp, exp.type);
4944 auto ctor
= new DotIdExp(exp
.loc
, tmp
, Id
.ctor
).expressionSemantic(sc
);
4945 auto ctorCall
= new CallExp(exp
.loc
, ctor
, exp
.arguments
);
4947 id
= Expression
.combine(idVal
, exp
.argprefix
).expressionSemantic(sc
);
4948 id
= Expression
.combine(id
, ctorCall
).expressionSemantic(sc
);
4949 // id = Expression.combine(id, castTmp).expressionSemantic(sc);
4951 result
= id
.expressionSemantic(sc
);
4954 else if (sc
.needsCodegen() && // interpreter doesn't need this lowered
4955 !exp
.onstack
&& !exp
.type
.isscope()) // these won't use the GC
4957 /* replace `new T(arguments)` with `core.lifetime._d_newclassT!T(arguments)`
4958 * or `_d_newclassTTrace`
4960 auto hook
= global
.params
.tracegc ? Id
._d_newclassTTrace
: Id
._d_newclassT
;
4961 if (!verifyHookExist(exp
.loc
, *sc
, hook
, "new class"))
4964 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
4965 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
4967 auto tiargs
= new Objects();
4968 auto t
= exp
.newtype
.unqualify(MODFlags
.wild
); // remove `inout`
4970 id
= new DotTemplateInstanceExp(exp
.loc
, id
, hook
, tiargs
);
4971 auto arguments
= new Expressions();
4972 if (global
.params
.tracegc
)
4974 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ?
4975 sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
4976 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
4977 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
4978 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
4980 id
= new CallExp(exp
.loc
, id
, arguments
);
4982 exp
.lowering
= id
.expressionSemantic(sc
);
4985 else if (auto ts
= tb
.isTypeStruct())
4989 if (sd
.sizeok
!= Sizeok
.done
)
4992 sd
.ctor
= sd
.searchCtor();
4993 if (sd
.noDefaultCtor
&& !nargs
)
4995 error(exp
.loc
, "default construction is disabled for type `%s`", sd
.type
.toChars());
4998 // checkDeprecated() is already done in newtype.typeSemantic().
5002 error(exp
.loc
, "cannot allocate `struct %s` with `new` because it is annotated with `@disable new()`",
5003 originalNewtype
.toChars());
5007 // https://issues.dlang.org/show_bug.cgi?id=22639
5008 // If the new expression has arguments, we either should call a
5009 // regular constructor of a copy constructor if the first argument
5010 // is the same type as the struct
5011 if (nargs
&& (sd
.hasRegularCtor() ||
(sd
.ctor
&& (*exp
.arguments
)[0].type
.mutableOf() == sd
.type
.mutableOf())))
5013 FuncDeclaration f
= resolveFuncCall(exp
.loc
, sc
, sd
.ctor
, null, tb
, exp
.argumentList
, FuncResolveFlag
.standard
);
5017 checkFunctionAttributes(exp
, sc
, f
);
5018 checkAccess(sd
, exp
.loc
, sc
, f
);
5020 TypeFunction tf
= f
.type
.isTypeFunction();
5022 exp
.arguments
= new Expressions();
5023 if (functionParameters(exp
.loc
, sc
, tf
, null, exp
.type
, exp
.argumentList
, f
, &exp
.type
, &exp
.argprefix
))
5026 exp
.member
= f
.isCtorDeclaration();
5029 if (checkFrameAccess(exp
.loc
, sc
, sd
, sd
.fields
.length
))
5036 exp
.arguments
= resolveStructLiteralNamedArgs(sd
, exp
.type
, sc
, exp
.loc
,
5037 exp
.names ?
(*exp
.names
)[] : null,
5038 (size_t i
, Type t
) => (*exp
.arguments
)[i
],
5039 i
=> (*exp
.arguments
)[i
].loc
5044 else if (!exp
.arguments
)
5046 exp
.arguments
= new Expressions();
5049 if (!sd
.fit(exp
.loc
, sc
, exp
.arguments
, tb
))
5052 if (!sd
.fill(exp
.loc
, *exp
.arguments
, false))
5055 if (checkFrameAccess(exp
.loc
, sc
, sd
, exp
.arguments ? exp
.arguments
.length
: 0))
5058 /* Since a `new` allocation may escape, check each of the arguments for escaping
5060 foreach (arg
; *exp
.arguments
)
5062 if (arg
&& checkNewEscape(sc
, arg
, false))
5067 exp
.type
= exp
.type
.pointerTo();
5068 tryLowerToNewItem(exp
);
5070 else if (tb
.ty
== Tarray
)
5074 // https://issues.dlang.org/show_bug.cgi?id=20422
5075 // Without this check the compiler would give a misleading error
5076 error(exp
.loc
, "missing length argument for array");
5080 Type tn
= tb
.nextOf().baseElemOf();
5081 Dsymbol s
= tn
.toDsymbol(sc
);
5082 AggregateDeclaration ad
= s ? s
.isAggregateDeclaration() : null;
5083 if (ad
&& ad
.noDefaultCtor
)
5085 error(exp
.loc
, "default construction is disabled for type `%s`", tb
.nextOf().toChars());
5088 for (size_t i
= 0; i
< nargs
; i
++)
5090 if (tb
.ty
!= Tarray
)
5092 error(exp
.loc
, "too many arguments for array");
5096 Expression arg
= (*exp
.arguments
)[i
];
5097 if (exp
.names
&& (*exp
.names
)[i
])
5099 error(exp
.loc
, "no named argument `%s` allowed for array dimension", (*exp
.names
)[i
].toChars());
5103 arg
= resolveProperties(sc
, arg
);
5104 arg
= arg
.implicitCastTo(sc
, Type
.tsize_t
);
5105 if (arg
.op
== EXP
.error
)
5107 arg
= arg
.optimize(WANTvalue
);
5108 if (arg
.op
== EXP
.int64
&& (target
.isLP64 ?
5109 cast(sinteger_t
)arg
.toInteger() : cast(int)arg
.toInteger()) < 0)
5111 error(exp
.loc
, "negative array dimension `%s`", (*exp
.arguments
)[i
].toChars());
5114 (*exp
.arguments
)[i
] = arg
;
5115 tb
= tb
.isTypeDArray().next
.toBasetype();
5118 if (global
.params
.betterC ||
!sc
.needsCodegen())
5119 goto LskipNewArrayLowering
;
5121 /* Class types may inherit base classes that have errors.
5122 * This may leak errors from the base class to the derived one
5123 * and then to the hook. Semantic analysis is performed eagerly
5126 if (auto tc
= exp
.type
.nextOf
.isTypeClass())
5128 tc
.sym
.dsymbolSemantic(sc
);
5130 goto LskipNewArrayLowering
;
5135 auto hook
= global
.params
.tracegc ? Id
._d_newarrayTTrace
: Id
._d_newarrayT
;
5136 if (!verifyHookExist(exp
.loc
, *sc
, hook
, "new array"))
5137 goto LskipNewArrayLowering
;
5139 /* Lower the memory allocation and initialization of `new T[n]`
5140 * to `_d_newarrayT!T(n)`.
5142 Expression lowering
= new IdentifierExp(exp
.loc
, Id
.empty
);
5143 lowering
= new DotIdExp(exp
.loc
, lowering
, Id
.object
);
5144 auto tiargs
= new Objects();
5145 /* Remove `inout`, `const`, `immutable` and `shared` to reduce
5146 * the number of generated `_d_newarrayT` instances.
5148 const isShared
= exp
.type
.nextOf
.isShared();
5149 auto t
= exp
.type
.nextOf
.unqualify(MODFlags
.wild | MODFlags
.const_ |
5150 MODFlags
.immutable_ | MODFlags
.shared_
);
5152 lowering
= new DotTemplateInstanceExp(exp
.loc
, lowering
, hook
, tiargs
);
5154 auto arguments
= new Expressions();
5155 if (global
.params
.tracegc
)
5157 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ?
5158 sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
5159 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
5160 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
5161 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
5163 arguments
.push((*exp
.arguments
)[0]);
5164 arguments
.push(new IntegerExp(exp
.loc
, isShared
, Type
.tbool
));
5166 lowering
= new CallExp(exp
.loc
, lowering
, arguments
);
5167 exp
.lowering
= lowering
.expressionSemantic(sc
);
5171 auto hook
= global
.params
.tracegc ? Id
._d_newarraymTXTrace
: Id
._d_newarraymTX
;
5172 if (!verifyHookExist(exp
.loc
, *sc
, hook
, "new multi-dimensional array"))
5173 goto LskipNewArrayLowering
;
5175 /* Lower the memory allocation and initialization of `new T[][]...[](n1, n2, ...)`
5176 * to `_d_newarraymTX!(T[][]...[], T)([n1, n2, ...])`.
5178 Expression lowering
= new IdentifierExp(exp
.loc
, Id
.empty
);
5179 lowering
= new DotIdExp(exp
.loc
, lowering
, Id
.object
);
5181 auto tbn
= exp
.type
.nextOf();
5182 while (tbn
.ty
== Tarray
)
5184 auto unqualTbn
= tbn
.unqualify(MODFlags
.wild | MODFlags
.const_ |
5185 MODFlags
.immutable_ | MODFlags
.shared_
);
5187 auto tiargs
= new Objects();
5188 tiargs
.push(exp
.type
);
5189 tiargs
.push(unqualTbn
);
5190 lowering
= new DotTemplateInstanceExp(exp
.loc
, lowering
, hook
, tiargs
);
5192 auto arguments
= new Expressions();
5193 if (global
.params
.tracegc
)
5195 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ?
5196 sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
5197 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
5198 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
5199 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
5202 arguments
.push(new ArrayLiteralExp(exp
.loc
, Type
.tsize_t
.sarrayOf(nargs
), exp
.arguments
));
5203 arguments
.push(new IntegerExp(exp
.loc
, tbn
.isShared(), Type
.tbool
));
5205 lowering
= new CallExp(exp
.loc
, lowering
, arguments
);
5206 exp
.lowering
= lowering
.expressionSemantic(sc
);
5209 else if (tb
.isscalar())
5214 else if (nargs
== 1)
5216 if (exp
.names
&& (*exp
.names
)[0])
5218 error(exp
.loc
, "no named argument `%s` allowed for scalar", (*exp
.names
)[0].toChars());
5221 Expression e
= (*exp
.arguments
)[0];
5222 e
= e
.implicitCastTo(sc
, tb
);
5223 (*exp
.arguments
)[0] = e
;
5227 error(exp
.loc
, "more than one argument for construction of `%s`", exp
.type
.toChars());
5231 exp
.type
= exp
.type
.pointerTo();
5232 tryLowerToNewItem(exp
);
5234 else if (tb
.ty
== Taarray
)
5236 // e.g. `new Alias(args)`
5239 error(exp
.loc
, "`new` cannot take arguments for an associative array");
5245 error(exp
.loc
, "cannot create a `%s` with `new`", exp
.type
.toChars());
5249 LskipNewArrayLowering
:
5250 //printf("NewExp: '%s'\n", toChars());
5251 //printf("NewExp:type '%s'\n", type.toChars());
5252 semanticTypeInfo(sc
, exp
.type
);
5256 result
= Expression
.combine(newprefix
, exp
);
5262 override void visit(NewAnonClassExp e
)
5264 static if (LOGSEMANTIC
)
5266 printf("NewAnonClassExp::semantic() %s\n", e
.toChars());
5267 //printf("thisexp = %p\n", thisexp);
5268 //printf("type: %s\n", type.toChars());
5271 Expression d
= new DeclarationExp(e
.loc
, e
.cd
);
5272 sc
= sc
.push(); // just create new scope
5273 sc
.flags
&= ~SCOPE
.ctfe
; // temporary stop CTFE
5274 d
= d
.expressionSemantic(sc
);
5277 if (!e
.cd
.errors
&& sc
.intypeof
&& !sc
.parent
.inNonRoot())
5279 ScopeDsymbol sds
= sc
.tinst ?
cast(ScopeDsymbol
)sc
.tinst
: sc
._module
;
5281 sds
.members
= new Dsymbols();
5282 sds
.members
.push(e
.cd
);
5285 Expression n
= new NewExp(e
.loc
, e
.thisexp
, e
.cd
.type
, e
.arguments
);
5287 Expression c
= new CommaExp(e
.loc
, d
, n
);
5288 result
= c
.expressionSemantic(sc
);
5291 override void visit(SymOffExp e
)
5293 static if (LOGSEMANTIC
)
5295 printf("SymOffExp::semantic('%s')\n", e
.toChars());
5297 //var.dsymbolSemantic(sc);
5299 e
.type
= e
.var
.type
.pointerTo();
5301 if (auto v
= e
.var
.isVarDeclaration())
5303 if (v
.checkNestedReference(sc
, e
.loc
))
5306 else if (auto f
= e
.var
.isFuncDeclaration())
5308 if (f
.checkNestedReference(sc
, e
.loc
))
5315 override void visit(VarExp e
)
5317 static if (LOGSEMANTIC
)
5319 printf("VarExp::semantic(%s)\n", e
.toChars());
5322 auto vd
= e
.var
.isVarDeclaration();
5323 auto fd
= e
.var
.isFuncDeclaration();
5327 //printf("L%d fd = %s\n", __LINE__, f.toChars());
5328 if (!fd
.functionSemantic())
5333 e
.type
= e
.var
.type
;
5334 if (e
.type
&& !e
.type
.deco
)
5336 auto decl
= e
.var
.isDeclaration();
5339 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
5344 /* Fix for 1161 doesn't work because it causes visibility
5345 * problems when instantiating imported templates passing private
5346 * variables as alias template parameters.
5348 //checkAccess(loc, sc, NULL, var);
5352 if (vd
.checkNestedReference(sc
, e
.loc
))
5355 // https://issues.dlang.org/show_bug.cgi?id=12025
5356 // If the variable is not actually used in runtime code,
5357 // the purity violation error is redundant.
5358 //checkPurity(sc, vd);
5362 // TODO: If fd isn't yet resolved its overload, the checkNestedReference
5363 // call would cause incorrect validation.
5364 // Maybe here should be moved in CallExp, or AddrExp for functions.
5365 if (fd
.checkNestedReference(sc
, e
.loc
))
5368 else if (auto od
= e
.var
.isOverDeclaration())
5370 e
.type
= Type
.tvoid
; // ambiguous type?
5376 private void genIdent(FuncExp exp
, Scope
* sc
)
5378 if (exp
.fd
.ident
== Id
.empty
)
5382 s
= "__foreachbody";
5383 else if (exp
.fd
.tok
== TOK
.reserved
)
5385 else if (exp
.fd
.tok
== TOK
.delegate_
)
5388 s
= "__funcliteral";
5390 DsymbolTable symtab
;
5391 if (FuncDeclaration func
= sc
.parent
.isFuncDeclaration())
5393 if (func
.localsymtab
is null)
5395 // Inside template constraint, symtab is not set yet.
5396 // Initialize it lazily.
5397 func
.localsymtab
= new DsymbolTable();
5399 symtab
= func
.localsymtab
;
5403 ScopeDsymbol sds
= sc
.parent
.isScopeDsymbol();
5406 // Inside template constraint, symtab may not be set yet.
5407 // Initialize it lazily.
5408 assert(sds
.isTemplateInstance());
5409 sds
.symtab
= new DsymbolTable();
5411 symtab
= sds
.symtab
;
5414 Identifier id
= Identifier
.generateId(s
, symtab
.length() + 1);
5418 symtab
.insert(exp
.td ?
cast(Dsymbol
)exp
.td
: cast(Dsymbol
)exp
.fd
);
5422 override void visit(FuncExp exp
)
5424 static if (LOGSEMANTIC
)
5426 printf("FuncExp::semantic(%s)\n", exp
.toChars());
5428 printf(" treq = %s\n", exp
.fd
.treq
.toChars());
5440 sc
= sc
.push(); // just create new scope
5441 sc
.flags
&= ~SCOPE
.ctfe
; // temporary stop CTFE
5442 sc
.visibility
= Visibility(Visibility
.Kind
.public_
); // https://issues.dlang.org/show_bug.cgi?id=12506
5444 /* fd.treq might be incomplete type,
5445 * so should not semantic it.
5446 * void foo(T)(T delegate(int) dg){}
5447 * foo(a=>a); // in IFTI, treq == T delegate(int)
5450 // fd.treq = fd.treq.dsymbolSemantic(loc, sc);
5454 // Set target of return type inference
5455 if (exp
.fd
.treq
&& !exp
.fd
.type
.nextOf())
5457 TypeFunction tfv
= null;
5458 if (exp
.fd
.treq
.ty
== Tdelegate || exp
.fd
.treq
.isPtrToFunction())
5459 tfv
= cast(TypeFunction
)exp
.fd
.treq
.nextOf();
5462 TypeFunction tfl
= cast(TypeFunction
)exp
.fd
.type
;
5463 tfl
.next
= tfv
.nextOf();
5467 //printf("td = %p, treq = %p\n", td, fd.treq);
5470 assert(exp
.td
.parameters
&& exp
.td
.parameters
.length
);
5471 exp
.td
.dsymbolSemantic(sc
);
5472 exp
.type
= Type
.tvoid
; // temporary type
5474 if (exp
.fd
.treq
) // defer type determination
5477 if (exp
.matchType(exp
.fd
.treq
, sc
, &fe
, sc
.eSink
) > MATCH
.nomatch
)
5485 olderrors
= global
.errors
;
5486 exp
.fd
.dsymbolSemantic(sc
);
5487 if (olderrors
== global
.errors
)
5489 exp
.fd
.semantic2(sc
);
5490 if (olderrors
== global
.errors
)
5491 exp
.fd
.semantic3(sc
);
5493 if (olderrors
!= global
.errors
)
5495 if (exp
.fd
.type
&& exp
.fd
.type
.ty
== Tfunction
&& !exp
.fd
.type
.nextOf())
5496 (cast(TypeFunction
)exp
.fd
.type
).next
= Type
.terror
;
5501 // Type is a "delegate to" or "pointer to" the function literal
5502 if ((exp
.fd
.isNested() && exp
.fd
.tok
== TOK
.delegate_
) ||
(exp
.tok
== TOK
.reserved
&& exp
.fd
.treq
&& exp
.fd
.treq
.ty
== Tdelegate
))
5504 // https://issues.dlang.org/show_bug.cgi?id=22686
5505 // if the delegate return type is an error
5506 // abort semantic of the FuncExp and propagate
5508 if (exp
.fd
.type
.isTypeError())
5513 exp
.type
= new TypeDelegate(exp
.fd
.type
.isTypeFunction());
5514 exp
.type
= exp
.type
.typeSemantic(exp
.loc
, sc
);
5516 exp
.fd
.tok
= TOK
.delegate_
;
5520 exp
.type
= new TypePointer(exp
.fd
.type
);
5521 exp
.type
= exp
.type
.typeSemantic(exp
.loc
, sc
);
5522 //type = fd.type.pointerTo();
5524 /* A lambda expression deduced to function pointer might become
5525 * to a delegate literal implicitly.
5527 * auto foo(void function() fp) { return 1; }
5528 * assert(foo({}) == 1);
5530 * So, should keep fd.tok == TOK.reserve if fd.treq == NULL.
5532 if (exp
.fd
.treq
&& exp
.fd
.treq
.ty
== Tpointer
)
5534 // change to non-nested
5535 exp
.fd
.tok
= TOK
.function_
;
5536 exp
.fd
.vthis
= null;
5539 exp
.fd
.tookAddressOf
++;
5547 * Perform semantic analysis on function literals
5549 * Test the following construct:
5551 * (x, y, z) { return x + y + z; }(42, 84, 1992);
5554 Expression
callExpSemantic(FuncExp exp
, Scope
* sc
, Expressions
* arguments
)
5556 if ((!exp
.type || exp
.type
== Type
.tvoid
) && exp
.td
&& arguments
&& arguments
.length
)
5558 for (size_t k
= 0; k
< arguments
.length
; k
++)
5560 Expression checkarg
= (*arguments
)[k
];
5561 if (checkarg
.op
== EXP
.error
)
5567 assert(exp
.td
.parameters
&& exp
.td
.parameters
.length
);
5568 exp
.td
.dsymbolSemantic(sc
);
5570 TypeFunction tfl
= cast(TypeFunction
)exp
.fd
.type
;
5571 size_t dim
= tfl
.parameterList
.length
;
5572 if (arguments
.length
< dim
)
5574 // Default arguments are always typed, so they don't need inference.
5575 Parameter p
= tfl
.parameterList
[arguments
.length
];
5577 dim
= arguments
.length
;
5580 if ((tfl
.parameterList
.varargs
== VarArg
.none
&& arguments
.length
> dim
) ||
5581 arguments
.length
< dim
)
5584 foreach (idx
, ref arg
; *arguments
)
5585 buf
.printf("%s%s", (idx ?
", ".ptr
: "".ptr
), arg
.type
.toChars());
5586 error(exp
.loc
, "function literal `%s%s` is not callable using argument types `(%s)`",
5587 exp
.fd
.toChars(), parametersTypeToChars(tfl
.parameterList
),
5589 errorSupplemental(exp
.loc
, "too %s arguments, expected %d, got %d",
5590 arguments
.length
< dim ?
"few".ptr
: "many".ptr
,
5591 cast(int)dim
, cast(int)arguments
.length
);
5592 return ErrorExp
.get();
5595 auto tiargs
= new Objects();
5596 tiargs
.reserve(exp
.td
.parameters
.length
);
5598 for (size_t i
= 0; i
< exp
.td
.parameters
.length
; i
++)
5600 TemplateParameter tp
= (*exp
.td
.parameters
)[i
];
5601 assert(dim
<= tfl
.parameterList
.length
);
5602 foreach (u
, p
; tfl
.parameterList
)
5607 if (p
.type
.ty
== Tident
&& (cast(TypeIdentifier
)p
.type
).ident
== tp
.ident
)
5609 Expression e
= (*arguments
)[u
];
5610 tiargs
.push(e
.type
);
5616 auto ti
= new TemplateInstance(exp
.loc
, exp
.td
, tiargs
);
5617 return (new ScopeExp(exp
.loc
, ti
)).expressionSemantic(sc
);
5619 return exp
.expressionSemantic(sc
);
5622 override void visit(CallExp exp
)
5624 static if (LOGSEMANTIC
)
5626 printf("CallExp::semantic() %s\n", exp
.toChars());
5631 return; // semantic() already run
5634 Objects
* tiargs
= null; // initial list of template arguments
5635 Expression ethis
= null;
5637 Expression e1org
= exp
.e1
;
5639 if (auto ce
= exp
.e1
.isCommaExp())
5641 /* Rewrite (a,b)(args) as (a,(b(args)))
5645 result
= ce
.expressionSemantic(sc
);
5648 if (DelegateExp
de = exp
.e1
.isDelegateExp())
5650 exp
.e1
= new DotVarExp(de.loc
, de.e1
, de.func
, de.hasOverloads
);
5654 if (FuncExp fe
= exp
.e1
.isFuncExp())
5656 if (arrayExpressionSemantic(exp
.arguments
.peekSlice(), sc
) ||
5657 preFunctionParameters(sc
, exp
.argumentList
))
5660 // Run e1 semantic even if arguments have any errors
5661 exp
.e1
= callExpSemantic(fe
, sc
, exp
.arguments
);
5662 if (exp
.e1
.op
== EXP
.error
)
5668 if (sc
.flags
& SCOPE
.Cfile
)
5670 /* See if need to rewrite the AST because of cast/call ambiguity
5672 if (auto e
= castCallAmbiguity(exp
, sc
))
5674 result
= expressionSemantic(e
, sc
);
5679 if (Expression ex
= resolveUFCS(sc
, exp
))
5686 * foo!(tiargs)(funcargs)
5688 if (ScopeExp se
= exp
.e1
.isScopeExp())
5690 TemplateInstance ti
= se
.sds
.isTemplateInstance();
5693 /* Attempt to instantiate ti. If that works, go with it.
5694 * If not, go with partial explicit specialization.
5696 WithScopeSymbol withsym
;
5697 if (!ti
.findTempDecl(sc
, &withsym
) ||
!ti
.semanticTiargs(sc
))
5699 if (withsym
&& withsym
.withstate
.wthis
)
5701 exp
.e1
= new VarExp(exp
.e1
.loc
, withsym
.withstate
.wthis
);
5702 exp
.e1
= new DotTemplateInstanceExp(exp
.e1
.loc
, exp
.e1
, ti
);
5705 if (ti
.needsTypeInference(sc
, 1))
5707 /* Go with partial explicit specialization
5710 assert(ti
.tempdecl
);
5711 if (TemplateDeclaration td
= ti
.tempdecl
.isTemplateDeclaration())
5712 exp
.e1
= new TemplateExp(exp
.loc
, td
);
5713 else if (OverDeclaration od
= ti
.tempdecl
.isOverDeclaration())
5714 exp
.e1
= new VarExp(exp
.loc
, od
);
5716 exp
.e1
= new OverExp(exp
.loc
, ti
.tempdecl
.isOverloadSet());
5720 Expression e1x
= exp
.e1
.expressionSemantic(sc
);
5721 if (e1x
.op
== EXP
.error
)
5732 * expr.foo!(tiargs)(funcargs)
5735 if (DotTemplateInstanceExp se
= exp
.e1
.isDotTemplateInstanceExp())
5737 TemplateInstance ti
= se
.ti
;
5739 /* Attempt to instantiate ti. If that works, go with it.
5740 * If not, go with partial explicit specialization.
5742 if (!se
.findTempDecl(sc
) ||
!ti
.semanticTiargs(sc
))
5744 if (ti
.needsTypeInference(sc
, 1))
5746 /* Go with partial explicit specialization
5749 assert(ti
.tempdecl
);
5750 if (TemplateDeclaration td
= ti
.tempdecl
.isTemplateDeclaration())
5751 exp
.e1
= new DotTemplateExp(exp
.loc
, se
.e1
, td
);
5752 else if (OverDeclaration od
= ti
.tempdecl
.isOverDeclaration())
5754 exp
.e1
= new DotVarExp(exp
.loc
, se
.e1
, od
, true);
5757 exp
.e1
= new DotExp(exp
.loc
, se
.e1
, new OverExp(exp
.loc
, ti
.tempdecl
.isOverloadSet()));
5761 Expression e1x
= exp
.e1
.expressionSemantic(sc
);
5762 if (e1x
.op
== EXP
.error
)
5774 //printf("Lagain: %s\n", toChars());
5776 if (exp
.e1
.op
== EXP
.this_ || exp
.e1
.op
== EXP
.super_
)
5778 // semantic() run later for these
5782 if (DotIdExp die
= exp
.e1
.isDotIdExp())
5784 exp
.e1
= die
.expressionSemantic(sc
);
5785 /* Look for e1 having been rewritten to expr.opDispatch!(string)
5786 * We handle such earlier, so go back.
5787 * Note that in the rewrite, we carefully did not run semantic() on e1
5789 if (exp
.e1
.op
== EXP
.dotTemplateInstance
)
5797 if (++nest
> global
.recursionLimit
)
5799 error(exp
.loc
, "recursive evaluation of `%s`", exp
.toChars());
5803 Expression ex
= unaSemantic(exp
, sc
);
5812 /* Look for e1 being a lazy parameter
5814 if (VarExp ve
= exp
.e1
.isVarExp())
5816 if (ve
.var
.storage_class
& STC
.lazy_
)
5818 // lazy parameters can be called without violating purity and safety
5819 Type tw
= ve
.var
.type
;
5820 Type tc
= ve
.var
.type
.substWildTo(MODFlags
.const_
);
5821 auto tf
= new TypeFunction(ParameterList(), tc
, LINK
.d
, STC
.safe | STC
.pure_
);
5822 (tf
= cast(TypeFunction
)tf
.typeSemantic(exp
.loc
, sc
)).next
= tw
; // hack for bug7757
5823 auto t
= new TypeDelegate(tf
);
5824 ve
.type
= t
.typeSemantic(exp
.loc
, sc
);
5826 VarDeclaration v
= ve
.var
.isVarDeclaration();
5827 if (v
&& v
.checkPurity(ve
.loc
, sc
))
5831 if (exp
.e1
.op
== EXP
.symbolOffset
&& (cast(SymOffExp
)exp
.e1
).hasOverloads
)
5833 SymOffExp se
= cast(SymOffExp
)exp
.e1
;
5834 exp
.e1
= new VarExp(se
.loc
, se
.var
, true);
5835 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
5837 else if (DotExp
de = exp
.e1
.isDotExp())
5839 if (de.e2
.op
== EXP
.overloadSet
)
5846 else if (exp
.e1
.op
== EXP
.star
&& exp
.e1
.type
.ty
== Tfunction
)
5848 // Rewrite (*fp)(arguments) to fp(arguments)
5849 exp
.e1
= (cast(PtrExp
)exp
.e1
).e1
;
5851 else if (exp
.e1
.op
== EXP
.type
&& (sc
&& sc
.flags
& SCOPE
.Cfile
))
5853 const numArgs
= exp
.arguments ? exp
.arguments
.length
: 0;
5855 /* Ambiguous cases arise from CParser where there is not enough
5856 * information to determine if we have a function call or declaration.
5857 * type-name ( identifier ) ;
5858 * identifier ( identifier ) ;
5859 * If exp.e1 is a type-name, then this is a declaration. C11 does not
5860 * have type construction syntax, so don't convert this to a cast().
5864 Expression arg
= (*exp
.arguments
)[0];
5865 if (auto ie
= (*exp
.arguments
)[0].isIdentifierExp())
5867 TypeExp te
= cast(TypeExp
)exp
.e1
;
5868 auto initializer
= new VoidInitializer(ie
.loc
);
5869 Dsymbol s
= new VarDeclaration(ie
.loc
, te
.type
, ie
.ident
, initializer
);
5870 auto decls
= new Dsymbols(1);
5872 s
= new LinkDeclaration(s
.loc
, LINK
.c
, decls
);
5873 result
= new DeclarationExp(exp
.loc
, s
);
5874 result
= result
.expressionSemantic(sc
);
5878 error(arg
.loc
, "identifier or `(` expected");
5879 result
= ErrorExp
.get();
5883 error(exp
.loc
, "identifier or `(` expected before `)`");
5884 result
= ErrorExp
.get();
5889 Type t1
= exp
.e1
.type ? exp
.e1
.type
.toBasetype() : null;
5891 if (exp
.e1
.op
== EXP
.error
)
5896 if (arrayExpressionSemantic(exp
.arguments
.peekSlice(), sc
) ||
5897 preFunctionParameters(sc
, exp
.argumentList
))
5900 // Check for call operator overload
5903 if (t1
.ty
== Tstruct
)
5905 auto sd
= (cast(TypeStruct
)t1
).sym
;
5906 sd
.size(exp
.loc
); // Resolve forward references to construct object
5907 if (sd
.sizeok
!= Sizeok
.done
)
5910 sd
.ctor
= sd
.searchCtor();
5911 /* If `sd.ctor` is a generated copy constructor, this means that it
5912 is the single constructor that this struct has. In order to not
5913 disable default construction, the ctor is nullified. The side effect
5914 of this is that the generated copy constructor cannot be called
5915 explicitly, but that is ok, because when calling a constructor the
5916 default constructor should have priority over the generated copy
5921 auto ctor
= sd
.ctor
.isCtorDeclaration();
5922 if (ctor
&& ctor
.isCpCtor
&& ctor
.isGenerated())
5926 // First look for constructor
5927 if (exp
.e1
.op
== EXP
.type
&& sd
.ctor
)
5929 if (!sd
.noDefaultCtor
&& !(exp
.arguments
&& exp
.arguments
.length
))
5932 /* https://issues.dlang.org/show_bug.cgi?id=20695
5933 If all constructors are copy constructors, then
5934 try default construction.
5936 if (!sd
.hasRegularCtor
&&
5937 // https://issues.dlang.org/show_bug.cgi?id=22639
5938 // we might still have a copy constructor that could be called
5939 (*exp
.arguments
)[0].type
.mutableOf
!= sd
.type
.mutableOf())
5942 auto sle
= new StructLiteralExp(exp
.loc
, sd
, null, exp
.e1
.type
);
5943 if (!sd
.fill(exp
.loc
, *sle
.elements
, true))
5945 if (checkFrameAccess(exp
.loc
, sc
, sd
, sle
.elements
.length
))
5948 // https://issues.dlang.org/show_bug.cgi?id=14556
5949 // Set concrete type to avoid further redundant semantic().
5950 sle
.type
= exp
.e1
.type
;
5952 /* Constructor takes a mutable object, so don't use
5953 * the immutable initializer symbol.
5955 sle
.useStaticInit
= false;
5958 if (auto cf
= sd
.ctor
.isCtorDeclaration())
5960 e
= new DotVarExp(exp
.loc
, e
, cf
, true);
5962 else if (auto td
= sd
.ctor
.isTemplateDeclaration())
5964 e
= new DotIdExp(exp
.loc
, e
, td
.ident
);
5966 else if (auto os
= sd
.ctor
.isOverloadSet())
5968 e
= new DotExp(exp
.loc
, e
, new OverExp(exp
.loc
, os
));
5972 e
= new CallExp(exp
.loc
, e
, exp
.arguments
, exp
.names
);
5973 e
= e
.expressionSemantic(sc
);
5977 // No constructor, look for overload of opCall
5978 if (search_function(sd
, Id
.call))
5980 // overload of opCall, therefore it's a call
5981 if (exp
.e1
.op
!= EXP
.type
)
5983 if (sd
.aliasthis
&& !isRecursiveAliasThis(att
, exp
.e1
.type
))
5985 exp
.e1
= resolveAliasThis(sc
, exp
.e1
);
5988 error(exp
.loc
, "%s `%s` does not overload ()", sd
.kind(), sd
.toChars());
5992 /* It's a struct literal
5995 Expressions
* resolvedArgs
= exp
.arguments
;
5998 resolvedArgs
= resolveStructLiteralNamedArgs(sd
, exp
.e1
.type
, sc
, exp
.loc
,
6000 (size_t i
, Type t
) => (*exp
.arguments
)[i
],
6001 i
=> (*exp
.arguments
)[i
].loc
6005 result
= ErrorExp
.get();
6010 Expression e
= new StructLiteralExp(exp
.loc
, sd
, resolvedArgs
, exp
.e1
.type
);
6011 e
= e
.expressionSemantic(sc
);
6015 else if (t1
.ty
== Tclass
)
6018 // Rewrite as e1.call(arguments)
6019 Expression e
= new DotIdExp(exp
.loc
, exp
.e1
, Id
.call);
6020 e
= new CallExp(exp
.loc
, e
, exp
.arguments
, exp
.names
);
6021 e
= e
.expressionSemantic(sc
);
6025 else if (exp
.e1
.op
== EXP
.type
&& t1
.isscalar())
6029 // Make sure to use the enum type itself rather than its
6031 // https://issues.dlang.org/show_bug.cgi?id=16346
6032 if (exp
.e1
.type
.ty
== Tenum
)
6037 if (!exp
.arguments || exp
.arguments
.length
== 0)
6039 e
= t1
.defaultInitLiteral(exp
.loc
);
6041 else if (exp
.arguments
.length
== 1)
6043 e
= (*exp
.arguments
)[0];
6044 e
= e
.implicitCastTo(sc
, t1
);
6045 e
= new CastExp(exp
.loc
, e
, t1
);
6049 error(exp
.loc
, "more than one argument for construction of `%s`", t1
.toChars());
6052 e
= e
.expressionSemantic(sc
);
6058 FuncDeclaration
resolveOverloadSet(Loc loc
, Scope
* sc
,
6059 OverloadSet os
, Objects
* tiargs
, Type tthis
, ArgumentList argumentList
)
6061 FuncDeclaration f
= null;
6064 if (tiargs
&& s
.isFuncDeclaration())
6066 if (auto f2
= resolveFuncCall(loc
, sc
, s
, tiargs
, tthis
, argumentList
, FuncResolveFlag
.quiet
))
6072 /* Match in more than one overload set,
6073 * even if one is a 'better' match than the other.
6075 if (f
.isCsymbol() && f2
.isCsymbol())
6077 /* C has global name space, so just pick one, such as f.
6078 * If f and f2 are not compatible, that's how C rolls.
6082 ScopeDsymbol
.multiplyDefined(loc
, f
, f2
); // issue error
6090 .error(loc
, "no overload matches for `%s`", exp
.toChars());
6091 errorSupplemental(loc
, "Candidates are:");
6094 overloadApply(s
, (ds){
6095 if (auto fd
= ds.isFuncDeclaration())
6096 .errorSupplemental(ds.loc
, "%s%s", fd
.toChars(),
6097 fd
.type
.toTypeFunction().parameterList
.parametersTypeToChars());
6099 .errorSupplemental(ds.loc
, "%s", ds.toChars());
6109 bool isSuper
= false;
6110 if (exp
.e1
.op
== EXP
.dotVariable
&& t1
.ty
== Tfunction || exp
.e1
.op
== EXP
.dotTemplateDeclaration
)
6112 UnaExp ue
= cast(UnaExp
)exp
.e1
;
6114 Expression ue1old
= ue
.e1
; // need for 'right this' check
6118 if (exp
.e1
.op
== EXP
.dotVariable
)
6120 dve
= cast(DotVarExp
)exp
.e1
;
6128 dte
= cast(DotTemplateExp
)exp
.e1
;
6132 // Do overload resolution
6133 exp
.f
= resolveFuncCall(exp
.loc
, sc
, s
, tiargs
, ue
.e1
.type
, exp
.argumentList
, FuncResolveFlag
.standard
);
6134 if (!exp
.f || exp
.f
.errors || exp
.f
.type
.ty
== Terror
)
6137 if (exp
.f
.interfaceVirtual
)
6139 /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent
6141 auto b
= exp
.f
.interfaceVirtual
;
6143 ue
.e1
= ue
.e1
.castTo(sc
, ad2
.type
.addMod(ue
.e1
.type
.mod
));
6144 ue
.e1
= ue
.e1
.expressionSemantic(sc
);
6145 auto vi
= exp
.f
.findVtblIndex(&ad2
.vtbl
, cast(int)ad2
.vtbl
.length
);
6147 exp
.f
= ad2
.vtbl
[vi
].isFuncDeclaration();
6150 if (exp
.f
.needThis())
6152 AggregateDeclaration ad
= exp
.f
.isMemberLocal();
6153 ue
.e1
= getRightThis(exp
.loc
, sc
, ad
, ue
.e1
, exp
.f
);
6154 if (ue
.e1
.op
== EXP
.error
)
6161 if (!(exp
.f
.type
.ty
== Tfunction
&& (cast(TypeFunction
)exp
.f
.type
).isScopeQual
))
6163 if (checkParamArgumentEscape(sc
, exp
.f
, Id
.This
, exp
.f
.vthis
, STC
.undefined_
, ethis
, false, false))
6168 /* Cannot call public functions from inside invariant
6169 * (because then the invariant would have infinite recursion)
6171 if (sc
.func
&& sc
.func
.isInvariantDeclaration() && ue
.e1
.op
== EXP
.this_
&& exp
.f
.addPostInvariant())
6173 error(exp
.loc
, "cannot call `public`/`export` function `%s` from invariant", exp
.f
.toChars());
6177 if (!exp
.ignoreAttributes
)
6178 checkFunctionAttributes(exp
, sc
, exp
.f
);
6180 // Cut-down version of checkAccess() that doesn't use the "most visible" version of exp.f.
6181 // We've already selected an overload here.
6182 const parent
= exp
.f
.toParent();
6183 if (parent
&& parent
.isTemplateInstance())
6185 // already a deprecation
6187 else if (!checkSymbolAccess(sc
, exp
.f
))
6189 error(exp
.loc
, "%s `%s` of type `%s` is not accessible from module `%s`",
6190 exp
.f
.kind(), exp
.f
.toPrettyChars(), exp
.f
.type
.toChars(), sc
._module
.toChars
);
6194 if (!exp
.f
.needThis())
6196 exp
.e1
= Expression
.combine(ue
.e1
, new VarExp(exp
.loc
, exp
.f
, false));
6200 if (ue1old
.checkRightThis(sc
))
6202 if (exp
.e1
.op
== EXP
.dotVariable
)
6205 exp
.e1
.type
= exp
.f
.type
;
6209 exp
.e1
= new DotVarExp(exp
.loc
, dte
.e1
, exp
.f
, false);
6210 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
6211 if (exp
.e1
.op
== EXP
.error
)
6213 ue
= cast(UnaExp
)exp
.e1
;
6217 printf("ue.e1 = %s\n", ue
.e1
.toChars());
6218 printf("f = %s\n", exp
.f
.toChars());
6219 printf("t1 = %s\n", t1
.toChars());
6220 printf("e1 = %s\n", exp
.e1
.toChars());
6221 printf("e1.type = %s\n", exp
.e1
.type
.toChars());
6224 // See if we need to adjust the 'this' pointer
6225 AggregateDeclaration ad
= exp
.f
.isThis();
6226 ClassDeclaration cd
= ue
.e1
.type
.isClassHandle();
6227 if (ad
&& cd
&& ad
.isClassDeclaration())
6229 if (ue
.e1
.op
== EXP
.dotType
)
6231 ue
.e1
= (cast(DotTypeExp
)ue
.e1
).e1
;
6232 exp
.directcall
= true;
6234 else if (ue
.e1
.op
== EXP
.super_
)
6235 exp
.directcall
= true;
6236 else if ((cd
.storage_class
& STC
.final_
) != 0) // https://issues.dlang.org/show_bug.cgi?id=14211
6237 exp
.directcall
= true;
6241 ue
.e1
= ue
.e1
.castTo(sc
, ad
.type
.addMod(ue
.e1
.type
.mod
));
6242 ue
.e1
= ue
.e1
.expressionSemantic(sc
);
6246 // If we've got a pointer to a function then deference it
6247 // https://issues.dlang.org/show_bug.cgi?id=16483
6248 if (exp
.e1
.type
.isPtrToFunction())
6250 Expression e
= new PtrExp(exp
.loc
, exp
.e1
);
6251 e
.type
= exp
.e1
.type
.nextOf();
6256 else if (exp
.e1
.op
== EXP
.super_ || exp
.e1
.op
== EXP
.this_
)
6258 auto ad
= sc
.func ? sc
.func
.isThis() : null;
6259 auto cd
= ad ? ad
.isClassDeclaration() : null;
6261 isSuper
= exp
.e1
.op
== EXP
.super_
;
6264 // Base class constructor call
6265 if (!cd ||
!cd
.baseClass ||
!sc
.func
.isCtorDeclaration())
6267 error(exp
.loc
, "super class constructor call must be in a constructor");
6270 if (!cd
.baseClass
.ctor
)
6272 error(exp
.loc
, "no super class constructor for `%s`", cd
.baseClass
.toChars());
6278 // `this` call expression must be inside a
6280 if (!ad ||
!sc
.func
.isCtorDeclaration())
6282 error(exp
.loc
, "constructor call must be in a constructor");
6286 // https://issues.dlang.org/show_bug.cgi?id=18719
6287 // If `exp` is a call expression to another constructor
6288 // then it means that all struct/class fields will be
6289 // initialized after this call.
6290 foreach (ref field
; sc
.ctorflow
.fieldinit
)
6292 field
.csx |
= CSX
.this_ctor
;
6296 if (!sc
.intypeof
&& !(sc
.ctorflow
.callSuper
& CSX
.halt
))
6298 if (sc
.inLoop || sc
.ctorflow
.callSuper
& CSX
.label
)
6299 error(exp
.loc
, "constructor calls not allowed in loops or after labels");
6300 if (sc
.ctorflow
.callSuper
& (CSX
.super_ctor | CSX
.this_ctor
))
6301 error(exp
.loc
, "multiple constructor calls");
6302 if ((sc
.ctorflow
.callSuper
& CSX
.return_
) && !(sc
.ctorflow
.callSuper
& CSX
.any_ctor
))
6303 error(exp
.loc
, "an earlier `return` statement skips constructor");
6304 sc
.ctorflow
.callSuper |
= CSX
.any_ctor |
(isSuper ? CSX
.super_ctor
: CSX
.this_ctor
);
6307 tthis
= ad
.type
.addMod(sc
.func
.type
.mod
);
6308 auto ctor
= isSuper ? cd
.baseClass
.ctor
: ad
.ctor
;
6309 if (auto os
= ctor
.isOverloadSet())
6310 exp
.f
= resolveOverloadSet(exp
.loc
, sc
, os
, null, tthis
, exp
.argumentList
);
6312 exp
.f
= resolveFuncCall(exp
.loc
, sc
, ctor
, null, tthis
, exp
.argumentList
, FuncResolveFlag
.standard
);
6314 if (!exp
.f || exp
.f
.errors
)
6317 checkFunctionAttributes(exp
, sc
, exp
.f
);
6318 checkAccess(exp
.loc
, sc
, null, exp
.f
);
6320 exp
.e1
= new DotVarExp(exp
.e1
.loc
, exp
.e1
, exp
.f
, false);
6321 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
6322 // https://issues.dlang.org/show_bug.cgi?id=21095
6323 if (exp
.e1
.op
== EXP
.error
)
6327 // BUG: this should really be done by checking the static
6329 if (exp
.f
== sc
.func
)
6331 error(exp
.loc
, "cyclic constructor call");
6335 else if (auto oe
= exp
.e1
.isOverExp())
6337 exp
.f
= resolveOverloadSet(exp
.loc
, sc
, oe
.vars
, tiargs
, tthis
, exp
.argumentList
);
6341 exp
.e1
= new DotVarExp(exp
.loc
, ethis
, exp
.f
, false);
6343 exp
.e1
= new VarExp(exp
.loc
, exp
.f
, false);
6348 error(exp
.loc
, "function expected before `()`, not `%s`", exp
.e1
.toChars());
6351 else if (t1
.ty
== Terror
)
6355 else if (t1
.ty
!= Tfunction
)
6361 if (auto fe
= exp
.e1
.isFuncExp())
6363 // function literal that direct called is always inferred.
6366 tf
= cast(TypeFunction
)exp
.f
.type
;
6367 p
= "function literal";
6369 else if (t1
.ty
== Tdelegate
)
6371 TypeDelegate td
= cast(TypeDelegate
)t1
;
6372 assert(td
.next
.ty
== Tfunction
);
6373 tf
= cast(TypeFunction
)td
.next
;
6376 else if (auto tfx
= t1
.isPtrToFunction())
6379 p
= "function pointer";
6381 else if (exp
.e1
.op
== EXP
.dotVariable
&& (cast(DotVarExp
)exp
.e1
).var
.isOverDeclaration())
6383 DotVarExp dve
= cast(DotVarExp
)exp
.e1
;
6384 exp
.f
= resolveFuncCall(exp
.loc
, sc
, dve
.var
, tiargs
, dve
.e1
.type
, exp
.argumentList
, FuncResolveFlag
.overloadOnly
);
6387 if (exp
.f
.needThis())
6390 dve
.type
= exp
.f
.type
;
6391 dve
.hasOverloads
= false;
6394 exp
.e1
= new VarExp(dve
.loc
, exp
.f
, false);
6395 Expression e
= new CommaExp(exp
.loc
, dve
.e1
, exp
);
6396 result
= e
.expressionSemantic(sc
);
6399 else if (exp
.e1
.op
== EXP
.variable
&& (cast(VarExp
)exp
.e1
).var
.isOverDeclaration())
6401 s
= (cast(VarExp
)exp
.e1
).var
;
6404 else if (exp
.e1
.op
== EXP
.template_
)
6406 s
= (cast(TemplateExp
)exp
.e1
).td
;
6408 exp
.f
= resolveFuncCall(exp
.loc
, sc
, s
, tiargs
, null, exp
.argumentList
,
6409 exp
.isUfcsRewrite ? FuncResolveFlag
.ufcs
: FuncResolveFlag
.standard
);
6410 if (!exp
.f || exp
.f
.errors
)
6412 if (exp
.f
.needThis())
6416 // Supply an implicit 'this', as in
6418 exp
.e1
= new DotVarExp(exp
.loc
, (new ThisExp(exp
.loc
)).expressionSemantic(sc
), exp
.f
, false);
6421 else if (isNeedThisScope(sc
, exp
.f
))
6423 return needThisError(exp
.loc
, exp
.f
);
6426 exp
.e1
= new VarExp(exp
.e1
.loc
, exp
.f
, false);
6431 error(exp
.loc
, "function expected before `()`, not `%s` of type `%s`", exp
.e1
.toChars(), exp
.e1
.type
.toChars());
6435 const(char)* failMessage
;
6436 if (!tf
.callMatch(null, exp
.argumentList
, 0, &failMessage
, sc
))
6440 argExpTypesToCBuffer(buf
, exp
.arguments
);
6443 tthis
.modToBuffer(buf
);
6445 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
6446 .error(exp
.loc
, "%s `%s%s` is not callable using argument types `%s`",
6447 p
, exp
.e1
.toChars(), parametersTypeToChars(tf
.parameterList
), buf
.peekChars());
6449 errorSupplemental(exp
.loc
, "%s", failMessage
);
6452 // Purity and safety check should run after testing arguments matching
6455 exp
.f
.checkPurity(exp
.loc
, sc
);
6456 exp
.f
.checkSafety(exp
.loc
, sc
);
6457 exp
.f
.checkNogc(exp
.loc
, sc
);
6458 if (exp
.f
.checkNestedReference(sc
, exp
.loc
))
6461 else if (sc
.func
&& sc
.intypeof
!= 1 && !(sc
.flags
& (SCOPE
.ctfe | SCOPE
.debug_
)))
6464 if (!tf
.purity
&& sc
.func
.setImpure(exp
.loc
, "`pure` %s `%s` cannot call impure `%s`", exp
.e1
))
6466 error(exp
.loc
, "`pure` %s `%s` cannot call impure %s `%s`",
6467 sc
.func
.kind(), sc
.func
.toPrettyChars(), p
, exp
.e1
.toChars());
6470 if (!tf
.isnogc
&& sc
.func
.setGC(exp
.loc
, "`@nogc` %s `%s` cannot call non-@nogc `%s`", exp
.e1
))
6472 error(exp
.loc
, "`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
6473 sc
.func
.kind(), sc
.func
.toPrettyChars(), p
, exp
.e1
.toChars());
6476 if (tf
.trust
<= TRUST
.system
&& sc
.setUnsafe(true, exp
.loc
,
6477 "`@safe` function `%s` cannot call `@system` `%s`", sc
.func
, exp
.e1
))
6479 error(exp
.loc
, "`@safe` %s `%s` cannot call `@system` %s `%s`",
6480 sc
.func
.kind(), sc
.func
.toPrettyChars(), p
, exp
.e1
.toChars());
6487 if (t1
.ty
== Tpointer
)
6489 Expression e
= new PtrExp(exp
.loc
, exp
.e1
);
6495 else if (VarExp ve
= exp
.e1
.isVarExp())
6497 // Do overload resolution
6498 exp
.f
= ve
.var
.isFuncDeclaration();
6503 exp
.f
= resolveFuncCall(exp
.loc
, sc
, exp
.f
, tiargs
, null, exp
.argumentList
, FuncResolveFlag
.overloadOnly
);
6506 exp
.f
= exp
.f
.toAliasFunc();
6507 TypeFunction tf
= cast(TypeFunction
)exp
.f
.type
;
6508 const(char)* failMessage
;
6509 if (!tf
.callMatch(null, exp
.argumentList
, 0, &failMessage
, sc
))
6513 argExpTypesToCBuffer(buf
, exp
.arguments
);
6516 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
6517 if (exp
.isUfcsRewrite
)
6519 const arg
= (*exp
.argumentList
.arguments
)[0];
6520 .error(exp
.loc
, "no property `%s` for `%s` of type `%s`", exp
.f
.ident
.toChars(), arg
.toChars(), arg
.type
.toChars());
6521 .errorSupplemental(exp
.loc
, "the following error occured while looking for a UFCS match");
6524 .error(exp
.loc
, "%s `%s%s` is not callable using argument types `%s`",
6525 exp
.f
.kind(), exp
.f
.toPrettyChars(), parametersTypeToChars(tf
.parameterList
), buf
.peekChars());
6527 errorSupplemental(exp
.loc
, "%s", failMessage
);
6531 if (!exp
.f || exp
.f
.errors
)
6534 if (exp
.f
.needThis())
6536 // Change the ancestor lambdas to delegate before hasThis(sc) call.
6537 if (exp
.f
.checkNestedReference(sc
, exp
.loc
))
6540 auto memberFunc
= hasThis(sc
);
6541 if (memberFunc
&& haveSameThis(memberFunc
, exp
.f
))
6543 // Supply an implicit 'this', as in
6545 exp
.e1
= new DotVarExp(exp
.loc
, (new ThisExp(exp
.loc
)).expressionSemantic(sc
), ve
.var
);
6546 // Note: we cannot use f directly, because further overload resolution
6547 // through the supplied 'this' may cause different result.
6550 else if (isNeedThisScope(sc
, exp
.f
))
6552 // At this point it is possible that `exp.f` had an ambiguity error that was
6553 // silenced because the previous call to `resolveFuncCall` was done using
6554 // `FuncResolveFlag.overloadOnly`. To make sure that a proper error message
6555 // is printed, redo the call with `FuncResolveFlag.standard`.
6557 // https://issues.dlang.org/show_bug.cgi?id=22157
6559 exp
.f
= resolveFuncCall(exp
.loc
, sc
, exp
.f
, tiargs
, null, exp
.argumentList
, FuncResolveFlag
.standard
);
6561 if (!exp
.f || exp
.f
.errors
)
6564 // If no error is printed, it means that `f` is the single matching overload
6565 // and it needs `this`.
6566 return needThisError(exp
.loc
, exp
.f
);
6570 checkFunctionAttributes(exp
, sc
, exp
.f
);
6571 checkAccess(exp
.loc
, sc
, null, exp
.f
);
6572 if (exp
.f
.checkNestedReference(sc
, exp
.loc
))
6578 if (ve
.hasOverloads
)
6580 exp
.e1
= new VarExp(ve
.loc
, exp
.f
, false);
6581 exp
.e1
.type
= exp
.f
.type
;
6585 assert(t1
.ty
== Tfunction
);
6587 Expression argprefix
;
6589 exp
.arguments
= new Expressions();
6590 if (functionParameters(exp
.loc
, sc
, cast(TypeFunction
)t1
, ethis
, tthis
, exp
.argumentList
, exp
.f
, &exp
.type
, &argprefix
))
6595 exp
.e1
= e1org
; // https://issues.dlang.org/show_bug.cgi?id=10922
6596 // avoid recursive expression printing
6597 error(exp
.loc
, "forward reference to inferred return type of function call `%s`", exp
.toChars());
6601 if (exp
.f
&& exp
.f
.tintro
)
6605 TypeFunction tf
= cast(TypeFunction
)exp
.f
.tintro
;
6606 if (tf
.next
.isBaseOf(t
, &offset
) && offset
)
6609 result
= Expression
.combine(argprefix
, exp
.castTo(sc
, t
));
6614 // Handle the case of a direct lambda call
6615 if (exp
.f
&& exp
.f
.isFuncLiteralDeclaration() && sc
.func
&& !sc
.intypeof
)
6617 exp
.f
.tookAddressOf
= 0;
6620 result
= Expression
.combine(argprefix
, exp
);
6624 auto ad
= sc
.func ? sc
.func
.isThis() : null;
6625 auto cd
= ad ? ad
.isClassDeclaration() : null;
6626 if (cd
&& cd
.classKind
== ClassKind
.cpp
&& exp
.f
&& !exp
.f
.fbody
)
6628 // if super is defined in C++, it sets the vtable pointer to the base class
6629 // so we have to restore it, but still return 'this' from super() call:
6630 // (auto __vptrTmp = this.__vptr, auto __superTmp = super()), (this.__vptr = __vptrTmp, __superTmp)
6633 auto vptr
= new DotIdExp(loc
, new ThisExp(loc
), Id
.__vptr
);
6634 auto vptrTmpDecl
= copyToTemp(0, "__vptrTmp", vptr
);
6635 auto declareVptrTmp
= new DeclarationExp(loc
, vptrTmpDecl
);
6637 auto superTmpDecl
= copyToTemp(0, "__superTmp", result
);
6638 auto declareSuperTmp
= new DeclarationExp(loc
, superTmpDecl
);
6640 auto declareTmps
= new CommaExp(loc
, declareVptrTmp
, declareSuperTmp
);
6642 auto restoreVptr
= new AssignExp(loc
, vptr
.syntaxCopy(), new VarExp(loc
, vptrTmpDecl
));
6644 Expression e
= new CommaExp(loc
, declareTmps
, new CommaExp(loc
, restoreVptr
, new VarExp(loc
, superTmpDecl
)));
6645 result
= e
.expressionSemantic(sc
);
6649 // `super.fun()` with fun being abstract and unimplemented
6650 auto supDotFun
= exp
.e1
.isDotVarExp();
6651 if (supDotFun
&& supDotFun
.e1
.isSuperExp() && exp
.f
&& exp
.f
.isAbstract() && !exp
.f
.fbody
)
6653 error(exp
.loc
, "call to unimplemented abstract function `%s`", exp
.f
.toFullSignature());
6654 errorSupplemental(exp
.loc
, "declared here: %s", exp
.f
.loc
.toChars());
6657 // declare dual-context container
6658 if (exp
.f
&& exp
.f
.hasDualContext() && !sc
.intypeof
&& sc
.func
)
6660 // check access to second `this`
6661 if (AggregateDeclaration ad2
= exp
.f
.isMember2())
6663 Expression te
= new ThisExp(exp
.loc
).expressionSemantic(sc
);
6664 if (te
.op
!= EXP
.error
)
6665 te
= getRightThis(exp
.loc
, sc
, ad2
, te
, exp
.f
);
6666 if (te
.op
== EXP
.error
)
6668 error(exp
.loc
, "need `this` of type `%s` to call function `%s`", ad2
.toChars(), exp
.f
.toChars());
6672 exp
.vthis2
= makeThis2Argument(exp
.loc
, sc
, exp
.f
);
6673 Expression
de = new DeclarationExp(exp
.loc
, exp
.vthis2
);
6674 result
= Expression
.combine(de, result
);
6675 result
= result
.expressionSemantic(sc
);
6679 override void visit(DeclarationExp e
)
6686 static if (LOGSEMANTIC
)
6688 printf("DeclarationExp::semantic() %s\n", e
.toChars());
6691 uint olderrors
= global
.errors
;
6693 /* This is here to support extern(linkage) declaration,
6694 * where the extern(linkage) winds up being an AttribDeclaration
6697 Dsymbol s
= e
.declaration
;
6701 AttribDeclaration ad
= s
.isAttribDeclaration();
6704 if (ad
.decl
&& ad
.decl
.length
== 1)
6713 //printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc);
6714 // Insert into both local scope and function scope.
6715 // Must be unique in both.
6718 VarDeclaration v
= s
.isVarDeclaration();
6721 if (sc
.flags
& SCOPE
.Cfile
)
6723 /* Do semantic() on the type before inserting v into the symbol table
6725 if (!v
.originalType
)
6726 v
.originalType
= v
.type
.syntaxCopy();
6727 Scope
* sc2
= sc
.push();
6728 sc2
.stc |
= v
.storage_class
& STC
.FUNCATTR
;
6729 sc2
.linkage
= LINK
.c
; // account for the extern(C) in front of the declaration
6731 v
.type
= v
.type
.typeSemantic(v
.loc
, sc2
);
6737 /* Do semantic() on initializer first so this will be illegal:
6740 e
.declaration
.dsymbolSemantic(sc
);
6741 s
.parent
= sc
.parent
;
6747 auto conflict
= sc
.search(Loc
.initial
, s
.ident
, null);
6748 error(e
.loc
, "declaration `%s` is already defined", s
.toPrettyChars());
6749 errorSupplemental(conflict
.loc
, "`%s` `%s` is defined here",
6750 conflict
.kind(), conflict
.toChars());
6754 if (v
&& (sc
.flags
& SCOPE
.Cfile
))
6756 /* Do semantic() on initializer last so this will be legal:
6759 e
.declaration
.dsymbolSemantic(sc
);
6760 s
.parent
= sc
.parent
;
6765 // https://issues.dlang.org/show_bug.cgi?id=11720
6766 if ((s
.isFuncDeclaration() ||
6767 s
.isAggregateDeclaration() ||
6768 s
.isEnumDeclaration() ||
6769 s
.isTemplateDeclaration() ||
6771 ) && !sc
.func
.localsymtab
.insert(s
))
6773 // Get the previous symbol
6774 Dsymbol originalSymbol
= sc
.func
.localsymtab
.lookup(s
.ident
);
6776 // Perturb the name mangling so that the symbols can co-exist
6777 // instead of colliding
6778 s
.localNum
= cast(ushort)(originalSymbol
.localNum
+ 1);
6779 // 65535 should be enough for anyone
6782 error(e
.loc
, "more than 65535 symbols with name `%s` generated", s
.ident
.toChars());
6786 // Replace originalSymbol with s, which updates the localCount
6787 sc
.func
.localsymtab
.update(s
);
6789 // The mangling change only works for D mangling
6792 if (!(sc
.flags
& SCOPE
.Cfile
))
6794 /* https://issues.dlang.org/show_bug.cgi?id=21272
6795 * If we are in a foreach body we need to extract the
6796 * function containing the foreach
6798 FuncDeclaration fes_enclosing_func
;
6799 if (sc
.func
&& sc
.func
.fes
)
6800 fes_enclosing_func
= sc
.enclosing
.enclosing
.func
;
6802 // Disallow shadowing
6803 for (Scope
* scx
= sc
.enclosing
; scx
&& (scx
.func
== sc
.func ||
(fes_enclosing_func
&& scx
.func
== fes_enclosing_func
)); scx
= scx
.enclosing
)
6806 if (scx
.scopesym
&& scx
.scopesym
.symtab
&& (s2
= scx
.scopesym
.symtab
.lookup(s
.ident
)) !is null && s
!= s2
)
6808 // allow STC.local symbols to be shadowed
6809 // TODO: not really an optimal design
6810 auto decl
= s2
.isDeclaration();
6811 if (!decl ||
!(decl
.storage_class
& STC
.local
))
6815 deprecation(e
.loc
, "%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.", s
.kind(), s
.ident
.toChars(), s2
.kind(), s2
.toPrettyChars());
6819 error(e
.loc
, "%s `%s` is shadowing %s `%s`", s
.kind(), s
.ident
.toChars(), s2
.kind(), s2
.toPrettyChars());
6828 if (!s
.isVarDeclaration())
6831 if (sc2
.stc & (STC
.pure_ | STC
.nothrow_ | STC
.nogc
))
6833 sc2
.stc &= ~(STC
.pure_ | STC
.nothrow_ | STC
.nogc
);
6834 e
.declaration
.dsymbolSemantic(sc2
);
6837 s
.parent
= sc
.parent
;
6839 if (global
.errors
== olderrors
)
6841 e
.declaration
.semantic2(sc
);
6842 if (global
.errors
== olderrors
)
6844 e
.declaration
.semantic3(sc
);
6847 // todo: error in declaration should be propagated.
6849 e
.type
= Type
.tvoid
;
6853 override void visit(TypeidExp exp
)
6855 static if (LOGSEMANTIC
)
6857 printf("TypeidExp::semantic() %s\n", exp
.toChars());
6859 Type ta
= isType(exp
.obj
);
6860 Expression ea
= isExpression(exp
.obj
);
6861 Dsymbol sa
= isDsymbol(exp
.obj
);
6862 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
6866 dmd
.typesem
.resolve(ta
, exp
.loc
, sc
, ea
, ta
, sa
, true);
6871 if (auto sym
= getDsymbol(ea
))
6872 ea
= symbolToExp(sym
, exp
.loc
, sc
, false);
6874 ea
= ea
.expressionSemantic(sc
);
6875 ea
= resolveProperties(sc
, ea
);
6877 if (ea
.op
== EXP
.type
)
6883 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
6884 error(exp
.loc
, "no type for `typeid(%s)`", ea ? ea
.toChars() : (sa ? sa
.toChars() : ""));
6888 ta
.checkComplexTransition(exp
.loc
, sc
);
6891 auto tb
= ta
.toBasetype();
6892 if (ea
&& tb
.ty
== Tclass
)
6894 if (tb
.toDsymbol(sc
).isClassDeclaration().classKind
== ClassKind
.cpp
)
6896 error(exp
.loc
, "runtime type information is not supported for `extern(C++)` classes");
6899 else if (!Type
.typeinfoclass
)
6901 error(exp
.loc
, "`object.TypeInfo_Class` could not be found, but is implicitly used");
6906 /* Get the dynamic type, which is .classinfo
6908 ea
= ea
.expressionSemantic(sc
);
6909 e
= new TypeidExp(ea
.loc
, ea
);
6910 e
.type
= Type
.typeinfoclass
.type
;
6913 else if (ta
.ty
== Terror
)
6919 // Handle this in the glue layer
6920 e
= new TypeidExp(exp
.loc
, ta
);
6922 bool genObjCode
= true;
6924 // https://issues.dlang.org/show_bug.cgi?id=23650
6925 // We generate object code for typeinfo, required
6926 // by typeid, only if in non-speculative context
6927 if (sc
.flags
& SCOPE
.compile
)
6932 e
.type
= getTypeInfoType(exp
.loc
, ta
, sc
, genObjCode
);
6933 semanticTypeInfo(sc
, ta
);
6937 e
= new CommaExp(exp
.loc
, ea
, e
); // execute ea
6938 e
= e
.expressionSemantic(sc
);
6944 override void visit(TraitsExp e
)
6946 result
= semanticTraits(e
, sc
);
6949 override void visit(HaltExp e
)
6951 static if (LOGSEMANTIC
)
6953 printf("HaltExp::semantic()\n");
6955 e
.type
= Type
.tnoreturn
;
6959 override void visit(IsExp e
)
6961 /* is(targ id tok tspec)
6962 * is(targ id : tok2)
6963 * is(targ id == tok2)
6972 result
= IntegerExp
.createBool(true);
6977 Tuple tup
= isTuple(tded
);
6979 s
= new TupleDeclaration(e
.loc
, e
.id
, &tup
.objects
);
6981 s
= new AliasDeclaration(e
.loc
, e
.id
, tded
);
6982 s
.dsymbolSemantic(sc
);
6984 /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there.
6985 * More investigation is needed.
6987 if (!tup
&& !sc
.insert(s
))
6989 auto conflict
= sc
.search(Loc
.initial
, s
.ident
, null);
6990 error(e
.loc
, "declaration `%s` is already defined", s
.toPrettyChars());
6991 errorSupplemental(conflict
.loc
, "`%s` `%s` is defined here",
6992 conflict
.kind(), conflict
.toChars());
6995 unSpeculative(sc
, s
);
6997 result
= IntegerExp
.createBool(true);
7001 result
= IntegerExp
.createBool(false);
7005 static if (LOGSEMANTIC
)
7007 printf("IsExp::semantic(%s)\n", e
.toChars());
7009 if (e
.id
&& !(sc
.flags
& SCOPE
.condition
))
7011 error(e
.loc
, "can only declare type aliases within `static if` conditionals or `static assert`s");
7015 if (e
.tok2
== TOK
.package_ || e
.tok2
== TOK
.module_
) // These is() expressions are special because they can work on modules, not just types.
7017 const oldErrors
= global
.startGagging();
7018 Dsymbol sym
= e
.targ
.toDsymbol(sc
);
7019 global
.endGagging(oldErrors
);
7023 Package p
= resolveIsPackage(sym
);
7026 if (e
.tok2
== TOK
.package_
&& p
.isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module.
7028 else if(e
.tok2
== TOK
.module_
&& !(p
.isModule() || p
.isPackageMod()))
7035 Scope
* sc2
= sc
.copy(); // keep sc.flags
7038 sc2
.flags |
= SCOPE
.fullinst
;
7039 Type t
= e
.targ
.trySemantic(e
.loc
, sc2
);
7041 if (!t
) // errors, so condition is false
7046 if (e
.tok2
!= TOK
.reserved
)
7051 if (e
.targ
.ty
!= Tstruct
)
7053 if ((cast(TypeStruct
)e
.targ
).sym
.isUnionDeclaration())
7059 if (e
.targ
.ty
!= Tstruct
)
7061 if (!(cast(TypeStruct
)e
.targ
).sym
.isUnionDeclaration())
7067 if (e
.targ
.ty
!= Tclass
)
7069 if ((cast(TypeClass
)e
.targ
).sym
.isInterfaceDeclaration())
7074 case TOK
.interface_
:
7075 if (e
.targ
.ty
!= Tclass
)
7077 if (!(cast(TypeClass
)e
.targ
).sym
.isInterfaceDeclaration())
7083 if (!e
.targ
.isConst())
7088 case TOK
.immutable_
:
7089 if (!e
.targ
.isImmutable())
7095 if (!e
.targ
.isShared())
7101 if (!e
.targ
.isWild())
7107 // If class or interface, get the base class and interfaces
7108 if (e
.targ
.ty
!= Tclass
)
7112 ClassDeclaration cd
= (cast(TypeClass
)e
.targ
).sym
;
7113 auto args
= new Parameters();
7114 args
.reserve(cd
.baseclasses
.length
);
7115 if (cd
.semanticRun
< PASS
.semanticdone
)
7116 cd
.dsymbolSemantic(null);
7117 for (size_t i
= 0; i
< cd
.baseclasses
.length
; i
++)
7119 BaseClass
* b
= (*cd
.baseclasses
)[i
];
7120 args
.push(new Parameter(Loc
.initial
, STC
.in_
, b
.type
, null, null, null));
7122 tded
= new TypeTuple(args
);
7127 if (e
.targ
.ty
!= Tenum
)
7130 tded
= (cast(TypeEnum
)e
.targ
).sym
.getMemtype(e
.loc
);
7134 if (tded
.ty
== Terror
)
7139 if (e
.targ
.ty
!= Tdelegate
)
7141 tded
= (cast(TypeDelegate
)e
.targ
).next
; // the underlying function type
7145 if (e
.targ
.ty
!= Tfunction
)
7148 case TOK
.parameters
:
7150 if (auto tf
= e
.targ
.isFunction_Delegate_PtrToFunction())
7155 /* Generate tuple from function parameter types.
7157 auto args
= new Parameters();
7158 foreach (i
, arg
; tded
.isTypeFunction().parameterList
)
7160 assert(arg
&& arg
.type
);
7161 /* If one of the default arguments was an error,
7162 don't return an invalid tuple
7164 if (e
.tok2
== TOK
.parameters
&& arg
.defaultArg
&& arg
.defaultArg
.op
== EXP
.error
)
7166 args
.push(new Parameter(arg
.loc
, arg
.storageClass
, arg
.type
, (e
.tok2
== TOK
.parameters
) ? arg
.ident
: null, (e
.tok2
== TOK
.parameters
) ? arg
.defaultArg
: null, arg
.userAttribDecl
));
7168 tded
= new TypeTuple(args
);
7172 /* Get the 'return type' for the function,
7173 * delegate, or pointer to function.
7175 if (auto tf
= e
.targ
.isFunction_Delegate_PtrToFunction())
7181 case TOK
.argumentTypes
:
7182 /* Generate a type tuple of the equivalent types used to determine if a
7183 * function argument of this type can be passed in registers.
7184 * The results of this are highly platform dependent, and intended
7185 * primarly for use in implementing va_arg().
7187 tded
= target
.toArgTypes(e
.targ
);
7190 // not valid for a parameter
7194 if (e
.targ
.ty
!= Tvector
)
7196 tded
= (cast(TypeVector
)e
.targ
).basetype
;
7203 // https://issues.dlang.org/show_bug.cgi?id=18753
7208 else if (e
.tspec
&& !e
.id
&& !(e
.parameters
&& e
.parameters
.length
))
7210 /* Evaluate to true if targ matches tspec
7214 e
.tspec
= e
.tspec
.typeSemantic(e
.loc
, sc
);
7215 //printf("targ = %s, %s\n", e.targ.toChars(), e.targ.deco);
7216 //printf("tspec = %s, %s\n", e.tspec.toChars(), e.tspec.deco);
7218 if (e
.tok
== TOK
.colon
)
7220 // current scope is itself deprecated, or deprecations are not errors
7221 const bool deprecationAllowed
= sc
.isDeprecated
7222 || global
.params
.useDeprecated
!= DiagnosticReporting
.error
;
7223 const bool preventAliasThis
= e
.targ
.hasDeprecatedAliasThis
&& !deprecationAllowed
;
7225 if (preventAliasThis
&& e
.targ
.ty
== Tstruct
)
7227 if ((cast(TypeStruct
) e
.targ
).implicitConvToWithoutAliasThis(e
.tspec
))
7232 else if (preventAliasThis
&& e
.targ
.ty
== Tclass
)
7234 if ((cast(TypeClass
) e
.targ
).implicitConvToWithoutAliasThis(e
.tspec
))
7239 else if (e
.targ
.implicitConvTo(e
.tspec
))
7246 if (e
.targ
.equals(e
.tspec
))
7254 /* Evaluate to true if targ matches tspec.
7255 * If true, declare id as an alias for the specialized type.
7256 * is(targ == tspec, tpl)
7257 * is(targ : tspec, tpl)
7258 * is(targ id == tspec)
7259 * is(targ id : tspec)
7260 * is(targ id == tspec, tpl)
7261 * is(targ id : tspec, tpl)
7263 Identifier tid
= e
.id ? e
.id
: Identifier
.generateId("__isexp_id");
7264 e
.parameters
.insert(0, new TemplateTypeParameter(e
.loc
, tid
, null, null));
7266 Objects dedtypes
= Objects(e
.parameters
.length
);
7269 MATCH m
= deduceType(e
.targ
, sc
, e
.tspec
, e
.parameters
, &dedtypes
, null, 0, e
.tok
== TOK
.equal
);
7271 if (m
== MATCH
.nomatch ||
(m
!= MATCH
.exact
&& e
.tok
== TOK
.equal
))
7277 tded
= cast(Type
)dedtypes
[0];
7280 Objects tiargs
= Objects(1);
7283 /* Declare trailing parameters
7285 for (size_t i
= 1; i
< e
.parameters
.length
; i
++)
7287 TemplateParameter tp
= (*e
.parameters
)[i
];
7288 Declaration s
= null;
7290 m
= tp
.matchArg(e
.loc
, sc
, &tiargs
, i
, e
.parameters
, &dedtypes
, &s
);
7291 if (m
== MATCH
.nomatch
)
7293 s
.dsymbolSemantic(sc
);
7296 auto conflict
= sc
.search(Loc
.initial
, s
.ident
, null);
7297 error(e
.loc
, "declaration `%s` is already defined", s
.toPrettyChars());
7298 errorSupplemental(conflict
.loc
, "`%s` `%s` is defined here",
7299 conflict
.kind(), conflict
.toChars());
7302 unSpeculative(sc
, s
);
7309 /* Declare id as an alias for type targ. Evaluate to true
7317 override void visit(BinAssignExp exp
)
7325 Expression e
= exp
.op_overload(sc
);
7332 if (exp
.e1
.op
== EXP
.arrayLength
)
7334 // arr.length op= e2;
7335 e
= rewriteOpAssign(exp
);
7336 e
= e
.expressionSemantic(sc
);
7340 if (exp
.e1
.op
== EXP
.slice || exp
.e1
.type
.ty
== Tarray || exp
.e1
.type
.ty
== Tsarray
)
7342 if (checkNonAssignmentArrayOp(exp
.e1
))
7345 if (exp
.e1
.op
== EXP
.slice
)
7346 (cast(SliceExp
)exp
.e1
).arrayop
= true;
7349 if (exp
.e2
.implicitConvTo(exp
.e1
.type
.nextOf()))
7352 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
.nextOf());
7354 else if (Expression ex
= typeCombine(exp
, sc
))
7359 exp
.type
= exp
.e1
.type
;
7360 result
= arrayOp(exp
, sc
);
7364 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
7365 exp
.e1
= exp
.e1
.modifiableLvalue(sc
);
7366 exp
.e1
= exp
.e1
.optimize(WANTvalue
, /*keepLvalue*/ true);
7367 exp
.type
= exp
.e1
.type
;
7369 if (auto ad
= isAggregate(exp
.e1
.type
))
7371 if (const s
= search_function(ad
, Id
.opOpAssign
))
7373 error(exp
.loc
, "none of the `opOpAssign` overloads of `%s` are callable for `%s` of type `%s`", ad
.toChars(), exp
.e1
.toChars(), exp
.e1
.type
.toChars());
7377 if (exp
.e1
.checkScalar() ||
7378 exp
.e1
.checkReadModifyWrite(exp
.op
, exp
.e2
) ||
7379 exp
.e1
.checkSharedAccess(sc
))
7382 int arith
= (exp
.op
== EXP
.addAssign || exp
.op
== EXP
.minAssign || exp
.op
== EXP
.mulAssign || exp
.op
== EXP
.divAssign || exp
.op
== EXP
.modAssign || exp
.op
== EXP
.powAssign
);
7383 int bitwise
= (exp
.op
== EXP
.andAssign || exp
.op
== EXP
.orAssign || exp
.op
== EXP
.xorAssign
);
7384 int shift
= (exp
.op
== EXP
.leftShiftAssign || exp
.op
== EXP
.rightShiftAssign || exp
.op
== EXP
.unsignedRightShiftAssign
);
7386 if (bitwise
&& exp
.type
.toBasetype().ty
== Tbool
)
7387 exp
.e2
= exp
.e2
.implicitCastTo(sc
, exp
.type
);
7388 else if (exp
.checkNoBool())
7391 if ((exp
.op
== EXP
.addAssign || exp
.op
== EXP
.minAssign
) && exp
.e1
.type
.toBasetype().ty
== Tpointer
&& exp
.e2
.type
.toBasetype().isintegral())
7393 result
= scaleFactor(exp
, sc
);
7397 if (Expression ex
= typeCombine(exp
, sc
))
7403 if (arith
&& (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
)))
7405 if ((bitwise || shift
) && (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
)))
7410 if (exp
.e2
.type
.toBasetype().ty
!= Tvector
)
7411 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tshiftcnt
);
7414 if (!target
.isVectorOpSupported(exp
.type
.toBasetype(), exp
.op
, exp
.e2
.type
.toBasetype()))
7416 result
= exp
.incompatibleTypes();
7420 if (exp
.e1
.op
== EXP
.error || exp
.e2
.op
== EXP
.error
)
7423 e
= exp
.checkOpAssignTypes(sc
);
7424 if (e
.op
== EXP
.error
)
7430 assert(e
.op
== EXP
.assign || e
== exp
);
7431 result
= (cast(BinExp
)e
).reorderSettingAAElem(sc
);
7434 private Expression
compileIt(MixinExp exp
)
7437 if (expressionsToString(buf
, sc
, exp
.exps
))
7440 uint errors
= global
.errors
;
7441 const len
= buf
.length
;
7442 const str = buf
.extractChars()[0 .. len
];
7443 const bool doUnittests
= global
.params
.parsingUnittestsRequired();
7444 auto loc
= adjustLocForMixin(str, exp
.loc
, global
.params
.mixinOut
);
7445 scope p
= new Parser
!ASTCodegen(loc
, sc
._module
, str, false, global
.errorSink
, &global
.compileEnv
, doUnittests
);
7446 p
.transitionIn
= global
.params
.v
.vin
;
7448 //printf("p.loc.linnum = %d\n", p.loc.linnum);
7450 Expression e
= p
.parseExpression();
7451 if (global
.errors
!= errors
)
7454 if (p
.token
.value
!= TOK
.endOfFile
)
7456 error(e
.loc
, "unexpected token `%s` after %s expression",
7457 p
.token
.toChars(), EXPtoString(e
.op
).ptr
);
7458 errorSupplemental(e
.loc
, "while parsing string mixin expression `%s`",
7465 override void visit(MixinExp exp
)
7467 /* https://dlang.org/spec/expression.html#mixin_expressions
7470 static if (LOGSEMANTIC
)
7472 printf("MixinExp::semantic('%s')\n", exp
.toChars());
7475 auto e
= compileIt(exp
);
7478 result
= e
.expressionSemantic(sc
);
7481 override void visit(ImportExp e
)
7483 static if (LOGSEMANTIC
)
7485 printf("ImportExp::semantic('%s')\n", e
.toChars());
7488 auto se
= semanticString(sc
, e
.e1
, "file name argument");
7493 auto namez
= se
.toStringz();
7494 if (!global
.filePath
)
7496 error(e
.loc
, "need `-J` switch to import text file `%s`", namez
.ptr
);
7500 /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
7501 * ('Path Traversal') attacks.
7502 * https://cwe.mitre.org/data/definitions/22.html
7505 if (FileName
.absolute(namez
))
7507 error(e
.loc
, "absolute path is not allowed in import expression: `%s`", se
.toChars());
7511 auto idxReserved
= FileName
.findReservedChar(namez
);
7512 if (idxReserved
!= size_t
.max
)
7514 error(e
.loc
, "`%s` is not a valid filename on this platform", se
.toChars());
7515 errorSupplemental(e
.loc
, "Character `'%c'` is reserved and cannot be used", namez
[idxReserved
]);
7519 if (FileName
.refersToParentDir(namez
))
7521 error(e
.loc
, "path refers to parent (`..`) directory: `%s`", se
.toChars());
7525 auto resolvedNamez
= FileName
.searchPath(global
.filePath
, namez
, false);
7528 error(e
.loc
, "file `%s` cannot be found or not in a path specified with `-J`", se
.toChars());
7529 errorSupplemental(e
.loc
, "Path(s) searched (as provided by `-J`):");
7530 foreach (idx
, path
; *global
.filePath
)
7532 const attr
= FileName
.exists(path
);
7533 const(char)* err
= attr
== 2 ?
"" :
7534 (attr
== 1 ?
" (not a directory)" : " (path not found)");
7535 errorSupplemental(e
.loc
, "[%llu]: `%s`%s", cast(ulong)idx
, path
, err
);
7540 sc
._module
.contentImportedFiles
.push(resolvedNamez
.ptr
);
7541 if (global
.params
.v
.verbose
)
7543 const slice
= se
.peekString();
7544 message("file %.*s\t(%s)", cast(int)slice
.length
, slice
.ptr
, resolvedNamez
.ptr
);
7546 if (global
.params
.moduleDeps
.buffer
!is null)
7548 OutBuffer
* ob
= global
.params
.moduleDeps
.buffer
;
7549 Module imod
= sc
._module
;
7551 if (!global
.params
.moduleDeps
.name
)
7552 ob
.writestring("depsFile ");
7553 ob
.writestring(imod
.toPrettyChars());
7554 ob
.writestring(" (");
7555 escapePath(ob
, imod
.srcfile
.toChars());
7556 ob
.writestring(") : ");
7557 if (global
.params
.moduleDeps
.name
)
7558 ob
.writestring("string : ");
7559 ob
.write(se
.peekString());
7560 ob
.writestring(" (");
7561 escapePath(ob
, resolvedNamez
.ptr
);
7562 ob
.writestring(")");
7565 if (global
.params
.makeDeps
.doOutput
)
7567 global
.params
.makeDeps
.files
.push(resolvedNamez
.ptr
);
7571 auto fileName
= FileName(resolvedNamez
);
7572 if (auto fmResult
= global
.fileManager
.lookup(fileName
))
7574 se
= new StringExp(e
.loc
, fmResult
);
7578 error(e
.loc
, "cannot read file `%s`", resolvedNamez
.ptr
);
7582 result
= se
.expressionSemantic(sc
);
7585 override void visit(AssertExp exp
)
7587 // https://dlang.org/spec/expression.html#assert_expressions
7588 static if (LOGSEMANTIC
)
7590 printf("AssertExp::semantic('%s')\n", exp
.toChars());
7593 const generateMsg
= !exp
.msg
&&
7594 sc
.needsCodegen() && // let ctfe interpreter handle the error message
7595 global
.params
.checkAction
== CHECKACTION
.context
&&
7596 global
.params
.useAssert
== CHECKENABLE
.on
&&
7597 !((exp
.e1
.isIntegerExp() && (exp
.e1
.toInteger() == 0)) ||
7598 exp
.e1
.isNullExp());
7599 Expression temporariesPrefix
;
7602 // no message - use assert expression as msg
7604 if (!verifyHookExist(exp
.loc
, *sc
, Id
._d_assert_fail
, "generating assert messages"))
7609 auto a = e1, b = e2;
7610 assert(a == b, _d_assert_fail!"=="(a, b));
7615 Stores the result of an operand expression into a temporary
7616 if necessary, e.g. if it is an impure fuction call containing side
7617 effects as in https://issues.dlang.org/show_bug.cgi?id=20114
7620 op = an expression which may require a temporary (added to
7621 `temporariesPrefix`: `auto tmp = op`) and will be replaced
7622 by `tmp` if necessary
7624 Returns: (possibly replaced) `op`
7626 Expression
maybePromoteToTmp(ref Expression op
)
7628 // https://issues.dlang.org/show_bug.cgi?id=20989
7629 // Flag that _d_assert_fail will never dereference `array.ptr` to avoid safety
7630 // errors for `assert(!array.ptr)` => `_d_assert_fail!"!"(array.ptr)`
7632 auto die
= op
.isDotIdExp();
7633 if (die
&& die
.ident
== Id
.ptr
)
7637 op
= op
.expressionSemantic(sc
);
7638 op
= resolveProperties(sc
, op
);
7640 // Detect assert's using static operator overloads (e.g. `"var" in environment`)
7641 if (auto te
= op
.isTypeExp())
7643 // Replace the TypeExp with it's textual representation
7644 // Including "..." in the error message isn't quite right but
7645 // proper solutions require more drastic changes, e.g. directly
7646 // using miniFormat and combine instead of calling _d_assert_fail
7647 auto name
= new StringExp(te
.loc
, te
.toString());
7648 return name
.expressionSemantic(sc
);
7651 // Create a temporary for expressions with side effects
7652 // Defensively assume that function calls may have side effects even
7653 // though it's not detected by hasSideEffect (e.g. `debug puts("Hello")` )
7654 // Rewriting CallExp's also avoids some issues with the inliner/debug generation
7655 if (op
.hasSideEffect(true))
7657 // Don't create an invalid temporary for void-expressions
7658 // Further semantic will issue an appropriate error
7659 if (op
.type
.ty
== Tvoid
)
7662 // https://issues.dlang.org/show_bug.cgi?id=21590
7663 // Don't create unnecessary temporaries and detect `assert(a = b)`
7664 if (op
.isAssignExp() || op
.isBinAssignExp())
7666 auto left
= (cast(BinExp
) op
).e1
;
7668 // Find leftmost expression to handle other rewrites,
7669 // e.g. --(++a) => a += 1 -= 1
7670 while (left
.isAssignExp() || left
.isBinAssignExp())
7671 left
= (cast(BinExp
) left
).e1
;
7673 // Only use the assignee if it's a variable and skip
7674 // other lvalues (e.g. ref's returned by functions)
7675 if (left
.isVarExp())
7678 // Sanity check that `op` can be converted to boolean
7679 // But don't raise errors for assignments enclosed in another expression
7684 // Tuples with side-effects already receive a temporary during semantic
7685 if (op
.type
.isTypeTuple())
7687 auto te
= op
.isTupleExp();
7690 // Create a new tuple without the associated temporary
7691 auto res
= new TupleExp(op
.loc
, te
.exps
);
7692 return res
.expressionSemantic(sc
);
7695 const stc = op
.isLvalue() ? STC
.ref_
: 0;
7696 auto tmp
= copyToTemp(stc, "__assertOp", op
);
7697 tmp
.dsymbolSemantic(sc
);
7699 auto decl
= new DeclarationExp(op
.loc
, tmp
);
7700 temporariesPrefix
= Expression
.combine(temporariesPrefix
, decl
);
7702 op
= new VarExp(op
.loc
, tmp
);
7703 op
= op
.expressionSemantic(sc
);
7708 // if the assert condition is a mixin expression, try to compile it
7709 if (auto ce
= exp
.e1
.isMixinExp())
7711 if (auto e1
= compileIt(ce
))
7717 Loc loc
= exp
.e1
.loc
;
7719 const op
= exp
.e1
.op
;
7720 bool isEqualsCallExpression
;
7721 if (const callExp
= exp
.e1
.isCallExp())
7723 // https://issues.dlang.org/show_bug.cgi?id=20331
7724 // callExp.f may be null if the assert contains a call to
7725 // a function pointer or literal
7726 if (const callExpFunc
= callExp
.f
)
7728 const callExpIdent
= callExpFunc
.ident
;
7729 isEqualsCallExpression
= callExpIdent
== Id
.__equals ||
7730 callExpIdent
== Id
.eq
;
7733 if (op
== EXP
.equal || op
== EXP
.notEqual ||
7734 op
== EXP
.lessThan || op
== EXP
.greaterThan ||
7735 op
== EXP
.lessOrEqual || op
== EXP
.greaterOrEqual ||
7736 op
== EXP
.identity || op
== EXP
.notIdentity ||
7738 isEqualsCallExpression
)
7740 es
= new Expressions(3);
7741 tiargs
= new Objects(1);
7743 if (isEqualsCallExpression
)
7745 auto callExp
= cast(CallExp
) exp
.e1
;
7746 auto args
= callExp
.arguments
;
7748 // structs with opEquals get rewritten to a DotVarExp:
7750 // https://issues.dlang.org/show_bug.cgi?id=20100
7751 if (args
.length
== 1)
7753 auto dv
= callExp
.e1
.isDotVarExp();
7757 (*es
)[1] = maybePromoteToTmp(dv
.e1
);
7758 (*es
)[2] = maybePromoteToTmp((*args
)[0]);
7763 (*es
)[1] = maybePromoteToTmp((*args
)[0]);
7764 (*es
)[2] = maybePromoteToTmp((*args
)[1]);
7769 auto binExp
= cast(EqualExp
) exp
.e1
;
7772 (*es
)[1] = maybePromoteToTmp(binExp
.e1
);
7773 (*es
)[2] = maybePromoteToTmp(binExp
.e2
);
7777 Expression comp
= new StringExp(loc
, isEqualsCallExpression ?
"==" : EXPtoString(exp
.e1
.op
));
7778 comp
= comp
.expressionSemantic(sc
);
7780 (*tiargs
)[0] = (*es
)[1].type
;
7783 // Format exp.e1 before any additional boolean conversion
7784 // Ignore &&/|| because "assert(...) failed" is more informative than "false != true"
7785 else if (op
!= EXP
.andAnd
&& op
!= EXP
.orOr
)
7787 es
= new Expressions(2);
7788 tiargs
= new Objects(1);
7790 if (auto ne
= exp
.e1
.isNotExp())
7792 // Fetch the (potential non-bool) expression and fold
7793 // (n) negations into (n % 2) negations, e.g. !!a => a
7794 for (bool neg = true; ; neg = !neg)
7796 if (auto ne2
= ne
.e1
.isNotExp())
7800 (*es
)[0] = new StringExp(loc
, neg ?
"!" : "");
7801 (*es
)[1] = maybePromoteToTmp(ne
.e1
);
7807 { // Simply format exp.e1
7808 (*es
)[0] = new StringExp(loc
, "");
7809 (*es
)[1] = maybePromoteToTmp(exp
.e1
);
7812 (*tiargs
)[0] = (*es
)[1].type
;
7814 // Passing __ctfe to auto ref infers ref and aborts compilation:
7815 // "cannot modify compiler-generated variable __ctfe"
7816 auto ve
= (*es
)[1].isVarExp();
7817 if (ve
&& ve
.var
.ident
== Id
.ctfe
)
7819 exp
.msg
= new StringExp(loc
, "assert(__ctfe) failed!");
7826 buf
.printf("`%s` failed", exp
.toChars());
7827 exp
.msg
= new StringExp(Loc
.initial
, buf
.extractSlice());
7831 Expression __assertFail
= new IdentifierExp(exp
.loc
, Id
.empty
);
7832 auto assertFail
= new DotIdExp(loc
, __assertFail
, Id
.object
);
7834 auto dt = new DotTemplateInstanceExp(loc
, assertFail
, Id
._d_assert_fail
, tiargs
);
7835 auto ec
= CallExp
.create(loc
, dt, es
);
7840 if (Expression ex
= unaSemantic(exp
, sc
))
7846 exp
.e1
= resolveProperties(sc
, exp
.e1
);
7847 // BUG: see if we can do compile time elimination of the Assert
7848 exp
.e1
= exp
.e1
.optimize(WANTvalue
);
7849 exp
.e1
= exp
.e1
.toBoolean(sc
);
7851 if (exp
.e1
.op
== EXP
.error
)
7859 exp
.msg
= expressionSemantic(exp
.msg
, sc
);
7860 exp
.msg
= resolveProperties(sc
, exp
.msg
);
7861 exp
.msg
= exp
.msg
.implicitCastTo(sc
, Type
.tchar
.constOf().arrayOf());
7862 exp
.msg
= exp
.msg
.optimize(WANTvalue
);
7863 checkParamArgumentEscape(sc
, null, null, null, STC
.undefined_
, exp
.msg
, true, false);
7866 if (exp
.msg
&& exp
.msg
.op
== EXP
.error
)
7872 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
7873 auto f2
= exp
.msg
&& checkNonAssignmentArrayOp(exp
.msg
);
7877 if (exp
.e1
.toBool().hasValue(false))
7879 /* This is an `assert(0)` which means halt program execution
7881 FuncDeclaration fd
= sc
.parent
.isFuncDeclaration();
7883 fd
.hasReturnExp |
= 4;
7884 sc
.ctorflow
.orCSX(CSX
.halt
);
7886 if (global
.params
.useAssert
== CHECKENABLE
.off
)
7888 Expression e
= new HaltExp(exp
.loc
);
7889 e
= e
.expressionSemantic(sc
);
7894 // Only override the type when it isn't already some flavour of noreturn,
7895 // e.g. when this assert was generated by defaultInitLiteral
7896 if (!exp
.type ||
!exp
.type
.isTypeNoreturn())
7897 exp
.type
= Type
.tnoreturn
;
7900 exp
.type
= Type
.tvoid
;
7902 result
= !temporariesPrefix
7904 : Expression
.combine(temporariesPrefix
, exp
).expressionSemantic(sc
);
7907 override void visit(ThrowExp te
)
7909 import dmd
.statementsem
;
7911 if (throwSemantic(te
.loc
, te
.e1
, sc
))
7917 override void visit(DotIdExp exp
)
7919 static if (LOGSEMANTIC
)
7921 printf("DotIdExp::semantic(this = %p, '%s')\n", exp
, exp
.toChars());
7922 //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op));
7925 if (sc
.flags
& SCOPE
.Cfile
)
7927 /* See if need to rewrite the AST because of cast/call ambiguity
7929 if (auto e
= castCallAmbiguity(exp
, sc
))
7931 result
= expressionSemantic(e
, sc
);
7935 if (exp
.arrow
) // ImportC only
7936 exp
.e1
= exp
.e1
.expressionSemantic(sc
).arrayFuncConv(sc
);
7938 if (exp
.ident
== Id
.__xalignof
&& exp
.e1
.isTypeExp())
7940 // C11 6.5.3 says _Alignof only applies to types
7944 dmd
.typesem
.resolve(exp
.e1
.type
, exp
.e1
.loc
, sc
, e
, t
, s
, true);
7947 error(exp
.e1
.loc
, "argument to `_Alignof` must be a type");
7952 // Note similarity to getProperty() implementation of __xalignof
7953 const explicitAlignment
= t
.alignment();
7954 const naturalAlignment
= t
.alignsize();
7955 const actualAlignment
= (explicitAlignment
.isDefault() ? naturalAlignment
: explicitAlignment
.get());
7956 result
= new IntegerExp(exp
.loc
, actualAlignment
, Type
.tsize_t
);
7960 error(exp
.e1
.loc
, "argument to `_Alignof` must be a type");
7968 if (exp
.ident
!= Id
.__sizeof
)
7970 result
= fieldLookup(exp
.e1
, sc
, exp
.ident
, exp
.arrow
);
7975 Expression e
= exp
.dotIdSemanticProp(sc
, 1);
7977 if (e
&& isDotOpDispatch(e
))
7980 uint errors
= global
.startGagging();
7981 e
= resolvePropertiesX(sc
, e
);
7982 // Any error or if 'e' is not resolved, go to UFCS
7983 if (global
.endGagging(errors
) || e
is ode
)
7984 e
= null; /* fall down to UFCS */
7991 if (!e
) // if failed to find the property
7993 /* If ident is not a valid property, rewrite:
7998 e
= resolveUFCSProperties(sc
, exp
);
8003 override void visit(DotTemplateExp e
)
8010 if (Expression ex
= unaSemantic(e
, sc
))
8015 // 'void' like TemplateExp
8016 e
.type
= Type
.tvoid
;
8020 override void visit(DotVarExp exp
)
8022 static if (LOGSEMANTIC
)
8024 printf("DotVarExp::semantic('%s')\n", exp
.toChars());
8032 exp
.var
= exp
.var
.toAlias().isDeclaration();
8034 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
8036 if (auto tup
= exp
.var
.isTupleDeclaration())
8041 * tuple(e1.a, e1.b, e1.c)
8044 Expression ev
= sc
.func ?
extractSideEffect(sc
, "__tup", e0
, exp
.e1
) : exp
.e1
;
8046 auto exps
= new Expressions();
8047 exps
.reserve(tup
.objects
.length
);
8048 for (size_t i
= 0; i
< tup
.objects
.length
; i
++)
8050 RootObject o
= (*tup
.objects
)[i
];
8053 switch (o
.dyncast()) with (DYNCAST
)
8056 e
= cast(Expression
)o
;
8057 if (auto se
= e
.isDsymbolExp())
8058 var
= se
.s
.isDeclaration();
8059 else if (auto ve
= e
.isVarExp())
8060 if (!ve
.var
.isFuncDeclaration())
8061 // Exempt functions for backwards compatibility reasons.
8062 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
8066 Dsymbol s
= cast(Dsymbol
) o
;
8067 Declaration d
= s
.isDeclaration();
8068 if (!d || d
.isFuncDeclaration())
8069 // Exempt functions for backwards compatibility reasons.
8070 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
8071 e
= new DsymbolExp(exp
.loc
, s
);
8076 e
= new TypeExp(exp
.loc
, cast(Type
)o
);
8079 error(exp
.loc
, "`%s` is not an expression", o
.toChars());
8083 e
= new DotVarExp(exp
.loc
, ev
, var
);
8087 Expression e
= new TupleExp(exp
.loc
, e0
, exps
);
8088 e
= e
.expressionSemantic(sc
);
8092 else if (auto ad
= exp
.var
.isAliasDeclaration())
8094 if (auto t
= ad
.getType())
8096 result
= new TypeExp(exp
.loc
, t
).expressionSemantic(sc
);
8101 exp
.e1
= exp
.e1
.addDtorHook(sc
);
8103 Type t1
= exp
.e1
.type
;
8105 if (FuncDeclaration fd
= exp
.var
.isFuncDeclaration())
8107 // for functions, do checks after overload resolution
8108 if (!fd
.functionSemantic())
8111 /* https://issues.dlang.org/show_bug.cgi?id=13843
8112 * If fd obviously has no overloads, we should
8113 * normalize AST, and it will give a chance to wrap fd with FuncExp.
8115 if ((fd
.isNested() && !fd
.isThis()) || fd
.isFuncLiteralDeclaration())
8118 auto e
= symbolToExp(fd
, exp
.loc
, sc
, false);
8119 result
= Expression
.combine(exp
.e1
, e
);
8126 else if (OverDeclaration od
= exp
.var
.isOverDeclaration())
8128 exp
.type
= Type
.tvoid
; // ambiguous type?
8132 exp
.type
= exp
.var
.type
;
8133 if (!exp
.type
&& global
.errors
) // var is goofed up, just return error.
8137 if (t1
.ty
== Tpointer
)
8140 exp
.type
= exp
.type
.addMod(t1
.mod
);
8142 // https://issues.dlang.org/show_bug.cgi?id=23109
8143 // Run semantic on the DotVarExp type
8144 if (auto handle
= exp
.type
.isClassHandle())
8146 if (handle
.semanticRun
< PASS
.semanticdone
&& !handle
.isBaseInfoComplete())
8147 handle
.dsymbolSemantic(null);
8150 Dsymbol vparent
= exp
.var
.toParent();
8151 AggregateDeclaration ad
= vparent ? vparent
.isAggregateDeclaration() : null;
8152 if (Expression e1x
= getRightThis(exp
.loc
, sc
, ad
, exp
.e1
, exp
.var
, 1))
8156 /* Later checkRightThis will report correct error for invalid field variable access.
8158 Expression e
= new VarExp(exp
.loc
, exp
.var
);
8159 e
= e
.expressionSemantic(sc
);
8163 checkAccess(exp
.loc
, sc
, exp
.e1
, exp
.var
);
8165 VarDeclaration v
= exp
.var
.isVarDeclaration();
8166 if (v
&& (v
.isDataseg() ||
(v
.storage_class
& STC
.manifest
)))
8168 Expression e
= expandVar(WANTvalue
, v
);
8176 if (v
&& (v
.isDataseg() ||
// fix https://issues.dlang.org/show_bug.cgi?id=8238
8177 (!v
.needThis() && v
.semanticRun
> PASS
.initial
))) // fix https://issues.dlang.org/show_bug.cgi?id=17258
8180 checkAccess(exp
.loc
, sc
, exp
.e1
, v
);
8181 Expression e
= new VarExp(exp
.loc
, v
);
8182 e
= new CommaExp(exp
.loc
, exp
.e1
, e
);
8183 e
= e
.expressionSemantic(sc
);
8188 //printf("-DotVarExp::semantic('%s')\n", toChars());
8192 override void visit(DotTemplateInstanceExp exp
)
8194 static if (LOGSEMANTIC
)
8196 printf("DotTemplateInstanceExp::semantic('%s')\n", exp
.toChars());
8203 // Indicate we need to resolve by UFCS.
8204 Expression e
= exp
.dotTemplateSemanticProp(sc
, DotExpFlag
.gag
);
8206 e
= resolveUFCSProperties(sc
, exp
);
8208 e
.type
= Type
.tvoid
; // Unresolved type, because it needs inference
8212 override void visit(DelegateExp e
)
8214 static if (LOGSEMANTIC
)
8216 printf("DelegateExp::semantic('%s')\n", e
.toChars());
8224 e
.e1
= e
.e1
.expressionSemantic(sc
);
8226 e
.type
= new TypeDelegate(e
.func
.type
.isTypeFunction());
8227 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
8229 FuncDeclaration f
= e
.func
.toAliasFunc();
8230 AggregateDeclaration ad
= f
.isMemberLocal();
8232 e
.e1
= getRightThis(e
.loc
, sc
, ad
, e
.e1
, f
);
8234 if (f
.type
.ty
== Tfunction
)
8236 TypeFunction tf
= cast(TypeFunction
)f
.type
;
8237 if (!MODmethodConv(e
.e1
.type
.mod
, f
.type
.mod
))
8239 OutBuffer thisBuf
, funcBuf
;
8240 MODMatchToBuffer(&thisBuf
, e
.e1
.type
.mod
, tf
.mod
);
8241 MODMatchToBuffer(&funcBuf
, tf
.mod
, e
.e1
.type
.mod
);
8242 error(e
.loc
, "%smethod `%s` is not callable using a %s`%s`",
8243 funcBuf
.peekChars(), f
.toPrettyChars(), thisBuf
.peekChars(), e
.e1
.toChars());
8247 if (ad
&& ad
.isClassDeclaration() && ad
.type
!= e
.e1
.type
)
8249 // A downcast is required for interfaces
8250 // https://issues.dlang.org/show_bug.cgi?id=3706
8251 e
.e1
= new CastExp(e
.loc
, e
.e1
, ad
.type
);
8252 e
.e1
= e
.e1
.expressionSemantic(sc
);
8255 // declare dual-context container
8256 if (f
.hasDualContext() && !sc
.intypeof
&& sc
.func
)
8258 // check access to second `this`
8259 if (AggregateDeclaration ad2
= f
.isMember2())
8261 Expression te
= new ThisExp(e
.loc
).expressionSemantic(sc
);
8262 if (te
.op
!= EXP
.error
)
8263 te
= getRightThis(e
.loc
, sc
, ad2
, te
, f
);
8264 if (te
.op
== EXP
.error
)
8266 error(e
.loc
, "need `this` of type `%s` to make delegate from function `%s`", ad2
.toChars(), f
.toChars());
8270 VarDeclaration vthis2
= makeThis2Argument(e
.loc
, sc
, f
);
8272 Expression
de = new DeclarationExp(e
.loc
, vthis2
);
8273 result
= Expression
.combine(de, result
);
8274 result
= result
.expressionSemantic(sc
);
8278 override void visit(DotTypeExp exp
)
8280 static if (LOGSEMANTIC
)
8282 printf("DotTypeExp::semantic('%s')\n", exp
.toChars());
8290 if (auto e
= unaSemantic(exp
, sc
))
8296 exp
.type
= exp
.sym
.getType().addMod(exp
.e1
.type
.mod
);
8300 override void visit(AddrExp exp
)
8302 static if (LOGSEMANTIC
)
8304 printf("AddrExp::semantic('%s')\n", exp
.toChars());
8312 if (Expression ex
= unaSemantic(exp
, sc
))
8318 if (sc
.flags
& SCOPE
.Cfile
)
8320 /* Special handling for &"string"/&(T[]){0, 1}
8321 * since C regards string/array literals as lvalues
8324 if(e
.isStringExp() || e
.isArrayLiteralExp())
8326 e
.type
= typeSemantic(e
.type
, Loc
.initial
, sc
);
8327 // if type is already a pointer exp is an illegal expression of the form `&(&"")`
8328 if (!e
.type
.isTypePointer())
8330 e
.type
= e
.type
.pointerTo();
8336 // `toLvalue` call further below is upon exp.e1, omitting & from the error message
8337 exp
.toLvalue(sc
, "take address of");
8343 int wasCond
= exp
.e1
.op
== EXP
.question
;
8345 if (exp
.e1
.op
== EXP
.dotTemplateInstance
)
8347 DotTemplateInstanceExp dti
= cast(DotTemplateInstanceExp
)exp
.e1
;
8348 TemplateInstance ti
= dti
.ti
;
8350 //assert(ti.needsTypeInference(sc));
8351 ti
.dsymbolSemantic(sc
);
8352 if (!ti
.inst || ti
.errors
) // if template failed to expand
8355 Dsymbol s
= ti
.toAlias();
8356 FuncDeclaration f
= s
.isFuncDeclaration();
8359 exp
.e1
= new DotVarExp(exp
.e1
.loc
, dti
.e1
, f
);
8360 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
8364 else if (exp
.e1
.op
== EXP
.scope_
)
8366 TemplateInstance ti
= (cast(ScopeExp
)exp
.e1
).sds
.isTemplateInstance();
8369 //assert(ti.needsTypeInference(sc));
8370 ti
.dsymbolSemantic(sc
);
8371 if (!ti
.inst || ti
.errors
) // if template failed to expand
8374 Dsymbol s
= ti
.toAlias();
8375 FuncDeclaration f
= s
.isFuncDeclaration();
8378 exp
.e1
= new VarExp(exp
.e1
.loc
, f
);
8379 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
8383 /* https://issues.dlang.org/show_bug.cgi?id=809
8385 * If the address of a lazy variable is taken,
8386 * the expression is rewritten so that the type
8387 * of it is the delegate type. This means that
8388 * the symbol is not going to represent a call
8389 * to the delegate anymore, but rather, the
8392 if (auto ve
= exp
.e1
.isVarExp())
8394 if (ve
.var
.storage_class
& STC
.lazy_
)
8396 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
8397 exp
.e1
= resolveProperties(sc
, exp
.e1
);
8398 if (auto callExp
= exp
.e1
.isCallExp())
8400 if (callExp
.e1
.type
.toBasetype().ty
== Tdelegate
)
8402 /* https://issues.dlang.org/show_bug.cgi?id=20551
8404 * Cannot take address of lazy parameter in @safe code
8405 * because it might end up being a pointer to undefined
8410 if (sc
.setUnsafe(false, exp
.loc
,
8411 "cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve
, sc
.func
))
8417 VarExp ve2
= callExp
.e1
.isVarExp();
8418 ve2
.delegateWasExtracted
= true;
8419 ve2
.var
.storage_class |
= STC
.scope_
;
8427 exp
.e1
= exp
.e1
.toLvalue(sc
, "take address of");
8428 if (exp
.e1
.op
== EXP
.error
)
8433 if (checkNonAssignmentArrayOp(exp
.e1
))
8438 error(exp
.loc
, "cannot take address of `%s`", exp
.e1
.toChars());
8441 if (!checkAddressable(exp
, sc
))
8445 if (auto f
= isFuncAddress(exp
, &hasOverloads
))
8447 if (!hasOverloads
&& f
.checkForwardRef(exp
.loc
))
8450 else if (!exp
.e1
.type
.deco
)
8452 // try to resolve the type
8453 exp
.e1
.type
= exp
.e1
.type
.typeSemantic(exp
.e1
.loc
, sc
);
8454 if (!exp
.e1
.type
.deco
) // still couldn't resolve it
8456 if (auto ve
= exp
.e1
.isVarExp())
8458 Declaration d
= ve
.var
;
8459 error(exp
.loc
, "forward reference to %s `%s`", d
.kind(), d
.toChars());
8462 error(exp
.loc
, "forward reference to type `%s` of expression `%s`", exp
.e1
.type
.toChars(), exp
.e1
.toChars());
8467 exp
.type
= exp
.e1
.type
.pointerTo();
8469 // See if this should really be a delegate
8470 if (exp
.e1
.op
== EXP
.dotVariable
)
8472 DotVarExp dve
= cast(DotVarExp
)exp
.e1
;
8473 FuncDeclaration f
= dve
.var
.isFuncDeclaration();
8476 f
= f
.toAliasFunc(); // FIXME, should see overloads
8477 // https://issues.dlang.org/show_bug.cgi?id=1983
8478 if (!dve
.hasOverloads
)
8483 e
= new DelegateExp(exp
.loc
, dve
.e1
, f
, dve
.hasOverloads
);
8484 else // It is a function pointer. Convert &v.f() --> (v, &V.f())
8485 e
= new CommaExp(exp
.loc
, dve
.e1
, new AddrExp(exp
.loc
, new VarExp(exp
.loc
, f
, dve
.hasOverloads
)));
8486 e
= e
.expressionSemantic(sc
);
8491 // Look for misaligned pointer in @safe mode
8492 if (checkUnsafeAccess(sc
, dve
, !exp
.type
.isMutable(), true))
8495 else if (exp
.e1
.op
== EXP
.variable
)
8497 VarExp ve
= cast(VarExp
)exp
.e1
;
8498 VarDeclaration v
= ve
.var
.isVarDeclaration();
8501 if (!checkAddressVar(sc
, exp
.e1
, v
))
8504 v
.checkPurity(ve
.loc
, sc
);
8506 FuncDeclaration f
= ve
.var
.isFuncDeclaration();
8509 /* Because nested functions cannot be overloaded,
8510 * mark here that we took its address because castTo()
8511 * may not be called with an exact match.
8513 * https://issues.dlang.org/show_bug.cgi?id=19285 :
8514 * We also need to make sure we aren't inside a typeof. Ideally the compiler
8515 * would do typeof(...) semantic analysis speculatively then collect information
8516 * about what it used rather than relying on what are effectively semantically-global
8517 * variables but it doesn't.
8519 if (!sc
.isFromSpeculativeSemanticContext() && (!ve
.hasOverloads ||
(f
.isNested() && !f
.needThis())))
8521 // TODO: Refactor to use a proper interface that can keep track of causes.
8525 if (f
.isNested() && !f
.needThis())
8527 if (f
.isFuncLiteralDeclaration())
8529 if (!f
.FuncDeclaration
.isNested())
8531 /* Supply a 'null' for a this pointer if no this is available
8533 Expression e
= new DelegateExp(exp
.loc
, new NullExp(exp
.loc
, Type
.tnull
), f
, ve
.hasOverloads
);
8534 e
= e
.expressionSemantic(sc
);
8539 Expression e
= new DelegateExp(exp
.loc
, exp
.e1
, f
, ve
.hasOverloads
);
8540 e
= e
.expressionSemantic(sc
);
8546 auto memberFunc
= hasThis(sc
);
8547 if (memberFunc
&& haveSameThis(memberFunc
, f
))
8549 /* Should probably supply 'this' after overload resolution,
8552 Expression ethis
= new ThisExp(exp
.loc
);
8553 Expression e
= new DelegateExp(exp
.loc
, ethis
, f
, ve
.hasOverloads
);
8554 e
= e
.expressionSemantic(sc
);
8558 if (sc
.func
&& !sc
.intypeof
&& !(sc
.flags
& SCOPE
.debug_
))
8560 sc
.setUnsafe(false, exp
.loc
,
8561 "`this` reference necessary to take address of member `%s` in `@safe` function `%s`",
8567 else if (exp
.e1
.op
== EXP
.index
)
8572 * check 'a' the same as for a regular variable
8574 if (VarDeclaration v
= expToVariable(exp
.e1
))
8576 v
.checkPurity(exp
.e1
.loc
, sc
);
8581 /* a ? b : c was transformed to *(a ? &b : &c), but we still
8582 * need to do safety checks
8584 assert(exp
.e1
.op
== EXP
.star
);
8585 PtrExp pe
= cast(PtrExp
)exp
.e1
;
8586 assert(pe
.e1
.op
== EXP
.question
);
8587 CondExp ce
= cast(CondExp
)pe
.e1
;
8588 assert(ce
.e1
.op
== EXP
.address
);
8589 assert(ce
.e2
.op
== EXP
.address
);
8591 // Re-run semantic on the address expressions only
8593 ce
.e1
= ce
.e1
.expressionSemantic(sc
);
8595 ce
.e2
= ce
.e2
.expressionSemantic(sc
);
8597 result
= exp
.optimize(WANTvalue
);
8600 override void visit(PtrExp exp
)
8602 static if (LOGSEMANTIC
)
8604 printf("PtrExp::semantic('%s')\n", exp
.toChars());
8612 Expression e
= exp
.op_overload(sc
);
8619 exp
.e1
= exp
.e1
.arrayFuncConv(sc
);
8621 Type tb
= exp
.e1
.type
.toBasetype();
8625 exp
.type
= (cast(TypePointer
)tb
).next
;
8630 if (isNonAssignmentArrayOp(exp
.e1
))
8632 error(exp
.loc
, "using `*` on an array is no longer supported; use `*(%s).ptr` instead", exp
.e1
.toChars());
8633 exp
.type
= (cast(TypeArray
)tb
).next
;
8634 exp
.e1
= exp
.e1
.castTo(sc
, exp
.type
.pointerTo());
8641 exp
.type
= Type
.tnoreturn
; // typeof(*null) is bottom type
8645 error(exp
.loc
, "can only `*` a pointer, not a `%s`", exp
.e1
.type
.toChars());
8649 if (sc
.flags
& SCOPE
.Cfile
&& exp
.type
&& exp
.type
.toBasetype().ty
== Tvoid
)
8651 // https://issues.dlang.org/show_bug.cgi?id=23752
8652 // `&*((void*)(0))` is allowed in C
8657 if (exp
.checkValue())
8663 override void visit(NegExp exp
)
8665 static if (LOGSEMANTIC
)
8667 printf("NegExp::semantic('%s')\n", exp
.toChars());
8675 Expression e
= exp
.op_overload(sc
);
8683 exp
.type
= exp
.e1
.type
;
8684 Type tb
= exp
.type
.toBasetype();
8685 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
8687 if (!isArrayOpValid(exp
.e1
))
8689 result
= arrayOpInvalidError(exp
);
8695 if (!target
.isVectorOpSupported(tb
, exp
.op
))
8697 result
= exp
.incompatibleTypes();
8700 if (exp
.e1
.checkNoBool())
8702 if (exp
.e1
.checkArithmetic(exp
.op
) ||
8703 exp
.e1
.checkSharedAccess(sc
))
8709 override void visit(UAddExp exp
)
8711 static if (LOGSEMANTIC
)
8713 printf("UAddExp::semantic('%s')\n", exp
.toChars());
8717 Expression e
= exp
.op_overload(sc
);
8725 if (!target
.isVectorOpSupported(exp
.e1
.type
.toBasetype(), exp
.op
))
8727 result
= exp
.incompatibleTypes();
8730 if (exp
.e1
.checkNoBool())
8732 if (exp
.e1
.checkArithmetic(exp
.op
))
8734 if (exp
.e1
.checkSharedAccess(sc
))
8740 override void visit(ComExp exp
)
8748 Expression e
= exp
.op_overload(sc
);
8756 exp
.type
= exp
.e1
.type
;
8757 Type tb
= exp
.type
.toBasetype();
8758 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
8760 if (!isArrayOpValid(exp
.e1
))
8762 result
= arrayOpInvalidError(exp
);
8768 if (!target
.isVectorOpSupported(tb
, exp
.op
))
8770 result
= exp
.incompatibleTypes();
8773 if (exp
.e1
.checkNoBool())
8775 if (exp
.e1
.checkIntegral() ||
8776 exp
.e1
.checkSharedAccess(sc
))
8782 override void visit(NotExp e
)
8790 e
.setNoderefOperand();
8792 // Note there is no operator overload
8793 if (Expression ex
= unaSemantic(e
, sc
))
8799 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
8800 if (e
.e1
.op
== EXP
.type
)
8801 e
.e1
= resolveAliasThis(sc
, e
.e1
);
8803 e
.e1
= resolveProperties(sc
, e
.e1
);
8804 e
.e1
= e
.e1
.toBoolean(sc
);
8805 if (e
.e1
.type
== Type
.terror
)
8811 if (!target
.isVectorOpSupported(e
.e1
.type
.toBasetype(), e
.op
))
8813 result
= e
.incompatibleTypes();
8815 // https://issues.dlang.org/show_bug.cgi?id=13910
8816 // Today NotExp can take an array as its operand.
8817 if (checkNonAssignmentArrayOp(e
.e1
))
8820 e
.type
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? Type
.tint32
: Type
.tbool
;
8824 override void visit(DeleteExp exp
)
8826 // @@@DEPRECATED_2.109@@@
8827 // 1. Deprecated since 2.079
8828 // 2. Error since 2.099
8829 // 3. Removal of keyword, "delete" can be used for other identities
8832 error(exp
.loc
, "the `delete` keyword is obsolete");
8833 errorSupplemental(exp
.loc
, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead");
8839 if (Expression ex
= unaSemantic(exp
, sc
))
8844 exp
.e1
= resolveProperties(sc
, exp
.e1
);
8845 exp
.e1
= exp
.e1
.modifiableLvalue(sc
);
8846 if (exp
.e1
.op
== EXP
.error
)
8851 exp
.type
= Type
.tvoid
;
8853 Type tb
= exp
.e1
.type
.toBasetype();
8855 /* Now that `delete` in user code is an error, we only get here when
8856 * `isRAII` has been set to true for the deletion of a `scope class`. */
8857 if (tb
.ty
!= Tclass
)
8859 error(exp
.loc
, "cannot delete type `%s`", exp
.e1
.type
.toChars());
8863 ClassDeclaration cd
= (cast(TypeClass
)tb
).sym
;
8864 if (cd
.isCOMinterface())
8866 /* Because COM classes are deleted by IUnknown.Release()
8868 error(exp
.loc
, "cannot `delete` instance of COM interface `%s`", cd
.toChars());
8875 err |
= !cd
.dtor
.functionSemantic();
8876 err |
= cd
.dtor
.checkPurity(exp
.loc
, sc
);
8877 err |
= cd
.dtor
.checkSafety(exp
.loc
, sc
);
8878 err |
= cd
.dtor
.checkNogc(exp
.loc
, sc
);
8886 override void visit(CastExp exp
)
8888 static if (LOGSEMANTIC
)
8890 printf("CastExp::semantic('%s')\n", exp
.toChars());
8892 //static int x; assert(++x < 10);
8899 if ((sc
&& sc
.flags
& SCOPE
.Cfile
) &&
8900 exp
.to
&& (exp
.to
.ty
== Tident || exp
.to
.ty
== Tsarray
) &&
8901 (exp
.e1
.op
== EXP
.address || exp
.e1
.op
== EXP
.star ||
8902 exp
.e1
.op
== EXP
.uadd || exp
.e1
.op
== EXP
.negate
))
8904 /* Ambiguous cases arise from CParser if type-name is just an identifier.
8905 * ( identifier ) cast-expression
8906 * ( identifier [expression]) cast-expression
8907 * If we determine that `identifier` is a variable, and cast-expression
8908 * is one of the unary operators (& * + -), then rewrite this cast
8909 * as a binary expression.
8915 exp
.to
.resolve(loc
, sc
, e
, t
, s
);
8918 if (auto ex
= exp
.e1
.isAddrExp()) // (ident) &exp -> (ident & exp)
8919 result
= new AndExp(loc
, e
, ex
.e1
);
8920 else if (auto ex
= exp
.e1
.isPtrExp()) // (ident) *exp -> (ident * exp)
8921 result
= new MulExp(loc
, e
, ex
.e1
);
8922 else if (auto ex
= exp
.e1
.isUAddExp()) // (ident) +exp -> (ident + exp)
8923 result
= new AddExp(loc
, e
, ex
.e1
);
8924 else if (auto ex
= exp
.e1
.isNegExp()) // (ident) -exp -> (ident - exp)
8925 result
= new MinExp(loc
, e
, ex
.e1
);
8928 result
= result
.expressionSemantic(sc
);
8935 exp
.to
= exp
.to
.typeSemantic(exp
.loc
, sc
);
8936 if (exp
.to
== Type
.terror
)
8939 if (!exp
.to
.hasPointers())
8940 exp
.setNoderefOperand();
8942 // When e1 is a template lambda, this cast may instantiate it with
8944 exp
.e1
= inferType(exp
.e1
, exp
.to
);
8947 if (auto e
= unaSemantic(exp
, sc
))
8953 if (exp
.to
&& !exp
.to
.isTypeSArray() && !exp
.to
.isTypeFunction())
8954 exp
.e1
= exp
.e1
.arrayFuncConv(sc
);
8956 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
8957 if (exp
.e1
.op
== EXP
.type
)
8958 exp
.e1
= resolveAliasThis(sc
, exp
.e1
);
8960 auto e1x
= resolveProperties(sc
, exp
.e1
);
8961 if (e1x
.op
== EXP
.error
)
8966 if (e1x
.checkType())
8972 error(exp
.loc
, "cannot cast `%s`", exp
.e1
.toChars());
8976 // https://issues.dlang.org/show_bug.cgi?id=19954
8977 if (exp
.e1
.type
.ty
== Ttuple
)
8981 if (TypeTuple tt
= exp
.to
.isTypeTuple())
8983 if (exp
.e1
.type
.implicitConvTo(tt
))
8985 result
= exp
.e1
.castTo(sc
, tt
);
8990 TupleExp te
= exp
.e1
.isTupleExp();
8991 if (te
.exps
.length
== 1)
8992 exp
.e1
= (*te
.exps
)[0];
8995 // only allow S(x) rewrite if cast specified S explicitly.
8996 // See https://issues.dlang.org/show_bug.cgi?id=18545
8997 const bool allowImplicitConstruction
= exp
.to
!is null;
8999 if (!exp
.to
) // Handle cast(const) and cast(immutable), etc.
9001 exp
.to
= exp
.e1
.type
.castMod(exp
.mod
);
9002 exp
.to
= exp
.to
.typeSemantic(exp
.loc
, sc
);
9004 if (exp
.to
== Type
.terror
)
9008 if (exp
.to
.ty
== Ttuple
)
9010 error(exp
.loc
, "cannot cast `%s` of type `%s` to type sequence `%s`", exp
.e1
.toChars(), exp
.e1
.type
.toChars(), exp
.to
.toChars());
9014 // cast(void) is used to mark e1 as unused, so it is safe
9015 if (exp
.to
.ty
== Tvoid
)
9022 if (!exp
.to
.equals(exp
.e1
.type
) && exp
.mod
== cast(ubyte)~0)
9024 if (Expression e
= exp
.op_overload(sc
))
9026 result
= e
.implicitCastTo(sc
, exp
.to
);
9031 Type t1b
= exp
.e1
.type
.toBasetype();
9032 Type tob
= exp
.to
.toBasetype();
9034 if (allowImplicitConstruction
&& tob
.ty
== Tstruct
&& !tob
.equals(t1b
))
9042 // Rewrite as to.call(e1)
9043 Expression e
= new TypeExp(exp
.loc
, exp
.to
);
9044 e
= new CallExp(exp
.loc
, e
, exp
.e1
);
9045 e
= e
.trySemantic(sc
);
9053 if (!t1b
.equals(tob
) && (t1b
.ty
== Tarray || t1b
.ty
== Tsarray
))
9055 if (checkNonAssignmentArrayOp(exp
.e1
))
9059 Expression ex
= exp
.e1
.castTo(sc
, exp
.to
);
9060 if (ex
.op
== EXP
.error
)
9066 // Check for unsafe casts
9067 if (!isSafeCast(ex
, t1b
, tob
))
9069 if (sc
.setUnsafe(false, exp
.loc
, "cast from `%s` to `%s` not allowed in safe code", exp
.e1
.type
, exp
.to
))
9075 // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built
9076 // to handle certain casts. Those casts which `object.__ArrayCast` does not support are filtered out.
9077 // See `e2ir.toElemCast` for other types of casts. If `object.__ArrayCast` is improved to support more
9078 // casts these conditions and potentially some logic in `e2ir.toElemCast` can be removed.
9079 if (tob
.ty
== Tarray
)
9081 // https://issues.dlang.org/show_bug.cgi?id=19840
9082 if (auto ad
= isAggregate(t1b
))
9086 Expression e
= resolveAliasThis(sc
, exp
.e1
);
9087 e
= new CastExp(exp
.loc
, e
, exp
.to
);
9088 result
= e
.expressionSemantic(sc
);
9093 if(t1b
.ty
== Tarray
&& exp
.e1
.op
!= EXP
.arrayLiteral
&& sc
.needsCodegen())
9095 auto tFrom
= t1b
.nextOf();
9096 auto tTo
= tob
.nextOf();
9098 // https://issues.dlang.org/show_bug.cgi?id=20130
9099 if (exp
.e1
.op
!= EXP
.string_ ||
!ex
.isStringExp
)
9101 const uint fromSize
= cast(uint)tFrom
.size();
9102 const uint toSize
= cast(uint)tTo
.size();
9103 if (fromSize
== SIZE_INVALID || toSize
== SIZE_INVALID
)
9106 // If array element sizes do not match, we must adjust the dimensions
9107 if (fromSize
!= toSize
)
9109 if (!verifyHookExist(exp
.loc
, *sc
, Id
.__ArrayCast
, "casting array of structs"))
9112 // A runtime check is needed in case arrays don't line up. That check should
9113 // be done in the implementation of `object.__ArrayCast`
9114 if (toSize
== 0 ||
(fromSize
% toSize
) != 0)
9116 // lower to `object.__ArrayCast!(TFrom, TTo)(from)`
9118 // fully qualify as `object.__ArrayCast`
9119 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
9120 auto dotid
= new DotIdExp(exp
.loc
, id
, Id
.object
);
9122 auto tiargs
= new Objects();
9125 auto dt = new DotTemplateInstanceExp(exp
.loc
, dotid
, Id
.__ArrayCast
, tiargs
);
9127 auto arguments
= new Expressions();
9128 arguments
.push(exp
.e1
);
9129 Expression ce
= new CallExp(exp
.loc
, dt, arguments
);
9131 result
= expressionSemantic(ce
, sc
);
9139 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
9141 /* C11 6.5.4-5: A cast does not yield an lvalue.
9142 * So ensure that castTo does not strip away the cast so that this
9143 * can be enforced in other semantic visitor methods.
9145 if (!ex
.isCastExp())
9147 ex
= new CastExp(exp
.loc
, ex
, exp
.to
);
9154 override void visit(VectorExp exp
)
9156 static if (LOGSEMANTIC
)
9158 printf("VectorExp::semantic('%s')\n", exp
.toChars());
9166 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
9167 exp
.type
= exp
.to
.typeSemantic(exp
.loc
, sc
);
9168 if (exp
.e1
.op
== EXP
.error || exp
.type
.ty
== Terror
)
9174 Type tb
= exp
.type
.toBasetype();
9175 assert(tb
.ty
== Tvector
);
9176 TypeVector tv
= cast(TypeVector
)tb
;
9177 Type te
= tv
.elementType();
9178 exp
.dim
= cast(int)(tv
.size(exp
.loc
) / te
.size(exp
.loc
));
9180 bool checkElem(Expression elem
)
9182 if (elem
.isConst() == 1)
9185 error(exp
.loc
, "constant expression expected, not `%s`", elem
.toChars());
9189 exp
.e1
= exp
.e1
.optimize(WANTvalue
);
9191 if (exp
.e1
.op
== EXP
.arrayLiteral
)
9193 foreach (i
; 0 .. exp
.dim
)
9195 // Do not stop on first error - check all AST nodes even if error found
9196 res |
= checkElem(exp
.e1
.isArrayLiteralExp()[i
]);
9199 else if (exp
.e1
.type
.ty
== Tvoid
)
9202 result
= res ? ErrorExp
.get() : exp
;
9205 override void visit(VectorArrayExp e
)
9207 static if (LOGSEMANTIC
)
9209 printf("VectorArrayExp::semantic('%s')\n", e
.toChars());
9214 e
.e1
= resolveProperties(sc
, e
.e1
);
9216 if (e
.e1
.op
== EXP
.error
)
9221 assert(e
.e1
.type
.ty
== Tvector
);
9222 e
.type
= e
.e1
.type
.isTypeVector().basetype
;
9227 override void visit(SliceExp exp
)
9229 static if (LOGSEMANTIC
)
9231 printf("SliceExp::semantic('%s')\n", exp
.toChars());
9239 // operator overloading should be handled in ArrayExp already.
9240 if (Expression ex
= unaSemantic(exp
, sc
))
9245 exp
.e1
= resolveProperties(sc
, exp
.e1
);
9246 if (exp
.e1
.op
== EXP
.type
&& exp
.e1
.type
.ty
!= Ttuple
)
9248 if (exp
.lwr || exp
.upr
)
9250 error(exp
.loc
, "cannot slice type `%s`", exp
.e1
.toChars());
9253 Expression e
= new TypeExp(exp
.loc
, exp
.e1
.type
.arrayOf());
9254 result
= e
.expressionSemantic(sc
);
9257 if (!exp
.lwr
&& !exp
.upr
)
9259 if (exp
.e1
.op
== EXP
.arrayLiteral
)
9261 // Convert [a,b,c][] to [a,b,c]
9262 Type t1b
= exp
.e1
.type
.toBasetype();
9263 Expression e
= exp
.e1
;
9264 if (t1b
.ty
== Tsarray
)
9267 e
.type
= t1b
.nextOf().arrayOf();
9272 if (exp
.e1
.op
== EXP
.slice
)
9274 // Convert e[][] to e[]
9275 SliceExp se
= cast(SliceExp
)exp
.e1
;
9276 if (!se
.lwr
&& !se
.upr
)
9282 if (isArrayOpOperand(exp
.e1
))
9284 // Convert (a[]+b[])[] to a[]+b[]
9289 if (exp
.e1
.op
== EXP
.error
)
9294 if (exp
.e1
.type
.ty
== Terror
)
9297 Type t1b
= exp
.e1
.type
.toBasetype();
9298 if (auto tp
= t1b
.isTypePointer())
9300 if (t1b
.isPtrToFunction())
9302 error(exp
.loc
, "cannot slice function pointer `%s`", exp
.e1
.toChars());
9305 if (!exp
.lwr ||
!exp
.upr
)
9307 error(exp
.loc
, "upper and lower bounds are needed to slice a pointer");
9308 if (auto ad
= isAggregate(tp
.next
.toBasetype()))
9310 auto s
= search_function(ad
, Id
.index
);
9311 if (!s
) s
= search_function(ad
, Id
.slice
);
9314 auto fd
= s
.isFuncDeclaration();
9315 if ((fd
&& !fd
.getParameterList().length
) || s
.isTemplateDeclaration())
9317 errorSupplemental(exp
.loc
,
9318 "pointer `%s` points to an aggregate that defines an `%s`, perhaps you meant `(*%s)[]`",
9330 if (sc
.setUnsafe(false, exp
.loc
, "pointer slicing not allowed in safe functions"))
9333 else if (t1b
.ty
== Tarray
)
9336 else if (t1b
.ty
== Tsarray
)
9339 else if (t1b
.ty
== Ttuple
)
9341 if (!exp
.lwr
&& !exp
.upr
)
9346 if (!exp
.lwr ||
!exp
.upr
)
9348 error(exp
.loc
, "need upper and lower bound to slice a sequence");
9352 else if (t1b
.ty
== Tvector
&& exp
.e1
.isLvalue())
9354 // Convert e1 to corresponding static array
9355 TypeVector tv1
= cast(TypeVector
)t1b
;
9357 t1b
= t1b
.castMod(tv1
.mod
);
9362 error(exp
.loc
, "`%s` cannot be sliced with `[]`", t1b
.ty
== Tvoid ? exp
.e1
.toChars() : t1b
.toChars());
9366 /* Run semantic on lwr and upr.
9369 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray || t1b
.ty
== Ttuple
)
9371 // Create scope for 'length' variable
9372 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, exp
);
9373 sym
.parent
= sc
.scopesym
;
9378 if (t1b
.ty
== Ttuple
)
9379 sc
= sc
.startCTFE();
9380 exp
.lwr
= exp
.lwr
.expressionSemantic(sc
);
9381 exp
.lwr
= resolveProperties(sc
, exp
.lwr
);
9382 if (t1b
.ty
== Ttuple
)
9384 exp
.lwr
= exp
.lwr
.implicitCastTo(sc
, Type
.tsize_t
);
9388 if (t1b
.ty
== Ttuple
)
9389 sc
= sc
.startCTFE();
9390 exp
.upr
= exp
.upr
.expressionSemantic(sc
);
9391 exp
.upr
= resolveProperties(sc
, exp
.upr
);
9392 if (t1b
.ty
== Ttuple
)
9394 exp
.upr
= exp
.upr
.implicitCastTo(sc
, Type
.tsize_t
);
9398 if (exp
.lwr
&& exp
.lwr
.type
== Type
.terror || exp
.upr
&& exp
.upr
.type
== Type
.terror
)
9401 if (t1b
.ty
== Ttuple
)
9403 exp
.lwr
= exp
.lwr
.ctfeInterpret();
9404 exp
.upr
= exp
.upr
.ctfeInterpret();
9405 uinteger_t i1
= exp
.lwr
.toUInteger();
9406 uinteger_t i2
= exp
.upr
.toUInteger();
9411 if (exp
.e1
.op
== EXP
.tuple
) // slicing an expression tuple
9413 te
= cast(TupleExp
)exp
.e1
;
9415 length
= te
.exps
.length
;
9417 else if (exp
.e1
.op
== EXP
.type
) // slicing a type tuple
9420 tup
= cast(TypeTuple
)t1b
;
9421 length
= Parameter
.dim(tup
.arguments
);
9426 if (i2
< i1 || length
< i2
)
9428 error(exp
.loc
, "string slice `[%llu .. %llu]` is out of bounds", i1
, i2
);
9432 size_t j1
= cast(size_t
)i1
;
9433 size_t j2
= cast(size_t
)i2
;
9435 if (exp
.e1
.op
== EXP
.tuple
)
9437 auto exps
= new Expressions(j2
- j1
);
9438 for (size_t i
= 0; i
< j2
- j1
; i
++)
9440 (*exps
)[i
] = (*te
.exps
)[j1
+ i
];
9442 e
= new TupleExp(exp
.loc
, te
.e0
, exps
);
9446 auto args
= new Parameters();
9447 args
.reserve(j2
- j1
);
9448 for (size_t i
= j1
; i
< j2
; i
++)
9450 Parameter arg
= Parameter
.getNth(tup
.arguments
, i
);
9453 e
= new TypeExp(exp
.e1
.loc
, new TypeTuple(args
));
9455 e
= e
.expressionSemantic(sc
);
9460 exp
.type
= t1b
.nextOf().arrayOf();
9461 // Allow typedef[] -> typedef[]
9462 if (exp
.type
.equals(t1b
))
9463 exp
.type
= exp
.e1
.type
;
9465 // We might know $ now
9466 setLengthVarIfKnown(exp
.lengthVar
, t1b
);
9468 if (exp
.lwr
&& exp
.upr
)
9470 exp
.lwr
= exp
.lwr
.optimize(WANTvalue
);
9471 exp
.upr
= exp
.upr
.optimize(WANTvalue
);
9473 IntRange lwrRange
= getIntRange(exp
.lwr
);
9474 IntRange uprRange
= getIntRange(exp
.upr
);
9476 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray
)
9478 Expression el
= new ArrayLengthExp(exp
.loc
, exp
.e1
);
9479 el
= el
.expressionSemantic(sc
);
9480 el
= el
.optimize(WANTvalue
);
9481 if (el
.op
== EXP
.int64
)
9483 // Array length is known at compile-time. Upper is in bounds if it fits length.
9484 dinteger_t length
= el
.toInteger();
9485 auto bounds
= IntRange(SignExtendedNumber(0), SignExtendedNumber(length
));
9486 exp
.upperIsInBounds
= bounds
.contains(uprRange
);
9488 else if (exp
.upr
.op
== EXP
.int64
&& exp
.upr
.toInteger() == 0)
9490 // Upper slice expression is '0'. Value is always in bounds.
9491 exp
.upperIsInBounds
= true;
9493 else if (exp
.upr
.op
== EXP
.variable
&& (cast(VarExp
)exp
.upr
).var
.ident
== Id
.dollar
)
9495 // Upper slice expression is '$'. Value is always in bounds.
9496 exp
.upperIsInBounds
= true;
9499 else if (t1b
.ty
== Tpointer
)
9501 exp
.upperIsInBounds
= true;
9506 exp
.lowerIsLessThanUpper
= (lwrRange
.imax
<= uprRange
.imin
);
9508 //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", exp.upperIsInBounds, exp.lowerIsLessThanUpper);
9514 override void visit(ArrayLengthExp e
)
9516 static if (LOGSEMANTIC
)
9518 printf("ArrayLengthExp::semantic('%s')\n", e
.toChars());
9526 if (Expression ex
= unaSemantic(e
, sc
))
9531 e
.e1
= resolveProperties(sc
, e
.e1
);
9533 e
.type
= Type
.tsize_t
;
9537 override void visit(ArrayExp exp
)
9539 static if (LOGSEMANTIC
)
9541 printf("ArrayExp::semantic('%s')\n", exp
.toChars());
9545 if (sc
.flags
& SCOPE
.Cfile
)
9547 /* See if need to rewrite the AST because of cast/call ambiguity
9549 if (auto e
= castCallAmbiguity(exp
, sc
))
9551 result
= expressionSemantic(e
, sc
);
9556 result
= exp
.carraySemantic(sc
); // C semantics
9560 Expression e
= exp
.op_overload(sc
);
9567 if (isAggregate(exp
.e1
.type
))
9568 error(exp
.loc
, "no `[]` operator overload for type `%s`", exp
.e1
.type
.toChars());
9569 else if (exp
.e1
.op
== EXP
.type
&& exp
.e1
.type
.ty
!= Ttuple
)
9570 error(exp
.loc
, "static array of `%s` with multiple lengths not allowed", exp
.e1
.type
.toChars());
9571 else if (isIndexableNonAggregate(exp
.e1
.type
))
9572 error(exp
.loc
, "only one index allowed to index `%s`", exp
.e1
.type
.toChars());
9574 error(exp
.loc
, "cannot use `[]` operator on expression of type `%s`", exp
.e1
.type
.toChars());
9576 result
= ErrorExp
.get();
9579 override void visit(DotExp exp
)
9581 static if (LOGSEMANTIC
)
9583 printf("DotExp::semantic('%s')\n", exp
.toChars());
9585 printf("\ttype = %s\n", exp
.type
.toChars());
9587 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
9588 exp
.e2
= exp
.e2
.expressionSemantic(sc
);
9590 if (exp
.e1
.op
== EXP
.type
)
9595 if (exp
.e2
.op
== EXP
.type
)
9600 if (auto te
= exp
.e2
.isTemplateExp())
9602 Expression e
= new DotTemplateExp(exp
.loc
, exp
.e1
, te
.td
);
9603 result
= e
.expressionSemantic(sc
);
9607 exp
.type
= exp
.e2
.type
;
9611 override void visit(CommaExp e
)
9613 //printf("Semantic.CommaExp() %s\n", e.toChars());
9620 // Allow `((a,b),(x,y))`
9621 if (e
.allowCommaExp
)
9623 CommaExp
.allow(e
.e1
);
9624 CommaExp
.allow(e
.e2
);
9627 if (Expression ex
= binSemanticProp(e
, sc
))
9632 e
.e1
= e
.e1
.addDtorHook(sc
);
9634 if (checkNonAssignmentArrayOp(e
.e1
))
9637 // Comma expressions trigger this conversion
9638 e
.e2
= e
.e2
.arrayFuncConv(sc
);
9643 if (sc
.flags
& SCOPE
.Cfile
)
9646 if (e
.type
is Type
.tvoid
)
9648 checkMustUse(e
.e1
, sc
);
9651 else if (!e
.allowCommaExp
&& !e
.isGenerated
)
9652 error(e
.loc
, "using the result of a comma expression is not allowed");
9655 override void visit(IntervalExp e
)
9657 static if (LOGSEMANTIC
)
9659 printf("IntervalExp::semantic('%s')\n", e
.toChars());
9667 Expression le
= e
.lwr
;
9668 le
= le
.expressionSemantic(sc
);
9669 le
= resolveProperties(sc
, le
);
9671 Expression ue
= e
.upr
;
9672 ue
= ue
.expressionSemantic(sc
);
9673 ue
= resolveProperties(sc
, ue
);
9675 if (le
.op
== EXP
.error
)
9680 if (ue
.op
== EXP
.error
)
9689 e
.type
= Type
.tvoid
;
9693 override void visit(DelegatePtrExp e
)
9695 static if (LOGSEMANTIC
)
9697 printf("DelegatePtrExp::semantic('%s')\n", e
.toChars());
9702 e
.e1
= resolveProperties(sc
, e
.e1
);
9704 if (e
.e1
.op
== EXP
.error
)
9709 e
.type
= Type
.tvoidptr
;
9714 override void visit(DelegateFuncptrExp e
)
9716 static if (LOGSEMANTIC
)
9718 printf("DelegateFuncptrExp::semantic('%s')\n", e
.toChars());
9723 e
.e1
= resolveProperties(sc
, e
.e1
);
9724 if (e
.e1
.op
== EXP
.error
)
9729 e
.type
= e
.e1
.type
.nextOf().pointerTo();
9734 override void visit(IndexExp exp
)
9736 static if (LOGSEMANTIC
)
9738 printf("IndexExp::semantic('%s')\n", exp
.toChars());
9746 // operator overloading should be handled in ArrayExp already.
9748 exp
.e1
= exp
.e1
.expressionSemantic(sc
).arrayFuncConv(sc
);
9749 assert(exp
.e1
.type
); // semantic() should already be run on it
9750 if (exp
.e1
.op
== EXP
.type
&& exp
.e1
.type
.ty
!= Ttuple
)
9752 exp
.e2
= exp
.e2
.expressionSemantic(sc
);
9753 exp
.e2
= resolveProperties(sc
, exp
.e2
);
9755 if (exp
.e2
.op
== EXP
.type
)
9756 nt
= new TypeAArray(exp
.e1
.type
, exp
.e2
.type
);
9758 nt
= new TypeSArray(exp
.e1
.type
, exp
.e2
);
9759 Expression e
= new TypeExp(exp
.loc
, nt
);
9760 result
= e
.expressionSemantic(sc
);
9763 if (exp
.e1
.op
== EXP
.error
)
9768 if (exp
.e1
.type
.ty
== Terror
)
9771 // Note that unlike C we do not implement the int[ptr]
9773 Type t1b
= exp
.e1
.type
.toBasetype();
9775 if (TypeVector tv1
= t1b
.isTypeVector())
9777 // Convert e1 to corresponding static array
9779 t1b
= t1b
.castMod(tv1
.mod
);
9780 exp
.e1
= exp
.e1
.castTo(sc
, t1b
);
9782 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray
)
9784 if (!checkAddressable(exp
, sc
))
9788 /* Run semantic on e2
9791 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray || t1b
.ty
== Ttuple
)
9793 // Create scope for 'length' variable
9794 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, exp
);
9795 sym
.parent
= sc
.scopesym
;
9798 if (t1b
.ty
== Ttuple
)
9799 sc
= sc
.startCTFE();
9800 exp
.e2
= exp
.e2
.expressionSemantic(sc
).arrayFuncConv(sc
);
9801 exp
.e2
= resolveProperties(sc
, exp
.e2
);
9802 if (t1b
.ty
== Ttuple
)
9804 if (exp
.e2
.op
== EXP
.tuple
)
9806 TupleExp te
= cast(TupleExp
)exp
.e2
;
9807 if (te
.exps
&& te
.exps
.length
== 1)
9808 exp
.e2
= Expression
.combine(te
.e0
, (*te
.exps
)[0]); // bug 4444 fix
9812 if (exp
.e2
.type
== Type
.terror
)
9815 if (checkNonAssignmentArrayOp(exp
.e1
))
9821 if (t1b
.isPtrToFunction())
9823 error(exp
.loc
, "cannot index function pointer `%s`", exp
.e1
.toChars());
9826 exp
.e2
= exp
.e2
.implicitCastTo(sc
, Type
.tsize_t
);
9827 if (exp
.e2
.type
== Type
.terror
)
9829 exp
.e2
= exp
.e2
.optimize(WANTvalue
);
9830 if (exp
.e2
.op
== EXP
.int64
&& exp
.e2
.toInteger() == 0)
9833 else if (sc
.setUnsafe(false, exp
.loc
, "`@safe` function `%s` cannot index pointer `%s`", sc
.func
, exp
.e1
))
9837 exp
.type
= (cast(TypeNext
)t1b
).next
;
9841 exp
.e2
= exp
.e2
.implicitCastTo(sc
, Type
.tsize_t
);
9842 if (exp
.e2
.type
== Type
.terror
)
9844 exp
.type
= (cast(TypeNext
)t1b
).next
;
9849 exp
.e2
= exp
.e2
.implicitCastTo(sc
, Type
.tsize_t
);
9850 if (exp
.e2
.type
== Type
.terror
)
9852 exp
.type
= t1b
.nextOf();
9857 TypeAArray taa
= cast(TypeAArray
)t1b
;
9858 /* We can skip the implicit conversion if they differ only by
9860 * https://issues.dlang.org/show_bug.cgi?id=2684
9861 * see also bug https://issues.dlang.org/show_bug.cgi?id=2954 b
9863 if (!arrayTypeCompatibleWithoutCasting(exp
.e2
.type
, taa
.index
))
9865 exp
.e2
= exp
.e2
.implicitCastTo(sc
, taa
.index
); // type checking
9866 if (exp
.e2
.type
== Type
.terror
)
9870 semanticTypeInfo(sc
, taa
);
9871 checkNewEscape(sc
, exp
.e2
, false);
9873 exp
.type
= taa
.next
;
9878 exp
.e2
= exp
.e2
.implicitCastTo(sc
, Type
.tsize_t
);
9879 if (exp
.e2
.type
== Type
.terror
)
9882 exp
.e2
= exp
.e2
.ctfeInterpret();
9883 uinteger_t index
= exp
.e2
.toUInteger();
9888 if (exp
.e1
.op
== EXP
.tuple
)
9890 te
= cast(TupleExp
)exp
.e1
;
9892 length
= te
.exps
.length
;
9894 else if (exp
.e1
.op
== EXP
.type
)
9897 tup
= cast(TypeTuple
)t1b
;
9898 length
= Parameter
.dim(tup
.arguments
);
9903 if (length
<= index
)
9905 error(exp
.loc
, "array index `[%llu]` is outside array bounds `[0 .. %llu]`", index
, cast(ulong)length
);
9909 if (exp
.e1
.op
== EXP
.tuple
)
9911 e
= (*te
.exps
)[cast(size_t
)index
];
9912 e
= Expression
.combine(te
.e0
, e
);
9915 e
= new TypeExp(exp
.e1
.loc
, Parameter
.getNth(tup
.arguments
, cast(size_t
)index
).type
);
9920 error(exp
.loc
, "`%s` must be an array or pointer type, not `%s`", exp
.e1
.toChars(), exp
.e1
.type
.toChars());
9924 // We might know $ now
9925 setLengthVarIfKnown(exp
.lengthVar
, t1b
);
9927 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray
)
9929 Expression el
= new ArrayLengthExp(exp
.loc
, exp
.e1
);
9930 el
= el
.expressionSemantic(sc
);
9931 el
= el
.optimize(WANTvalue
);
9932 if (el
.op
== EXP
.int64
)
9934 exp
.e2
= exp
.e2
.optimize(WANTvalue
);
9935 dinteger_t length
= el
.toInteger();
9938 auto bounds
= IntRange(SignExtendedNumber(0), SignExtendedNumber(length
- 1));
9939 // OR it in, because it might already be set for C array indexing
9940 exp
.indexIsInBounds |
= bounds
.contains(getIntRange(exp
.e2
));
9942 else if (sc
.flags
& SCOPE
.Cfile
&& t1b
.ty
== Tsarray
)
9944 if (auto ve
= exp
.e1
.isVarExp())
9946 /* Rewrite 0-length C array ve[exp.e2] as *(ve + exp.e2)
9948 auto vp
= ve
.castTo(sc
, t1b
.isTypeSArray().next
.pointerTo());
9949 auto e
= new AddExp(exp
.loc
, vp
, exp
.e2
);
9950 auto pe
= new PtrExp(exp
.loc
, e
);
9951 result
= pe
.expressionSemantic(sc
).optimize(WANTvalue
);
9961 override void visit(PostExp exp
)
9963 static if (LOGSEMANTIC
)
9965 printf("PostExp::semantic('%s')\n", exp
.toChars());
9973 if (sc
.flags
& SCOPE
.Cfile
)
9975 /* See if need to rewrite the AST because of cast/call ambiguity
9977 if (auto e
= castCallAmbiguity(exp
, sc
))
9979 result
= expressionSemantic(e
, sc
);
9984 if (Expression ex
= binSemantic(exp
, sc
))
9989 Expression e1x
= resolveProperties(sc
, exp
.e1
);
9990 if (e1x
.op
== EXP
.error
)
9997 Expression e
= exp
.op_overload(sc
);
10004 if (exp
.e1
.checkReadModifyWrite(exp
.op
))
10007 if (exp
.e1
.op
== EXP
.slice
)
10009 const(char)* s
= exp
.op
== EXP
.plusPlus ?
"increment" : "decrement";
10010 error(exp
.loc
, "cannot post-%s array slice `%s`, use pre-%s instead", s
, exp
.e1
.toChars(), s
);
10014 Type t1
= exp
.e1
.type
.toBasetype();
10015 if (t1
.ty
== Tclass || t1
.ty
== Tstruct || exp
.e1
.op
== EXP
.arrayLength
)
10017 /* Check for operator overloading,
10018 * but rewrite in terms of ++e instead of e++
10021 /* If e1 is not trivial, take a reference to it
10023 Expression
de = null;
10024 if (exp
.e1
.op
!= EXP
.variable
&& exp
.e1
.op
!= EXP
.arrayLength
)
10027 auto v
= copyToTemp(STC
.ref_
, "__postref", exp
.e1
);
10028 de = new DeclarationExp(exp
.loc
, v
);
10029 exp
.e1
= new VarExp(exp
.e1
.loc
, v
);
10033 * auto tmp = e1; ++e1; tmp
10035 auto tmp
= copyToTemp(0, "__pitmp", exp
.e1
);
10036 Expression ea
= new DeclarationExp(exp
.loc
, tmp
);
10038 Expression eb
= exp
.e1
.syntaxCopy();
10039 eb
= new PreExp(exp
.op
== EXP
.plusPlus ? EXP
.prePlusPlus
: EXP
.preMinusMinus
, exp
.loc
, eb
);
10041 Expression ec
= new VarExp(exp
.loc
, tmp
);
10043 // Combine de,ea,eb,ec
10045 ea
= new CommaExp(exp
.loc
, de, ea
);
10046 e
= new CommaExp(exp
.loc
, ea
, eb
);
10047 e
= new CommaExp(exp
.loc
, e
, ec
);
10048 e
= e
.expressionSemantic(sc
);
10053 exp
.e1
= exp
.e1
.modifiableLvalue(sc
);
10054 exp
.e1
= exp
.e1
.optimize(WANTvalue
, /*keepLvalue*/ true);
10057 if (exp
.e1
.checkScalar() ||
10058 exp
.e1
.checkSharedAccess(sc
))
10060 if (exp
.e1
.checkNoBool())
10063 if (exp
.e1
.type
.ty
== Tpointer
)
10064 e
= scaleFactor(exp
, sc
);
10066 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
);
10067 e
.type
= exp
.e1
.type
;
10071 override void visit(PreExp exp
)
10073 Expression e
= exp
.op_overload(sc
);
10074 // printf("PreExp::semantic('%s')\n", toChars());
10081 // Rewrite as e1+=1 or e1-=1
10082 if (exp
.op
== EXP
.prePlusPlus
)
10083 e
= new AddAssignExp(exp
.loc
, exp
.e1
, IntegerExp
.literal
!1);
10085 e
= new MinAssignExp(exp
.loc
, exp
.e1
, IntegerExp
.literal
!1);
10086 result
= e
.expressionSemantic(sc
);
10090 * Get the expression initializer for a specific struct
10093 * sd = the struct for which the expression initializer is needed
10094 * loc = the location of the initializer
10095 * sc = the scope where the expression is located
10096 * t = the type of the expression
10099 * The expression initializer or error expression if any errors occured
10101 private Expression
getInitExp(StructDeclaration sd
, Loc loc
, Scope
* sc
, Type t
)
10103 if (sd
.zeroInit
&& !sd
.isNested())
10105 // https://issues.dlang.org/show_bug.cgi?id=14606
10106 // Always use BlitExp for the special expression: (struct = 0)
10107 return IntegerExp
.literal
!0;
10112 auto sle
= new StructLiteralExp(loc
, sd
, null, t
);
10113 if (!sd
.fill(loc
, *sle
.elements
, true))
10114 return ErrorExp
.get();
10115 if (checkFrameAccess(loc
, sc
, sd
, sle
.elements
.length
))
10116 return ErrorExp
.get();
10122 return t
.defaultInit(loc
);
10125 override void visit(AssignExp exp
)
10127 static if (LOGSEMANTIC
)
10129 if (exp
.op
== EXP
.blit
) printf("BlitExp.toElem('%s')\n", exp
.toChars());
10130 if (exp
.op
== EXP
.assign
) printf("AssignExp.toElem('%s')\n", exp
.toChars());
10131 if (exp
.op
== EXP
.construct
) printf("ConstructExp.toElem('%s')\n", exp
.toChars());
10134 void setResult(Expression e
, int line
= __LINE__
)
10136 //printf("line %d\n", line);
10142 return setResult(exp
);
10145 Expression e1old
= exp
.e1
;
10147 if (auto e2comma
= exp
.e2
.isCommaExp())
10149 if (!e2comma
.isGenerated
&& !(sc
.flags
& SCOPE
.Cfile
))
10150 error(exp
.loc
, "using the result of a comma expression is not allowed");
10152 /* Rewrite to get rid of the comma from rvalue
10153 * e1=(e0,e2) => e0,(e1=e2)
10156 exp
.e2
= Expression
.extractLast(e2comma
, e0
);
10157 Expression e
= Expression
.combine(e0
, exp
);
10158 return setResult(e
.expressionSemantic(sc
));
10161 /* Look for operator overloading of a[arguments] = e2.
10162 * Do it before e1.expressionSemantic() otherwise the ArrayExp will have been
10163 * converted to unary operator overloading already.
10165 if (auto ae
= exp
.e1
.isArrayExp())
10169 ae
.e1
= ae
.e1
.expressionSemantic(sc
);
10170 ae
.e1
= resolveProperties(sc
, ae
.e1
);
10171 Expression ae1old
= ae
.e1
;
10173 const(bool) maybeSlice
=
10174 (ae
.arguments
.length
== 0 ||
10175 ae
.arguments
.length
== 1 && (*ae
.arguments
)[0].op
== EXP
.interval
);
10177 IntervalExp ie
= null;
10178 if (maybeSlice
&& ae
.arguments
.length
)
10180 assert((*ae
.arguments
)[0].op
== EXP
.interval
);
10181 ie
= cast(IntervalExp
)(*ae
.arguments
)[0];
10183 Type att
= null; // first cyclic `alias this` type
10186 if (ae
.e1
.op
== EXP
.error
)
10187 return setResult(ae
.e1
);
10189 Expression e0
= null;
10190 Expression ae1save
= ae
.e1
;
10191 ae
.lengthVar
= null;
10193 Type t1b
= ae
.e1
.type
.toBasetype();
10194 AggregateDeclaration ad
= isAggregate(t1b
);
10197 if (search_function(ad
, Id
.indexass
))
10200 res
= resolveOpDollar(sc
, ae
, &e0
);
10201 if (!res
) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
10203 if (res
.op
== EXP
.error
)
10204 return setResult(res
);
10206 res
= exp
.e2
.expressionSemantic(sc
);
10207 if (res
.op
== EXP
.error
)
10208 return setResult(res
);
10211 /* Rewrite (a[arguments] = e2) as:
10212 * a.opIndexAssign(e2, arguments)
10214 Expressions
* a
= ae
.arguments
.copy();
10215 a
.insert(0, exp
.e2
);
10216 res
= new DotIdExp(exp
.loc
, ae
.e1
, Id
.indexass
);
10217 res
= new CallExp(exp
.loc
, res
, a
);
10218 if (maybeSlice
) // a[] = e2 might be: a.opSliceAssign(e2)
10219 res
= res
.trySemantic(sc
);
10221 res
= res
.expressionSemantic(sc
);
10223 return setResult(Expression
.combine(e0
, res
));
10227 if (maybeSlice
&& search_function(ad
, Id
.sliceass
))
10230 res
= resolveOpDollar(sc
, ae
, ie
, &e0
);
10231 if (res
.op
== EXP
.error
)
10232 return setResult(res
);
10234 res
= exp
.e2
.expressionSemantic(sc
);
10235 if (res
.op
== EXP
.error
)
10236 return setResult(res
);
10240 /* Rewrite (a[i..j] = e2) as:
10241 * a.opSliceAssign(e2, i, j)
10243 auto a
= new Expressions();
10250 res
= new DotIdExp(exp
.loc
, ae
.e1
, Id
.sliceass
);
10251 res
= new CallExp(exp
.loc
, res
, a
);
10252 res
= res
.expressionSemantic(sc
);
10253 return setResult(Expression
.combine(e0
, res
));
10256 // No operator overloading member function found yet, but
10257 // there might be an alias this to try.
10258 if (ad
.aliasthis
&& !isRecursiveAliasThis(att
, ae
.e1
.type
))
10260 /* Rewrite (a[arguments] op e2) as:
10261 * a.aliasthis[arguments] op e2
10263 ae
.e1
= resolveAliasThis(sc
, ae1save
, true);
10269 ae
.e1
= ae1old
; // recovery
10270 ae
.lengthVar
= null;
10273 /* Run this.e1 semantic.
10276 Expression e1x
= exp
.e1
;
10278 /* With UFCS, e.f = value
10284 if (auto dti
= e1x
.isDotTemplateInstanceExp())
10286 Expression e
= dti
.dotTemplateSemanticProp(sc
, DotExpFlag
.gag
);
10289 return setResult(resolveUFCSProperties(sc
, e1x
, exp
.e2
));
10294 else if (sc
.flags
& SCOPE
.Cfile
&& e1x
.isDotIdExp())
10296 auto die
= e1x
.isDotIdExp();
10297 e1x
= fieldLookup(die
.e1
, sc
, die
.ident
, die
.arrow
);
10299 else if (auto die
= e1x
.isDotIdExp())
10301 Expression e
= die
.dotIdSemanticProp(sc
, 1);
10302 if (e
&& isDotOpDispatch(e
))
10304 /* https://issues.dlang.org/show_bug.cgi?id=19687
10306 * On this branch, e2 is semantically analyzed in resolvePropertiesX,
10307 * but that call is done with gagged errors. That is the only time when
10308 * semantic gets ran on e2, that is why the error never gets to be printed.
10309 * In order to make sure that UFCS is tried with correct parameters, e2
10310 * needs to have semantic ran on it.
10313 exp
.e2
= exp
.e2
.expressionSemantic(sc
);
10314 uint errors
= global
.startGagging();
10315 e
= resolvePropertiesX(sc
, e
, exp
.e2
);
10316 // Any error or if 'e' is not resolved, go to UFCS
10317 if (global
.endGagging(errors
) || e
is ode
)
10318 e
= null; /* fall down to UFCS */
10320 return setResult(e
);
10323 return setResult(resolveUFCSProperties(sc
, e1x
, exp
.e2
));
10328 if (auto se
= e1x
.isSliceExp())
10331 e1x
= e1x
.expressionSemantic(sc
);
10334 /* We have f = value.
10340 if (Expression e
= resolvePropertiesX(sc
, e1x
, exp
.e2
, exp
))
10341 return setResult(e
);
10343 if (e1x
.checkRightThis(sc
))
10348 assert(exp
.e1
.type
);
10350 Type t1
= exp
.e1
.type
.isTypeEnum() ? exp
.e1
.type
: exp
.e1
.type
.toBasetype();
10352 /* Run this.e2 semantic.
10353 * Different from other binary expressions, the analysis of e2
10354 * depends on the result of e1 in assignments.
10357 Expression e2x
= inferType(exp
.e2
, t1
.baseElemOf());
10358 e2x
= e2x
.expressionSemantic(sc
);
10359 if (!t1
.isTypeSArray())
10360 e2x
= e2x
.arrayFuncConv(sc
);
10361 e2x
= resolveProperties(sc
, e2x
);
10362 if (e2x
.op
== EXP
.type
)
10363 e2x
= resolveAliasThis(sc
, e2x
); //https://issues.dlang.org/show_bug.cgi?id=17684
10364 if (e2x
.op
== EXP
.error
)
10365 return setResult(e2x
);
10366 // We delay checking the value for structs/classes as these might have
10367 // an opAssign defined.
10368 if ((t1
.ty
!= Tstruct
&& t1
.ty
!= Tclass
&& e2x
.checkValue()) ||
10369 e2x
.checkSharedAccess(sc
))
10372 auto etmp
= checkNoreturnVarAccess(e2x
);
10374 return setResult(etmp
);
10379 /* Rewrite tuple assignment as a tuple of assignments.
10382 Expression e2x
= exp
.e2
;
10385 if (exp
.e1
.op
== EXP
.tuple
&& e2x
.op
== EXP
.tuple
)
10387 TupleExp tup1
= cast(TupleExp
)exp
.e1
;
10388 TupleExp tup2
= cast(TupleExp
)e2x
;
10389 size_t dim
= tup1
.exps
.length
;
10390 Expression e
= null;
10391 if (dim
!= tup2
.exps
.length
)
10393 error(exp
.loc
, "mismatched sequence lengths, %d and %d", cast(int)dim
, cast(int)tup2
.exps
.length
);
10398 e
= IntegerExp
.literal
!0;
10399 e
= new CastExp(exp
.loc
, e
, Type
.tvoid
); // avoid "has no effect" error
10400 e
= Expression
.combine(tup1
.e0
, tup2
.e0
, e
);
10404 auto exps
= new Expressions(dim
);
10405 for (size_t i
= 0; i
< dim
; i
++)
10407 Expression ex1
= (*tup1
.exps
)[i
];
10408 Expression ex2
= (*tup2
.exps
)[i
];
10409 (*exps
)[i
] = new AssignExp(exp
.loc
, ex1
, ex2
);
10411 e
= new TupleExp(exp
.loc
, Expression
.combine(tup1
.e0
, tup2
.e0
), exps
);
10413 return setResult(e
.expressionSemantic(sc
));
10416 /* Look for form: e1 = e2.aliasthis.
10418 if (exp
.e1
.op
== EXP
.tuple
)
10420 TupleDeclaration td
= isAliasThisTuple(e2x
);
10424 assert(exp
.e1
.type
.ty
== Ttuple
);
10425 TypeTuple tt
= cast(TypeTuple
)exp
.e1
.type
;
10428 Expression ev
= extractSideEffect(sc
, "__tup", e0
, e2x
);
10430 auto iexps
= new Expressions();
10432 for (size_t u
= 0; u
< iexps
.length
; u
++)
10435 Expression e
= (*iexps
)[u
];
10437 Parameter arg
= Parameter
.getNth(tt
.arguments
, u
);
10438 //printf("[%d] iexps.length = %d, ", u, iexps.length);
10439 //printf("e = (%s %s, %s), ", Token.toChars[e.op], e.toChars(), e.type.toChars());
10440 //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
10442 if (!arg ||
!e
.type
.implicitConvTo(arg
.type
))
10444 // expand initializer to tuple
10445 if (expandAliasThisTuples(iexps
, u
) != -1)
10447 if (iexps
.length
<= u
)
10454 e2x
= new TupleExp(e2x
.loc
, e0
, iexps
);
10455 e2x
= e2x
.expressionSemantic(sc
);
10456 if (e2x
.op
== EXP
.error
)
10461 // Do not need to overwrite this.e2
10467 /* Inside constructor, if this is the first assignment of object field,
10468 * rewrite this to initializing the field.
10470 if (exp
.op
== EXP
.assign
10471 && exp
.e1
.checkModifiable(sc
) == Modifiable
.initialization
)
10473 //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars());
10475 exp
= new ConstructExp(exp
.loc
, exp
.e1
, exp
.e2
);
10478 // https://issues.dlang.org/show_bug.cgi?id=13515
10479 // set Index::modifiable flag for complex AA element initialization
10480 if (auto ie1
= exp
.e1
.isIndexExp())
10482 Expression e1x
= ie1
.markSettingAAElem();
10483 if (e1x
.op
== EXP
.error
)
10490 else if (exp
.op
== EXP
.construct
&& exp
.e1
.op
== EXP
.variable
&&
10491 (cast(VarExp
)exp
.e1
).var
.storage_class
& (STC
.out_ | STC
.ref_
))
10493 exp
.memset
= MemorySet
.referenceInit
;
10496 if (exp
.op
== EXP
.assign
) // skip EXP.blit and EXP.construct, which are initializations
10498 exp
.e1
.checkSharedAccess(sc
);
10499 checkUnsafeAccess(sc
, exp
.e1
, false, true);
10502 checkUnsafeAccess(sc
, exp
.e2
, true, true); // Initializer must always be checked
10504 /* If it is an assignment from a 'foreign' type,
10505 * check for operator overloading.
10507 if (exp
.memset
== MemorySet
.referenceInit
)
10509 // If this is an initialization of a reference,
10512 else if (t1
.ty
== Tstruct
)
10516 auto sd
= (cast(TypeStruct
)t1
).sym
;
10518 if (exp
.op
== EXP
.construct
)
10520 Type t2
= e2x
.type
.toBasetype();
10521 if (t2
.ty
== Tstruct
&& sd
== (cast(TypeStruct
)t2
).sym
)
10524 if (sd
.sizeok
!= Sizeok
.done
)
10527 sd
.ctor
= sd
.searchCtor();
10529 // https://issues.dlang.org/show_bug.cgi?id=15661
10530 // Look for the form from last of comma chain.
10531 auto e2y
= lastComma(e2x
);
10533 CallExp ce
= (e2y
.op
== EXP
.call) ?
cast(CallExp
)e2y
: null;
10534 DotVarExp dve
= (ce
&& ce
.e1
.op
== EXP
.dotVariable
)
10535 ?
cast(DotVarExp
)ce
.e1
: null;
10536 if (sd
.ctor
&& ce
&& dve
&& dve
.var
.isCtorDeclaration() &&
10537 // https://issues.dlang.org/show_bug.cgi?id=19389
10538 dve
.e1
.op
!= EXP
.dotVariable
&&
10539 e2y
.type
.implicitConvTo(t1
))
10541 /* Look for form of constructor call which is:
10542 * __ctmp.ctor(arguments...)
10545 /* Before calling the constructor, initialize
10546 * variable with a bit copy of the default
10549 Expression einit
= getInitExp(sd
, exp
.loc
, sc
, t1
);
10550 if (einit
.op
== EXP
.error
)
10556 auto ae
= new BlitExp(exp
.loc
, exp
.e1
, einit
);
10557 ae
.type
= e1x
.type
;
10559 /* Replace __ctmp being constructed with e1.
10560 * We need to copy constructor call expression,
10561 * because it may be used in other place.
10563 auto dvx
= cast(DotVarExp
)dve
.copy();
10565 auto cx
= cast(CallExp
)ce
.copy();
10567 if (checkConstructorEscape(sc
, cx
, false))
10571 Expression
.extractLast(e2x
, e0
);
10573 auto e
= Expression
.combine(e0
, ae
, cx
);
10574 e
= e
.expressionSemantic(sc
);
10578 // https://issues.dlang.org/show_bug.cgi?id=21586
10579 // Rewrite CondExp or e1 will miss direct construction, e.g.
10580 // e1 = a ? S(1) : ...; -> AST: e1 = a ? (S(0)).this(1) : ...;
10581 // a temporary created and an extra destructor call.
10582 // AST will be rewritten to:
10583 // a ? e1 = 0, e1.this(1) : ...; -> blitting plus construction
10584 if (e2x
.op
== EXP
.question
)
10587 * a ? e1 = b : e1 = c;
10589 CondExp econd
= cast(CondExp
)e2x
;
10590 Expression ea1
= new ConstructExp(econd
.e1
.loc
, e1x
, econd
.e1
);
10591 Expression ea2
= new ConstructExp(econd
.e2
.loc
, e1x
, econd
.e2
);
10592 Expression e
= new CondExp(exp
.loc
, econd
.econd
, ea1
, ea2
);
10593 result
= e
.expressionSemantic(sc
);
10596 if (sd
.postblit || sd
.hasCopyCtor
)
10598 /* We have a copy constructor for this
10601 if (e2x
.isLvalue())
10603 if (sd
.hasCopyCtor
)
10606 * e1 = init, e1.copyCtor(e2);
10608 Expression einit
= new BlitExp(exp
.loc
, exp
.e1
, getInitExp(sd
, exp
.loc
, sc
, t1
));
10609 einit
.type
= e1x
.type
;
10612 e
= new DotIdExp(exp
.loc
, e1x
, Id
.ctor
);
10613 e
= new CallExp(exp
.loc
, e
, e2x
);
10614 e
= new CommaExp(exp
.loc
, einit
, e
);
10616 //printf("e: %s\n", e.toChars());
10618 result
= e
.expressionSemantic(sc
);
10623 if (!e2x
.type
.implicitConvTo(e1x
.type
))
10625 error(exp
.loc
, "conversion error from `%s` to `%s`",
10626 e2x
.type
.toChars(), e1x
.type
.toChars());
10631 * (e1 = e2).postblit();
10633 * Blit assignment e1 = e2 returns a reference to the original e1,
10634 * then call the postblit on it.
10636 Expression e
= e1x
.copy();
10637 e
.type
= e
.type
.mutableOf();
10638 if (e
.type
.isShared
&& !sd
.type
.isShared
)
10639 e
.type
= e
.type
.unSharedOf();
10640 e
= new BlitExp(exp
.loc
, e
, e2x
);
10641 e
= new DotVarExp(exp
.loc
, e
, sd
.postblit
, false);
10642 e
= new CallExp(exp
.loc
, e
);
10643 result
= e
.expressionSemantic(sc
);
10649 /* The struct value returned from the function is transferred
10650 * so should not call the destructor on it.
10652 e2x
= valueNoDtor(e2x
);
10656 // https://issues.dlang.org/show_bug.cgi?id=19251
10657 // if e2 cannot be converted to e1.type, maybe there is an alias this
10658 if (!e2x
.implicitConvTo(t1
))
10660 AggregateDeclaration ad2
= isAggregate(e2x
.type
);
10661 if (ad2
&& ad2
.aliasthis
&& !isRecursiveAliasThis(exp
.att2
, exp
.e2
.type
))
10663 /* Rewrite (e1 op e2) as:
10664 * (e1 op e2.aliasthis)
10666 exp
.e2
= new DotIdExp(exp
.e2
.loc
, exp
.e2
, ad2
.aliasthis
.ident
);
10667 result
= exp
.expressionSemantic(sc
);
10672 else if (!e2x
.implicitConvTo(t1
))
10675 if (sd
.sizeok
!= Sizeok
.done
)
10678 sd
.ctor
= sd
.searchCtor();
10682 /* Look for implicit constructor call
10684 * e1 = init, e1.ctor(e2)
10687 /* Fix Issue 5153 : https://issues.dlang.org/show_bug.cgi?id=5153
10688 * Using `new` to initialize a struct object is a common mistake, but
10689 * the error message from the compiler is not very helpful in that
10690 * case. If exp.e2 is a NewExp and the type of new is the same as
10691 * the type as exp.e1 (struct in this case), then we know for sure
10692 * that the user wants to instantiate a struct. This is done to avoid
10693 * issuing an error when the user actually wants to call a constructor
10694 * which receives a class object.
10696 * Foo f = new Foo2(0); is a valid expression if Foo has a constructor
10697 * which receives an instance of a Foo2 class
10699 if (exp
.e2
.op
== EXP
.new_
)
10701 auto newExp
= cast(NewExp
)(exp
.e2
);
10702 if (newExp
.newtype
&& newExp
.newtype
== t1
)
10704 error(exp
.loc
, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
10705 newExp
.toChars(), newExp
.type
.toChars(), t1
.toChars());
10706 errorSupplemental(exp
.loc
, "Perhaps remove the `new` keyword?");
10711 Expression einit
= new BlitExp(exp
.loc
, e1x
, getInitExp(sd
, exp
.loc
, sc
, t1
));
10712 einit
.type
= e1x
.type
;
10715 e
= new DotIdExp(exp
.loc
, e1x
, Id
.ctor
);
10716 e
= new CallExp(exp
.loc
, e
, e2x
);
10717 e
= new CommaExp(exp
.loc
, einit
, e
);
10718 e
= e
.expressionSemantic(sc
);
10722 if (search_function(sd
, Id
.call))
10724 /* Look for static opCall
10725 * https://issues.dlang.org/show_bug.cgi?id=2702
10727 * e1 = typeof(e1).opCall(arguments)
10729 e2x
= typeDotIdExp(e2x
.loc
, e1x
.type
, Id
.call);
10730 e2x
= new CallExp(exp
.loc
, e2x
, exp
.e2
);
10732 e2x
= e2x
.expressionSemantic(sc
);
10733 e2x
= resolveProperties(sc
, e2x
);
10734 if (e2x
.op
== EXP
.error
)
10739 if (e2x
.checkValue() || e2x
.checkSharedAccess(sc
))
10743 else // https://issues.dlang.org/show_bug.cgi?id=11355
10745 AggregateDeclaration ad2
= isAggregate(e2x
.type
);
10746 if (ad2
&& ad2
.aliasthis
&& !isRecursiveAliasThis(exp
.att2
, exp
.e2
.type
))
10748 /* Rewrite (e1 op e2) as:
10749 * (e1 op e2.aliasthis)
10751 exp
.e2
= new DotIdExp(exp
.e2
.loc
, exp
.e2
, ad2
.aliasthis
.ident
);
10752 result
= exp
.expressionSemantic(sc
);
10757 else if (exp
.op
== EXP
.assign
)
10759 if (e1x
.op
== EXP
.index
&& (cast(IndexExp
)e1x
).e1
.type
.toBasetype().ty
== Taarray
)
10765 * ref __aatmp = aa;
10766 * ref __aakey = key;
10767 * ref __aaval = e2;
10768 * (__aakey in __aatmp
10769 * ? __aatmp[__aakey].opAssign(__aaval)
10770 * : ConstructExp(__aatmp[__aakey], __aaval));
10772 // ensure we keep the expr modifiable
10773 Expression esetting
= (cast(IndexExp
)e1x
).markSettingAAElem();
10774 if (esetting
.op
== EXP
.error
)
10779 assert(esetting
.op
== EXP
.index
);
10780 IndexExp ie
= cast(IndexExp
) esetting
;
10781 Type t2
= e2x
.type
.toBasetype();
10783 Expression e0
= null;
10784 Expression ea
= extractSideEffect(sc
, "__aatmp", e0
, ie
.e1
);
10785 Expression ek
= extractSideEffect(sc
, "__aakey", e0
, ie
.e2
);
10786 Expression ev
= extractSideEffect(sc
, "__aaval", e0
, e2x
);
10788 AssignExp ae
= cast(AssignExp
)exp
.copy();
10789 ae
.e1
= new IndexExp(exp
.loc
, ea
, ek
);
10790 ae
.e1
= ae
.e1
.expressionSemantic(sc
);
10791 ae
.e1
= ae
.e1
.optimize(WANTvalue
);
10793 Expression e
= ae
.op_overload(sc
);
10796 Expression ey
= null;
10797 if (t2
.ty
== Tstruct
&& sd
== t2
.toDsymbol(sc
))
10801 else if (!ev
.implicitConvTo(ie
.type
) && sd
.ctor
)
10803 // Look for implicit constructor call
10804 // Rewrite as S().ctor(e2)
10805 ey
= new StructLiteralExp(exp
.loc
, sd
, null);
10806 ey
= new DotIdExp(exp
.loc
, ey
, Id
.ctor
);
10807 ey
= new CallExp(exp
.loc
, ey
, ev
);
10808 ey
= ey
.trySemantic(sc
);
10813 ex
= new IndexExp(exp
.loc
, ea
, ek
);
10814 ex
= ex
.expressionSemantic(sc
);
10815 ex
= ex
.modifiableLvalue(sc
); // allocate new slot
10816 ex
= ex
.optimize(WANTvalue
);
10818 ey
= new ConstructExp(exp
.loc
, ex
, ey
);
10819 ey
= ey
.expressionSemantic(sc
);
10820 if (ey
.op
== EXP
.error
)
10827 // https://issues.dlang.org/show_bug.cgi?id=14144
10828 // The whole expression should have the common type
10829 // of opAssign() return and assigned AA entry.
10830 // Even if there's no common type, expression should be typed as void.
10831 if (!typeMerge(sc
, EXP
.question
, ex
, ey
))
10833 ex
= new CastExp(ex
.loc
, ex
, Type
.tvoid
);
10834 ey
= new CastExp(ey
.loc
, ey
, Type
.tvoid
);
10836 e
= new CondExp(exp
.loc
, new InExp(exp
.loc
, ek
, ea
), ex
, ey
);
10838 e
= Expression
.combine(e0
, e
);
10839 e
= e
.expressionSemantic(sc
);
10846 Expression e
= exp
.op_overload(sc
);
10855 assert(exp
.op
== EXP
.blit
);
10857 if (e2x
.checkValue())
10863 else if (t1
.ty
== Tclass
)
10865 // Disallow assignment operator overloads for same type
10866 if (exp
.op
== EXP
.assign
&& !exp
.e2
.implicitConvTo(exp
.e1
.type
))
10868 Expression e
= exp
.op_overload(sc
);
10875 if (exp
.e2
.checkValue())
10878 else if (t1
.ty
== Tsarray
)
10880 // SliceExp cannot have static array type without context inference.
10881 assert(exp
.e1
.op
!= EXP
.slice
);
10882 Expression e1x
= exp
.e1
;
10883 Expression e2x
= exp
.e2
;
10885 /* C strings come through as static arrays. May need to adjust the size of the
10886 * string to match the size of e1.
10888 Type t2
= e2x
.type
.toBasetype();
10889 if (sc
.flags
& SCOPE
.Cfile
&& e2x
.isStringExp() && t2
.isTypeSArray())
10891 uinteger_t dim1
= t1
.isTypeSArray().dim
.toInteger();
10892 uinteger_t dim2
= t2
.isTypeSArray().dim
.toInteger();
10893 if (dim1
+ 1 == dim2 || dim2
< dim1
)
10895 auto tsa2
= t2
.isTypeSArray();
10896 auto newt
= tsa2
.next
.sarrayOf(dim1
).immutableOf();
10897 e2x
= castTo(e2x
, sc
, newt
);
10902 if (e2x
.implicitConvTo(e1x
.type
))
10904 if (exp
.op
!= EXP
.blit
&& (e2x
.op
== EXP
.slice
&& (cast(UnaExp
)e2x
).e1
.isLvalue() || e2x
.op
== EXP
.cast_
&& (cast(UnaExp
)e2x
).e1
.isLvalue() || e2x
.op
!= EXP
.slice
&& e2x
.isLvalue()))
10906 if (t1
.checkPostblit(e1x
.loc
, sc
))
10910 // e2 matches to t1 because of the implicit length match, so
10911 if (isUnaArrayOp(e2x
.op
) ||
isBinArrayOp(e2x
.op
))
10913 // convert e1 to e1[]
10914 // e.g. e1[] = a[] + b[];
10915 auto sle
= new SliceExp(e1x
.loc
, e1x
, null, null);
10916 sle
.arrayop
= true;
10917 e1x
= sle
.expressionSemantic(sc
);
10921 // convert e2 to t1 later
10922 // e.g. e1 = [1, 2, 3];
10927 if (e2x
.implicitConvTo(t1
.nextOf().arrayOf()) > MATCH
.nomatch
)
10929 uinteger_t dim1
= (cast(TypeSArray
)t1
).dim
.toInteger();
10930 uinteger_t dim2
= dim1
;
10931 if (auto ale
= e2x
.isArrayLiteralExp())
10933 dim2
= ale
.elements ? ale
.elements
.length
: 0;
10935 else if (auto se
= e2x
.isSliceExp())
10937 Type tx
= toStaticArrayType(se
);
10939 dim2
= (cast(TypeSArray
)tx
).dim
.toInteger();
10943 error(exp
.loc
, "mismatched array lengths, %d and %d", cast(int)dim1
, cast(int)dim2
);
10948 // May be block or element-wise assignment, so
10949 // convert e1 to e1[]
10950 if (exp
.op
!= EXP
.assign
)
10952 // If multidimensional static array, treat as one large array
10954 // Find the appropriate array type depending on the assignment, e.g.
10955 // int[3] = int => int[3]
10956 // int[3][2] = int => int[6]
10957 // int[3][2] = int[] => int[3][2]
10958 // int[3][2][4] + int => int[24]
10959 // int[3][2][4] + int[] => int[3][8]
10960 ulong dim
= t1
.isTypeSArray().dim
.toUInteger();
10961 auto type
= t1
.nextOf();
10963 for (TypeSArray tsa
; (tsa
= type
.isTypeSArray()) !is null; )
10965 import core
.checkedint
: mulu
;
10967 // Accumulate skipped dimensions
10968 bool overflow
= false;
10969 dim
= mulu(dim
, tsa
.dim
.toUInteger(), overflow
);
10970 if (overflow || dim
>= uint.max
)
10972 // dym exceeds maximum array size
10973 error(exp
.loc
, "static array `%s` size overflowed to %llu",
10974 e1x
.type
.toChars(), cast(ulong) dim
);
10978 // Move to the element type
10979 type
= tsa
.nextOf().toBasetype();
10981 // Rewrite ex1 as a static array if a matching type was found
10982 if (e2x
.implicitConvTo(type
) > MATCH
.nomatch
)
10984 e1x
.type
= type
.sarrayOf(dim
);
10989 auto sle
= new SliceExp(e1x
.loc
, e1x
, null, null);
10990 sle
.arrayop
= true;
10991 e1x
= sle
.expressionSemantic(sc
);
10993 if (e1x
.op
== EXP
.error
)
10994 return setResult(e1x
);
10995 if (e2x
.op
== EXP
.error
)
10996 return setResult(e2x
);
11000 t1
= e1x
.type
.toBasetype();
11002 /* Check the mutability of e1.
11004 if (auto ale
= exp
.e1
.isArrayLengthExp())
11006 // e1 is not an lvalue, but we let code generator handle it
11008 auto ale1x
= ale
.e1
.modifiableLvalueImpl(sc
, exp
.e1
);
11009 if (ale1x
.op
== EXP
.error
)
11010 return setResult(ale1x
);
11013 Type tn
= ale
.e1
.type
.toBasetype().nextOf();
11014 checkDefCtor(ale
.loc
, tn
);
11016 Identifier hook
= global
.params
.tracegc ? Id
._d_arraysetlengthTTrace
: Id
._d_arraysetlengthT
;
11017 if (!verifyHookExist(exp
.loc
, *sc
, Id
._d_arraysetlengthTImpl
, "resizing arrays"))
11020 exp
.e2
= exp
.e2
.expressionSemantic(sc
);
11021 auto lc
= lastComma(exp
.e2
);
11022 lc
= lc
.optimize(WANTvalue
);
11023 // use slice expression when arr.length = 0 to avoid runtime call
11024 if(lc
.op
== EXP
.int64
&& lc
.toInteger() == 0)
11026 Expression se
= new SliceExp(ale
.loc
, ale
.e1
, lc
, lc
);
11027 Expression as
= new AssignExp(ale
.loc
, ale
.e1
, se
);
11028 as
= as
.expressionSemantic(sc
);
11029 auto res
= Expression
.combine(as
, exp
.e2
);
11030 res
.type
= ale
.type
;
11031 return setResult(res
);
11034 if (!sc
.needsCodegen()) // if compile time creature only
11036 exp
.type
= Type
.tsize_t
;
11037 return setResult(exp
);
11040 // Lower to object._d_arraysetlengthTImpl!(typeof(e1))._d_arraysetlengthT{,Trace}(e1, e2)
11041 Expression id
= new IdentifierExp(ale
.loc
, Id
.empty
);
11042 id
= new DotIdExp(ale
.loc
, id
, Id
.object
);
11043 auto tiargs
= new Objects();
11044 tiargs
.push(ale
.e1
.type
);
11045 id
= new DotTemplateInstanceExp(ale
.loc
, id
, Id
._d_arraysetlengthTImpl
, tiargs
);
11046 id
= new DotIdExp(ale
.loc
, id
, hook
);
11047 id
= id
.expressionSemantic(sc
);
11049 auto arguments
= new Expressions();
11050 arguments
.reserve(5);
11051 if (global
.params
.tracegc
)
11053 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ? sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
11054 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
11055 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
11056 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
11058 arguments
.push(ale
.e1
);
11059 arguments
.push(exp
.e2
);
11061 Expression ce
= new CallExp(ale
.loc
, id
, arguments
).expressionSemantic(sc
);
11062 auto res
= new LoweredAssignExp(exp
, ce
);
11063 // if (global.params.verbose)
11064 // message("lowered %s =>\n %s", exp.toChars(), res.toChars());
11065 res
.type
= Type
.tsize_t
;
11066 return setResult(res
);
11068 else if (auto se
= exp
.e1
.isSliceExp())
11070 Type tn
= se
.type
.nextOf();
11071 const fun
= sc
.func
;
11072 if (exp
.op
== EXP
.assign
&& !tn
.isMutable() &&
11073 // allow modifiation in module ctor, see
11074 // https://issues.dlang.org/show_bug.cgi?id=9884
11075 (!fun ||
(fun
&& !fun
.isStaticCtorDeclaration())))
11077 error(exp
.loc
, "slice `%s` is not mutable", se
.toChars());
11081 if (exp
.op
== EXP
.assign
&& !tn
.baseElemOf().isAssignable())
11083 error(exp
.loc
, "slice `%s` is not mutable, struct `%s` has immutable members",
11084 exp
.e1
.toChars(), tn
.baseElemOf().toChars());
11085 result
= ErrorExp
.get();
11089 // For conditional operator, both branches need conversion.
11090 while (se
.e1
.op
== EXP
.slice
)
11091 se
= cast(SliceExp
)se
.e1
;
11092 if (se
.e1
.op
== EXP
.question
&& se
.e1
.type
.toBasetype().ty
== Tsarray
)
11094 se
.e1
= se
.e1
.modifiableLvalueImpl(sc
, exp
.e1
);
11095 if (se
.e1
.op
== EXP
.error
)
11096 return setResult(se
.e1
);
11101 if (t1
.ty
== Tsarray
&& exp
.op
== EXP
.assign
)
11103 Type tn
= exp
.e1
.type
.nextOf();
11104 if (tn
&& !tn
.baseElemOf().isAssignable())
11106 error(exp
.loc
, "array `%s` is not mutable, struct `%s` has immutable members",
11107 exp
.e1
.toChars(), tn
.baseElemOf().toChars());
11108 result
= ErrorExp
.get();
11113 Expression e1x
= exp
.e1
;
11115 // Try to do a decent error message with the expression
11116 // before it gets constant folded
11117 if (exp
.op
== EXP
.assign
)
11118 e1x
= e1x
.modifiableLvalueImpl(sc
, e1old
);
11120 e1x
= e1x
.optimize(WANTvalue
, /*keepLvalue*/ true);
11122 if (e1x
.op
== EXP
.error
)
11130 /* Tweak e2 based on the type of e1.
11132 Expression e2x
= exp
.e2
;
11133 Type t2
= e2x
.type
.toBasetype();
11135 // If it is a array, get the element type. Note that it may be
11136 // multi-dimensional.
11138 while (telem
.ty
== Tarray
)
11139 telem
= telem
.nextOf();
11141 if (exp
.e1
.op
== EXP
.slice
&& t1
.nextOf() &&
11142 (telem
.ty
!= Tvoid || e2x
.op
== EXP
.null_
) &&
11143 e2x
.implicitConvTo(t1
.nextOf()))
11145 // Check for block assignment. If it is of type void[], void[][], etc,
11146 // '= null' is the only allowable block assignment (Bug 7493)
11147 exp
.memset
= MemorySet
.blockAssign
; // make it easy for back end to tell what this is
11148 e2x
= e2x
.implicitCastTo(sc
, t1
.nextOf());
11149 if (exp
.op
!= EXP
.blit
&& e2x
.isLvalue() && t1
.nextOf
.checkPostblit(exp
.e1
.loc
, sc
))
11152 else if (exp
.e1
.op
== EXP
.slice
&&
11153 (t2
.ty
== Tarray || t2
.ty
== Tsarray
) &&
11154 t2
.nextOf().implicitConvTo(t1
.nextOf()))
11156 // Check element-wise assignment.
11158 /* If assigned elements number is known at compile time,
11159 * check the mismatch.
11161 SliceExp se1
= cast(SliceExp
)exp
.e1
;
11162 TypeSArray tsa1
= cast(TypeSArray
)toStaticArrayType(se1
);
11163 TypeSArray tsa2
= null;
11164 if (auto ale
= e2x
.isArrayLiteralExp())
11165 tsa2
= cast(TypeSArray
)t2
.nextOf().sarrayOf(ale
.elements
.length
);
11166 else if (auto se
= e2x
.isSliceExp())
11167 tsa2
= cast(TypeSArray
)toStaticArrayType(se
);
11169 tsa2
= t2
.isTypeSArray();
11173 uinteger_t dim1
= tsa1
.dim
.toInteger();
11174 uinteger_t dim2
= tsa2
.dim
.toInteger();
11177 error(exp
.loc
, "mismatched array lengths %d and %d for assignment `%s`", cast(int)dim1
, cast(int)dim2
, exp
.toChars());
11182 if (exp
.op
!= EXP
.blit
&&
11183 (e2x
.op
== EXP
.slice
&& (cast(UnaExp
)e2x
).e1
.isLvalue() ||
11184 e2x
.op
== EXP
.cast_
&& (cast(UnaExp
)e2x
).e1
.isLvalue() ||
11185 e2x
.op
!= EXP
.slice
&& e2x
.isLvalue()))
11187 if (t1
.nextOf().checkPostblit(exp
.e1
.loc
, sc
))
11191 Type t2n
= t2
.nextOf();
11192 Type t1n
= t1
.nextOf();
11194 if (t2n
.equivalent(t1n
) ||
11195 t1n
.isBaseOf(t2n
, &offset
) && offset
== 0)
11197 /* Allow copy of distinct qualifier elements.
11199 * char[] dst; const(char)[] src;
11202 * class C {} class D : C {}
11206 if (isArrayOpValid(e2x
))
11208 // Don't add CastExp to keep AST for array operations
11210 e2x
.type
= exp
.e1
.type
.constOf();
11213 e2x
= e2x
.castTo(sc
, exp
.e1
.type
.constOf());
11217 /* https://issues.dlang.org/show_bug.cgi?id=15778
11218 * A string literal has an array type of immutable
11219 * elements by default, and normally it cannot be convertible to
11220 * array type of mutable elements. But for element-wise assignment,
11221 * elements need to be const at best. So we should give a chance
11222 * to change code unit size for polysemous string literal.
11224 if (e2x
.op
== EXP
.string_
)
11225 e2x
= e2x
.implicitCastTo(sc
, exp
.e1
.type
.constOf());
11227 e2x
= e2x
.implicitCastTo(sc
, exp
.e1
.type
);
11229 if (t1n
.toBasetype
.ty
== Tvoid
&& t2n
.toBasetype
.ty
== Tvoid
)
11231 if (sc
.setUnsafe(false, exp
.loc
, "cannot copy `void[]` to `void[]` in `@safe` code"))
11237 if (exp
.op
== EXP
.blit
)
11238 e2x
= e2x
.castTo(sc
, exp
.e1
.type
);
11241 e2x
= e2x
.implicitCastTo(sc
, exp
.e1
.type
);
11243 // Fix Issue 13435: https://issues.dlang.org/show_bug.cgi?id=13435
11245 // If the implicit cast has failed and the assign expression is
11246 // the initialization of a struct member field
11247 if (e2x
.op
== EXP
.error
&& exp
.op
== EXP
.construct
&& t1
.ty
== Tstruct
)
11249 scope sd
= (cast(TypeStruct
)t1
).sym
;
11250 Dsymbol opAssign
= search_function(sd
, Id
.assign
);
11252 // and the struct defines an opAssign
11255 // offer more information about the cause of the problem
11256 errorSupplemental(exp
.loc
,
11257 "`%s` is the first assignment of `%s` therefore it represents its initialization",
11258 exp
.toChars(), exp
.e1
.toChars());
11259 errorSupplemental(exp
.loc
,
11260 "`opAssign` methods are not used for initialization, but for subsequent assignments");
11265 if (e2x
.op
== EXP
.error
)
11271 t2
= exp
.e2
.type
.toBasetype();
11273 /* Look for array operations
11275 if ((t2
.ty
== Tarray || t2
.ty
== Tsarray
) && isArrayOpValid(exp
.e2
))
11277 // Look for valid array operations
11278 if (exp
.memset
!= MemorySet
.blockAssign
&&
11279 exp
.e1
.op
== EXP
.slice
&&
11280 (isUnaArrayOp(exp
.e2
.op
) ||
isBinArrayOp(exp
.e2
.op
)))
11282 exp
.type
= exp
.e1
.type
;
11283 if (exp
.op
== EXP
.construct
) // https://issues.dlang.org/show_bug.cgi?id=10282
11284 // tweak mutability of e1 element
11285 exp
.e1
.type
= exp
.e1
.type
.nextOf().mutableOf().arrayOf();
11286 result
= arrayOp(exp
, sc
);
11290 // Drop invalid array operations in e2
11291 // d = a[] + b[], d = (a[] + b[])[0..2], etc
11292 if (checkNonAssignmentArrayOp(exp
.e2
, exp
.memset
!= MemorySet
.blockAssign
&& exp
.op
== EXP
.assign
))
11295 // Remains valid array assignments
11296 // d = d[], d = [1,2,3], etc
11299 /* Don't allow assignment to classes that were allocated on the stack with:
11300 * scope Class c = new Class();
11302 if (exp
.e1
.op
== EXP
.variable
&& exp
.op
== EXP
.assign
)
11304 VarExp ve
= cast(VarExp
)exp
.e1
;
11305 VarDeclaration vd
= ve
.var
.isVarDeclaration();
11306 if (vd
&& vd
.onstack
)
11308 assert(t1
.ty
== Tclass
);
11309 error(exp
.loc
, "cannot rebind scope variables");
11313 if (exp
.e1
.op
== EXP
.variable
&& (cast(VarExp
)exp
.e1
).var
.ident
== Id
.ctfe
)
11315 error(exp
.loc
, "cannot modify compiler-generated variable `__ctfe`");
11318 exp
.type
= exp
.e1
.type
;
11320 auto assignElem
= exp
.e2
;
11321 auto res
= exp
.op
== EXP
.assign ? exp
.reorderSettingAAElem(sc
) : exp
;
11322 /* https://issues.dlang.org/show_bug.cgi?id=22366
11324 * `reorderSettingAAElem` creates a tree of comma expressions, however,
11325 * `checkAssignExp` expects only AssignExps.
11327 if (res
== exp
) // no `AA[k] = v` rewrite was performed
11328 checkAssignEscape(sc
, res
, false, false);
11330 checkNewEscape(sc
, assignElem
, false); // assigning to AA puts it on heap
11332 if (auto ae
= res
.isConstructExp())
11334 Type t1b
= ae
.e1
.type
.toBasetype();
11335 if (t1b
.ty
!= Tsarray
&& t1b
.ty
!= Tarray
)
11336 return setResult(res
);
11338 // only non-trivial array constructions may need to be lowered (non-POD elements basically)
11339 Type t1e
= t1b
.nextOf();
11340 TypeStruct ts
= t1e
.baseElemOf().isTypeStruct();
11341 if (!ts ||
(!ts
.sym
.postblit
&& !ts
.sym
.hasCopyCtor
&& !ts
.sym
.dtor
))
11342 return setResult(res
);
11344 // don't lower ref-constructions etc.
11345 if (!(t1b
.ty
== Tsarray || ae
.e1
.isSliceExp
) ||
11346 (ae
.e1
.isVarExp
&& ae
.e1
.isVarExp
.var
.isVarDeclaration
.isReference
))
11347 return setResult(res
);
11349 // Construction from an equivalent other array?
11350 // Only lower with lvalue RHS elements; let the glue layer move rvalue elements.
11351 Type t2b
= ae
.e2
.type
.toBasetype();
11352 // skip over a (possibly implicit) cast of a static array RHS to a slice
11353 Expression rhs
= ae
.e2
;
11354 Type rhsType
= t2b
;
11355 if (t2b
.ty
== Tarray
)
11357 if (auto ce
= rhs
.isCastExp())
11359 auto ct
= ce
.e1
.type
.toBasetype();
11360 if (ct
.ty
== Tsarray
)
11368 if (!sc
.needsCodegen()) // interpreter can handle these
11369 return setResult(res
);
11371 const lowerToArrayCtor
=
11372 ( (rhsType
.ty
== Tarray
&& !rhs
.isArrayLiteralExp
) ||
11373 (rhsType
.ty
== Tsarray
&& rhs
.isLvalue
) ) &&
11374 t1e
.equivalent(t2b
.nextOf
);
11376 // Construction from a single element?
11377 // If the RHS is an rvalue, then we'll need to make a temporary for it (copied multiple times).
11378 const lowerToArraySetCtor
= !lowerToArrayCtor
&& t1e
.equivalent(t2b
);
11380 if (lowerToArrayCtor || lowerToArraySetCtor
)
11382 auto func
= lowerToArrayCtor ? Id
._d_arrayctor
: Id
._d_arraysetctor
;
11383 const other
= lowerToArrayCtor ?
"other array" : "value";
11384 if (!verifyHookExist(exp
.loc
, *sc
, func
, "construct array with " ~ other
, Id
.object
))
11387 // Lower to object._d_array{,set}ctor(e1, e2)
11388 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
11389 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
11390 id
= new DotIdExp(exp
.loc
, id
, func
);
11392 auto arguments
= new Expressions();
11393 arguments
.push(new CastExp(ae
.loc
, ae
.e1
, t1e
.arrayOf
).expressionSemantic(sc
));
11394 if (lowerToArrayCtor
)
11396 arguments
.push(new CastExp(ae
.loc
, rhs
, t2b
.nextOf
.arrayOf
).expressionSemantic(sc
));
11397 Expression ce
= new CallExp(exp
.loc
, id
, arguments
);
11398 res
= ce
.expressionSemantic(sc
);
11403 // promote an rvalue RHS element to a temporary, it's passed by ref to _d_arraysetctor
11404 if (!ae
.e2
.isLvalue
)
11406 auto vd
= copyToTemp(STC
.scope_
, "__setctor", ae
.e2
);
11407 e0
= new DeclarationExp(vd
.loc
, vd
).expressionSemantic(sc
);
11408 arguments
.push(new VarExp(vd
.loc
, vd
).expressionSemantic(sc
));
11411 arguments
.push(ae
.e2
);
11413 Expression ce
= new CallExp(exp
.loc
, id
, arguments
);
11414 res
= Expression
.combine(e0
, ce
).expressionSemantic(sc
);
11417 if (global
.params
.v
.verbose
)
11418 message("lowered %s =>\n %s", exp
.toChars(), res
.toChars());
11421 else if (auto ae
= res
.isAssignExp())
11422 res
= lowerArrayAssign(ae
);
11423 else if (auto ce
= res
.isCommaExp())
11425 if (auto ae1
= ce
.e1
.isAssignExp())
11426 ce
.e1
= lowerArrayAssign(ae1
, true);
11427 if (auto ae2
= ce
.e2
.isAssignExp())
11428 ce
.e2
= lowerArrayAssign(ae2
, true);
11431 return setResult(res
);
11434 /***************************************
11435 * Lower AssignExp to `_d_array{setassign,assign_l,assign_r}` if needed.
11438 * ae = the AssignExp to be lowered
11439 * fromCommaExp = indicates whether `ae` is part of a CommaExp or not,
11440 * so no unnecessary temporay variable is created.
11442 * a CommaExp contiaining call a to `_d_array{setassign,assign_l,assign_r}`
11443 * if needed or `ae` otherwise
11445 private Expression
lowerArrayAssign(AssignExp ae
, bool fromCommaExp
= false)
11447 Type t1b
= ae
.e1
.type
.toBasetype();
11448 if (t1b
.ty
!= Tsarray
&& t1b
.ty
!= Tarray
)
11451 const isArrayAssign
= (ae
.e1
.isSliceExp() || ae
.e1
.type
.ty
== Tsarray
) &&
11452 (ae
.e2
.type
.ty
== Tsarray || ae
.e2
.type
.ty
== Tarray
) &&
11453 (ae
.e1
.type
.nextOf() && ae
.e2
.type
.nextOf() && ae
.e1
.type
.nextOf
.mutableOf
.equals(ae
.e2
.type
.nextOf
.mutableOf()));
11455 const isArraySetAssign
= (ae
.e1
.isSliceExp() || ae
.e1
.type
.ty
== Tsarray
) &&
11456 (ae
.e1
.type
.nextOf() && ae
.e2
.type
.implicitConvTo(ae
.e1
.type
.nextOf()));
11458 if (!isArrayAssign
&& !isArraySetAssign
)
11461 const ts
= t1b
.nextOf().baseElemOf().isTypeStruct();
11462 if (!ts ||
(!ts
.sym
.postblit
&& !ts
.sym
.dtor
))
11466 Identifier func
= isArraySetAssign ? Id
._d_arraysetassign
:
11467 ae
.e2
.isLvalue() || ae
.e2
.isSliceExp() ? Id
._d_arrayassign_l
: Id
._d_arrayassign_r
;
11469 // Lower to `.object._d_array{setassign,assign_l,assign_r}(e1, e2)``
11470 Expression id
= new IdentifierExp(ae
.loc
, Id
.empty
);
11471 id
= new DotIdExp(ae
.loc
, id
, Id
.object
);
11472 id
= new DotIdExp(ae
.loc
, id
, func
);
11474 auto arguments
= new Expressions();
11475 arguments
.push(new CastExp(ae
.loc
, ae
.e1
, ae
.e1
.type
.nextOf
.arrayOf
)
11476 .expressionSemantic(sc
));
11478 Expression eValue2
, value2
= ae
.e2
;
11479 if (isArrayAssign
&& value2
.isLvalue())
11480 value2
= new CastExp(ae
.loc
, ae
.e2
, ae
.e2
.type
.nextOf
.arrayOf())
11481 .expressionSemantic(sc
);
11482 else if (!fromCommaExp
&&
11483 (isArrayAssign ||
(isArraySetAssign
&& !value2
.isLvalue())))
11485 // Rvalues from CommaExps were introduced in `visit(AssignExp)`
11486 // and are temporary variables themselves. Rvalues from trivial
11487 // SliceExps are simply passed by reference without any copying.
11489 // `__assigntmp` will be destroyed together with the array `ae.e1`.
11490 // When `ae.e2` is a variadic arg array, it is also `scope`, so
11491 // `__assigntmp` may also be scope.
11492 StorageClass
stc = STC
.nodtor
;
11494 stc |
= STC
.rvalue | STC
.scope_
;
11496 auto vd
= copyToTemp(stc, "__assigntmp", ae
.e2
);
11497 eValue2
= new DeclarationExp(vd
.loc
, vd
).expressionSemantic(sc
);
11498 value2
= new VarExp(vd
.loc
, vd
).expressionSemantic(sc
);
11500 arguments
.push(value2
);
11502 Expression ce
= new CallExp(ae
.loc
, id
, arguments
);
11503 res
= Expression
.combine(eValue2
, ce
).expressionSemantic(sc
);
11505 res
= Expression
.combine(res
, ae
.e1
).expressionSemantic(sc
);
11507 if (global
.params
.v
.verbose
)
11508 message("lowered %s =>\n %s", ae
.toChars(), res
.toChars());
11510 res
= new LoweredAssignExp(ae
, res
);
11511 res
.type
= ae
.type
;
11516 override void visit(PowAssignExp exp
)
11524 Expression e
= exp
.op_overload(sc
);
11531 if (exp
.e1
.checkReadModifyWrite(exp
.op
, exp
.e2
))
11534 assert(exp
.e1
.type
&& exp
.e2
.type
);
11535 if (exp
.e1
.op
== EXP
.slice || exp
.e1
.type
.ty
== Tarray || exp
.e1
.type
.ty
== Tsarray
)
11537 if (checkNonAssignmentArrayOp(exp
.e1
))
11541 if (exp
.e2
.implicitConvTo(exp
.e1
.type
.nextOf()))
11544 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
.nextOf());
11546 else if (Expression ex
= typeCombine(exp
, sc
))
11552 // Check element types are arithmetic
11553 Type tb1
= exp
.e1
.type
.nextOf().toBasetype();
11554 Type tb2
= exp
.e2
.type
.toBasetype();
11555 if (tb2
.ty
== Tarray || tb2
.ty
== Tsarray
)
11556 tb2
= tb2
.nextOf().toBasetype();
11557 if ((tb1
.isintegral() || tb1
.isfloating()) && (tb2
.isintegral() || tb2
.isfloating()))
11559 exp
.type
= exp
.e1
.type
;
11560 result
= arrayOp(exp
, sc
);
11566 exp
.e1
= exp
.e1
.modifiableLvalue(sc
);
11569 if ((exp
.e1
.type
.isintegral() || exp
.e1
.type
.isfloating()) && (exp
.e2
.type
.isintegral() || exp
.e2
.type
.isfloating()))
11571 Expression e0
= null;
11572 e
= exp
.reorderSettingAAElem(sc
);
11573 e
= Expression
.extractLast(e
, e0
);
11576 if (exp
.e1
.op
== EXP
.variable
)
11578 // Rewrite: e1 = e1 ^^ e2
11579 e
= new PowExp(exp
.loc
, exp
.e1
.syntaxCopy(), exp
.e2
);
11580 e
= new AssignExp(exp
.loc
, exp
.e1
, e
);
11584 // Rewrite: ref tmp = e1; tmp = tmp ^^ e2
11585 auto v
= copyToTemp(STC
.ref_
, "__powtmp", exp
.e1
);
11586 auto de = new DeclarationExp(exp
.e1
.loc
, v
);
11587 auto ve
= new VarExp(exp
.e1
.loc
, v
);
11588 e
= new PowExp(exp
.loc
, ve
, exp
.e2
);
11589 e
= new AssignExp(exp
.loc
, new VarExp(exp
.e1
.loc
, v
), e
);
11590 e
= new CommaExp(exp
.loc
, de, e
);
11592 e
= Expression
.combine(e0
, e
);
11593 e
= e
.expressionSemantic(sc
);
11597 result
= exp
.incompatibleTypes();
11600 override void visit(CatAssignExp exp
)
11608 //printf("CatAssignExp::semantic() %s\n", exp.toChars());
11609 Expression e
= exp
.op_overload(sc
);
11616 if (SliceExp se
= exp
.e1
.isSliceExp())
11618 if (se
.e1
.type
.toBasetype().ty
== Tsarray
)
11620 error(exp
.loc
, "cannot append to static array `%s`", se
.e1
.type
.toChars());
11625 exp
.e1
= exp
.e1
.modifiableLvalue(sc
);
11626 if (exp
.e1
.op
== EXP
.error
)
11631 if (exp
.e2
.op
== EXP
.error
)
11637 if (checkNonAssignmentArrayOp(exp
.e2
))
11640 Type tb1
= exp
.e1
.type
.toBasetype();
11641 Type tb1next
= tb1
.nextOf();
11642 Type tb2
= exp
.e2
.type
.toBasetype();
11645 * EXP.concatenateAssign: appending T[] to T[]
11646 * EXP.concatenateElemAssign: appending T to T[]
11647 * EXP.concatenateDcharAssign: appending dchar to T[]
11649 if ((tb1
.ty
== Tarray
) &&
11650 (tb2
.ty
== Tarray || tb2
.ty
== Tsarray
) &&
11651 (exp
.e2
.implicitConvTo(exp
.e1
.type
) ||
11652 (tb2
.nextOf().implicitConvTo(tb1next
) &&
11653 (tb2
.nextOf().size(Loc
.initial
) == tb1next
.size(Loc
.initial
)))))
11655 // EXP.concatenateAssign
11656 assert(exp
.op
== EXP
.concatenateAssign
);
11657 if (tb1next
.checkPostblit(exp
.e1
.loc
, sc
))
11660 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
);
11662 else if ((tb1
.ty
== Tarray
) && exp
.e2
.implicitConvTo(tb1next
))
11664 /* https://issues.dlang.org/show_bug.cgi?id=19782
11666 * If e2 is implicitly convertible to tb1next, the conversion
11667 * might be done through alias this, in which case, e2 needs to
11668 * be modified accordingly (e2 => e2.aliasthis).
11670 if (tb2
.ty
== Tstruct
&& (cast(TypeStruct
)tb2
).implicitConvToThroughAliasThis(tb1next
))
11672 if (tb2
.ty
== Tclass
&& (cast(TypeClass
)tb2
).implicitConvToThroughAliasThis(tb1next
))
11675 if (tb2
.checkPostblit(exp
.e2
.loc
, sc
))
11678 if (checkNewEscape(sc
, exp
.e2
, false))
11681 exp
= new CatElemAssignExp(exp
.loc
, exp
.type
, exp
.e1
, exp
.e2
.castTo(sc
, tb1next
));
11682 exp
.e2
= doCopyOrMove(sc
, exp
.e2
);
11684 else if (tb1
.ty
== Tarray
&&
11685 (tb1next
.ty
== Tchar || tb1next
.ty
== Twchar
) &&
11686 exp
.e2
.type
.ty
!= tb1next
.ty
&&
11687 exp
.e2
.implicitConvTo(Type
.tdchar
))
11689 // Append dchar to char[] or wchar[]
11690 exp
= new CatDcharAssignExp(exp
.loc
, exp
.type
, exp
.e1
, exp
.e2
.castTo(sc
, Type
.tdchar
));
11692 /* Do not allow appending wchar to char[] because if wchar happens
11693 * to be a surrogate pair, nothing good can result.
11698 // Try alias this on first operand
11699 static Expression
tryAliasThisForLhs(BinAssignExp exp
, Scope
* sc
)
11701 AggregateDeclaration ad1
= isAggregate(exp
.e1
.type
);
11702 if (!ad1 ||
!ad1
.aliasthis
)
11705 /* Rewrite (e1 op e2) as:
11706 * (e1.aliasthis op e2)
11708 if (isRecursiveAliasThis(exp
.att1
, exp
.e1
.type
))
11710 //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
11711 Expression e1
= new DotIdExp(exp
.loc
, exp
.e1
, ad1
.aliasthis
.ident
);
11712 BinExp be
= cast(BinExp
)exp
.copy();
11714 return be
.trySemantic(sc
);
11717 // Try alias this on second operand
11718 static Expression
tryAliasThisForRhs(BinAssignExp exp
, Scope
* sc
)
11720 AggregateDeclaration ad2
= isAggregate(exp
.e2
.type
);
11721 if (!ad2 ||
!ad2
.aliasthis
)
11723 /* Rewrite (e1 op e2) as:
11724 * (e1 op e2.aliasthis)
11726 if (isRecursiveAliasThis(exp
.att2
, exp
.e2
.type
))
11728 //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
11729 Expression e2
= new DotIdExp(exp
.loc
, exp
.e2
, ad2
.aliasthis
.ident
);
11730 BinExp be
= cast(BinExp
)exp
.copy();
11732 return be
.trySemantic(sc
);
11736 result
= tryAliasThisForLhs(exp
, sc
);
11740 result
= tryAliasThisForRhs(exp
, sc
);
11744 error(exp
.loc
, "cannot append type `%s` to type `%s`", tb2
.toChars(), tb1
.toChars());
11748 if (exp
.e2
.checkValue() || exp
.e2
.checkSharedAccess(sc
))
11751 exp
.type
= exp
.e1
.type
;
11752 auto assignElem
= exp
.e2
;
11753 auto res
= exp
.reorderSettingAAElem(sc
);
11754 if (res
!= exp
) // `AA[k] = v` rewrite was performed
11755 checkNewEscape(sc
, assignElem
, false);
11756 else if (exp
.op
== EXP
.concatenateElemAssign || exp
.op
== EXP
.concatenateDcharAssign
)
11757 checkAssignEscape(sc
, res
, false, false);
11761 if ((exp
.op
== EXP
.concatenateAssign || exp
.op
== EXP
.concatenateElemAssign
) && sc
.needsCodegen())
11763 // if aa ordering is triggered, `res` will be a CommaExp
11764 // and `.e2` will be the rewritten original expression.
11766 // `output` will point to the expression that the lowering will overwrite
11767 Expression
* output
;
11768 if (auto comma
= res
.isCommaExp())
11770 output
= &comma
.e2
;
11771 // manual cast because it could be either CatAssignExp or CatElemAssignExp
11772 exp
= cast(CatAssignExp
)comma
.e2
;
11777 exp
= cast(CatAssignExp
)result
;
11780 if (exp
.op
== EXP
.concatenateAssign
)
11782 Identifier hook
= global
.params
.tracegc ? Id
._d_arrayappendTTrace
: Id
._d_arrayappendT
;
11784 if (!verifyHookExist(exp
.loc
, *sc
, hook
, "appending array to arrays", Id
.object
))
11787 // Lower to object._d_arrayappendT{,Trace}({file, line, funcname}, e1, e2)
11788 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
11789 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
11790 id
= new DotIdExp(exp
.loc
, id
, hook
);
11792 auto arguments
= new Expressions();
11793 arguments
.reserve(5);
11794 if (global
.params
.tracegc
)
11796 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ? sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
11797 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
11798 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
11799 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
11802 arguments
.push(exp
.e1
);
11803 arguments
.push(exp
.e2
);
11804 Expression ce
= new CallExp(exp
.loc
, id
, arguments
);
11806 exp
.lowering
= ce
.expressionSemantic(sc
);
11809 else if (exp
.op
== EXP
.concatenateElemAssign
)
11811 /* Do not lower concats to the indices array returned by
11812 *`static foreach`, as this array is only used at compile-time.
11814 if (auto ve
= exp
.e1
.isVarExp
)
11816 import core
.stdc
.ctype
: isdigit
;
11817 // The name of the indices array that static foreach loops uses.
11818 // See dmd.cond.lowerNonArrayAggregate
11819 enum varName
= "__res";
11820 const(char)[] id
= ve
.var
.ident
.toString
;
11821 if (ve
.var
.storage_class
& STC
.temp
&& id
.length
> varName
.length
&&
11822 id
[0 .. varName
.length
] == varName
&& id
[varName
.length
].isdigit
)
11826 Identifier hook
= global
.params
.tracegc ? Id
._d_arrayappendcTXTrace
: Id
._d_arrayappendcTX
;
11827 if (!verifyHookExist(exp
.loc
, *sc
, hook
, "appending element to arrays", Id
.object
))
11830 // Lower to object._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2
11831 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
11832 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
11833 id
= new DotIdExp(exp
.loc
, id
, hook
);
11835 auto arguments
= new Expressions();
11836 arguments
.reserve(5);
11837 if (global
.params
.tracegc
)
11839 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ? sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
11840 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
11841 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
11842 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
11845 Expression eValue1
;
11846 Expression value1
= extractSideEffect(sc
, "__appendtmp", eValue1
, exp
.e1
);
11848 arguments
.push(value1
);
11849 arguments
.push(new IntegerExp(exp
.loc
, 1, Type
.tsize_t
));
11851 Expression ce
= new CallExp(exp
.loc
, id
, arguments
);
11853 Expression eValue2
;
11854 Expression value2
= exp
.e2
;
11855 if (!value2
.isVarExp() && !value2
.isConst())
11857 /* Before the template hook, this check was performed in e2ir.d
11858 * for expressions like `a ~= a[$-1]`. Here, $ will be modified
11859 * by calling `_d_arrayappendcTX`, so we need to save `a[$-1]` in
11860 * a temporary variable.
11862 value2
= extractSideEffect(sc
, "__appendtmp", eValue2
, value2
, true);
11864 // `__appendtmp*` will be destroyed together with the array `exp.e1`.
11865 auto vd
= eValue2
.isDeclarationExp().declaration
.isVarDeclaration();
11866 vd
.storage_class |
= STC
.nodtor
;
11867 // Be more explicit that this "declaration" is local to the expression
11868 vd
.storage_class |
= STC
.exptemp
;
11871 auto ale
= new ArrayLengthExp(exp
.loc
, value1
);
11872 auto elem
= new IndexExp(exp
.loc
, value1
, new MinExp(exp
.loc
, ale
, IntegerExp
.literal
!1));
11873 auto ae
= new ConstructExp(exp
.loc
, elem
, value2
);
11875 auto e0
= Expression
.combine(ce
, ae
).expressionSemantic(sc
);
11876 e0
= Expression
.combine(e0
, value1
);
11877 e0
= Expression
.combine(eValue1
, e0
);
11878 e0
= Expression
.combine(eValue2
, e0
);
11880 exp
.lowering
= e0
.expressionSemantic(sc
);
11886 override void visit(AddExp exp
)
11888 static if (LOGSEMANTIC
)
11890 printf("AddExp::semantic('%s')\n", exp
.toChars());
11898 if (Expression ex
= binSemanticProp(exp
, sc
))
11903 Expression e
= exp
.op_overload(sc
);
11910 /* ImportC: convert arrays to pointers, functions to pointers to functions
11912 exp
.e1
= exp
.e1
.arrayFuncConv(sc
);
11913 exp
.e2
= exp
.e2
.arrayFuncConv(sc
);
11915 Type tb1
= exp
.e1
.type
.toBasetype();
11916 Type tb2
= exp
.e2
.type
.toBasetype();
11919 if (tb1
.ty
== Tdelegate || tb1
.isPtrToFunction())
11921 err |
= exp
.e1
.checkArithmetic(exp
.op
) || exp
.e1
.checkSharedAccess(sc
);
11923 if (tb2
.ty
== Tdelegate || tb2
.isPtrToFunction())
11925 err |
= exp
.e2
.checkArithmetic(exp
.op
) || exp
.e2
.checkSharedAccess(sc
);
11930 if (tb1
.ty
== Tpointer
&& exp
.e2
.type
.isintegral() || tb2
.ty
== Tpointer
&& exp
.e1
.type
.isintegral())
11932 result
= scaleFactor(exp
, sc
);
11936 if (tb1
.ty
== Tpointer
&& tb2
.ty
== Tpointer
)
11938 result
= exp
.incompatibleTypes();
11942 if (Expression ex
= typeCombine(exp
, sc
))
11948 Type tb
= exp
.type
.toBasetype();
11949 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
11951 if (!isArrayOpValid(exp
))
11953 result
= arrayOpInvalidError(exp
);
11960 tb1
= exp
.e1
.type
.toBasetype();
11961 if (!target
.isVectorOpSupported(tb1
, exp
.op
, tb2
))
11963 result
= exp
.incompatibleTypes();
11966 if ((tb1
.isreal() && exp
.e2
.type
.isimaginary()) ||
(tb1
.isimaginary() && exp
.e2
.type
.isreal()))
11968 switch (exp
.type
.toBasetype().ty
)
11972 exp
.type
= Type
.tcomplex32
;
11977 exp
.type
= Type
.tcomplex64
;
11982 exp
.type
= Type
.tcomplex80
;
11992 override void visit(MinExp exp
)
11994 static if (LOGSEMANTIC
)
11996 printf("MinExp::semantic('%s')\n", exp
.toChars());
12004 if (Expression ex
= binSemanticProp(exp
, sc
))
12009 Expression e
= exp
.op_overload(sc
);
12016 /* ImportC: convert arrays to pointers, functions to pointers to functions
12018 exp
.e1
= exp
.e1
.arrayFuncConv(sc
);
12019 exp
.e2
= exp
.e2
.arrayFuncConv(sc
);
12021 Type t1
= exp
.e1
.type
.toBasetype();
12022 Type t2
= exp
.e2
.type
.toBasetype();
12025 if (t1
.ty
== Tdelegate || t1
.isPtrToFunction())
12027 err |
= exp
.e1
.checkArithmetic(exp
.op
) || exp
.e1
.checkSharedAccess(sc
);
12029 if (t2
.ty
== Tdelegate || t2
.isPtrToFunction())
12031 err |
= exp
.e2
.checkArithmetic(exp
.op
) || exp
.e2
.checkSharedAccess(sc
);
12036 if (t1
.ty
== Tpointer
)
12038 if (t2
.ty
== Tpointer
)
12040 // https://dlang.org/spec/expression.html#add_expressions
12041 // "If both operands are pointers, and the operator is -, the pointers are
12042 // subtracted and the result is divided by the size of the type pointed to
12043 // by the operands. It is an error if the pointers point to different types."
12044 Type p1
= t1
.nextOf();
12045 Type p2
= t2
.nextOf();
12047 if (!p1
.equivalent(p2
))
12049 // Deprecation to remain for at least a year, after which this should be
12050 // changed to an error
12051 // See https://github.com/dlang/dmd/pull/7332
12052 deprecation(exp
.loc
,
12053 "cannot subtract pointers to different types: `%s` and `%s`.",
12054 t1
.toChars(), t2
.toChars());
12057 // Need to divide the result by the stride
12058 // Replace (ptr - ptr) with (ptr - ptr) / stride
12061 // make sure pointer types are compatible
12062 if (Expression ex
= typeCombine(exp
, sc
))
12068 exp
.type
= Type
.tptrdiff_t
;
12069 stride
= t2
.nextOf().size();
12072 e
= new IntegerExp(exp
.loc
, 0, Type
.tptrdiff_t
);
12074 else if (stride
== cast(long)SIZE_INVALID
)
12075 e
= ErrorExp
.get();
12078 e
= new DivExp(exp
.loc
, exp
, new IntegerExp(Loc
.initial
, stride
, Type
.tptrdiff_t
));
12079 e
.type
= Type
.tptrdiff_t
;
12082 else if (t2
.isintegral())
12083 e
= scaleFactor(exp
, sc
);
12086 error(exp
.loc
, "can't subtract `%s` from pointer", t2
.toChars());
12087 e
= ErrorExp
.get();
12092 if (t2
.ty
== Tpointer
)
12094 exp
.type
= exp
.e2
.type
;
12095 error(exp
.loc
, "can't subtract pointer from `%s`", exp
.e1
.type
.toChars());
12099 if (Expression ex
= typeCombine(exp
, sc
))
12105 Type tb
= exp
.type
.toBasetype();
12106 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
12108 if (!isArrayOpValid(exp
))
12110 result
= arrayOpInvalidError(exp
);
12117 t1
= exp
.e1
.type
.toBasetype();
12118 t2
= exp
.e2
.type
.toBasetype();
12119 if (!target
.isVectorOpSupported(t1
, exp
.op
, t2
))
12121 result
= exp
.incompatibleTypes();
12124 if ((t1
.isreal() && t2
.isimaginary()) ||
(t1
.isimaginary() && t2
.isreal()))
12126 switch (exp
.type
.ty
)
12130 exp
.type
= Type
.tcomplex32
;
12135 exp
.type
= Type
.tcomplex64
;
12140 exp
.type
= Type
.tcomplex80
;
12152 * If the given expression is a `CatExp`, the function tries to lower it to
12153 * `_d_arraycatnTX`.
12156 * ee = the `CatExp` to lower
12158 * `_d_arraycatnTX(e1, e2, ..., en)` if `ee` is `e1 ~ e2 ~ ... en`
12161 private Expression
lowerToArrayCat(CatExp exp
)
12163 // String literals are concatenated by the compiler. No lowering is needed.
12164 if ((exp
.e1
.isStringExp() && (exp
.e2
.isIntegerExp() || exp
.e2
.isStringExp())) ||
12165 (exp
.e2
.isStringExp() && (exp
.e1
.isIntegerExp() || exp
.e1
.isStringExp())))
12168 bool useTraceGCHook
= global
.params
.tracegc
&& sc
.needsCodegen();
12170 Identifier hook
= useTraceGCHook ? Id
._d_arraycatnTXTrace
: Id
._d_arraycatnTX
;
12171 if (!verifyHookExist(exp
.loc
, *sc
, hook
, "concatenating arrays"))
12177 void handleCatArgument(Expressions
*arguments
, Expression e
)
12179 if (auto ce
= e
.isCatExp())
12181 Expression lowering
= ce
.lowering
;
12183 /* Skip `file`, `line`, and `funcname` if the hook of the parent
12184 * `CatExp` is `_d_arraycatnTXTrace`.
12186 if (auto callExp
= isRuntimeHook(lowering
, hook
))
12188 if (hook
== Id
._d_arraycatnTX
)
12189 arguments
.pushSlice((*callExp
.arguments
)[]);
12191 arguments
.pushSlice((*callExp
.arguments
)[3 .. $]);
12198 auto arguments
= new Expressions();
12199 if (useTraceGCHook
)
12201 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ?
12202 sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
12203 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
12204 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
12205 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
12208 handleCatArgument(arguments
, exp
.e1
);
12209 handleCatArgument(arguments
, exp
.e2
);
12211 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
12212 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
12214 auto tiargs
= new Objects();
12215 tiargs
.push(exp
.type
);
12216 id
= new DotTemplateInstanceExp(exp
.loc
, id
, hook
, tiargs
);
12217 id
= new CallExp(exp
.loc
, id
, arguments
);
12218 return id
.expressionSemantic(sc
);
12221 void trySetCatExpLowering(Expression exp
)
12223 /* `_d_arraycatnTX` canot be used with `-betterC`, but `CatExp`s may be
12224 * used with `-betterC`, but only during CTFE.
12226 if (!global
.params
.useGC
)
12229 if (auto ce
= exp
.isCatExp())
12230 ce
.lowering
= lowerToArrayCat(ce
);
12233 override void visit(CatExp exp
)
12235 // https://dlang.org/spec/expression.html#cat_expressions
12236 //printf("CatExp.semantic() %s\n", toChars());
12243 if (Expression ex
= binSemanticProp(exp
, sc
))
12248 Expression e
= exp
.op_overload(sc
);
12255 Type tb1
= exp
.e1
.type
.toBasetype();
12256 Type tb2
= exp
.e2
.type
.toBasetype();
12258 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
12259 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
12263 Type tb1next
= tb1
.nextOf();
12264 Type tb2next
= tb2
.nextOf();
12266 // Check for: array ~ array
12267 if (tb1next
&& tb2next
&& (tb1next
.implicitConvTo(tb2next
) >= MATCH
.constant || tb2next
.implicitConvTo(tb1next
) >= MATCH
.constant || exp
.e1
.op
== EXP
.arrayLiteral
&& exp
.e1
.implicitConvTo(tb2
) || exp
.e2
.op
== EXP
.arrayLiteral
&& exp
.e2
.implicitConvTo(tb1
)))
12269 /* https://issues.dlang.org/show_bug.cgi?id=9248
12270 * Here to avoid the case of:
12271 * void*[] a = [cast(void*)1];
12272 * void*[] b = [cast(void*)2];
12275 * a ~ [cast(void*)b];
12278 /* https://issues.dlang.org/show_bug.cgi?id=14682
12279 * Also to avoid the case of:
12283 * a ~ cast(int[])[];
12288 // Check for: array ~ element
12289 if ((tb1
.ty
== Tsarray || tb1
.ty
== Tarray
) && tb2
.ty
!= Tvoid
)
12291 if (exp
.e1
.op
== EXP
.arrayLiteral
)
12293 exp
.e2
= doCopyOrMove(sc
, exp
.e2
);
12294 // https://issues.dlang.org/show_bug.cgi?id=14686
12295 // Postblit call appears in AST, and this is
12296 // finally translated to an ArrayLiteralExp in below optimize().
12298 else if (exp
.e1
.op
== EXP
.string_
)
12300 // No postblit call exists on character (integer) value.
12304 if (tb2
.checkPostblit(exp
.e2
.loc
, sc
))
12306 // Postblit call will be done in runtime helper function
12309 if (exp
.e1
.op
== EXP
.arrayLiteral
&& exp
.e1
.implicitConvTo(tb2
.arrayOf()))
12311 exp
.e1
= exp
.e1
.implicitCastTo(sc
, tb2
.arrayOf());
12312 exp
.type
= tb2
.arrayOf();
12315 if (exp
.e2
.implicitConvTo(tb1next
) >= MATCH
.convert
)
12317 exp
.e2
= exp
.e2
.implicitCastTo(sc
, tb1next
);
12318 exp
.type
= tb1next
.arrayOf();
12320 if (checkNewEscape(sc
, exp
.e2
, false))
12322 result
= exp
.optimize(WANTvalue
);
12323 trySetCatExpLowering(result
);
12327 // Check for: element ~ array
12328 if ((tb2
.ty
== Tsarray || tb2
.ty
== Tarray
) && tb1
.ty
!= Tvoid
)
12330 if (exp
.e2
.op
== EXP
.arrayLiteral
)
12332 exp
.e1
= doCopyOrMove(sc
, exp
.e1
);
12334 else if (exp
.e2
.op
== EXP
.string_
)
12339 if (tb1
.checkPostblit(exp
.e1
.loc
, sc
))
12343 if (exp
.e2
.op
== EXP
.arrayLiteral
&& exp
.e2
.implicitConvTo(tb1
.arrayOf()))
12345 exp
.e2
= exp
.e2
.implicitCastTo(sc
, tb1
.arrayOf());
12346 exp
.type
= tb1
.arrayOf();
12349 if (exp
.e1
.implicitConvTo(tb2next
) >= MATCH
.convert
)
12351 exp
.e1
= exp
.e1
.implicitCastTo(sc
, tb2next
);
12352 exp
.type
= tb2next
.arrayOf();
12354 if (checkNewEscape(sc
, exp
.e1
, false))
12356 result
= exp
.optimize(WANTvalue
);
12357 trySetCatExpLowering(result
);
12363 if ((tb1
.ty
== Tsarray || tb1
.ty
== Tarray
) && (tb2
.ty
== Tsarray || tb2
.ty
== Tarray
) && (tb1next
.mod || tb2next
.mod
) && (tb1next
.mod
!= tb2next
.mod
))
12365 Type t1
= tb1next
.mutableOf().constOf().arrayOf();
12366 Type t2
= tb2next
.mutableOf().constOf().arrayOf();
12367 if (exp
.e1
.op
== EXP
.string_
&& !(cast(StringExp
)exp
.e1
).committed
)
12370 exp
.e1
= exp
.e1
.castTo(sc
, t1
);
12371 if (exp
.e2
.op
== EXP
.string_
&& !(cast(StringExp
)exp
.e2
).committed
)
12374 exp
.e2
= exp
.e2
.castTo(sc
, t2
);
12377 if (Expression ex
= typeCombine(exp
, sc
))
12380 trySetCatExpLowering(result
);
12383 exp
.type
= exp
.type
.toHeadMutable();
12385 Type tb
= exp
.type
.toBasetype();
12386 if (tb
.ty
== Tsarray
)
12387 exp
.type
= tb
.nextOf().arrayOf();
12388 if (exp
.type
.ty
== Tarray
&& tb1next
&& tb2next
&& tb1next
.mod
!= tb2next
.mod
)
12390 exp
.type
= exp
.type
.nextOf().toHeadMutable().arrayOf();
12392 if (Type tbn
= tb
.nextOf())
12394 if (tbn
.checkPostblit(exp
.loc
, sc
))
12397 Type t1
= exp
.e1
.type
.toBasetype();
12398 Type t2
= exp
.e2
.type
.toBasetype();
12399 if ((t1
.ty
== Tarray || t1
.ty
== Tsarray
) &&
12400 (t2
.ty
== Tarray || t2
.ty
== Tsarray
))
12402 // Normalize to ArrayLiteralExp or StringExp as far as possible
12403 e
= exp
.optimize(WANTvalue
);
12407 //printf("(%s) ~ (%s)\n", e1.toChars(), e2.toChars());
12408 result
= exp
.incompatibleTypes();
12413 trySetCatExpLowering(result
);
12416 override void visit(MulExp exp
)
12420 printf("MulExp::semantic() %s\n", exp
.toChars());
12428 if (Expression ex
= binSemanticProp(exp
, sc
))
12433 Expression e
= exp
.op_overload(sc
);
12440 if (Expression ex
= typeCombine(exp
, sc
))
12446 Type tb
= exp
.type
.toBasetype();
12447 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
12449 if (!isArrayOpValid(exp
))
12451 result
= arrayOpInvalidError(exp
);
12458 if (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
))
12461 if (exp
.type
.isfloating())
12463 Type t1
= exp
.e1
.type
;
12464 Type t2
= exp
.e2
.type
;
12470 else if (t2
.isreal())
12474 else if (t1
.isimaginary())
12476 if (t2
.isimaginary())
12478 switch (t1
.toBasetype().ty
)
12481 exp
.type
= Type
.tfloat32
;
12485 exp
.type
= Type
.tfloat64
;
12489 exp
.type
= Type
.tfloat80
;
12497 exp
.e1
.type
= exp
.type
;
12498 exp
.e2
.type
= exp
.type
;
12499 e
= new NegExp(exp
.loc
, exp
);
12500 e
= e
.expressionSemantic(sc
);
12505 exp
.type
= t2
; // t2 is complex
12507 else if (t2
.isimaginary())
12509 exp
.type
= t1
; // t1 is complex
12512 else if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
12514 result
= exp
.incompatibleTypes();
12520 override void visit(DivExp exp
)
12528 if (Expression ex
= binSemanticProp(exp
, sc
))
12533 Expression e
= exp
.op_overload(sc
);
12540 if (Expression ex
= typeCombine(exp
, sc
))
12546 Type tb
= exp
.type
.toBasetype();
12547 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
12549 if (!isArrayOpValid(exp
))
12551 result
= arrayOpInvalidError(exp
);
12558 if (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
))
12561 if (exp
.type
.isfloating())
12563 Type t1
= exp
.e1
.type
;
12564 Type t2
= exp
.e2
.type
;
12569 if (t2
.isimaginary())
12573 e
= new NegExp(exp
.loc
, exp
);
12574 e
= e
.expressionSemantic(sc
);
12579 else if (t2
.isreal())
12583 else if (t1
.isimaginary())
12585 if (t2
.isimaginary())
12587 switch (t1
.toBasetype().ty
)
12590 exp
.type
= Type
.tfloat32
;
12594 exp
.type
= Type
.tfloat64
;
12598 exp
.type
= Type
.tfloat80
;
12606 exp
.type
= t2
; // t2 is complex
12608 else if (t2
.isimaginary())
12610 exp
.type
= t1
; // t1 is complex
12613 else if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
12615 result
= exp
.incompatibleTypes();
12621 override void visit(ModExp exp
)
12629 if (Expression ex
= binSemanticProp(exp
, sc
))
12634 Expression e
= exp
.op_overload(sc
);
12641 if (Expression ex
= typeCombine(exp
, sc
))
12647 Type tb
= exp
.type
.toBasetype();
12648 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
12650 if (!isArrayOpValid(exp
))
12652 result
= arrayOpInvalidError(exp
);
12658 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
12660 result
= exp
.incompatibleTypes();
12664 if (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
))
12667 if (exp
.type
.isfloating())
12669 exp
.type
= exp
.e1
.type
;
12670 if (exp
.e2
.type
.iscomplex())
12672 error(exp
.loc
, "cannot perform modulo complex arithmetic");
12679 override void visit(PowExp exp
)
12687 //printf("PowExp::semantic() %s\n", toChars());
12688 if (Expression ex
= binSemanticProp(exp
, sc
))
12693 Expression e
= exp
.op_overload(sc
);
12700 if (Expression ex
= typeCombine(exp
, sc
))
12706 Type tb
= exp
.type
.toBasetype();
12707 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
12709 if (!isArrayOpValid(exp
))
12711 result
= arrayOpInvalidError(exp
);
12718 if (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
))
12721 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
12723 result
= exp
.incompatibleTypes();
12727 // First, attempt to fold the expression.
12728 e
= exp
.optimize(WANTvalue
);
12729 if (e
.op
!= EXP
.pow
)
12731 e
= e
.expressionSemantic(sc
);
12736 Module mmath
= Module
.loadStdMath();
12739 error(e
.loc
, "`%s` requires `std.math` for `^^` operators", e
.toChars());
12742 e
= new ScopeExp(exp
.loc
, mmath
);
12744 if (exp
.e2
.op
== EXP
.float64
&& exp
.e2
.toReal() == CTFloat
.half
)
12746 // Replace e1 ^^ 0.5 with .std.math.sqrt(e1)
12747 e
= new CallExp(exp
.loc
, new DotIdExp(exp
.loc
, e
, Id
._sqrt
), exp
.e1
);
12751 // Replace e1 ^^ e2 with .std.math.pow(e1, e2)
12752 e
= new CallExp(exp
.loc
, new DotIdExp(exp
.loc
, e
, Id
._pow
), exp
.e1
, exp
.e2
);
12754 e
= e
.expressionSemantic(sc
);
12759 override void visit(ShlExp exp
)
12761 //printf("ShlExp::semantic(), type = %p\n", type);
12768 if (Expression ex
= binSemanticProp(exp
, sc
))
12773 Expression e
= exp
.op_overload(sc
);
12780 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
12783 if (!target
.isVectorOpSupported(exp
.e1
.type
.toBasetype(), exp
.op
, exp
.e2
.type
.toBasetype()))
12785 result
= exp
.incompatibleTypes();
12788 exp
.e1
= integralPromotions(exp
.e1
, sc
);
12789 if (exp
.e2
.type
.toBasetype().ty
!= Tvector
)
12790 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tshiftcnt
);
12792 exp
.type
= exp
.e1
.type
;
12796 override void visit(ShrExp exp
)
12804 if (Expression ex
= binSemanticProp(exp
, sc
))
12809 Expression e
= exp
.op_overload(sc
);
12816 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
12819 if (!target
.isVectorOpSupported(exp
.e1
.type
.toBasetype(), exp
.op
, exp
.e2
.type
.toBasetype()))
12821 result
= exp
.incompatibleTypes();
12824 exp
.e1
= integralPromotions(exp
.e1
, sc
);
12825 if (exp
.e2
.type
.toBasetype().ty
!= Tvector
)
12826 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tshiftcnt
);
12828 exp
.type
= exp
.e1
.type
;
12832 override void visit(UshrExp exp
)
12840 if (Expression ex
= binSemanticProp(exp
, sc
))
12845 Expression e
= exp
.op_overload(sc
);
12852 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
12855 if (!target
.isVectorOpSupported(exp
.e1
.type
.toBasetype(), exp
.op
, exp
.e2
.type
.toBasetype()))
12857 result
= exp
.incompatibleTypes();
12860 exp
.e1
= integralPromotions(exp
.e1
, sc
);
12861 if (exp
.e2
.type
.toBasetype().ty
!= Tvector
)
12862 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tshiftcnt
);
12864 exp
.type
= exp
.e1
.type
;
12868 override void visit(AndExp exp
)
12876 if (Expression ex
= binSemanticProp(exp
, sc
))
12881 Expression e
= exp
.op_overload(sc
);
12888 if (exp
.e1
.type
.toBasetype().ty
== Tbool
&& exp
.e2
.type
.toBasetype().ty
== Tbool
)
12890 exp
.type
= exp
.e1
.type
;
12895 if (Expression ex
= typeCombine(exp
, sc
))
12901 Type tb
= exp
.type
.toBasetype();
12902 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
12904 if (!isArrayOpValid(exp
))
12906 result
= arrayOpInvalidError(exp
);
12912 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
12914 result
= exp
.incompatibleTypes();
12917 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
12923 override void visit(OrExp exp
)
12931 if (Expression ex
= binSemanticProp(exp
, sc
))
12936 Expression e
= exp
.op_overload(sc
);
12943 if (exp
.e1
.type
.toBasetype().ty
== Tbool
&& exp
.e2
.type
.toBasetype().ty
== Tbool
)
12945 exp
.type
= exp
.e1
.type
;
12950 if (Expression ex
= typeCombine(exp
, sc
))
12956 Type tb
= exp
.type
.toBasetype();
12957 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
12959 if (!isArrayOpValid(exp
))
12961 result
= arrayOpInvalidError(exp
);
12967 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
12969 result
= exp
.incompatibleTypes();
12972 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
12978 override void visit(XorExp exp
)
12986 if (Expression ex
= binSemanticProp(exp
, sc
))
12991 Expression e
= exp
.op_overload(sc
);
12998 if (exp
.e1
.type
.toBasetype().ty
== Tbool
&& exp
.e2
.type
.toBasetype().ty
== Tbool
)
13000 exp
.type
= exp
.e1
.type
;
13005 if (Expression ex
= typeCombine(exp
, sc
))
13011 Type tb
= exp
.type
.toBasetype();
13012 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
13014 if (!isArrayOpValid(exp
))
13016 result
= arrayOpInvalidError(exp
);
13022 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
13024 result
= exp
.incompatibleTypes();
13027 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
13033 override void visit(LogicalExp exp
)
13035 static if (LOGSEMANTIC
)
13037 printf("LogicalExp::semantic() %s\n", exp
.toChars());
13046 exp
.setNoderefOperands();
13048 Expression e1x
= exp
.e1
.expressionSemantic(sc
);
13050 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
13051 if (e1x
.op
== EXP
.type
)
13052 e1x
= resolveAliasThis(sc
, e1x
);
13054 e1x
= resolveProperties(sc
, e1x
);
13055 e1x
= e1x
.toBoolean(sc
);
13057 if (sc
.flags
& SCOPE
.condition
)
13059 /* If in static if, don't evaluate e2 if we don't have to.
13061 e1x
= e1x
.optimize(WANTvalue
);
13062 if (e1x
.toBool().hasValue(exp
.op
== EXP
.orOr
))
13064 if (sc
.flags
& SCOPE
.Cfile
)
13065 result
= new IntegerExp(exp
.op
== EXP
.orOr
);
13067 result
= IntegerExp
.createBool(exp
.op
== EXP
.orOr
);
13072 CtorFlow ctorflow
= sc
.ctorflow
.clone();
13073 Expression e2x
= exp
.e2
.expressionSemantic(sc
);
13074 sc
.merge(exp
.loc
, ctorflow
);
13075 ctorflow
.freeFieldinit();
13077 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
13078 if (e2x
.op
== EXP
.type
)
13079 e2x
= resolveAliasThis(sc
, e2x
);
13081 e2x
= resolveProperties(sc
, e2x
);
13083 auto f1
= checkNonAssignmentArrayOp(e1x
);
13084 auto f2
= checkNonAssignmentArrayOp(e2x
);
13088 // Unless the right operand is 'void', the expression is converted to 'bool'.
13089 if (e2x
.type
.ty
!= Tvoid
)
13090 e2x
= e2x
.toBoolean(sc
);
13092 if (e2x
.op
== EXP
.type || e2x
.op
== EXP
.scope_
)
13094 error(exp
.loc
, "`%s` is not an expression", exp
.e2
.toChars());
13097 if (e1x
.op
== EXP
.error || e1x
.type
.ty
== Tnoreturn
)
13102 if (e2x
.op
== EXP
.error
)
13108 // The result type is 'bool', unless the right operand has type 'void'.
13109 if (e2x
.type
.ty
== Tvoid
)
13110 exp
.type
= Type
.tvoid
;
13112 exp
.type
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? Type
.tint32
: Type
.tbool
;
13120 override void visit(CmpExp exp
)
13122 static if (LOGSEMANTIC
)
13124 printf("CmpExp::semantic('%s')\n", exp
.toChars());
13132 exp
.setNoderefOperands();
13134 if (Expression ex
= binSemanticProp(exp
, sc
))
13139 Type t1
= exp
.e1
.type
.toBasetype();
13140 Type t2
= exp
.e2
.type
.toBasetype();
13141 if (t1
.ty
== Tclass
&& exp
.e2
.op
== EXP
.null_ || t2
.ty
== Tclass
&& exp
.e1
.op
== EXP
.null_
)
13143 error(exp
.loc
, "do not use `null` when comparing class types");
13148 EXP cmpop
= exp
.op
;
13149 if (auto e
= exp
.op_overload(sc
, &cmpop
))
13151 if (!e
.type
.isscalar() && e
.type
.equals(exp
.e1
.type
))
13153 error(exp
.loc
, "recursive `opCmp` expansion");
13156 if (e
.op
== EXP
.call)
13159 if (t1
.ty
== Tclass
&& t2
.ty
== Tclass
)
13161 // Lower to object.__cmp(e1, e2)
13162 Expression cl
= new IdentifierExp(exp
.loc
, Id
.empty
);
13163 cl
= new DotIdExp(exp
.loc
, cl
, Id
.object
);
13164 cl
= new DotIdExp(exp
.loc
, cl
, Id
.__cmp
);
13165 cl
= cl
.expressionSemantic(sc
);
13167 auto arguments
= new Expressions();
13168 // Check if op_overload found a better match by calling e2.opCmp(e1)
13169 // If the operands were swapped, then the result must be reversed
13170 // e1.opCmp(e2) == -e2.opCmp(e1)
13171 // cmpop takes care of this
13172 if (exp
.op
== cmpop
)
13174 arguments
.push(exp
.e1
);
13175 arguments
.push(exp
.e2
);
13179 // Use better match found by op_overload
13180 arguments
.push(exp
.e2
);
13181 arguments
.push(exp
.e1
);
13184 cl
= new CallExp(exp
.loc
, cl
, arguments
);
13185 cl
= new CmpExp(cmpop
, exp
.loc
, cl
, new IntegerExp(0));
13186 result
= cl
.expressionSemantic(sc
);
13190 e
= new CmpExp(cmpop
, exp
.loc
, e
, IntegerExp
.literal
!0);
13191 e
= e
.expressionSemantic(sc
);
13198 if (Expression ex
= typeCombine(exp
, sc
))
13204 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
13205 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
13209 exp
.type
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? Type
.tint32
: Type
.tbool
;
13211 // Special handling for array comparisons
13212 Expression arrayLowering
= null;
13213 t1
= exp
.e1
.type
.toBasetype();
13214 t2
= exp
.e2
.type
.toBasetype();
13215 if ((t1
.ty
== Tarray || t1
.ty
== Tsarray || t1
.ty
== Tpointer
) && (t2
.ty
== Tarray || t2
.ty
== Tsarray || t2
.ty
== Tpointer
))
13217 Type t1next
= t1
.nextOf();
13218 Type t2next
= t2
.nextOf();
13219 if (t1next
.implicitConvTo(t2next
) < MATCH
.constant
&& t2next
.implicitConvTo(t1next
) < MATCH
.constant
&& (t1next
.ty
!= Tvoid
&& t2next
.ty
!= Tvoid
))
13221 error(exp
.loc
, "array comparison type mismatch, `%s` vs `%s`", t1next
.toChars(), t2next
.toChars());
13225 if ((t1
.ty
== Tarray || t1
.ty
== Tsarray
) &&
13226 (t2
.ty
== Tarray || t2
.ty
== Tsarray
))
13228 if (!verifyHookExist(exp
.loc
, *sc
, Id
.__cmp
, "comparing arrays"))
13231 // Lower to object.__cmp(e1, e2)
13232 Expression al
= new IdentifierExp(exp
.loc
, Id
.empty
);
13233 al
= new DotIdExp(exp
.loc
, al
, Id
.object
);
13234 al
= new DotIdExp(exp
.loc
, al
, Id
.__cmp
);
13235 al
= al
.expressionSemantic(sc
);
13237 auto arguments
= new Expressions(2);
13238 (*arguments
)[0] = exp
.e1
;
13239 (*arguments
)[1] = exp
.e2
;
13241 al
= new CallExp(exp
.loc
, al
, arguments
);
13242 al
= new CmpExp(exp
.op
, exp
.loc
, al
, IntegerExp
.literal
!0);
13244 arrayLowering
= al
;
13247 else if (t1
.ty
== Tstruct || t2
.ty
== Tstruct ||
(t1
.ty
== Tclass
&& t2
.ty
== Tclass
))
13249 if (t2
.ty
== Tstruct
)
13250 error(exp
.loc
, "need member function `opCmp()` for %s `%s` to compare", t2
.toDsymbol(sc
).kind(), t2
.toChars());
13252 error(exp
.loc
, "need member function `opCmp()` for %s `%s` to compare", t1
.toDsymbol(sc
).kind(), t1
.toChars());
13255 else if (t1
.iscomplex() || t2
.iscomplex())
13257 error(exp
.loc
, "compare not defined for complex operands");
13260 else if (t1
.ty
== Taarray || t2
.ty
== Taarray
)
13262 error(exp
.loc
, "`%s` is not defined for associative arrays", EXPtoString(exp
.op
).ptr
);
13265 else if (!target
.isVectorOpSupported(t1
, exp
.op
, t2
))
13267 result
= exp
.incompatibleTypes();
13272 bool r1
= exp
.e1
.checkValue() || exp
.e1
.checkSharedAccess(sc
);
13273 bool r2
= exp
.e2
.checkValue() || exp
.e2
.checkSharedAccess(sc
);
13278 //printf("CmpExp: %s, type = %s\n", e.toChars(), e.type.toChars());
13281 arrayLowering
= arrayLowering
.expressionSemantic(sc
);
13282 result
= arrayLowering
;
13286 if (auto tv
= t1
.isTypeVector())
13287 exp
.type
= tv
.toBooleanVector();
13293 override void visit(InExp exp
)
13301 if (Expression ex
= binSemanticProp(exp
, sc
))
13306 Expression e
= exp
.op_overload(sc
);
13313 Type t2b
= exp
.e2
.type
.toBasetype();
13318 TypeAArray ta
= cast(TypeAArray
)t2b
;
13320 // Special handling for array keys
13321 if (!arrayTypeCompatibleWithoutCasting(exp
.e1
.type
, ta
.index
))
13323 // Convert key to type of key
13324 exp
.e1
= exp
.e1
.implicitCastTo(sc
, ta
.index
);
13327 semanticTypeInfo(sc
, ta
.index
);
13329 // Return type is pointer to value
13330 exp
.type
= ta
.nextOf().pointerTo();
13337 case Tarray
, Tsarray
:
13338 result
= exp
.incompatibleTypes();
13339 errorSupplemental(exp
.loc
, "`in` is only allowed on associative arrays");
13340 const(char)* slice
= (t2b
.ty
== Tsarray
) ?
"[]" : "";
13341 errorSupplemental(exp
.loc
, "perhaps use `std.algorithm.find(%s, %s%s)` instead",
13342 exp
.e1
.toChars(), exp
.e2
.toChars(), slice
);
13346 result
= exp
.incompatibleTypes();
13352 override void visit(RemoveExp e
)
13354 if (Expression ex
= binSemantic(e
, sc
))
13362 override void visit(EqualExp exp
)
13364 //printf("EqualExp::semantic('%s')\n", exp.toChars());
13371 exp
.setNoderefOperands();
13373 if (auto e
= binSemanticProp(exp
, sc
))
13378 if (exp
.e1
.op
== EXP
.type || exp
.e2
.op
== EXP
.type
)
13380 /* https://issues.dlang.org/show_bug.cgi?id=12520
13381 * empty tuples are represented as types so special cases are added
13382 * so that they can be compared for equality with tuples of values.
13384 static auto extractTypeTupAndExpTup(Expression e
)
13386 static struct Result
{ bool ttEmpty
; bool te
; }
13387 auto tt
= e
.op
== EXP
.type ? e
.isTypeExp().type
.isTypeTuple() : null;
13388 return Result(tt
&& (!tt
.arguments ||
!tt
.arguments
.length
), e
.isTupleExp() !is null);
13390 auto tups1
= extractTypeTupAndExpTup(exp
.e1
);
13391 auto tups2
= extractTypeTupAndExpTup(exp
.e2
);
13392 // AliasSeq!() == AliasSeq!(<at least a value>)
13393 if (tups1
.ttEmpty
&& tups2
.te
)
13395 result
= IntegerExp
.createBool(exp
.op
!= EXP
.equal
);
13398 // AliasSeq!(<at least a value>) == AliasSeq!()
13399 else if (tups1
.te
&& tups2
.ttEmpty
)
13401 result
= IntegerExp
.createBool(exp
.op
!= EXP
.equal
);
13404 // AliasSeq!() == AliasSeq!()
13405 else if (tups1
.ttEmpty
&& tups2
.ttEmpty
)
13407 result
= IntegerExp
.createBool(exp
.op
== EXP
.equal
);
13410 // otherwise, two types are really not comparable
13411 result
= exp
.incompatibleTypes();
13416 auto t1
= exp
.e1
.type
;
13417 auto t2
= exp
.e2
.type
;
13418 if (t1
.ty
== Tenum
&& t2
.ty
== Tenum
&& !t1
.equivalent(t2
))
13419 error(exp
.loc
, "comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`",
13420 t1
.toChars(), t2
.toChars());
13423 /* Before checking for operator overloading, check to see if we're
13424 * comparing the addresses of two statics. If so, we can just see
13425 * if they are the same symbol.
13427 if (exp
.e1
.op
== EXP
.address
&& exp
.e2
.op
== EXP
.address
)
13429 AddrExp ae1
= cast(AddrExp
)exp
.e1
;
13430 AddrExp ae2
= cast(AddrExp
)exp
.e2
;
13431 if (ae1
.e1
.op
== EXP
.variable
&& ae2
.e1
.op
== EXP
.variable
)
13433 VarExp ve1
= cast(VarExp
)ae1
.e1
;
13434 VarExp ve2
= cast(VarExp
)ae2
.e1
;
13435 if (ve1
.var
== ve2
.var
)
13437 // They are the same, result is 'true' for ==, 'false' for !=
13438 result
= IntegerExp
.createBool(exp
.op
== EXP
.equal
);
13444 Type t1
= exp
.e1
.type
.toBasetype();
13445 Type t2
= exp
.e2
.type
.toBasetype();
13447 // Indicates whether the comparison of the 2 specified array types
13448 // requires an object.__equals() lowering.
13449 static bool needsDirectEq(Type t1
, Type t2
, Scope
* sc
)
13451 Type t1n
= t1
.nextOf().toBasetype();
13452 Type t2n
= t2
.nextOf().toBasetype();
13453 if ((t1n
.ty
.isSomeChar
&& t2n
.ty
.isSomeChar
) ||
13454 (t1n
.ty
== Tvoid || t2n
.ty
== Tvoid
))
13458 if (t1n
.constOf() != t2n
.constOf())
13462 while (t
.toBasetype().nextOf())
13463 t
= t
.nextOf().toBasetype();
13464 if (auto ts
= t
.isTypeStruct())
13466 // semanticTypeInfo() makes sure hasIdentityEquals has been computed
13467 if (global
.params
.useTypeInfo
&& Type
.dtypeinfo
)
13468 semanticTypeInfo(sc
, ts
);
13470 return ts
.sym
.hasIdentityEquals
; // has custom opEquals
13476 if (auto e
= exp
.op_overload(sc
))
13483 const isArrayComparison
= (t1
.ty
== Tarray || t1
.ty
== Tsarray
) &&
13484 (t2
.ty
== Tarray || t2
.ty
== Tsarray
);
13485 const needsArrayLowering
= isArrayComparison
&& needsDirectEq(t1
, t2
, sc
);
13487 if (!needsArrayLowering
)
13489 // https://issues.dlang.org/show_bug.cgi?id=23783
13490 if (exp
.e1
.checkSharedAccess(sc
) || exp
.e2
.checkSharedAccess(sc
))
13492 if (auto e
= typeCombine(exp
, sc
))
13499 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
13500 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
13504 exp
.type
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? Type
.tint32
: Type
.tbool
;
13506 if (!isArrayComparison
)
13508 if (exp
.e1
.type
!= exp
.e2
.type
&& exp
.e1
.type
.isfloating() && exp
.e2
.type
.isfloating())
13510 // Cast both to complex
13511 exp
.e1
= exp
.e1
.castTo(sc
, Type
.tcomplex80
);
13512 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tcomplex80
);
13516 // lower some array comparisons to object.__equals(e1, e2)
13517 if (needsArrayLowering ||
(t1
.ty
== Tarray
&& t2
.ty
== Tarray
))
13519 //printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars());
13521 // https://issues.dlang.org/show_bug.cgi?id=22390
13522 // Equality comparison between array of noreturns simply lowers to length equality comparison
13523 if (t1
.nextOf
.isTypeNoreturn() && t2
.nextOf
.isTypeNoreturn())
13525 Expression exp_l1
= new DotIdExp(exp
.e1
.loc
, exp
.e1
, Id
.length
);
13526 Expression exp_l2
= new DotIdExp(exp
.e2
.loc
, exp
.e2
, Id
.length
);
13527 auto e
= new EqualExp(EXP
.equal
, exp
.loc
, exp_l1
, exp_l2
);
13528 result
= e
.expressionSemantic(sc
);
13532 if (!verifyHookExist(exp
.loc
, *sc
, Id
.__equals
, "equal checks on arrays"))
13535 Expression __equals
= new IdentifierExp(exp
.loc
, Id
.empty
);
13536 Identifier id
= Identifier
.idPool("__equals");
13537 __equals
= new DotIdExp(exp
.loc
, __equals
, Id
.object
);
13538 __equals
= new DotIdExp(exp
.loc
, __equals
, id
);
13540 /* https://issues.dlang.org/show_bug.cgi?id=23674
13542 * Optimize before creating the call expression to the
13543 * druntime hook as the optimizer may output errors
13544 * that will get swallowed otherwise.
13546 exp
.e1
= exp
.e1
.optimize(WANTvalue
);
13547 exp
.e2
= exp
.e2
.optimize(WANTvalue
);
13549 auto arguments
= new Expressions(2);
13550 (*arguments
)[0] = exp
.e1
;
13551 (*arguments
)[1] = exp
.e2
;
13553 __equals
= new CallExp(exp
.loc
, __equals
, arguments
);
13554 if (exp
.op
== EXP
.notEqual
)
13556 __equals
= new NotExp(exp
.loc
, __equals
);
13558 __equals
= __equals
.trySemantic(sc
); // for better error message
13561 error(exp
.loc
, "incompatible types for array comparison: `%s` and `%s`",
13562 exp
.e1
.type
.toChars(), exp
.e2
.type
.toChars());
13563 __equals
= ErrorExp
.get();
13570 if (exp
.e1
.type
.toBasetype().ty
== Taarray
)
13571 semanticTypeInfo(sc
, exp
.e1
.type
.toBasetype());
13574 if (!target
.isVectorOpSupported(t1
, exp
.op
, t2
))
13576 result
= exp
.incompatibleTypes();
13580 if (auto tv
= t1
.isTypeVector())
13581 exp
.type
= tv
.toBooleanVector();
13586 override void visit(IdentityExp exp
)
13594 exp
.setNoderefOperands();
13596 if (auto e
= binSemanticProp(exp
, sc
))
13602 if (auto e
= typeCombine(exp
, sc
))
13608 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
13609 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
13613 if (exp
.e1
.op
== EXP
.type || exp
.e2
.op
== EXP
.type
)
13615 result
= exp
.incompatibleTypes();
13619 exp
.type
= Type
.tbool
;
13621 if (exp
.e1
.type
!= exp
.e2
.type
&& exp
.e1
.type
.isfloating() && exp
.e2
.type
.isfloating())
13623 // Cast both to complex
13624 exp
.e1
= exp
.e1
.castTo(sc
, Type
.tcomplex80
);
13625 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tcomplex80
);
13628 auto tb1
= exp
.e1
.type
.toBasetype();
13629 auto tb2
= exp
.e2
.type
.toBasetype();
13630 if (!target
.isVectorOpSupported(tb1
, exp
.op
, tb2
))
13632 result
= exp
.incompatibleTypes();
13636 if (exp
.e1
.op
== EXP
.call)
13637 exp
.e1
= (cast(CallExp
)exp
.e1
).addDtorHook(sc
);
13638 if (exp
.e2
.op
== EXP
.call)
13639 exp
.e2
= (cast(CallExp
)exp
.e2
).addDtorHook(sc
);
13641 if (exp
.e1
.type
.toBasetype().ty
== Tsarray ||
13642 exp
.e2
.type
.toBasetype().ty
== Tsarray
)
13643 deprecation(exp
.loc
, "identity comparison of static arrays "
13644 ~ "implicitly coerces them to slices, "
13645 ~ "which are compared by reference");
13650 override void visit(CondExp exp
)
13652 static if (LOGSEMANTIC
)
13654 printf("CondExp::semantic('%s')\n", exp
.toChars());
13662 if (auto die
= exp
.econd
.isDotIdExp())
13663 die
.noderef
= true;
13665 Expression ec
= exp
.econd
.expressionSemantic(sc
);
13666 ec
= resolveProperties(sc
, ec
);
13667 ec
= ec
.toBoolean(sc
);
13669 CtorFlow ctorflow_root
= sc
.ctorflow
.clone();
13670 Expression e1x
= exp
.e1
.expressionSemantic(sc
).arrayFuncConv(sc
);
13671 e1x
= resolveProperties(sc
, e1x
);
13673 CtorFlow ctorflow1
= sc
.ctorflow
;
13674 sc
.ctorflow
= ctorflow_root
;
13675 Expression e2x
= exp
.e2
.expressionSemantic(sc
).arrayFuncConv(sc
);
13676 e2x
= resolveProperties(sc
, e2x
);
13678 sc
.merge(exp
.loc
, ctorflow1
);
13679 ctorflow1
.freeFieldinit();
13681 if (ec
.op
== EXP
.error
)
13686 if (ec
.type
== Type
.terror
)
13690 if (e1x
.op
== EXP
.error
)
13695 if (e1x
.type
== Type
.terror
)
13699 if (e2x
.op
== EXP
.error
)
13704 if (e2x
.type
== Type
.terror
)
13708 auto f0
= checkNonAssignmentArrayOp(exp
.econd
);
13709 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
13710 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
13711 if (f0 || f1 || f2
)
13714 Type t1
= exp
.e1
.type
;
13715 Type t2
= exp
.e2
.type
;
13717 // https://issues.dlang.org/show_bug.cgi?id=23767
13718 // `cast(void*) 0` should be treated as `null` so the ternary expression
13719 // gets the pointer type of the other branch
13720 if (sc
.flags
& SCOPE
.Cfile
)
13722 static void rewriteCNull(ref Expression e
, ref Type t
)
13724 if (!t
.isTypePointer())
13726 if (auto ie
= e
.optimize(WANTvalue
).isIntegerExp())
13728 if (ie
.getInteger() == 0)
13730 e
= new NullExp(e
.loc
, Type
.tnull
);
13735 rewriteCNull(exp
.e1
, t1
);
13736 rewriteCNull(exp
.e2
, t2
);
13739 if (t1
.ty
== Tnoreturn
)
13742 exp
.e1
= specialNoreturnCast(exp
.e1
, exp
.type
);
13744 else if (t2
.ty
== Tnoreturn
)
13747 exp
.e2
= specialNoreturnCast(exp
.e2
, exp
.type
);
13749 // If either operand is void the result is void, we have to cast both
13750 // the expression to void so that we explicitly discard the expression
13752 // https://issues.dlang.org/show_bug.cgi?id=16598
13753 else if (t1
.ty
== Tvoid || t2
.ty
== Tvoid
)
13755 exp
.type
= Type
.tvoid
;
13756 exp
.e1
= exp
.e1
.castTo(sc
, exp
.type
);
13757 exp
.e2
= exp
.e2
.castTo(sc
, exp
.type
);
13763 if (Expression ex
= typeCombine(exp
, sc
))
13769 switch (exp
.e1
.type
.toBasetype().ty
)
13774 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
);
13779 switch (exp
.e2
.type
.toBasetype().ty
)
13784 exp
.e1
= exp
.e1
.castTo(sc
, exp
.e2
.type
);
13789 if (exp
.type
.toBasetype().ty
== Tarray
)
13791 exp
.e1
= exp
.e1
.castTo(sc
, exp
.type
);
13792 exp
.e2
= exp
.e2
.castTo(sc
, exp
.type
);
13795 exp
.type
= exp
.type
.merge2();
13798 printf("res: %s\n", exp
.type
.toChars());
13799 printf("e1 : %s\n", exp
.e1
.type
.toChars());
13800 printf("e2 : %s\n", exp
.e2
.type
.toChars());
13803 /* https://issues.dlang.org/show_bug.cgi?id=14696
13804 * If either e1 or e2 contain temporaries which need dtor,
13805 * make them conditional.
13807 * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2)
13809 * (auto __cond = cond) ? (... __tmp1) : (... __tmp2)
13810 * and replace edtors of __tmp1 and __tmp2 with:
13811 * __tmp1.edtor --> __cond && __tmp1.dtor()
13812 * __tmp2.edtor --> __cond || __tmp2.dtor()
13819 override void visit(GenericExp exp
)
13821 static if (LOGSEMANTIC
)
13823 printf("GenericExp::semantic('%s')\n", exp
.toChars());
13825 // C11 6.5.1.1 Generic Selection
13827 auto ec
= exp
.cntlExp
.expressionSemantic(sc
).arrayFuncConv(sc
);
13828 bool errors
= ec
.isErrorExp() !is null;
13831 auto types
= (*exp
.types
)[];
13832 foreach (i
, ref t
; types
)
13835 continue; // `default:` case
13836 t
= t
.typeSemantic(ec
.loc
, sc
);
13837 if (t
.isTypeError())
13843 /* C11 6.5.1-2 duplicate check
13845 /* C11 distinguishes int, long, and long long. But D doesn't, so depending on the
13846 * C target, a long may have the same type as `int` in the D type system.
13847 * So, skip checks when this may be the case. Later pick the first match
13850 (t
.ty
== Tint32 || t
.ty
== Tuns32
) && target
.c
.longsize
== 4 ||
13851 (t
.ty
== Tint64 || t
.ty
== Tuns64
) && target
.c
.longsize
== 8 ||
13852 (t
.ty
== Tfloat64 || t
.ty
== Timaginary64 || t
.ty
== Tcomplex64
) && target
.c
.long_doublesize
== 8
13856 foreach (t2
; types
[0 .. i
])
13858 if (t2
&& t2
.equals(t
))
13860 error(ec
.loc
, "generic association type `%s` can only appear once", t
.toChars());
13867 auto exps
= (*exp
.exps
)[];
13868 foreach (ref e
; exps
)
13870 e
= e
.expressionSemantic(sc
);
13871 if (e
.isErrorExp())
13878 enum size_t None
= ~0;
13879 size_t imatch
= None
;
13880 size_t idefault
= None
;
13881 foreach (const i
, t
; types
)
13885 /* if tc is compatible with t, it's a match
13886 * C11 6.2.7 defines a compatible type as being the same type, including qualifiers
13890 assert(imatch
== None
);
13892 break; // pick first match
13896 idefault
= i
; // multiple defaults are not allowed, and are caught by cparse
13899 if (imatch
== None
)
13901 if (imatch
== None
)
13903 error(exp
.loc
, "no compatible generic association type for controlling expression type `%s`", tc
.toChars());
13907 result
= exps
[imatch
];
13910 override void visit(FileInitExp e
)
13912 //printf("FileInitExp::semantic()\n");
13913 e
.type
= Type
.tstring
;
13917 override void visit(LineInitExp e
)
13919 e
.type
= Type
.tint32
;
13923 override void visit(ModuleInitExp e
)
13925 //printf("ModuleInitExp::semantic()\n");
13926 e
.type
= Type
.tstring
;
13930 override void visit(FuncInitExp e
)
13932 //printf("FuncInitExp::semantic()\n");
13933 e
.type
= Type
.tstring
;
13936 result
= e
.resolveLoc(Loc
.initial
, sc
);
13942 override void visit(PrettyFuncInitExp e
)
13944 //printf("PrettyFuncInitExp::semantic()\n");
13945 e
.type
= Type
.tstring
;
13948 result
= e
.resolveLoc(Loc
.initial
, sc
);
13956 /**********************************
13957 * Try to run semantic routines.
13958 * If they fail, return NULL.
13960 Expression
trySemantic(Expression exp
, Scope
* sc
)
13962 //printf("+trySemantic(%s)\n", exp.toChars());
13963 uint errors
= global
.startGagging();
13964 Expression e
= expressionSemantic(exp
, sc
);
13965 if (global
.endGagging(errors
))
13969 //printf("-trySemantic(%s)\n", exp.toChars());
13973 /**************************
13974 * Helper function for easy error propagation.
13975 * If error occurs, returns ErrorExp. Otherwise returns NULL.
13977 Expression
unaSemantic(UnaExp e
, Scope
* sc
)
13979 static if (LOGSEMANTIC
)
13981 printf("UnaExp::semantic('%s')\n", e
.toChars());
13983 Expression e1x
= e
.e1
.expressionSemantic(sc
);
13984 if (e1x
.op
== EXP
.error
)
13990 /**************************
13991 * Helper function for easy error propagation.
13992 * If error occurs, returns ErrorExp. Otherwise returns NULL.
13994 Expression
binSemantic(BinExp e
, Scope
* sc
)
13996 static if (LOGSEMANTIC
)
13998 printf("BinExp::semantic('%s')\n", e
.toChars());
14000 Expression e1x
= e
.e1
.expressionSemantic(sc
);
14001 Expression e2x
= e
.e2
.expressionSemantic(sc
);
14003 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
14004 if (e1x
.op
== EXP
.type
)
14005 e1x
= resolveAliasThis(sc
, e1x
);
14006 if (e2x
.op
== EXP
.type
)
14007 e2x
= resolveAliasThis(sc
, e2x
);
14009 if (e1x
.op
== EXP
.error
)
14011 if (e2x
.op
== EXP
.error
)
14018 Expression
binSemanticProp(BinExp e
, Scope
* sc
)
14020 if (Expression ex
= binSemantic(e
, sc
))
14022 Expression e1x
= resolveProperties(sc
, e
.e1
);
14023 Expression e2x
= resolveProperties(sc
, e
.e2
);
14024 if (e1x
.op
== EXP
.error
)
14026 if (e2x
.op
== EXP
.error
)
14033 // entrypoint for semantic ExpressionSemanticVisitor
14034 extern (C
++) Expression
expressionSemantic(Expression e
, Scope
* sc
)
14036 scope v
= new ExpressionSemanticVisitor(sc
);
14041 private Expression
dotIdSemanticPropX(DotIdExp exp
, Scope
* sc
)
14043 //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars());
14044 if (Expression ex
= unaSemantic(exp
, sc
))
14047 if (!(sc
.flags
& SCOPE
.Cfile
) && exp
.ident
== Id
._mangleof
)
14051 // return mangleof as an Expression
14052 static Expression
dotMangleof(const ref Loc loc
, Scope
* sc
, Dsymbol
ds)
14055 if (auto f
= ds.isFuncDeclaration())
14057 if (f
.checkForwardRef(loc
))
14058 return ErrorExp
.get();
14060 if (f
.purityInprocess || f
.safetyInprocess || f
.nothrowInprocess || f
.nogcInprocess
)
14062 error(loc
, "%s `%s` cannot retrieve its `.mangleof` while inferring attributes", f
.kind
, f
.toPrettyChars
);
14063 return ErrorExp
.get();
14067 mangleToBuffer(ds, buf
);
14068 Expression e
= new StringExp(loc
, buf
.extractSlice());
14069 return e
.expressionSemantic(sc
);
14075 case EXP
.scope_
: return dotMangleof(exp
.loc
, sc
, exp
.e1
.isScopeExp().sds
);
14076 case EXP
.variable
: return dotMangleof(exp
.loc
, sc
, exp
.e1
.isVarExp().var
);
14077 case EXP
.dotVariable
: return dotMangleof(exp
.loc
, sc
, exp
.e1
.isDotVarExp().var
);
14078 case EXP
.overloadSet
: return dotMangleof(exp
.loc
, sc
, exp
.e1
.isOverExp().vars
);
14079 case EXP
.template_
:
14081 TemplateExp te
= exp
.e1
.isTemplateExp();
14082 return dotMangleof(exp
.loc
, sc
, ds = te
.fd ? te
.fd
.isDsymbol() : te
.td
);
14090 if (exp
.e1
.isVarExp() && exp
.e1
.type
.toBasetype().isTypeSArray() && exp
.ident
== Id
.length
)
14092 // bypass checkPurity
14093 return exp
.e1
.type
.dotExp(sc
, exp
.e1
, exp
.ident
, cast(DotExpFlag
) (exp
.noderef
* DotExpFlag
.noDeref
));
14096 if (!exp
.e1
.isDotExp())
14098 exp
.e1
= resolvePropertiesX(sc
, exp
.e1
);
14101 if (auto te
= exp
.e1
.isTupleExp())
14103 if (exp
.ident
== Id
.offsetof
)
14105 /* 'distribute' the .offsetof to each of the tuple elements.
14107 auto exps
= new Expressions(te
.exps
.length
);
14108 foreach (i
, e
; (*te
.exps
)[])
14110 (*exps
)[i
] = new DotIdExp(e
.loc
, e
, Id
.offsetof
);
14112 // Don't evaluate te.e0 in runtime
14113 Expression e
= new TupleExp(exp
.loc
, null, exps
);
14114 e
= e
.expressionSemantic(sc
);
14117 if (exp
.ident
== Id
.length
)
14119 // Don't evaluate te.e0 in runtime
14120 return new IntegerExp(exp
.loc
, te
.exps
.length
, Type
.tsize_t
);
14124 // https://issues.dlang.org/show_bug.cgi?id=14416
14125 // Template has no built-in properties except for 'stringof'.
14126 if ((exp
.e1
.isDotTemplateExp() || exp
.e1
.isTemplateExp()) && exp
.ident
!= Id
.stringof
)
14128 error(exp
.loc
, "template `%s` does not have property `%s`", exp
.e1
.toChars(), exp
.ident
.toChars());
14129 return ErrorExp
.get();
14133 error(exp
.loc
, "expression `%s` does not have property `%s`", exp
.e1
.toChars(), exp
.ident
.toChars());
14134 return ErrorExp
.get();
14140 private bool checkDisabled(Dsymbol s
, ref Loc loc
, Scope
* sc
)
14142 if (auto d
= s
.isDeclaration())
14143 return d
.checkDisabled(loc
, sc
);
14148 /******************************
14149 * Resolve properties, i.e. `e1.ident`, without seeing UFCS.
14151 * exp = expression to resolve
14153 * gag = do not emit error messages, just return `null`
14155 * resolved expression, null if error
14157 Expression
dotIdSemanticProp(DotIdExp exp
, Scope
* sc
, bool gag
)
14159 //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars());
14161 //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
14163 const cfile
= (sc
.flags
& SCOPE
.Cfile
) != 0;
14165 /* Special case: rewrite this.id and super.id
14166 * to be classtype.id and baseclasstype.id
14167 * if we have no this pointer.
14169 if ((exp
.e1
.isThisExp() || exp
.e1
.isSuperExp()) && !hasThis(sc
))
14171 if (AggregateDeclaration ad
= sc
.getStructClassScope())
14173 if (exp
.e1
.isThisExp())
14175 exp
.e1
= new TypeExp(exp
.e1
.loc
, ad
.type
);
14179 if (auto cd
= ad
.isClassDeclaration())
14182 exp
.e1
= new TypeExp(exp
.e1
.loc
, cd
.baseClass
.type
);
14189 Expression e
= dotIdSemanticPropX(exp
, sc
);
14196 if (auto de = exp
.e1
.isDotExp())
14207 Type t1b
= exp
.e1
.type
.toBasetype();
14209 if (auto ie
= eright
.isScopeExp()) // also used for template alias's
14211 auto flags
= SearchLocalsOnly
;
14212 /* Disable access to another module's private imports.
14213 * The check for 'is sds our current module' is because
14214 * the current module should have access to its own imports.
14216 if (ie
.sds
.isModule() && ie
.sds
!= sc
._module
)
14217 flags |
= IgnorePrivateImports
;
14218 if (sc
.flags
& SCOPE
.ignoresymbolvisibility
)
14219 flags |
= IgnoreSymbolVisibility
;
14220 Dsymbol s
= ie
.sds
.search(exp
.loc
, exp
.ident
, flags
);
14221 /* Check for visibility before resolving aliases because public
14222 * aliases to private symbols are public.
14224 if (s
&& !(sc
.flags
& SCOPE
.ignoresymbolvisibility
) && !symbolIsVisible(sc
._module
, s
))
14230 auto p
= s
.isPackage();
14231 if (p
&& checkAccess(sc
, p
))
14238 // if 's' is a tuple variable, the tuple is returned.
14241 s
.checkDeprecated(exp
.loc
, sc
);
14242 s
.checkDisabled(exp
.loc
, sc
);
14244 if (auto em
= s
.isEnumMember())
14246 return em
.getVarExp(exp
.loc
, sc
);
14248 if (auto v
= s
.isVarDeclaration())
14250 //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars());
14252 !v
.type
.deco
&& v
.inuse
)
14255 error(exp
.loc
, "circular reference to %s `%s`", v
.kind(), v
.toPrettyChars());
14257 error(exp
.loc
, "forward reference to %s `%s`", v
.kind(), v
.toPrettyChars());
14258 return ErrorExp
.get();
14260 if (v
.type
.isTypeError())
14261 return ErrorExp
.get();
14263 if ((v
.storage_class
& STC
.manifest
) && v
._init
&& !exp
.wantsym
)
14265 /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2().
14266 * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably
14267 * be reverted. `wantsym` is the hack to work around the problem.
14271 error(exp
.loc
, "circular initialization of %s `%s`", v
.kind(), v
.toPrettyChars());
14272 return ErrorExp
.get();
14274 auto e
= v
.expandInitializer(exp
.loc
);
14276 e
= e
.expressionSemantic(sc
);
14285 eleft
= new ThisExp(exp
.loc
);
14286 e
= new DotVarExp(exp
.loc
, eleft
, v
);
14287 e
= e
.expressionSemantic(sc
);
14291 e
= new VarExp(exp
.loc
, v
);
14294 e
= new CommaExp(exp
.loc
, eleft
, e
);
14299 return e
.expressionSemantic(sc
);
14302 if (auto f
= s
.isFuncDeclaration())
14304 //printf("it's a function\n");
14305 if (!f
.functionSemantic())
14306 return ErrorExp
.get();
14311 eleft
= new ThisExp(exp
.loc
);
14312 e
= new DotVarExp(exp
.loc
, eleft
, f
, true);
14313 e
= e
.expressionSemantic(sc
);
14317 e
= new VarExp(exp
.loc
, f
, true);
14320 e
= new CommaExp(exp
.loc
, eleft
, e
);
14326 if (auto td
= s
.isTemplateDeclaration())
14330 e
= new DotTemplateExp(exp
.loc
, eleft
, td
);
14332 e
= new TemplateExp(exp
.loc
, td
);
14333 e
= e
.expressionSemantic(sc
);
14336 if (OverDeclaration od
= s
.isOverDeclaration())
14338 Expression e
= new VarExp(exp
.loc
, od
, true);
14341 e
= new CommaExp(exp
.loc
, eleft
, e
);
14342 e
.type
= Type
.tvoid
; // ambiguous type?
14344 return e
.expressionSemantic(sc
);
14346 if (auto o
= s
.isOverloadSet())
14348 //printf("'%s' is an overload set\n", o.toChars());
14349 return new OverExp(exp
.loc
, o
);
14352 if (auto t
= s
.getType())
14354 return (new TypeExp(exp
.loc
, t
)).expressionSemantic(sc
);
14357 if (auto tup
= s
.isTupleDeclaration())
14361 Expression e
= new DotVarExp(exp
.loc
, eleft
, tup
);
14362 e
= e
.expressionSemantic(sc
);
14365 Expression e
= new TupleExp(exp
.loc
, tup
);
14366 e
= e
.expressionSemantic(sc
);
14370 if (auto sds
= s
.isScopeDsymbol())
14372 //printf("it's a ScopeDsymbol %s\n", ident.toChars());
14373 Expression e
= new ScopeExp(exp
.loc
, sds
);
14374 e
= e
.expressionSemantic(sc
);
14376 e
= new DotExp(exp
.loc
, eleft
, e
);
14380 if (auto imp
= s
.isImport())
14382 Expression se
= new ScopeExp(exp
.loc
, imp
.pkg
);
14383 return se
.expressionSemantic(sc
);
14386 if (auto attr
= s
.isAttribDeclaration())
14388 if (auto sm
= ie
.sds
.search(exp
.loc
, exp
.ident
, flags
))
14390 auto es
= new DsymbolExp(exp
.loc
, sm
);
14395 // BUG: handle other cases like in IdentifierExp::semantic()
14398 printf("s = %p '%s', kind = '%s'\n", s
, s
.toChars(), s
.kind());
14402 else if (exp
.ident
== Id
.stringof
)
14404 Expression e
= new StringExp(exp
.loc
, ie
.toString());
14405 e
= e
.expressionSemantic(sc
);
14408 if (ie
.sds
.isPackage() || ie
.sds
.isImport() || ie
.sds
.isModule())
14414 s
= ie
.sds
.search_correct(exp
.ident
);
14415 if (s
&& symbolIsVisible(sc
, s
))
14418 error(exp
.loc
, "undefined identifier `%s` in %s `%s`, perhaps add `static import %s;`", exp
.ident
.toChars(), ie
.sds
.kind(), ie
.sds
.toPrettyChars(), s
.toPrettyChars());
14420 error(exp
.loc
, "undefined identifier `%s` in %s `%s`, did you mean %s `%s`?", exp
.ident
.toChars(), ie
.sds
.kind(), ie
.sds
.toPrettyChars(), s
.kind(), s
.toChars());
14423 error(exp
.loc
, "undefined identifier `%s` in %s `%s`", exp
.ident
.toChars(), ie
.sds
.kind(), ie
.sds
.toPrettyChars());
14424 return ErrorExp
.get();
14426 else if (t1b
.ty
== Tpointer
&& exp
.e1
.type
.ty
!= Tenum
&&
14428 exp
.ident
== Id
.__sizeof ||
14429 exp
.ident
== Id
.__xalignof ||
14431 (exp
.ident
== Id
._mangleof ||
14432 exp
.ident
== Id
.offsetof ||
14433 exp
.ident
== Id
._init ||
14434 exp
.ident
== Id
.stringof
)
14437 Type t1bn
= t1b
.nextOf();
14440 if (AggregateDeclaration ad
= isAggregate(t1bn
))
14442 if (!ad
.members
) // https://issues.dlang.org/show_bug.cgi?id=11312
14452 if (gag
&& t1bn
.ty
== Tvoid
)
14454 Expression e
= new PtrExp(exp
.loc
, exp
.e1
);
14455 e
= e
.expressionSemantic(sc
);
14456 const newFlag
= cast(DotExpFlag
) (gag
* DotExpFlag
.gag | exp
.noderef
* DotExpFlag
.noDeref
);
14457 return e
.type
.dotExp(sc
, e
, exp
.ident
, newFlag
);
14459 else if (exp
.ident
== Id
.__xalignof
&&
14460 exp
.e1
.isVarExp() &&
14461 exp
.e1
.isVarExp().var
.isVarDeclaration() &&
14462 !exp
.e1
.isVarExp().var
.isVarDeclaration().alignment
.isUnknown())
14464 // For `x.alignof` get the alignment of the variable, not the alignment of its type
14465 const explicitAlignment
= exp
.e1
.isVarExp().var
.isVarDeclaration().alignment
;
14466 const naturalAlignment
= exp
.e1
.type
.alignsize();
14467 const actualAlignment
= explicitAlignment
.isDefault() ? naturalAlignment
: explicitAlignment
.get();
14468 Expression e
= new IntegerExp(exp
.loc
, actualAlignment
, Type
.tsize_t
);
14471 else if ((exp
.ident
== Id
.max || exp
.ident
== Id
.min
) &&
14472 exp
.e1
.isVarExp() &&
14473 exp
.e1
.isVarExp().var
.isBitFieldDeclaration())
14475 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
14476 auto bf
= exp
.e1
.isVarExp().var
.isBitFieldDeclaration();
14477 return new IntegerExp(exp
.loc
, bf
.getMinMax(exp
.ident
), bf
.type
);
14479 else if ((exp
.ident
== Id
.max || exp
.ident
== Id
.min
) &&
14480 exp
.e1
.isDotVarExp() &&
14481 exp
.e1
.isDotVarExp().var
.isBitFieldDeclaration())
14483 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
14484 auto bf
= exp
.e1
.isDotVarExp().var
.isBitFieldDeclaration();
14485 return new IntegerExp(exp
.loc
, bf
.getMinMax(exp
.ident
), bf
.type
);
14489 if (exp
.e1
.isTypeExp() || exp
.e1
.isTemplateExp())
14492 const flag
= cast(DotExpFlag
) (exp
.noderef
* DotExpFlag
.noDeref | gag
* DotExpFlag
.gag
);
14494 Expression e
= exp
.e1
.type
.dotExp(sc
, exp
.e1
, exp
.ident
, flag
);
14497 e
= e
.expressionSemantic(sc
);
14504 * Resolve `e1.ident!tiargs` without seeing UFCS.
14506 * exp = the `DotTemplateInstanceExp` to resolve
14507 * sc = the semantic scope
14508 * gag = stop "not a property" error and return `null`.
14510 * `null` if error or not found, or the resolved expression.
14512 Expression
dotTemplateSemanticProp(DotTemplateInstanceExp exp
, Scope
* sc
, bool gag
)
14514 static if (LOGSEMANTIC
)
14516 printf("DotTemplateInstanceExpY::semantic('%s')\n", exp
.toChars());
14519 static Expression
errorExp()
14521 return ErrorExp
.get();
14524 Expression e1
= exp
.e1
;
14526 if (exp
.ti
.tempdecl
&& exp
.ti
.tempdecl
.parent
&& exp
.ti
.tempdecl
.parent
.isTemplateMixin())
14528 // if 'ti.tempdecl' happens to be found in a mixin template don't lose that info
14529 // and do the symbol search in that context (Issue: 19476)
14530 auto tm
= cast(TemplateMixin
)exp
.ti
.tempdecl
.parent
;
14531 e1
= new DotExp(exp
.e1
.loc
, exp
.e1
, new ScopeExp(tm
.loc
, tm
));
14534 auto die
= new DotIdExp(exp
.loc
, e1
, exp
.ti
.name
);
14536 Expression e
= die
.dotIdSemanticPropX(sc
);
14539 exp
.e1
= die
.e1
; // take back
14540 Type t1b
= exp
.e1
.type
.toBasetype();
14541 if (t1b
.ty
== Tarray || t1b
.ty
== Tsarray || t1b
.ty
== Taarray || t1b
.ty
== Tnull ||
(t1b
.isTypeBasic() && t1b
.ty
!= Tvoid
))
14543 /* No built-in type has templatized properties, so do shortcut.
14544 * It is necessary in: 1024.max!"a < b"
14549 e
= die
.dotIdSemanticProp(sc
, gag
);
14553 isDotOpDispatch(e
))
14555 /* opDispatch!tiargs would be a function template that needs IFTI,
14556 * so it's not a template
14564 if (e
.op
== EXP
.error
)
14566 if (DotVarExp dve
= e
.isDotVarExp())
14568 if (FuncDeclaration fd
= dve
.var
.isFuncDeclaration())
14570 if (TemplateDeclaration td
= fd
.findTemplateDeclRoot())
14572 e
= new DotTemplateExp(dve
.loc
, dve
.e1
, td
);
14573 e
= e
.expressionSemantic(sc
);
14576 else if (OverDeclaration od
= dve
.var
.isOverDeclaration())
14578 exp
.e1
= dve
.e1
; // pull semantic() result
14580 if (!exp
.findTempDecl(sc
))
14582 if (exp
.ti
.needsTypeInference(sc
))
14584 exp
.ti
.dsymbolSemantic(sc
);
14585 if (!exp
.ti
.inst || exp
.ti
.errors
) // if template failed to expand
14588 if (Declaration v
= exp
.ti
.toAlias().isDeclaration())
14590 if (v
.type
&& !v
.type
.deco
)
14591 v
.type
= v
.type
.typeSemantic(v
.loc
, sc
);
14592 return new DotVarExp(exp
.loc
, exp
.e1
, v
)
14593 .expressionSemantic(sc
);
14595 return new DotExp(exp
.loc
, exp
.e1
, new ScopeExp(exp
.loc
, exp
.ti
))
14596 .expressionSemantic(sc
);
14599 else if (e
.op
== EXP
.variable
)
14601 VarExp ve
= cast(VarExp
)e
;
14602 if (FuncDeclaration fd
= ve
.var
.isFuncDeclaration())
14604 if (TemplateDeclaration td
= fd
.findTemplateDeclRoot())
14606 e
= new TemplateExp(ve
.loc
, td
)
14607 .expressionSemantic(sc
);
14610 else if (OverDeclaration od
= ve
.var
.isOverDeclaration())
14612 exp
.ti
.tempdecl
= od
;
14613 return new ScopeExp(exp
.loc
, exp
.ti
)
14614 .expressionSemantic(sc
);
14618 if (DotTemplateExp dte
= e
.isDotTemplateExp())
14620 exp
.e1
= dte
.e1
; // pull semantic() result
14622 exp
.ti
.tempdecl
= dte
.td
;
14623 if (!exp
.ti
.semanticTiargs(sc
))
14625 if (exp
.ti
.needsTypeInference(sc
))
14627 exp
.ti
.dsymbolSemantic(sc
);
14628 if (!exp
.ti
.inst || exp
.ti
.errors
) // if template failed to expand
14631 if (Declaration v
= exp
.ti
.toAlias().isDeclaration())
14633 return new DotVarExp(exp
.loc
, exp
.e1
, v
)
14634 .expressionSemantic(sc
);
14636 return new DotExp(exp
.loc
, exp
.e1
, new ScopeExp(exp
.loc
, exp
.ti
))
14637 .expressionSemantic(sc
);
14639 else if (e
.op
== EXP
.template_
)
14641 exp
.ti
.tempdecl
= (cast(TemplateExp
)e
).td
;
14642 return new ScopeExp(exp
.loc
, exp
.ti
)
14643 .expressionSemantic(sc
);
14645 else if (DotExp
de = e
.isDotExp())
14647 if (de.e2
.op
== EXP
.overloadSet
)
14649 if (!exp
.findTempDecl(sc
) ||
!exp
.ti
.semanticTiargs(sc
))
14653 if (exp
.ti
.needsTypeInference(sc
))
14655 exp
.ti
.dsymbolSemantic(sc
);
14656 if (!exp
.ti
.inst || exp
.ti
.errors
) // if template failed to expand
14659 if (Declaration v
= exp
.ti
.toAlias().isDeclaration())
14661 if (v
.type
&& !v
.type
.deco
)
14662 v
.type
= v
.type
.typeSemantic(v
.loc
, sc
);
14663 return new DotVarExp(exp
.loc
, exp
.e1
, v
)
14664 .expressionSemantic(sc
);
14666 return new DotExp(exp
.loc
, exp
.e1
, new ScopeExp(exp
.loc
, exp
.ti
))
14667 .expressionSemantic(sc
);
14670 else if (OverExp oe
= e
.isOverExp())
14672 exp
.ti
.tempdecl
= oe
.vars
;
14673 return new ScopeExp(exp
.loc
, exp
.ti
)
14674 .expressionSemantic(sc
);
14678 error(exp
.loc
, "`%s` isn't a template", e
.toChars());
14682 MATCH
matchType(FuncExp funcExp
, Type to
, Scope
* sc
, FuncExp
* presult
, ErrorSink eSink
)
14684 auto loc
= funcExp
.loc
;
14685 auto tok
= funcExp
.tok
;
14686 auto td
= funcExp
.td
;
14687 auto fd
= funcExp
.fd
;
14688 auto type
= funcExp
.type
;
14690 MATCH
cannotInfer()
14692 eSink
.error(loc
, "cannot infer parameter types from `%s`", to
.toChars());
14693 return MATCH
.nomatch
;
14696 //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars());
14700 TypeFunction tof
= null;
14701 if (to
.ty
== Tdelegate
)
14703 if (tok
== TOK
.function_
)
14705 eSink
.error(loc
, "cannot match function literal to delegate type `%s`", to
.toChars());
14706 return MATCH
.nomatch
;
14708 tof
= cast(TypeFunction
)to
.nextOf();
14710 else if (to
.ty
== Tpointer
&& (tof
= to
.nextOf().isTypeFunction()) !is null)
14712 if (tok
== TOK
.delegate_
)
14714 eSink
.error(loc
, "cannot match delegate literal to function pointer type `%s`", to
.toChars());
14715 return MATCH
.nomatch
;
14723 return cannotInfer();
14726 // Parameter types inference from 'tof'
14728 TypeFunction tf
= fd
.type
.isTypeFunction();
14729 //printf("\ttof = %s\n", tof.toChars());
14730 //printf("\ttf = %s\n", tf.toChars());
14731 const dim
= tf
.parameterList
.length
;
14733 if (tof
.parameterList
.length
!= dim || tof
.parameterList
.varargs
!= tf
.parameterList
.varargs
)
14734 return cannotInfer();
14736 auto tiargs
= new Objects();
14737 tiargs
.reserve(td
.parameters
.length
);
14739 foreach (tp
; *td
.parameters
)
14742 foreach (i
, p
; tf
.parameterList
)
14744 if (auto ti
= p
.type
.isTypeIdentifier())
14745 if (ti
&& ti
.ident
== tp
.ident
)
14751 Parameter pto
= tof
.parameterList
[u
];
14753 if (t
.ty
== Terror
)
14754 return cannotInfer();
14755 tf
.parameterList
[u
].storageClass
= tof
.parameterList
[u
].storageClass
;
14759 // Set target of return type inference
14760 if (!tf
.next
&& tof
.next
)
14763 auto ti
= new TemplateInstance(loc
, td
, tiargs
);
14764 Expression ex
= (new ScopeExp(loc
, ti
)).expressionSemantic(td
._scope
);
14766 // Reset inference target for the later re-semantic
14769 if (ex
.op
== EXP
.error
)
14770 return MATCH
.nomatch
;
14771 if (auto ef
= ex
.isFuncExp())
14772 return ef
.matchType(to
, sc
, presult
, eSink
);
14774 return cannotInfer();
14777 if (!tof ||
!tof
.next
)
14778 return MATCH
.nomatch
;
14780 assert(type
&& type
!= Type
.tvoid
);
14781 if (fd
.type
.ty
== Terror
)
14782 return MATCH
.nomatch
;
14783 auto tfx
= fd
.type
.isTypeFunction();
14784 bool convertMatch
= (type
.ty
!= to
.ty
);
14786 if (fd
.inferRetType
&& tfx
.next
.implicitConvTo(tof
.next
) == MATCH
.convert
)
14788 /* If return type is inferred and covariant return,
14789 * tweak return statements to required return type.
14792 * class C : Object, I{}
14794 * I delegate() dg = delegate() { return new class C(); }
14796 convertMatch
= true;
14798 auto tfy
= new TypeFunction(tfx
.parameterList
, tof
.next
,
14799 tfx
.linkage
, STC
.undefined_
);
14801 tfy
.trust
= tfx
.trust
;
14802 tfy
.isnothrow
= tfx
.isnothrow
;
14803 tfy
.isnogc
= tfx
.isnogc
;
14804 tfy
.purity
= tfx
.purity
;
14805 tfy
.isproperty
= tfx
.isproperty
;
14806 tfy
.isref
= tfx
.isref
;
14807 tfy
.isInOutParam
= tfx
.isInOutParam
;
14808 tfy
.isInOutQual
= tfx
.isInOutQual
;
14809 tfy
.deco
= tfy
.merge().deco
;
14814 if (tok
== TOK
.delegate_ ||
14815 tok
== TOK
.reserved
&& (type
.ty
== Tdelegate || type
.ty
== Tpointer
&& to
.ty
== Tdelegate
))
14817 // Allow conversion from implicit function pointer to delegate
14818 tx
= new TypeDelegate(tfx
);
14819 tx
.deco
= tx
.merge().deco
;
14823 assert(tok
== TOK
.function_ || tok
== TOK
.reserved
&& type
.ty
== Tpointer || fd
.errors
);
14824 tx
= tfx
.pointerTo();
14826 //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars());
14828 MATCH m
= tx
.implicitConvTo(to
);
14829 if (m
> MATCH
.nomatch
)
14831 // MATCH.exact: exact type match
14832 // MATCH.constant: covairiant type match (eg. attributes difference)
14833 // MATCH.convert: context conversion
14834 m
= convertMatch ? MATCH
.convert
: tx
.equals(to
) ? MATCH
.exact
: MATCH
.constant
;
14838 (*presult
) = cast(FuncExp
)funcExp
.copy();
14839 (*presult
).type
= to
;
14841 // https://issues.dlang.org/show_bug.cgi?id=12508
14842 // Tweak function body for covariant returns.
14843 (*presult
).fd
.modifyReturns(sc
, tof
.next
);
14846 else if (!cast(ErrorSinkNull
)eSink
)
14848 auto ts
= toAutoQualChars(tx
, to
);
14849 eSink
.error(loc
, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
14850 funcExp
.toChars(), ts
[0], ts
[1]);
14855 private bool checkSharedAccessBin(BinExp binExp
, Scope
* sc
)
14857 const r1
= binExp
.e1
.checkSharedAccess(sc
);
14858 const r2
= binExp
.e2
.checkSharedAccess(sc
);
14862 /***************************************
14863 * If expression is shared, check that we can access it.
14864 * Give error message if not.
14867 * e = expression to check
14869 * returnRef = Whether this expression is for a `return` statement
14870 * off a `ref` function, in which case a single level
14871 * of dereference is allowed (e.g. `shared(int)*`).
14875 bool checkSharedAccess(Expression e
, Scope
* sc
, bool returnRef
= false)
14877 if (global
.params
.noSharedAccess
!= FeatureState
.enabled ||
14880 sc
.flags
& SCOPE
.ctfe
)
14885 //printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef);
14887 bool check(Expression e
, bool allowRef
)
14889 bool sharedError(Expression e
)
14891 // https://dlang.org/phobos/core_atomic.html
14892 error(e
.loc
, "direct access to shared `%s` is not allowed, see `core.atomic`", e
.toChars());
14896 // Error by default
14897 bool visit(Expression e
)
14899 // https://issues.dlang.org/show_bug.cgi?id=23639
14900 // Should be able to cast(shared)
14901 if (!e
.isCastExp() && e
.type
.isShared())
14902 return sharedError(e
);
14906 bool visitNew(NewExp e
)
14909 check(e
.thisexp
, false);
14913 bool visitVar(VarExp e
)
14915 // https://issues.dlang.org/show_bug.cgi?id=20908
14916 // direct access to init symbols is ok as they
14917 // cannot be modified.
14918 if (e
.var
.isSymbolDeclaration())
14921 // https://issues.dlang.org/show_bug.cgi?id=22626
14922 // Synchronized functions don't need to use core.atomic
14923 // when accessing `this`.
14924 if (sc
.func
&& sc
.func
.isSynchronized())
14926 if (e
.var
.isThisDeclaration())
14929 return sharedError(e
);
14931 else if (!allowRef
&& e
.var
.type
.isShared())
14932 return sharedError(e
);
14937 bool visitAddr(AddrExp e
)
14939 return check(e
.e1
, true);
14942 bool visitPtr(PtrExp e
)
14944 if (!allowRef
&& e
.type
.isShared())
14945 return sharedError(e
);
14947 if (e
.e1
.type
.isShared())
14948 return sharedError(e
);
14950 return check(e
.e1
, false);
14953 bool visitDotVar(DotVarExp e
)
14955 //printf("dotvarexp = %s\n", e.toChars());
14956 if (e
.type
.isShared())
14958 if (e
.e1
.isThisExp())
14960 // https://issues.dlang.org/show_bug.cgi?id=22626
14961 if (sc
.func
&& sc
.func
.isSynchronized())
14964 // https://issues.dlang.org/show_bug.cgi?id=23790
14965 if (e
.e1
.type
.isTypeStruct())
14969 auto fd
= e
.var
.isFuncDeclaration();
14970 const sharedFunc
= fd
&& fd
.type
.isShared
;
14971 if (!allowRef
&& !sharedFunc
)
14972 return sharedError(e
);
14974 // Allow using `DotVarExp` within value types
14975 if (e
.e1
.type
.isTypeSArray() || e
.e1
.type
.isTypeStruct())
14976 return check(e
.e1
, allowRef
);
14978 // If we end up with a single `VarExp`, it might be a `ref` param
14979 // `shared ref T` param == `shared(T)*`.
14980 if (auto ve
= e
.e1
.isVarExp())
14982 return check(e
.e1
, allowRef
&& (ve
.var
.storage_class
& STC
.ref_
));
14985 return sharedError(e
);
14988 return check(e
.e1
, false);
14991 bool visitIndex(IndexExp e
)
14993 if (!allowRef
&& e
.type
.isShared())
14994 return sharedError(e
);
14996 if (e
.e1
.type
.isShared())
14997 return sharedError(e
);
14999 return check(e
.e1
, false);
15002 bool visitComma(CommaExp e
)
15004 // Cannot be `return ref` since we can't use the return,
15005 // but it's better to show that error than an unrelated `shared` one
15006 return check(e
.e2
, true);
15011 default: return visit(e
);
15013 // Those have no indirections / can be ignored
15016 case EXP
.complex80
:
15018 case EXP
.null_
: return false;
15020 case EXP
.variable
: return visitVar(e
.isVarExp());
15021 case EXP
.new_
: return visitNew(e
.isNewExp());
15022 case EXP
.address
: return visitAddr(e
.isAddrExp());
15023 case EXP
.star
: return visitPtr(e
.isPtrExp());
15024 case EXP
.dotVariable
: return visitDotVar(e
.isDotVarExp());
15025 case EXP
.index
: return visitIndex(e
.isIndexExp());
15029 return check(e
, returnRef
);
15032 /****************************************
15033 * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE_FULL_PATH__ to loc.
15035 Expression
resolveLoc(Expression exp
, const ref Loc loc
, Scope
* sc
)
15037 Expression
visit(Expression exp
)
15039 if (auto unaExp
= exp
.isUnaExp())
15041 unaExp
.e1
= unaExp
.e1
.resolveLoc(loc
, sc
);
15048 Expression
visitCat(CatExp exp
)
15050 exp
.e1
= exp
.e1
.resolveLoc(loc
, sc
);
15051 exp
.e2
= exp
.e2
.resolveLoc(loc
, sc
);
15055 Expression
visitFileInit(FileInitExp exp
)
15057 //printf("FileInitExp::resolve() %s\n", exp.toChars());
15059 if (exp
.op
== EXP
.fileFullPath
)
15060 s
= FileName
.toAbsolute(loc
.isValid() ? loc
.filename
: sc
._module
.srcfile
.toChars());
15062 s
= loc
.isValid() ? loc
.filename
: sc
._module
.ident
.toChars();
15064 Expression e
= new StringExp(loc
, s
.toDString());
15065 return e
.expressionSemantic(sc
);
15068 Expression
visitLineInit(LineInitExp _
)
15070 Expression e
= new IntegerExp(loc
, loc
.linnum
, Type
.tint32
);
15071 return e
.expressionSemantic(sc
);
15074 Expression
visitModuleInit(ModuleInitExp _
)
15076 const auto s
= (sc
.callsc ? sc
.callsc
: sc
)._module
.toPrettyChars().toDString();
15077 Expression e
= new StringExp(loc
, s
);
15078 return e
.expressionSemantic(sc
);
15081 Expression
visitFuncInit(FuncInitExp _
)
15084 if (sc
.callsc
&& sc
.callsc
.func
)
15085 s
= sc
.callsc
.func
.Dsymbol
.toPrettyChars();
15087 s
= sc
.func
.Dsymbol
.toPrettyChars();
15090 Expression e
= new StringExp(loc
, s
.toDString());
15091 return e
.expressionSemantic(sc
);
15094 Expression
visitPrettyFunc(PrettyFuncInitExp _
)
15096 FuncDeclaration fd
= (sc
.callsc
&& sc
.callsc
.func
)
15103 const funcStr
= fd
.Dsymbol
.toPrettyChars();
15105 functionToBufferWithIdent(fd
.type
.isTypeFunction(), buf
, funcStr
, fd
.isStatic
);
15106 s
= buf
.extractChars();
15113 Expression e
= new StringExp(loc
, s
.toDString());
15114 e
= e
.expressionSemantic(sc
);
15115 e
.type
= Type
.tstring
;
15121 default: return visit(exp
);
15122 case EXP
.concatenate
: return visitCat(exp
.isCatExp());
15124 case EXP
.fileFullPath
: return visitFileInit(exp
.isFileInitExp());
15125 case EXP
.line
: return visitLineInit(exp
.isLineInitExp
);
15126 case EXP
.moduleString
: return visitModuleInit(exp
.isModuleInitExp());
15127 case EXP
.functionString
: return visitFuncInit(exp
.isFuncInitExp());
15128 case EXP
.prettyFunction
: return visitPrettyFunc(exp
.isPrettyFuncInitExp());
15132 /************************************************
15133 * Destructors are attached to VarDeclarations.
15134 * Hence, if expression returns a temp that needs a destructor,
15135 * make sure and create a VarDeclaration for that temp.
15137 Expression
addDtorHook(Expression e
, Scope
* sc
)
15139 Expression
visit(Expression exp
)
15144 Expression
visitStructLiteral(StructLiteralExp exp
)
15147 /* If struct requires a destructor, rewrite as:
15148 * (S tmp = S()),tmp
15149 * so that the destructor can be hung on tmp.
15151 if (sd
.dtor
&& sc
.func
)
15153 /* Make an identifier for the temporary of the form:
15154 * __sl%s%d, where %s is the struct name
15156 char[10] buf
= void;
15157 const prefix
= "__sl";
15158 const ident
= sd
.ident
.toString
;
15159 const fullLen
= prefix
.length
+ ident
.length
;
15160 const len
= fullLen
< buf
.length ? fullLen
: buf
.length
;
15161 buf
[0 .. prefix
.length
] = prefix
;
15162 buf
[prefix
.length
.. len
] = ident
[0 .. len
- prefix
.length
];
15164 auto tmp
= copyToTemp(0, buf
[0 .. len
], exp
);
15165 Expression ae
= new DeclarationExp(exp
.loc
, tmp
);
15166 Expression e
= new CommaExp(exp
.loc
, ae
, new VarExp(exp
.loc
, tmp
));
15167 e
= e
.expressionSemantic(sc
);
15174 Expression
visitCall(CallExp exp
)
15177 auto type
= exp
.type
;
15178 /* Only need to add dtor hook if it's a type that needs destruction.
15179 * Use same logic as VarDeclaration::callScopeDtor()
15182 if (auto tf
= e1
.type
.isTypeFunction())
15188 Type tv
= type
.baseElemOf();
15189 if (auto ts
= tv
.isTypeStruct())
15191 StructDeclaration sd
= ts
.sym
;
15194 /* Type needs destruction, so declare a tmp
15195 * which the back end will recognize and call dtor on
15197 auto tmp
= copyToTemp(0, Id
.__tmpfordtor
.toString(), exp
);
15198 auto de = new DeclarationExp(exp
.loc
, tmp
);
15199 auto ve
= new VarExp(exp
.loc
, tmp
);
15200 Expression e
= new CommaExp(exp
.loc
, de, ve
);
15201 e
= e
.expressionSemantic(sc
);
15209 Expression
visitCast(CastExp exp
)
15211 if (exp
.to
.toBasetype().ty
== Tvoid
) // look past the cast(void)
15212 exp
.e1
= exp
.e1
.addDtorHook(sc
);
15216 Expression
visitComma(CommaExp exp
)
15218 exp
.e2
= exp
.e2
.addDtorHook(sc
);
15224 default: return visit(e
);
15226 case EXP
.structLiteral
: return visitStructLiteral(e
.isStructLiteralExp());
15227 case EXP
.call: return visitCall(e
.isCallExp());
15228 case EXP
.cast_
: return visitCast(e
.isCastExp());
15229 case EXP
.comma
: return visitComma(e
.isCommaExp());
15233 /*******************************
15234 * Try to convert an expression to be an lvalue.
15236 * Give error if we're not an lvalue.
15238 * _this = expression to convert
15240 * action = for error messages, what the lvalue is needed for (e.g. take address of for `&x`, modify for `x++`)
15241 * Returns: converted expression, or `ErrorExp` on error
15243 extern(C
++) Expression
toLvalue(Expression _this
, Scope
* sc
, const(char)* action
)
15245 return toLvalueImpl(_this
, sc
, action
, _this
);
15248 // e = original un-lowered expression for error messages, in case of recursive calls
15249 private Expression
toLvalueImpl(Expression _this
, Scope
* sc
, const(char)* action
, Expression e
)
15252 action
= "create lvalue of";
15255 Expression
visit(Expression _this
)
15257 // BinaryAssignExp does not have an EXP associated
15258 // so it's treated on the default path.
15259 // Lvalue-ness will be handled in glue :layer.
15260 if (_this
.isBinAssignExp())
15262 if (!_this
.loc
.isValid())
15265 if (e
.op
== EXP
.type
)
15266 error(_this
.loc
, "cannot %s type `%s`", action
, e
.type
.toChars());
15267 else if (e
.op
== EXP
.template_
)
15268 error(_this
.loc
, "cannot %s template `%s`, perhaps instantiate it first", action
, e
.toChars());
15270 error(_this
.loc
, "cannot %s expression `%s` because it is not an lvalue", action
, e
.toChars());
15272 return ErrorExp
.get();
15275 Expression
visitInteger(IntegerExp _this
)
15277 if (!_this
.loc
.isValid())
15279 error(e
.loc
, "cannot %s constant `%s`", action
, e
.toChars());
15280 return ErrorExp
.get();
15283 Expression
visitThis(ThisExp _this
)
15285 if (_this
.type
.toBasetype().ty
== Tclass
)
15287 // Class `this` is an rvalue; struct `this` is an lvalue.
15288 return visit(_this
);
15294 Expression
visitString(StringExp _this
)
15296 //printf("StringExp::toLvalue(%s) type = %s\n", _this.toChars(), _this.type ? _this.type.toChars() : NULL);
15297 return (_this
.type
&& _this
.type
.toBasetype().ty
== Tsarray
) ? _this
: visit(_this
);
15300 Expression
visitStructLiteral(StructLiteralExp _this
)
15302 if (sc
.flags
& SCOPE
.Cfile
)
15303 return _this
; // C struct literals are lvalues
15305 return visit(_this
);
15308 Expression
visitTemplate(TemplateExp _this
)
15311 return visit(_this
);
15314 return symbolToExp(_this
.fd
, _this
.loc
, sc
, true);
15318 Expression
visitVar(VarExp _this
)
15320 auto var
= _this
.var
;
15321 if (var
.storage_class
& STC
.manifest
)
15323 error(_this
.loc
, "cannot %s manifest constant `%s`", action
, var
.toChars());
15324 return ErrorExp
.get();
15326 if (var
.storage_class
& STC
.lazy_
&& !_this
.delegateWasExtracted
)
15328 error(_this
.loc
, "cannot %s lazy variable `%s`", action
, var
.toChars());
15329 return ErrorExp
.get();
15331 if (var
.ident
== Id
.ctfe
)
15333 error(_this
.loc
, "cannot %s compiler-generated variable `__ctfe`", action
);
15334 return ErrorExp
.get();
15336 if (var
.ident
== Id
.dollar
) // https://issues.dlang.org/show_bug.cgi?id=13574
15338 error(_this
.loc
, "cannot %s operator `$`", action
);
15339 return ErrorExp
.get();
15344 Expression
visitDotVar(DotVarExp _this
)
15346 auto e1
= _this
.e1
;
15347 auto var
= _this
.var
;
15348 //printf("DotVarExp::toLvalue(%s)\n", toChars());
15349 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
15351 /* C11 6.5.2.3-3: A postfix expression followed by the '.' or '->' operator
15352 * is an lvalue if the first expression is an lvalue.
15354 if (!e1
.isLvalue())
15355 return visit(_this
);
15357 if (!_this
.isLvalue())
15358 return visit(_this
);
15359 if (e1
.op
== EXP
.this_
&& sc
.ctorflow
.fieldinit
.length
&& !(sc
.ctorflow
.callSuper
& CSX
.any_ctor
))
15361 if (VarDeclaration vd
= var
.isVarDeclaration())
15363 auto ad
= vd
.isMember2();
15364 if (ad
&& ad
.fields
.length
== sc
.ctorflow
.fieldinit
.length
)
15366 foreach (i
, f
; ad
.fields
)
15370 if (!(sc
.ctorflow
.fieldinit
[i
].csx
& CSX
.this_ctor
))
15372 /* If the address of vd is taken, assume it is thereby initialized
15373 * https://issues.dlang.org/show_bug.cgi?id=15869
15375 modifyFieldVar(_this
.loc
, sc
, vd
, e1
);
15386 Expression
visitCall(CallExp _this
)
15388 if (_this
.isLvalue())
15390 return visit(_this
);
15393 Expression
visitCast(CastExp _this
)
15395 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
15397 /* C11 6.5.4-5: A cast does not yield an lvalue.
15399 return visit(_this
);
15401 if (_this
.isLvalue())
15403 return visit(_this
);
15406 Expression
visitVectorArray(VectorArrayExp _this
)
15408 _this
.e1
= _this
.e1
.toLvalueImpl(sc
, action
, e
);
15412 Expression
visitSlice(SliceExp _this
)
15414 //printf("SliceExp::toLvalue(%s) _this.type = %s\n", _this.toChars(), _this.type ? _this.type.toChars() : NULL);
15415 return (_this
.type
&& _this
.type
.toBasetype().ty
== Tsarray
) ? _this
: visit(_this
);
15418 Expression
visitArray(ArrayExp _this
)
15420 if (_this
.type
&& _this
.type
.toBasetype().ty
== Tvoid
)
15421 error(_this
.loc
, "`void`s have no value");
15425 Expression
visitComma(CommaExp _this
)
15427 _this
.e2
= _this
.e2
.toLvalue(sc
, action
);
15431 Expression
visitDelegatePointer(DelegatePtrExp _this
)
15433 _this
.e1
= _this
.e1
.toLvalueImpl(sc
, action
, e
);
15437 Expression
visitDelegateFuncptr(DelegateFuncptrExp _this
)
15439 _this
.e1
= _this
.e1
.toLvalueImpl(sc
, action
, e
);
15443 Expression
visitIndex(IndexExp _this
)
15445 if (_this
.isLvalue())
15447 return visit(_this
);
15450 Expression
visitAssign(AssignExp _this
)
15452 if (_this
.e1
.op
== EXP
.slice || _this
.e1
.op
== EXP
.arrayLength
)
15454 return visit(_this
);
15457 /* In front-end level, AssignExp should make an lvalue of e1.
15458 * Taking the address of e1 will be handled in low level layer,
15459 * so this function does nothing.
15464 Expression
visitCond(CondExp _this
)
15466 // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
15467 CondExp e
= cast(CondExp
)(_this
.copy());
15468 e
.e1
= _this
.e1
.toLvalue(sc
, action
).addressOf();
15469 e
.e2
= _this
.e2
.toLvalue(sc
, action
).addressOf();
15470 e
.type
= _this
.type
.pointerTo();
15471 return new PtrExp(_this
.loc
, e
, _this
.type
);
15477 default: return visit(_this
);
15479 case EXP
.int64
: return visitInteger(_this
.isIntegerExp());
15480 case EXP
.error
: return _this
;
15481 case EXP
.identifier
: return _this
;
15482 case EXP
.dSymbol
: return _this
;
15483 case EXP
.this_
: return visitThis(_this
.isThisExp());
15484 case EXP
.super_
: return visitThis(_this
.isSuperExp());
15485 case EXP
.string_
: return visitString(_this
.isStringExp());
15486 case EXP
.structLiteral
: return visitStructLiteral(_this
.isStructLiteralExp());
15487 case EXP
.template_
: return visitTemplate(_this
.isTemplateExp());
15488 case EXP
.variable
: return visitVar(_this
.isVarExp());
15489 case EXP
.overloadSet
: return _this
;
15490 case EXP
.dotVariable
: return visitDotVar(_this
.isDotVarExp());
15491 case EXP
.call: return visitCall(_this
.isCallExp());
15492 case EXP
.star
: return _this
;
15493 case EXP
.cast_
: return visitCast(_this
.isCastExp());
15494 case EXP
.vectorArray
: return visitVectorArray(_this
.isVectorArrayExp());
15495 case EXP
.slice
: return visitSlice(_this
.isSliceExp());
15496 case EXP
.array
: return visitArray(_this
.isArrayExp());
15497 case EXP
.comma
: return visitComma(_this
.isCommaExp());
15498 case EXP
.delegatePointer
: return visitDelegatePointer(_this
.isDelegatePtrExp());
15499 case EXP
.delegateFunctionPointer
: return visitDelegateFuncptr(_this
.isDelegateFuncptrExp());
15500 case EXP
.index
: return visitIndex(_this
.isIndexExp());
15501 case EXP
.construct
: return visitAssign(_this
.isConstructExp());
15502 case EXP
.loweredAssignExp
: return visitAssign(_this
.isLoweredAssignExp());
15503 case EXP
.blit
: return visitAssign(_this
.isBlitExp());
15504 case EXP
.assign
: return visitAssign(_this
.isAssignExp());
15505 case EXP
.question
: return visitCond(_this
.isCondExp());
15509 /***************************************
15512 * flag: 1: do not issue error message for invalid modification
15513 2: the exp is a DotVarExp and a subfield of the leftmost
15514 variable is modified
15516 * Whether the type is modifiable
15518 Modifiable
checkModifiable(Expression exp
, Scope
* sc
, ModifyFlags flag
= ModifyFlags
.none
)
15523 auto varExp
= cast(VarExp
)exp
;
15525 //printf("VarExp::checkModifiable %s", varExp.toChars());
15526 assert(varExp
.type
);
15527 return varExp
.var
.checkModify(varExp
.loc
, sc
, null, flag
);
15529 case EXP
.dotVariable
:
15530 auto dotVarExp
= cast(DotVarExp
)exp
;
15532 //printf("DotVarExp::checkModifiable %s %s\n", dotVarExp.toChars(), dotVarExp.type.toChars());
15533 if (dotVarExp
.e1
.op
== EXP
.this_
)
15534 return dotVarExp
.var
.checkModify(dotVarExp
.loc
, sc
, dotVarExp
.e1
, flag
);
15536 /* https://issues.dlang.org/show_bug.cgi?id=12764
15537 * If inside a constructor and an expression of type `this.field.var`
15538 * is encountered, where `field` is a struct declaration with
15539 * default construction disabled, we must make sure that
15540 * assigning to `var` does not imply that `field` was initialized
15542 if (sc
.func
&& sc
.func
.isCtorDeclaration())
15544 // if inside a constructor scope and e1 of this DotVarExp
15545 // is another DotVarExp, then check if the leftmost expression is a `this` identifier
15546 if (auto dve
= dotVarExp
.e1
.isDotVarExp())
15548 // Iterate the chain of DotVarExp to find `this`
15549 // Keep track whether access to fields was limited to union members
15550 // s.t. one can initialize an entire struct inside nested unions
15551 // (but not its members)
15552 bool onlyUnion
= true;
15555 auto v
= dve
.var
.isVarDeclaration();
15558 // Accessing union member?
15559 auto t
= v
.type
.isTypeStruct();
15560 if (!t ||
!t
.sym
.isUnionDeclaration())
15563 // Another DotVarExp left?
15564 if (!dve
.e1 || dve
.e1
.op
!= EXP
.dotVariable
)
15567 dve
= cast(DotVarExp
) dve
.e1
;
15570 if (dve
.e1
.op
== EXP
.this_
)
15572 scope v
= dve
.var
.isVarDeclaration();
15573 /* if v is a struct member field with no initializer, no default construction
15574 * and v wasn't intialized before
15576 if (v
&& v
.isField() && !v
._init
&& !v
.ctorinit
)
15578 if (auto ts
= v
.type
.isTypeStruct())
15580 if (ts
.sym
.noDefaultCtor
)
15582 /* checkModify will consider that this is an initialization
15583 * of v while it is actually an assignment of a field of v
15585 scope modifyLevel
= v
.checkModify(dotVarExp
.loc
, sc
, dve
.e1
, !onlyUnion ?
(flag | ModifyFlags
.fieldAssign
) : flag
);
15586 if (modifyLevel
== Modifiable
.initialization
)
15588 // https://issues.dlang.org/show_bug.cgi?id=22118
15589 // v is a union type field that was assigned
15590 // a variable, therefore it counts as initialization
15592 return Modifiable
.initialization
;
15594 return Modifiable
.yes
;
15596 return modifyLevel
;
15604 //printf("\te1 = %s\n", e1.toChars());
15605 return dotVarExp
.e1
.checkModifiable(sc
, flag
);
15608 auto ptrExp
= cast(PtrExp
)exp
;
15609 if (auto se
= ptrExp
.e1
.isSymOffExp())
15611 return se
.var
.checkModify(ptrExp
.loc
, sc
, null, flag
);
15613 else if (auto ae
= ptrExp
.e1
.isAddrExp())
15615 return ae
.e1
.checkModifiable(sc
, flag
);
15617 return Modifiable
.yes
;
15620 auto sliceExp
= cast(SliceExp
)exp
;
15622 //printf("SliceExp::checkModifiable %s\n", sliceExp.toChars());
15623 auto e1
= sliceExp
.e1
;
15624 if (e1
.type
.ty
== Tsarray ||
(e1
.op
== EXP
.index
&& e1
.type
.ty
!= Tarray
) || e1
.op
== EXP
.slice
)
15626 return e1
.checkModifiable(sc
, flag
);
15628 return Modifiable
.yes
;
15631 return (cast(CommaExp
)exp
).e2
.checkModifiable(sc
, flag
);
15634 auto indexExp
= cast(IndexExp
)exp
;
15635 auto e1
= indexExp
.e1
;
15636 if (e1
.type
.ty
== Tsarray ||
15637 e1
.type
.ty
== Taarray ||
15638 (e1
.op
== EXP
.index
&& e1
.type
.ty
!= Tarray
) ||
15639 e1
.op
== EXP
.slice
)
15641 return e1
.checkModifiable(sc
, flag
);
15643 return Modifiable
.yes
;
15646 auto condExp
= cast(CondExp
)exp
;
15647 if (condExp
.e1
.checkModifiable(sc
, flag
) != Modifiable
.no
15648 && condExp
.e2
.checkModifiable(sc
, flag
) != Modifiable
.no
)
15649 return Modifiable
.yes
;
15650 return Modifiable
.no
;
15653 return exp
.type ? Modifiable
.yes
: Modifiable
.no
; // default modifiable
15658 * Similar to `toLvalue`, but also enforce it is mutable or raise an error.
15660 * _this = Expression to convert
15662 * Returns: `_this` converted to an lvalue, or an `ErrorExp`
15664 extern(C
++) Expression
modifiableLvalue(Expression _this
, Scope
* sc
)
15666 return modifiableLvalueImpl(_this
, sc
, _this
);
15669 // e = original / un-lowered expression to print in error messages
15670 private Expression
modifiableLvalueImpl(Expression _this
, Scope
* sc
, Expression e
)
15673 Expression
visit(Expression exp
)
15675 //printf("Expression::modifiableLvalue() %s, type = %s\n", exp.toChars(), exp.type.toChars());
15676 // See if this expression is a modifiable lvalue (i.e. not const)
15677 if (exp
.isBinAssignExp())
15678 return exp
.toLvalue(sc
, "modify");
15680 auto type
= exp
.type
;
15681 if (checkModifiable(exp
, sc
) == Modifiable
.yes
)
15684 if (!type
.isMutable())
15686 if (auto dve
= exp
.isDotVarExp())
15688 if (isNeedThisScope(sc
, dve
.var
))
15689 for (Dsymbol s
= sc
.func
; s
; s
= s
.toParentLocal())
15691 FuncDeclaration ff
= s
.isFuncDeclaration();
15694 if (!ff
.type
.isMutable
)
15696 error(exp
.loc
, "cannot modify `%s` in `%s` function", exp
.toChars(), MODtoChars(type
.mod
));
15697 return ErrorExp
.get();
15701 error(exp
.loc
, "cannot modify `%s` expression `%s`", MODtoChars(type
.mod
), exp
.toChars());
15702 return ErrorExp
.get();
15704 else if (!type
.isAssignable())
15706 error(exp
.loc
, "cannot modify struct instance `%s` of type `%s` because it contains `const` or `immutable` members",
15707 exp
.toChars(), type
.toChars());
15708 return ErrorExp
.get();
15711 return exp
.toLvalueImpl(sc
, "modify", e
);
15714 Expression
visitString(StringExp exp
)
15716 error(exp
.loc
, "cannot modify string literal `%s`", exp
.toChars());
15717 return ErrorExp
.get();
15720 Expression
visitVar(VarExp exp
)
15722 //printf("VarExp::modifiableLvalue('%s')\n", exp.var.toChars());
15723 if (exp
.var
.storage_class
& STC
.manifest
)
15725 error(exp
.loc
, "cannot modify manifest constant `%s`", exp
.toChars());
15726 return ErrorExp
.get();
15728 // See if this expression is a modifiable lvalue (i.e. not const)
15732 Expression
visitPtr(PtrExp exp
)
15734 //printf("PtrExp::modifiableLvalue() %s, type %s\n", exp.toChars(), exp.type.toChars());
15737 if (auto se
= e1
.isSymOffExp())
15739 else if (auto ve
= e1
.isVarExp())
15741 if (var
&& var
.type
.isFunction_Delegate_PtrToFunction())
15743 if (var
.type
.isTypeFunction())
15744 error(exp
.loc
, "function `%s` is not an lvalue and cannot be modified", var
.toChars());
15746 error(exp
.loc
, "function pointed to by `%s` is not an lvalue and cannot be modified", var
.toChars());
15747 return ErrorExp
.get();
15752 Expression
visitSlice(SliceExp exp
)
15754 error(exp
.loc
, "slice expression `%s` is not a modifiable lvalue", exp
.toChars());
15758 Expression
visitComma(CommaExp exp
)
15760 exp
.e2
= exp
.e2
.modifiableLvalueImpl(sc
, e
);
15764 Expression
visitDelegatePtr(DelegatePtrExp exp
)
15766 if (sc
.setUnsafe(false, exp
.loc
, "cannot modify delegate pointer in `@safe` code `%s`", exp
))
15768 return ErrorExp
.get();
15773 Expression
visitDelegateFuncptr(DelegateFuncptrExp exp
)
15775 if (sc
.setUnsafe(false, exp
.loc
, "cannot modify delegate function pointer in `@safe` code `%s`", exp
))
15777 return ErrorExp
.get();
15782 Expression
visitIndex(IndexExp exp
)
15784 //printf("IndexExp::modifiableLvalue(%s)\n", exp.toChars());
15785 Expression ex
= exp
.markSettingAAElem();
15786 if (ex
.op
== EXP
.error
)
15792 Expression
visitCond(CondExp exp
)
15794 if (!exp
.e1
.isLvalue() && !exp
.e2
.isLvalue())
15796 error(exp
.loc
, "conditional expression `%s` is not a modifiable lvalue", exp
.toChars());
15797 return ErrorExp
.get();
15799 exp
.e1
= exp
.e1
.modifiableLvalue(sc
);
15800 exp
.e2
= exp
.e2
.modifiableLvalue(sc
);
15801 return exp
.toLvalue(sc
, "modify");
15806 default: return visit(_this
);
15807 case EXP
.string_
: return visitString(_this
.isStringExp());
15808 case EXP
.variable
: return visitVar(_this
.isVarExp());
15809 case EXP
.star
: return visitPtr(_this
.isPtrExp());
15810 case EXP
.slice
: return visitSlice(_this
.isSliceExp());
15811 case EXP
.comma
: return visitComma(_this
.isCommaExp());
15812 case EXP
.delegatePointer
: return visitDelegatePtr(_this
.isDelegatePtrExp());
15813 case EXP
.delegateFunctionPointer
: return visitDelegateFuncptr(_this
.isDelegateFuncptrExp());
15814 case EXP
.index
: return visitIndex(_this
.isIndexExp());
15815 case EXP
.question
: return visitCond(_this
.isCondExp());
15820 /****************************************************
15821 * Determine if `exp`, which gets its address taken, can do so safely.
15824 * exp = expression having its address taken
15825 * v = the variable getting its address taken
15827 * `true` if ok, `false` for error
15829 bool checkAddressVar(Scope
* sc
, Expression exp
, VarDeclaration v
)
15831 //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars());
15835 if (!v
.canTakeAddressOf())
15837 error(exp
.loc
, "cannot take address of `%s`", exp
.toChars());
15840 if (sc
.func
&& !sc
.intypeof
&& !v
.isDataseg())
15842 if (sc
.useDIP1000
!= FeatureState
.enabled
&&
15843 !(v
.storage_class
& STC
.temp
) &&
15844 sc
.setUnsafe(false, exp
.loc
, "cannot take address of local `%s` in `@safe` function `%s`", v
, sc
.func
))
15852 /**************************************
15853 * This check ensures that the object in `exp` can have its address taken, or
15854 * issue a diagnostic error.
15856 * e = expression to check
15859 * true if the expression is addressable
15861 bool checkAddressable(Expression e
, Scope
* sc
)
15868 case EXP
.dotVariable
:
15869 // https://issues.dlang.org/show_bug.cgi?id=22749
15870 // Error about taking address of any bit-field, regardless of
15871 // whether SCOPE.Cfile is set.
15872 if (auto bf
= ex
.isDotVarExp().var
.isBitFieldDeclaration())
15874 error(e
.loc
, "cannot take address of bit-field `%s`", bf
.toChars());
15877 goto case EXP
.cast_
;
15880 ex
= ex
.isBinExp().e1
;
15886 ex
= ex
.isUnaExp().e1
;
15890 if (sc
.flags
& SCOPE
.Cfile
)
15892 // C11 6.5.3.2: A variable that has its address taken cannot be
15893 // stored in a register.
15894 // C11 6.3.2.1: An array that has its address computed with `[]`
15895 // or cast to an lvalue pointer cannot be stored in a register.
15896 if (ex
.isVarExp().var
.storage_class
& STC
.register
)
15898 if (e
.isIndexExp())
15899 error(e
.loc
, "cannot index through register variable `%s`", ex
.toChars());
15901 error(e
.loc
, "cannot take address of register variable `%s`", ex
.toChars());
15916 /*******************************
15917 * Checks the attributes of a function.
15918 * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`)
15919 * and usage of `deprecated` and `@disabled`-ed symbols are checked.
15922 * exp = expression to check attributes for
15923 * sc = scope of the function
15924 * f = function to be checked
15925 * Returns: `true` if error occur.
15927 private bool checkFunctionAttributes(Expression exp
, Scope
* sc
, FuncDeclaration f
)
15929 bool error
= f
.checkDisabled(exp
.loc
, sc
);
15930 error |
= f
.checkDeprecated(exp
.loc
, sc
);
15931 error |
= f
.checkPurity(exp
.loc
, sc
);
15932 error |
= f
.checkSafety(exp
.loc
, sc
);
15933 error |
= f
.checkNogc(exp
.loc
, sc
);
15937 /*******************************
15938 * Helper function for `getRightThis()`.
15939 * Gets `this` of the next outer aggregate.
15941 * loc = location to use for error messages
15943 * s = the parent symbol of the existing `this`
15944 * ad = struct or class we need the correct `this` for
15945 * e1 = existing `this`
15946 * t = type of the existing `this`
15947 * var = the specific member of ad we're accessing
15948 * flag = if true, return `null` instead of throwing an error
15950 * Expression representing the `this` for the var
15952 Expression
getThisSkipNestedFuncs(const ref Loc loc
, Scope
* sc
, Dsymbol s
, AggregateDeclaration ad
, Expression e1
, Type t
, Dsymbol var
, bool flag
= false)
15955 while (s
&& s
.isFuncDeclaration())
15957 FuncDeclaration f
= s
.isFuncDeclaration();
15961 e1
= new VarExp(loc
, f
.vthis
);
15962 if (f
.hasDualContext())
15966 e1
= e1
.expressionSemantic(sc
);
15967 e1
= new PtrExp(loc
, e1
);
15968 uint i
= f
.followInstantiationContext(ad
);
15969 e1
= new IndexExp(loc
, e1
, new IntegerExp(i
));
15970 s
= f
.toParentP(ad
);
15978 error(e1
.loc
, "need `this` of type `%s` to access member `%s` from static function `%s`", ad
.toChars(), var
.toChars(), f
.toChars());
15979 e1
= ErrorExp
.get();
15984 if (n
> 1 || e1
.op
== EXP
.index
)
15985 e1
= e1
.expressionSemantic(sc
);
15986 if (s
&& e1
.type
.equivalent(Type
.tvoidptr
))
15988 if (auto sad
= s
.isAggregateDeclaration())
15990 Type ta
= sad
.handleType();
15991 if (ta
.ty
== Tstruct
)
15992 ta
= ta
.pointerTo();
15996 e1
.type
= e1
.type
.addMod(t
.mod
);
16000 /*******************************
16001 * Make a dual-context container for use as a `this` argument.
16003 * loc = location to use for error messages
16004 * sc = current scope
16005 * fd = target function that will take the `this` argument
16007 * Temporary closure variable.
16009 * The function `fd` is added to the nested references of the
16010 * newly created variable such that a closure is made for the variable when
16011 * the address of `fd` is taken.
16013 VarDeclaration
makeThis2Argument(const ref Loc loc
, Scope
* sc
, FuncDeclaration fd
)
16015 Type tthis2
= Type
.tvoidptr
.sarrayOf(2);
16016 VarDeclaration vthis2
= new VarDeclaration(loc
, tthis2
, Identifier
.generateId("__this"), null);
16017 vthis2
.storage_class |
= STC
.temp
;
16018 vthis2
.dsymbolSemantic(sc
);
16019 vthis2
.parent
= sc
.parent
;
16020 // make it a closure var
16022 sc
.func
.closureVars
.push(vthis2
);
16023 // add `fd` to the nested refs
16024 vthis2
.nestedrefs
.push(fd
);
16028 /*******************************
16029 * Make sure that the runtime hook `id` exists.
16031 * loc = location to use for error messages
16032 * sc = current scope
16033 * id = the hook identifier
16034 * description = what the hook does
16035 * module_ = what module the hook is located in
16037 * a `bool` indicating if the hook is present.
16039 bool verifyHookExist(const ref Loc loc
, ref Scope sc
, Identifier id
, string description
, Identifier module_
= Id
.object
)
16041 auto rootSymbol
= sc
.search(loc
, Id
.empty
, null);
16042 if (auto moduleSymbol
= rootSymbol
.search(loc
, module_
))
16043 if (moduleSymbol
.search(loc
, id
))
16045 error(loc
, "`%s.%s` not found. The current runtime does not support %.*s, or the runtime is corrupt.", module_
.toChars(), id
.toChars(), cast(int)description
.length
, description
.ptr
);
16049 /***************************************
16050 * Fit elements[] to the corresponding types of the `sd`'s fields.
16053 * sd = the struct declaration
16054 * loc = location to use for error messages
16056 * elements = explicit arguments used to construct object
16057 * stype = the constructed object type.
16059 * false if any errors occur,
16060 * otherwise true and elements[] are rewritten for the output.
16062 private bool fit(StructDeclaration sd
, const ref Loc loc
, Scope
* sc
, Expressions
* elements
, Type stype
)
16067 const nfields
= sd
.nonHiddenFields();
16069 for (size_t i
= 0; i
< elements
.length
; i
++)
16071 Expression e
= (*elements
)[i
];
16075 e
= resolveProperties(sc
, e
);
16078 if (i
< sd
.fields
.length
&& e
.op
== EXP
.null_
)
16080 // CTFE sometimes creates null as hidden pointer; we'll allow this.
16083 .error(loc
, "more initializers than fields (%llu) of `%s`", cast(ulong)nfields
, sd
.toChars());
16086 VarDeclaration v
= sd
.fields
[i
];
16087 if (v
.offset
< offset
)
16089 .error(loc
, "overlapping initialization for `%s`", v
.toChars());
16090 if (!sd
.isUnionDeclaration())
16092 enum errorMsg
= "`struct` initializers that contain anonymous unions" ~
16093 " must initialize only the first member of a `union`. All subsequent" ~
16094 " non-overlapping fields are default initialized";
16095 .errorSupplemental(loc
, errorMsg
);
16099 const vsize
= v
.type
.size();
16100 if (vsize
== SIZE_INVALID
)
16102 offset
= cast(uint)(v
.offset
+ vsize
);
16106 t
= t
.addMod(stype
.mod
);
16108 Type tb
= t
.toBasetype();
16110 const hasPointers
= tb
.hasPointers();
16113 if ((!stype
.alignment
.isDefault() && stype
.alignment
.get() < target
.ptrsize ||
16114 (v
.offset
& (target
.ptrsize
- 1))) &&
16115 (sc
.setUnsafe(false, loc
,
16116 "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd
, v
)))
16122 /* Look for case of initializing a static array with a too-short
16123 * string literal, such as:
16124 * char[5] foo = "abc";
16125 * Allow this by doing an explicit cast, which will lengthen the string
16128 if (e
.op
== EXP
.string_
&& tb
.ty
== Tsarray
)
16130 StringExp se
= cast(StringExp
)e
;
16131 Type typeb
= se
.type
.toBasetype();
16132 TY tynto
= tb
.nextOf().ty
;
16133 if (!se
.committed
&&
16134 (typeb
.ty
== Tarray || typeb
.ty
== Tsarray
) && tynto
.isSomeChar
&&
16135 se
.numberOfCodeUnits(tynto
) < (cast(TypeSArray
)tb
).dim
.toInteger())
16137 e
= se
.castTo(sc
, t
);
16142 while (!e
.implicitConvTo(t
) && tb
.ty
== Tsarray
)
16144 /* Static array initialization, as in:
16148 tb
= t
.toBasetype();
16150 if (!e
.implicitConvTo(t
))
16151 t
= origType
; // restore type for better diagnostic
16153 e
= e
.implicitCastTo(sc
, t
);
16155 if (e
.op
== EXP
.error
)
16158 (*elements
)[i
] = doCopyOrMove(sc
, e
);
16165 * Returns `em` as a VariableExp
16167 * em = the EnumMember to wrap
16168 * loc = location of use of em
16169 * sc = scope of use of em
16171 * VarExp referenceing `em` or ErrorExp if `em` if disabled/deprecated
16173 Expression
getVarExp(EnumMember em
, const ref Loc loc
, Scope
* sc
)
16175 dsymbolSemantic(em
, sc
);
16177 return ErrorExp
.get();
16178 em
.checkDisabled(loc
, sc
);
16180 if (em
.depdecl
&& !em
.depdecl
._scope
)
16181 em
.depdecl
._scope
= sc
;
16182 em
.checkDeprecated(loc
, sc
);
16185 return ErrorExp
.get();
16186 Expression e
= new VarExp(loc
, em
);
16187 e
= e
.expressionSemantic(sc
);
16188 if (!(sc
.flags
& SCOPE
.Cfile
) && em
.isCsymbol())
16190 /* C11 types them as int. But if in D file,
16191 * type qualified names as the enum
16193 e
.type
= em
.parent
.isEnumDeclaration().type
;
16200 /*****************************
16201 * Try to treat `exp` as a boolean,
16203 * exp = the expression
16204 * sc = scope to evalute `exp` in
16206 * Modified expression on success, ErrorExp on error
16208 Expression
toBoolean(Expression exp
, Scope
* sc
)
16213 error(exp
.loc
, "`delete` does not give a boolean result");
16214 return ErrorExp
.get();
16217 auto ce
= exp
.isCommaExp();
16218 auto ex2
= ce
.e2
.toBoolean(sc
);
16219 if (ex2
.op
== EXP
.error
)
16222 ce
.type
= ce
.e2
.type
;
16226 case EXP
.construct
:
16228 case EXP
.loweredAssignExp
:
16229 if (sc
.flags
& SCOPE
.Cfile
)
16233 // are usually mistakes.
16234 error(exp
.loc
, "assignment cannot be used as a condition, perhaps `==` was meant?");
16235 return ErrorExp
.get();
16240 auto le
= exp
.isLogicalExp();
16241 auto ex2
= le
.e2
.toBoolean(sc
);
16242 if (ex2
.op
== EXP
.error
)
16248 auto ce
= exp
.isCondExp();
16249 auto ex1
= ce
.e1
.toBoolean(sc
);
16250 auto ex2
= ce
.e2
.toBoolean(sc
);
16251 if (ex1
.op
== EXP
.error
)
16253 if (ex2
.op
== EXP
.error
)
16261 // Default is 'yes' - do nothing
16262 Expression e
= arrayFuncConv(exp
, sc
);
16264 Type tb
= t
.toBasetype();
16269 // Structs can be converted to bool using opCast(bool)()
16270 if (auto ts
= tb
.isTypeStruct())
16272 AggregateDeclaration ad
= ts
.sym
;
16273 /* Don't really need to check for opCast first, but by doing so we
16274 * get better error messages if it isn't there.
16276 if (Dsymbol fd
= search_function(ad
, Id
._cast
))
16278 e
= new CastExp(exp
.loc
, e
, Type
.tbool
);
16279 e
= e
.expressionSemantic(sc
);
16283 // Forward to aliasthis.
16284 if (ad
.aliasthis
&& !isRecursiveAliasThis(att
, tb
))
16286 e
= resolveAliasThis(sc
, e
);
16288 tb
= e
.type
.toBasetype();
16295 if (!t
.isBoolean())
16297 if (tb
!= Type
.terror
)
16298 error(exp
.loc
, "expression `%s` of type `%s` does not have a boolean value",
16299 exp
.toChars(), t
.toChars());
16300 return ErrorExp
.get();