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(SearchOptFlags flags
)
881 for (Scope
* scx
= sc
; scx
; scx
= scx
.enclosing
)
885 if (scx
.scopesym
.isModule())
886 flags |
= SearchOpt
.unqualifiedModule
; // tell Module.search() that SearchOpt.localsOnly 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
))
913 SearchOptFlags flags
= SearchOpt
.all
;
916 if (sc
.flags
& SCOPE
.ignoresymbolvisibility
)
917 flags |
= SearchOpt
.ignoreVisibility
;
919 // First look in local scopes
920 s
= searchScopes(flags | SearchOpt
.localsOnly
);
923 // Second look in imported modules
924 s
= searchScopes(flags | SearchOpt
.importsOnly
);
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", toChars(init
));
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
;
6748 auto conflict
= sc
.search(Loc
.initial
, s
.ident
, pscopesym
);
6749 error(e
.loc
, "declaration `%s` is already defined", s
.toPrettyChars());
6750 errorSupplemental(conflict
.loc
, "`%s` `%s` is defined here",
6751 conflict
.kind(), conflict
.toChars());
6755 if (v
&& (sc
.flags
& SCOPE
.Cfile
))
6757 /* Do semantic() on initializer last so this will be legal:
6760 e
.declaration
.dsymbolSemantic(sc
);
6761 s
.parent
= sc
.parent
;
6766 // https://issues.dlang.org/show_bug.cgi?id=11720
6767 if ((s
.isFuncDeclaration() ||
6768 s
.isAggregateDeclaration() ||
6769 s
.isEnumDeclaration() ||
6770 s
.isTemplateDeclaration() ||
6772 ) && !sc
.func
.localsymtab
.insert(s
))
6774 // Get the previous symbol
6775 Dsymbol originalSymbol
= sc
.func
.localsymtab
.lookup(s
.ident
);
6777 // Perturb the name mangling so that the symbols can co-exist
6778 // instead of colliding
6779 s
.localNum
= cast(ushort)(originalSymbol
.localNum
+ 1);
6780 // 65535 should be enough for anyone
6783 error(e
.loc
, "more than 65535 symbols with name `%s` generated", s
.ident
.toChars());
6787 // Replace originalSymbol with s, which updates the localCount
6788 sc
.func
.localsymtab
.update(s
);
6790 // The mangling change only works for D mangling
6793 if (!(sc
.flags
& SCOPE
.Cfile
))
6795 /* https://issues.dlang.org/show_bug.cgi?id=21272
6796 * If we are in a foreach body we need to extract the
6797 * function containing the foreach
6799 FuncDeclaration fes_enclosing_func
;
6800 if (sc
.func
&& sc
.func
.fes
)
6801 fes_enclosing_func
= sc
.enclosing
.enclosing
.func
;
6803 // Disallow shadowing
6804 for (Scope
* scx
= sc
.enclosing
; scx
&& (scx
.func
== sc
.func ||
(fes_enclosing_func
&& scx
.func
== fes_enclosing_func
)); scx
= scx
.enclosing
)
6807 if (scx
.scopesym
&& scx
.scopesym
.symtab
&& (s2
= scx
.scopesym
.symtab
.lookup(s
.ident
)) !is null && s
!= s2
)
6809 // allow STC.local symbols to be shadowed
6810 // TODO: not really an optimal design
6811 auto decl
= s2
.isDeclaration();
6812 if (!decl ||
!(decl
.storage_class
& STC
.local
))
6816 deprecation(e
.loc
, "%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.", s
.kind(), s
.ident
.toChars(), s2
.kind(), s2
.toPrettyChars());
6820 error(e
.loc
, "%s `%s` is shadowing %s `%s`", s
.kind(), s
.ident
.toChars(), s2
.kind(), s2
.toPrettyChars());
6829 if (!s
.isVarDeclaration())
6832 if (sc2
.stc & (STC
.pure_ | STC
.nothrow_ | STC
.nogc
))
6834 sc2
.stc &= ~(STC
.pure_ | STC
.nothrow_ | STC
.nogc
);
6835 e
.declaration
.dsymbolSemantic(sc2
);
6838 s
.parent
= sc
.parent
;
6840 if (global
.errors
== olderrors
)
6842 e
.declaration
.semantic2(sc
);
6843 if (global
.errors
== olderrors
)
6845 e
.declaration
.semantic3(sc
);
6848 // todo: error in declaration should be propagated.
6850 e
.type
= Type
.tvoid
;
6854 override void visit(TypeidExp exp
)
6856 static if (LOGSEMANTIC
)
6858 printf("TypeidExp::semantic() %s\n", exp
.toChars());
6860 Type ta
= isType(exp
.obj
);
6861 Expression ea
= isExpression(exp
.obj
);
6862 Dsymbol sa
= isDsymbol(exp
.obj
);
6863 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
6867 dmd
.typesem
.resolve(ta
, exp
.loc
, sc
, ea
, ta
, sa
, true);
6872 if (auto sym
= getDsymbol(ea
))
6873 ea
= symbolToExp(sym
, exp
.loc
, sc
, false);
6875 ea
= ea
.expressionSemantic(sc
);
6876 ea
= resolveProperties(sc
, ea
);
6878 if (ea
.op
== EXP
.type
)
6884 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
6885 error(exp
.loc
, "no type for `typeid(%s)`", ea ? ea
.toChars() : (sa ? sa
.toChars() : ""));
6889 ta
.checkComplexTransition(exp
.loc
, sc
);
6892 auto tb
= ta
.toBasetype();
6893 if (ea
&& tb
.ty
== Tclass
)
6895 if (tb
.toDsymbol(sc
).isClassDeclaration().classKind
== ClassKind
.cpp
)
6897 error(exp
.loc
, "runtime type information is not supported for `extern(C++)` classes");
6900 else if (!Type
.typeinfoclass
)
6902 error(exp
.loc
, "`object.TypeInfo_Class` could not be found, but is implicitly used");
6907 /* Get the dynamic type, which is .classinfo
6909 ea
= ea
.expressionSemantic(sc
);
6910 e
= new TypeidExp(ea
.loc
, ea
);
6911 e
.type
= Type
.typeinfoclass
.type
;
6914 else if (ta
.ty
== Terror
)
6920 // Handle this in the glue layer
6921 e
= new TypeidExp(exp
.loc
, ta
);
6923 bool genObjCode
= true;
6925 // https://issues.dlang.org/show_bug.cgi?id=23650
6926 // We generate object code for typeinfo, required
6927 // by typeid, only if in non-speculative context
6928 if (sc
.flags
& SCOPE
.compile
)
6933 e
.type
= getTypeInfoType(exp
.loc
, ta
, sc
, genObjCode
);
6934 semanticTypeInfo(sc
, ta
);
6938 e
= new CommaExp(exp
.loc
, ea
, e
); // execute ea
6939 e
= e
.expressionSemantic(sc
);
6945 override void visit(TraitsExp e
)
6947 result
= semanticTraits(e
, sc
);
6950 override void visit(HaltExp e
)
6952 static if (LOGSEMANTIC
)
6954 printf("HaltExp::semantic()\n");
6956 e
.type
= Type
.tnoreturn
;
6960 override void visit(IsExp e
)
6962 /* is(targ id tok tspec)
6963 * is(targ id : tok2)
6964 * is(targ id == tok2)
6973 result
= IntegerExp
.createBool(true);
6978 Tuple tup
= isTuple(tded
);
6980 s
= new TupleDeclaration(e
.loc
, e
.id
, &tup
.objects
);
6982 s
= new AliasDeclaration(e
.loc
, e
.id
, tded
);
6983 s
.dsymbolSemantic(sc
);
6985 /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there.
6986 * More investigation is needed.
6988 if (!tup
&& !sc
.insert(s
))
6991 auto conflict
= sc
.search(Loc
.initial
, s
.ident
, pscopesym
);
6992 error(e
.loc
, "declaration `%s` is already defined", s
.toPrettyChars());
6993 errorSupplemental(conflict
.loc
, "`%s` `%s` is defined here",
6994 conflict
.kind(), conflict
.toChars());
6997 unSpeculative(sc
, s
);
6999 result
= IntegerExp
.createBool(true);
7003 result
= IntegerExp
.createBool(false);
7007 static if (LOGSEMANTIC
)
7009 printf("IsExp::semantic(%s)\n", e
.toChars());
7011 if (e
.id
&& !(sc
.flags
& SCOPE
.condition
))
7013 error(e
.loc
, "can only declare type aliases within `static if` conditionals or `static assert`s");
7017 if (e
.tok2
== TOK
.package_ || e
.tok2
== TOK
.module_
) // These is() expressions are special because they can work on modules, not just types.
7019 const oldErrors
= global
.startGagging();
7020 Dsymbol sym
= e
.targ
.toDsymbol(sc
);
7021 global
.endGagging(oldErrors
);
7025 Package p
= resolveIsPackage(sym
);
7028 if (e
.tok2
== TOK
.package_
&& p
.isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module.
7030 else if(e
.tok2
== TOK
.module_
&& !(p
.isModule() || p
.isPackageMod()))
7037 Scope
* sc2
= sc
.copy(); // keep sc.flags
7040 sc2
.flags |
= SCOPE
.fullinst
;
7041 Type t
= e
.targ
.trySemantic(e
.loc
, sc2
);
7043 if (!t
) // errors, so condition is false
7048 if (e
.tok2
!= TOK
.reserved
)
7053 if (e
.targ
.ty
!= Tstruct
)
7055 if ((cast(TypeStruct
)e
.targ
).sym
.isUnionDeclaration())
7061 if (e
.targ
.ty
!= Tstruct
)
7063 if (!(cast(TypeStruct
)e
.targ
).sym
.isUnionDeclaration())
7069 if (e
.targ
.ty
!= Tclass
)
7071 if ((cast(TypeClass
)e
.targ
).sym
.isInterfaceDeclaration())
7076 case TOK
.interface_
:
7077 if (e
.targ
.ty
!= Tclass
)
7079 if (!(cast(TypeClass
)e
.targ
).sym
.isInterfaceDeclaration())
7085 if (!e
.targ
.isConst())
7090 case TOK
.immutable_
:
7091 if (!e
.targ
.isImmutable())
7097 if (!e
.targ
.isShared())
7103 if (!e
.targ
.isWild())
7109 // If class or interface, get the base class and interfaces
7110 if (e
.targ
.ty
!= Tclass
)
7114 ClassDeclaration cd
= (cast(TypeClass
)e
.targ
).sym
;
7115 auto args
= new Parameters();
7116 args
.reserve(cd
.baseclasses
.length
);
7117 if (cd
.semanticRun
< PASS
.semanticdone
)
7118 cd
.dsymbolSemantic(null);
7119 for (size_t i
= 0; i
< cd
.baseclasses
.length
; i
++)
7121 BaseClass
* b
= (*cd
.baseclasses
)[i
];
7122 args
.push(new Parameter(Loc
.initial
, STC
.in_
, b
.type
, null, null, null));
7124 tded
= new TypeTuple(args
);
7129 if (e
.targ
.ty
!= Tenum
)
7132 tded
= (cast(TypeEnum
)e
.targ
).sym
.getMemtype(e
.loc
);
7136 if (tded
.ty
== Terror
)
7141 if (e
.targ
.ty
!= Tdelegate
)
7143 tded
= (cast(TypeDelegate
)e
.targ
).next
; // the underlying function type
7147 if (e
.targ
.ty
!= Tfunction
)
7150 case TOK
.parameters
:
7152 if (auto tf
= e
.targ
.isFunction_Delegate_PtrToFunction())
7157 /* Generate tuple from function parameter types.
7159 auto args
= new Parameters();
7160 foreach (i
, arg
; tded
.isTypeFunction().parameterList
)
7162 assert(arg
&& arg
.type
);
7163 /* If one of the default arguments was an error,
7164 don't return an invalid tuple
7166 if (e
.tok2
== TOK
.parameters
&& arg
.defaultArg
&& arg
.defaultArg
.op
== EXP
.error
)
7168 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
));
7170 tded
= new TypeTuple(args
);
7174 /* Get the 'return type' for the function,
7175 * delegate, or pointer to function.
7177 if (auto tf
= e
.targ
.isFunction_Delegate_PtrToFunction())
7183 case TOK
.argumentTypes
:
7184 /* Generate a type tuple of the equivalent types used to determine if a
7185 * function argument of this type can be passed in registers.
7186 * The results of this are highly platform dependent, and intended
7187 * primarly for use in implementing va_arg().
7189 tded
= target
.toArgTypes(e
.targ
);
7192 // not valid for a parameter
7196 if (e
.targ
.ty
!= Tvector
)
7198 tded
= (cast(TypeVector
)e
.targ
).basetype
;
7205 // https://issues.dlang.org/show_bug.cgi?id=18753
7210 else if (e
.tspec
&& !e
.id
&& !(e
.parameters
&& e
.parameters
.length
))
7212 /* Evaluate to true if targ matches tspec
7216 e
.tspec
= e
.tspec
.typeSemantic(e
.loc
, sc
);
7217 //printf("targ = %s, %s\n", e.targ.toChars(), e.targ.deco);
7218 //printf("tspec = %s, %s\n", e.tspec.toChars(), e.tspec.deco);
7220 if (e
.tok
== TOK
.colon
)
7222 // current scope is itself deprecated, or deprecations are not errors
7223 const bool deprecationAllowed
= sc
.isDeprecated
7224 || global
.params
.useDeprecated
!= DiagnosticReporting
.error
;
7225 const bool preventAliasThis
= e
.targ
.hasDeprecatedAliasThis
&& !deprecationAllowed
;
7227 if (preventAliasThis
&& e
.targ
.ty
== Tstruct
)
7229 if ((cast(TypeStruct
) e
.targ
).implicitConvToWithoutAliasThis(e
.tspec
))
7234 else if (preventAliasThis
&& e
.targ
.ty
== Tclass
)
7236 if ((cast(TypeClass
) e
.targ
).implicitConvToWithoutAliasThis(e
.tspec
))
7241 else if (e
.targ
.implicitConvTo(e
.tspec
))
7248 if (e
.targ
.equals(e
.tspec
))
7256 /* Evaluate to true if targ matches tspec.
7257 * If true, declare id as an alias for the specialized type.
7258 * is(targ == tspec, tpl)
7259 * is(targ : tspec, tpl)
7260 * is(targ id == tspec)
7261 * is(targ id : tspec)
7262 * is(targ id == tspec, tpl)
7263 * is(targ id : tspec, tpl)
7265 Identifier tid
= e
.id ? e
.id
: Identifier
.generateId("__isexp_id");
7266 e
.parameters
.insert(0, new TemplateTypeParameter(e
.loc
, tid
, null, null));
7268 Objects dedtypes
= Objects(e
.parameters
.length
);
7271 MATCH m
= deduceType(e
.targ
, sc
, e
.tspec
, e
.parameters
, &dedtypes
, null, 0, e
.tok
== TOK
.equal
);
7273 if (m
== MATCH
.nomatch ||
(m
!= MATCH
.exact
&& e
.tok
== TOK
.equal
))
7279 tded
= cast(Type
)dedtypes
[0];
7282 Objects tiargs
= Objects(1);
7285 /* Declare trailing parameters
7287 for (size_t i
= 1; i
< e
.parameters
.length
; i
++)
7289 TemplateParameter tp
= (*e
.parameters
)[i
];
7290 Declaration s
= null;
7292 m
= tp
.matchArg(e
.loc
, sc
, &tiargs
, i
, e
.parameters
, &dedtypes
, &s
);
7293 if (m
== MATCH
.nomatch
)
7295 s
.dsymbolSemantic(sc
);
7299 auto conflict
= sc
.search(Loc
.initial
, s
.ident
, pscopesym
);
7300 error(e
.loc
, "declaration `%s` is already defined", s
.toPrettyChars());
7301 errorSupplemental(conflict
.loc
, "`%s` `%s` is defined here",
7302 conflict
.kind(), conflict
.toChars());
7305 unSpeculative(sc
, s
);
7312 /* Declare id as an alias for type targ. Evaluate to true
7320 override void visit(BinAssignExp exp
)
7328 Expression e
= exp
.op_overload(sc
);
7335 if (exp
.e1
.op
== EXP
.arrayLength
)
7337 // arr.length op= e2;
7338 e
= rewriteOpAssign(exp
);
7339 e
= e
.expressionSemantic(sc
);
7343 if (exp
.e1
.op
== EXP
.slice || exp
.e1
.type
.ty
== Tarray || exp
.e1
.type
.ty
== Tsarray
)
7345 if (checkNonAssignmentArrayOp(exp
.e1
))
7348 if (exp
.e1
.op
== EXP
.slice
)
7349 (cast(SliceExp
)exp
.e1
).arrayop
= true;
7352 if (exp
.e2
.implicitConvTo(exp
.e1
.type
.nextOf()))
7355 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
.nextOf());
7357 else if (Expression ex
= typeCombine(exp
, sc
))
7362 exp
.type
= exp
.e1
.type
;
7363 result
= arrayOp(exp
, sc
);
7367 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
7368 exp
.e1
= exp
.e1
.modifiableLvalue(sc
);
7369 exp
.e1
= exp
.e1
.optimize(WANTvalue
, /*keepLvalue*/ true);
7370 exp
.type
= exp
.e1
.type
;
7372 if (auto ad
= isAggregate(exp
.e1
.type
))
7374 if (const s
= search_function(ad
, Id
.opOpAssign
))
7376 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());
7380 if (exp
.e1
.checkScalar() ||
7381 exp
.e1
.checkReadModifyWrite(exp
.op
, exp
.e2
) ||
7382 exp
.e1
.checkSharedAccess(sc
))
7385 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
);
7386 int bitwise
= (exp
.op
== EXP
.andAssign || exp
.op
== EXP
.orAssign || exp
.op
== EXP
.xorAssign
);
7387 int shift
= (exp
.op
== EXP
.leftShiftAssign || exp
.op
== EXP
.rightShiftAssign || exp
.op
== EXP
.unsignedRightShiftAssign
);
7389 if (bitwise
&& exp
.type
.toBasetype().ty
== Tbool
)
7390 exp
.e2
= exp
.e2
.implicitCastTo(sc
, exp
.type
);
7391 else if (exp
.checkNoBool())
7394 if ((exp
.op
== EXP
.addAssign || exp
.op
== EXP
.minAssign
) && exp
.e1
.type
.toBasetype().ty
== Tpointer
&& exp
.e2
.type
.toBasetype().isintegral())
7396 result
= scaleFactor(exp
, sc
);
7400 if (Expression ex
= typeCombine(exp
, sc
))
7406 if (arith
&& (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
)))
7408 if ((bitwise || shift
) && (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
)))
7413 if (exp
.e2
.type
.toBasetype().ty
!= Tvector
)
7414 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tshiftcnt
);
7417 if (!target
.isVectorOpSupported(exp
.type
.toBasetype(), exp
.op
, exp
.e2
.type
.toBasetype()))
7419 result
= exp
.incompatibleTypes();
7423 if (exp
.e1
.op
== EXP
.error || exp
.e2
.op
== EXP
.error
)
7426 e
= exp
.checkOpAssignTypes(sc
);
7427 if (e
.op
== EXP
.error
)
7433 assert(e
.op
== EXP
.assign || e
== exp
);
7434 result
= (cast(BinExp
)e
).reorderSettingAAElem(sc
);
7437 private Expression
compileIt(MixinExp exp
)
7440 if (expressionsToString(buf
, sc
, exp
.exps
))
7443 uint errors
= global
.errors
;
7444 const len
= buf
.length
;
7445 const str = buf
.extractChars()[0 .. len
];
7446 const bool doUnittests
= global
.params
.parsingUnittestsRequired();
7447 auto loc
= adjustLocForMixin(str, exp
.loc
, global
.params
.mixinOut
);
7448 scope p
= new Parser
!ASTCodegen(loc
, sc
._module
, str, false, global
.errorSink
, &global
.compileEnv
, doUnittests
);
7449 p
.transitionIn
= global
.params
.v
.vin
;
7451 //printf("p.loc.linnum = %d\n", p.loc.linnum);
7453 Expression e
= p
.parseExpression();
7454 if (global
.errors
!= errors
)
7457 if (p
.token
.value
!= TOK
.endOfFile
)
7459 error(e
.loc
, "unexpected token `%s` after %s expression",
7460 p
.token
.toChars(), EXPtoString(e
.op
).ptr
);
7461 errorSupplemental(e
.loc
, "while parsing string mixin expression `%s`",
7468 override void visit(MixinExp exp
)
7470 /* https://dlang.org/spec/expression.html#mixin_expressions
7473 static if (LOGSEMANTIC
)
7475 printf("MixinExp::semantic('%s')\n", exp
.toChars());
7478 auto e
= compileIt(exp
);
7481 result
= e
.expressionSemantic(sc
);
7484 override void visit(ImportExp e
)
7486 static if (LOGSEMANTIC
)
7488 printf("ImportExp::semantic('%s')\n", e
.toChars());
7491 auto se
= semanticString(sc
, e
.e1
, "file name argument");
7496 auto namez
= se
.toStringz();
7497 if (!global
.filePath
)
7499 error(e
.loc
, "need `-J` switch to import text file `%s`", namez
.ptr
);
7503 /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
7504 * ('Path Traversal') attacks.
7505 * https://cwe.mitre.org/data/definitions/22.html
7508 if (FileName
.absolute(namez
))
7510 error(e
.loc
, "absolute path is not allowed in import expression: `%s`", se
.toChars());
7514 auto idxReserved
= FileName
.findReservedChar(namez
);
7515 if (idxReserved
!= size_t
.max
)
7517 error(e
.loc
, "`%s` is not a valid filename on this platform", se
.toChars());
7518 errorSupplemental(e
.loc
, "Character `'%c'` is reserved and cannot be used", namez
[idxReserved
]);
7522 if (FileName
.refersToParentDir(namez
))
7524 error(e
.loc
, "path refers to parent (`..`) directory: `%s`", se
.toChars());
7528 auto resolvedNamez
= FileName
.searchPath(global
.filePath
, namez
, false);
7531 error(e
.loc
, "file `%s` cannot be found or not in a path specified with `-J`", se
.toChars());
7532 errorSupplemental(e
.loc
, "Path(s) searched (as provided by `-J`):");
7533 foreach (idx
, path
; *global
.filePath
)
7535 const attr
= FileName
.exists(path
);
7536 const(char)* err
= attr
== 2 ?
"" :
7537 (attr
== 1 ?
" (not a directory)" : " (path not found)");
7538 errorSupplemental(e
.loc
, "[%llu]: `%s`%s", cast(ulong)idx
, path
, err
);
7543 sc
._module
.contentImportedFiles
.push(resolvedNamez
.ptr
);
7544 if (global
.params
.v
.verbose
)
7546 const slice
= se
.peekString();
7547 message("file %.*s\t(%s)", cast(int)slice
.length
, slice
.ptr
, resolvedNamez
.ptr
);
7549 if (global
.params
.moduleDeps
.buffer
!is null)
7551 OutBuffer
* ob
= global
.params
.moduleDeps
.buffer
;
7552 Module imod
= sc
._module
;
7554 if (!global
.params
.moduleDeps
.name
)
7555 ob
.writestring("depsFile ");
7556 ob
.writestring(imod
.toPrettyChars());
7557 ob
.writestring(" (");
7558 escapePath(ob
, imod
.srcfile
.toChars());
7559 ob
.writestring(") : ");
7560 if (global
.params
.moduleDeps
.name
)
7561 ob
.writestring("string : ");
7562 ob
.write(se
.peekString());
7563 ob
.writestring(" (");
7564 escapePath(ob
, resolvedNamez
.ptr
);
7565 ob
.writestring(")");
7568 if (global
.params
.makeDeps
.doOutput
)
7570 global
.params
.makeDeps
.files
.push(resolvedNamez
.ptr
);
7574 auto fileName
= FileName(resolvedNamez
);
7575 if (auto fmResult
= global
.fileManager
.lookup(fileName
))
7577 se
= new StringExp(e
.loc
, fmResult
);
7581 error(e
.loc
, "cannot read file `%s`", resolvedNamez
.ptr
);
7585 result
= se
.expressionSemantic(sc
);
7588 override void visit(AssertExp exp
)
7590 // https://dlang.org/spec/expression.html#assert_expressions
7591 static if (LOGSEMANTIC
)
7593 printf("AssertExp::semantic('%s')\n", exp
.toChars());
7596 const generateMsg
= !exp
.msg
&&
7597 sc
.needsCodegen() && // let ctfe interpreter handle the error message
7598 global
.params
.checkAction
== CHECKACTION
.context
&&
7599 global
.params
.useAssert
== CHECKENABLE
.on
&&
7600 !((exp
.e1
.isIntegerExp() && (exp
.e1
.toInteger() == 0)) ||
7601 exp
.e1
.isNullExp());
7602 Expression temporariesPrefix
;
7605 // no message - use assert expression as msg
7607 if (!verifyHookExist(exp
.loc
, *sc
, Id
._d_assert_fail
, "generating assert messages"))
7612 auto a = e1, b = e2;
7613 assert(a == b, _d_assert_fail!"=="(a, b));
7618 Stores the result of an operand expression into a temporary
7619 if necessary, e.g. if it is an impure fuction call containing side
7620 effects as in https://issues.dlang.org/show_bug.cgi?id=20114
7623 op = an expression which may require a temporary (added to
7624 `temporariesPrefix`: `auto tmp = op`) and will be replaced
7625 by `tmp` if necessary
7627 Returns: (possibly replaced) `op`
7629 Expression
maybePromoteToTmp(ref Expression op
)
7631 // https://issues.dlang.org/show_bug.cgi?id=20989
7632 // Flag that _d_assert_fail will never dereference `array.ptr` to avoid safety
7633 // errors for `assert(!array.ptr)` => `_d_assert_fail!"!"(array.ptr)`
7635 auto die
= op
.isDotIdExp();
7636 if (die
&& die
.ident
== Id
.ptr
)
7640 op
= op
.expressionSemantic(sc
);
7641 op
= resolveProperties(sc
, op
);
7643 // Detect assert's using static operator overloads (e.g. `"var" in environment`)
7644 if (auto te
= op
.isTypeExp())
7646 // Replace the TypeExp with it's textual representation
7647 // Including "..." in the error message isn't quite right but
7648 // proper solutions require more drastic changes, e.g. directly
7649 // using miniFormat and combine instead of calling _d_assert_fail
7650 auto name
= new StringExp(te
.loc
, te
.toString());
7651 return name
.expressionSemantic(sc
);
7654 // Create a temporary for expressions with side effects
7655 // Defensively assume that function calls may have side effects even
7656 // though it's not detected by hasSideEffect (e.g. `debug puts("Hello")` )
7657 // Rewriting CallExp's also avoids some issues with the inliner/debug generation
7658 if (op
.hasSideEffect(true))
7660 // Don't create an invalid temporary for void-expressions
7661 // Further semantic will issue an appropriate error
7662 if (op
.type
.ty
== Tvoid
)
7665 // https://issues.dlang.org/show_bug.cgi?id=21590
7666 // Don't create unnecessary temporaries and detect `assert(a = b)`
7667 if (op
.isAssignExp() || op
.isBinAssignExp())
7669 auto left
= (cast(BinExp
) op
).e1
;
7671 // Find leftmost expression to handle other rewrites,
7672 // e.g. --(++a) => a += 1 -= 1
7673 while (left
.isAssignExp() || left
.isBinAssignExp())
7674 left
= (cast(BinExp
) left
).e1
;
7676 // Only use the assignee if it's a variable and skip
7677 // other lvalues (e.g. ref's returned by functions)
7678 if (left
.isVarExp())
7681 // Sanity check that `op` can be converted to boolean
7682 // But don't raise errors for assignments enclosed in another expression
7687 // Tuples with side-effects already receive a temporary during semantic
7688 if (op
.type
.isTypeTuple())
7690 auto te
= op
.isTupleExp();
7693 // Create a new tuple without the associated temporary
7694 auto res
= new TupleExp(op
.loc
, te
.exps
);
7695 return res
.expressionSemantic(sc
);
7698 const stc = op
.isLvalue() ? STC
.ref_
: 0;
7699 auto tmp
= copyToTemp(stc, "__assertOp", op
);
7700 tmp
.dsymbolSemantic(sc
);
7702 auto decl
= new DeclarationExp(op
.loc
, tmp
);
7703 temporariesPrefix
= Expression
.combine(temporariesPrefix
, decl
);
7705 op
= new VarExp(op
.loc
, tmp
);
7706 op
= op
.expressionSemantic(sc
);
7711 // if the assert condition is a mixin expression, try to compile it
7712 if (auto ce
= exp
.e1
.isMixinExp())
7714 if (auto e1
= compileIt(ce
))
7720 Loc loc
= exp
.e1
.loc
;
7722 const op
= exp
.e1
.op
;
7723 bool isEqualsCallExpression
;
7724 if (const callExp
= exp
.e1
.isCallExp())
7726 // https://issues.dlang.org/show_bug.cgi?id=20331
7727 // callExp.f may be null if the assert contains a call to
7728 // a function pointer or literal
7729 if (const callExpFunc
= callExp
.f
)
7731 const callExpIdent
= callExpFunc
.ident
;
7732 isEqualsCallExpression
= callExpIdent
== Id
.__equals ||
7733 callExpIdent
== Id
.eq
;
7736 if (op
== EXP
.equal || op
== EXP
.notEqual ||
7737 op
== EXP
.lessThan || op
== EXP
.greaterThan ||
7738 op
== EXP
.lessOrEqual || op
== EXP
.greaterOrEqual ||
7739 op
== EXP
.identity || op
== EXP
.notIdentity ||
7741 isEqualsCallExpression
)
7743 es
= new Expressions(3);
7744 tiargs
= new Objects(1);
7746 if (isEqualsCallExpression
)
7748 auto callExp
= cast(CallExp
) exp
.e1
;
7749 auto args
= callExp
.arguments
;
7751 // structs with opEquals get rewritten to a DotVarExp:
7753 // https://issues.dlang.org/show_bug.cgi?id=20100
7754 if (args
.length
== 1)
7756 auto dv
= callExp
.e1
.isDotVarExp();
7760 (*es
)[1] = maybePromoteToTmp(dv
.e1
);
7761 (*es
)[2] = maybePromoteToTmp((*args
)[0]);
7766 (*es
)[1] = maybePromoteToTmp((*args
)[0]);
7767 (*es
)[2] = maybePromoteToTmp((*args
)[1]);
7772 auto binExp
= cast(EqualExp
) exp
.e1
;
7775 (*es
)[1] = maybePromoteToTmp(binExp
.e1
);
7776 (*es
)[2] = maybePromoteToTmp(binExp
.e2
);
7780 Expression comp
= new StringExp(loc
, isEqualsCallExpression ?
"==" : EXPtoString(exp
.e1
.op
));
7781 comp
= comp
.expressionSemantic(sc
);
7783 (*tiargs
)[0] = (*es
)[1].type
;
7786 // Format exp.e1 before any additional boolean conversion
7787 // Ignore &&/|| because "assert(...) failed" is more informative than "false != true"
7788 else if (op
!= EXP
.andAnd
&& op
!= EXP
.orOr
)
7790 es
= new Expressions(2);
7791 tiargs
= new Objects(1);
7793 if (auto ne
= exp
.e1
.isNotExp())
7795 // Fetch the (potential non-bool) expression and fold
7796 // (n) negations into (n % 2) negations, e.g. !!a => a
7797 for (bool neg = true; ; neg = !neg)
7799 if (auto ne2
= ne
.e1
.isNotExp())
7803 (*es
)[0] = new StringExp(loc
, neg ?
"!" : "");
7804 (*es
)[1] = maybePromoteToTmp(ne
.e1
);
7810 { // Simply format exp.e1
7811 (*es
)[0] = new StringExp(loc
, "");
7812 (*es
)[1] = maybePromoteToTmp(exp
.e1
);
7815 (*tiargs
)[0] = (*es
)[1].type
;
7817 // Passing __ctfe to auto ref infers ref and aborts compilation:
7818 // "cannot modify compiler-generated variable __ctfe"
7819 auto ve
= (*es
)[1].isVarExp();
7820 if (ve
&& ve
.var
.ident
== Id
.ctfe
)
7822 exp
.msg
= new StringExp(loc
, "assert(__ctfe) failed!");
7829 buf
.printf("`%s` failed", exp
.toChars());
7830 exp
.msg
= new StringExp(Loc
.initial
, buf
.extractSlice());
7834 Expression __assertFail
= new IdentifierExp(exp
.loc
, Id
.empty
);
7835 auto assertFail
= new DotIdExp(loc
, __assertFail
, Id
.object
);
7837 auto dt = new DotTemplateInstanceExp(loc
, assertFail
, Id
._d_assert_fail
, tiargs
);
7838 auto ec
= CallExp
.create(loc
, dt, es
);
7843 if (Expression ex
= unaSemantic(exp
, sc
))
7849 exp
.e1
= resolveProperties(sc
, exp
.e1
);
7850 // BUG: see if we can do compile time elimination of the Assert
7851 exp
.e1
= exp
.e1
.optimize(WANTvalue
);
7852 exp
.e1
= exp
.e1
.toBoolean(sc
);
7854 if (exp
.e1
.op
== EXP
.error
)
7862 exp
.msg
= expressionSemantic(exp
.msg
, sc
);
7863 exp
.msg
= resolveProperties(sc
, exp
.msg
);
7864 exp
.msg
= exp
.msg
.implicitCastTo(sc
, Type
.tchar
.constOf().arrayOf());
7865 exp
.msg
= exp
.msg
.optimize(WANTvalue
);
7866 checkParamArgumentEscape(sc
, null, null, null, STC
.undefined_
, exp
.msg
, true, false);
7869 if (exp
.msg
&& exp
.msg
.op
== EXP
.error
)
7875 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
7876 auto f2
= exp
.msg
&& checkNonAssignmentArrayOp(exp
.msg
);
7880 if (exp
.e1
.toBool().hasValue(false))
7882 /* This is an `assert(0)` which means halt program execution
7884 FuncDeclaration fd
= sc
.parent
.isFuncDeclaration();
7886 fd
.hasReturnExp |
= 4;
7887 sc
.ctorflow
.orCSX(CSX
.halt
);
7889 if (global
.params
.useAssert
== CHECKENABLE
.off
)
7891 Expression e
= new HaltExp(exp
.loc
);
7892 e
= e
.expressionSemantic(sc
);
7897 // Only override the type when it isn't already some flavour of noreturn,
7898 // e.g. when this assert was generated by defaultInitLiteral
7899 if (!exp
.type ||
!exp
.type
.isTypeNoreturn())
7900 exp
.type
= Type
.tnoreturn
;
7903 exp
.type
= Type
.tvoid
;
7905 result
= !temporariesPrefix
7907 : Expression
.combine(temporariesPrefix
, exp
).expressionSemantic(sc
);
7910 override void visit(ThrowExp te
)
7912 import dmd
.statementsem
;
7914 if (throwSemantic(te
.loc
, te
.e1
, sc
))
7920 override void visit(DotIdExp exp
)
7922 static if (LOGSEMANTIC
)
7924 printf("DotIdExp::semantic(this = %p, '%s')\n", exp
, exp
.toChars());
7925 //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op));
7928 if (sc
.flags
& SCOPE
.Cfile
)
7930 /* See if need to rewrite the AST because of cast/call ambiguity
7932 if (auto e
= castCallAmbiguity(exp
, sc
))
7934 result
= expressionSemantic(e
, sc
);
7938 if (exp
.arrow
) // ImportC only
7939 exp
.e1
= exp
.e1
.expressionSemantic(sc
).arrayFuncConv(sc
);
7941 if (exp
.ident
== Id
.__xalignof
&& exp
.e1
.isTypeExp())
7943 // C11 6.5.3 says _Alignof only applies to types
7947 dmd
.typesem
.resolve(exp
.e1
.type
, exp
.e1
.loc
, sc
, e
, t
, s
, true);
7950 error(exp
.e1
.loc
, "argument to `_Alignof` must be a type");
7955 // Note similarity to getProperty() implementation of __xalignof
7956 const explicitAlignment
= t
.alignment();
7957 const naturalAlignment
= t
.alignsize();
7958 const actualAlignment
= (explicitAlignment
.isDefault() ? naturalAlignment
: explicitAlignment
.get());
7959 result
= new IntegerExp(exp
.loc
, actualAlignment
, Type
.tsize_t
);
7963 error(exp
.e1
.loc
, "argument to `_Alignof` must be a type");
7971 if (exp
.ident
!= Id
.__sizeof
)
7973 result
= fieldLookup(exp
.e1
, sc
, exp
.ident
, exp
.arrow
);
7978 Expression e
= exp
.dotIdSemanticProp(sc
, 1);
7980 if (e
&& isDotOpDispatch(e
))
7983 uint errors
= global
.startGagging();
7984 e
= resolvePropertiesX(sc
, e
);
7985 // Any error or if 'e' is not resolved, go to UFCS
7986 if (global
.endGagging(errors
) || e
is ode
)
7987 e
= null; /* fall down to UFCS */
7994 if (!e
) // if failed to find the property
7996 /* If ident is not a valid property, rewrite:
8001 e
= resolveUFCSProperties(sc
, exp
);
8006 override void visit(DotTemplateExp e
)
8013 if (Expression ex
= unaSemantic(e
, sc
))
8018 // 'void' like TemplateExp
8019 e
.type
= Type
.tvoid
;
8023 override void visit(DotVarExp exp
)
8025 static if (LOGSEMANTIC
)
8027 printf("DotVarExp::semantic('%s')\n", exp
.toChars());
8035 exp
.var
= exp
.var
.toAlias().isDeclaration();
8037 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
8039 if (auto tup
= exp
.var
.isTupleDeclaration())
8044 * tuple(e1.a, e1.b, e1.c)
8047 Expression ev
= sc
.func ?
extractSideEffect(sc
, "__tup", e0
, exp
.e1
) : exp
.e1
;
8049 auto exps
= new Expressions();
8050 exps
.reserve(tup
.objects
.length
);
8051 for (size_t i
= 0; i
< tup
.objects
.length
; i
++)
8053 RootObject o
= (*tup
.objects
)[i
];
8056 switch (o
.dyncast()) with (DYNCAST
)
8059 e
= cast(Expression
)o
;
8060 if (auto se
= e
.isDsymbolExp())
8061 var
= se
.s
.isDeclaration();
8062 else if (auto ve
= e
.isVarExp())
8063 if (!ve
.var
.isFuncDeclaration())
8064 // Exempt functions for backwards compatibility reasons.
8065 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
8069 Dsymbol s
= cast(Dsymbol
) o
;
8070 Declaration d
= s
.isDeclaration();
8071 if (!d || d
.isFuncDeclaration())
8072 // Exempt functions for backwards compatibility reasons.
8073 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
8074 e
= new DsymbolExp(exp
.loc
, s
);
8079 e
= new TypeExp(exp
.loc
, cast(Type
)o
);
8082 error(exp
.loc
, "`%s` is not an expression", o
.toChars());
8086 e
= new DotVarExp(exp
.loc
, ev
, var
);
8090 Expression e
= new TupleExp(exp
.loc
, e0
, exps
);
8091 e
= e
.expressionSemantic(sc
);
8095 else if (auto ad
= exp
.var
.isAliasDeclaration())
8097 if (auto t
= ad
.getType())
8099 result
= new TypeExp(exp
.loc
, t
).expressionSemantic(sc
);
8104 exp
.e1
= exp
.e1
.addDtorHook(sc
);
8106 Type t1
= exp
.e1
.type
;
8108 if (FuncDeclaration fd
= exp
.var
.isFuncDeclaration())
8110 // for functions, do checks after overload resolution
8111 if (!fd
.functionSemantic())
8114 /* https://issues.dlang.org/show_bug.cgi?id=13843
8115 * If fd obviously has no overloads, we should
8116 * normalize AST, and it will give a chance to wrap fd with FuncExp.
8118 if ((fd
.isNested() && !fd
.isThis()) || fd
.isFuncLiteralDeclaration())
8121 auto e
= symbolToExp(fd
, exp
.loc
, sc
, false);
8122 result
= Expression
.combine(exp
.e1
, e
);
8129 else if (OverDeclaration od
= exp
.var
.isOverDeclaration())
8131 exp
.type
= Type
.tvoid
; // ambiguous type?
8135 exp
.type
= exp
.var
.type
;
8136 if (!exp
.type
&& global
.errors
) // var is goofed up, just return error.
8140 if (t1
.ty
== Tpointer
)
8143 exp
.type
= exp
.type
.addMod(t1
.mod
);
8145 // https://issues.dlang.org/show_bug.cgi?id=23109
8146 // Run semantic on the DotVarExp type
8147 if (auto handle
= exp
.type
.isClassHandle())
8149 if (handle
.semanticRun
< PASS
.semanticdone
&& !handle
.isBaseInfoComplete())
8150 handle
.dsymbolSemantic(null);
8153 Dsymbol vparent
= exp
.var
.toParent();
8154 AggregateDeclaration ad
= vparent ? vparent
.isAggregateDeclaration() : null;
8155 if (Expression e1x
= getRightThis(exp
.loc
, sc
, ad
, exp
.e1
, exp
.var
, 1))
8159 /* Later checkRightThis will report correct error for invalid field variable access.
8161 Expression e
= new VarExp(exp
.loc
, exp
.var
);
8162 e
= e
.expressionSemantic(sc
);
8166 checkAccess(exp
.loc
, sc
, exp
.e1
, exp
.var
);
8168 VarDeclaration v
= exp
.var
.isVarDeclaration();
8169 if (v
&& (v
.isDataseg() ||
(v
.storage_class
& STC
.manifest
)))
8171 Expression e
= expandVar(WANTvalue
, v
);
8179 if (v
&& (v
.isDataseg() ||
// fix https://issues.dlang.org/show_bug.cgi?id=8238
8180 (!v
.needThis() && v
.semanticRun
> PASS
.initial
))) // fix https://issues.dlang.org/show_bug.cgi?id=17258
8183 checkAccess(exp
.loc
, sc
, exp
.e1
, v
);
8184 Expression e
= new VarExp(exp
.loc
, v
);
8185 e
= new CommaExp(exp
.loc
, exp
.e1
, e
);
8186 e
= e
.expressionSemantic(sc
);
8191 //printf("-DotVarExp::semantic('%s')\n", toChars());
8195 override void visit(DotTemplateInstanceExp exp
)
8197 static if (LOGSEMANTIC
)
8199 printf("DotTemplateInstanceExp::semantic('%s')\n", exp
.toChars());
8206 // Indicate we need to resolve by UFCS.
8207 Expression e
= exp
.dotTemplateSemanticProp(sc
, DotExpFlag
.gag
);
8209 e
= resolveUFCSProperties(sc
, exp
);
8211 e
.type
= Type
.tvoid
; // Unresolved type, because it needs inference
8215 override void visit(DelegateExp e
)
8217 static if (LOGSEMANTIC
)
8219 printf("DelegateExp::semantic('%s')\n", e
.toChars());
8227 e
.e1
= e
.e1
.expressionSemantic(sc
);
8229 e
.type
= new TypeDelegate(e
.func
.type
.isTypeFunction());
8230 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
8232 FuncDeclaration f
= e
.func
.toAliasFunc();
8233 AggregateDeclaration ad
= f
.isMemberLocal();
8235 e
.e1
= getRightThis(e
.loc
, sc
, ad
, e
.e1
, f
);
8237 if (f
.type
.ty
== Tfunction
)
8239 TypeFunction tf
= cast(TypeFunction
)f
.type
;
8240 if (!MODmethodConv(e
.e1
.type
.mod
, f
.type
.mod
))
8242 OutBuffer thisBuf
, funcBuf
;
8243 MODMatchToBuffer(&thisBuf
, e
.e1
.type
.mod
, tf
.mod
);
8244 MODMatchToBuffer(&funcBuf
, tf
.mod
, e
.e1
.type
.mod
);
8245 error(e
.loc
, "%smethod `%s` is not callable using a %s`%s`",
8246 funcBuf
.peekChars(), f
.toPrettyChars(), thisBuf
.peekChars(), e
.e1
.toChars());
8250 if (ad
&& ad
.isClassDeclaration() && ad
.type
!= e
.e1
.type
)
8252 // A downcast is required for interfaces
8253 // https://issues.dlang.org/show_bug.cgi?id=3706
8254 e
.e1
= new CastExp(e
.loc
, e
.e1
, ad
.type
);
8255 e
.e1
= e
.e1
.expressionSemantic(sc
);
8258 // declare dual-context container
8259 if (f
.hasDualContext() && !sc
.intypeof
&& sc
.func
)
8261 // check access to second `this`
8262 if (AggregateDeclaration ad2
= f
.isMember2())
8264 Expression te
= new ThisExp(e
.loc
).expressionSemantic(sc
);
8265 if (te
.op
!= EXP
.error
)
8266 te
= getRightThis(e
.loc
, sc
, ad2
, te
, f
);
8267 if (te
.op
== EXP
.error
)
8269 error(e
.loc
, "need `this` of type `%s` to make delegate from function `%s`", ad2
.toChars(), f
.toChars());
8273 VarDeclaration vthis2
= makeThis2Argument(e
.loc
, sc
, f
);
8275 Expression
de = new DeclarationExp(e
.loc
, vthis2
);
8276 result
= Expression
.combine(de, result
);
8277 result
= result
.expressionSemantic(sc
);
8281 override void visit(DotTypeExp exp
)
8283 static if (LOGSEMANTIC
)
8285 printf("DotTypeExp::semantic('%s')\n", exp
.toChars());
8293 if (auto e
= unaSemantic(exp
, sc
))
8299 exp
.type
= exp
.sym
.getType().addMod(exp
.e1
.type
.mod
);
8303 override void visit(AddrExp exp
)
8305 static if (LOGSEMANTIC
)
8307 printf("AddrExp::semantic('%s')\n", exp
.toChars());
8315 if (Expression ex
= unaSemantic(exp
, sc
))
8321 if (sc
.flags
& SCOPE
.Cfile
)
8323 /* Special handling for &"string"/&(T[]){0, 1}
8324 * since C regards string/array literals as lvalues
8327 if(e
.isStringExp() || e
.isArrayLiteralExp())
8329 e
.type
= typeSemantic(e
.type
, Loc
.initial
, sc
);
8330 // if type is already a pointer exp is an illegal expression of the form `&(&"")`
8331 if (!e
.type
.isTypePointer())
8333 e
.type
= e
.type
.pointerTo();
8339 // `toLvalue` call further below is upon exp.e1, omitting & from the error message
8340 exp
.toLvalue(sc
, "take address of");
8346 int wasCond
= exp
.e1
.op
== EXP
.question
;
8348 if (exp
.e1
.op
== EXP
.dotTemplateInstance
)
8350 DotTemplateInstanceExp dti
= cast(DotTemplateInstanceExp
)exp
.e1
;
8351 TemplateInstance ti
= dti
.ti
;
8353 //assert(ti.needsTypeInference(sc));
8354 ti
.dsymbolSemantic(sc
);
8355 if (!ti
.inst || ti
.errors
) // if template failed to expand
8358 Dsymbol s
= ti
.toAlias();
8359 FuncDeclaration f
= s
.isFuncDeclaration();
8362 exp
.e1
= new DotVarExp(exp
.e1
.loc
, dti
.e1
, f
);
8363 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
8367 else if (exp
.e1
.op
== EXP
.scope_
)
8369 TemplateInstance ti
= (cast(ScopeExp
)exp
.e1
).sds
.isTemplateInstance();
8372 //assert(ti.needsTypeInference(sc));
8373 ti
.dsymbolSemantic(sc
);
8374 if (!ti
.inst || ti
.errors
) // if template failed to expand
8377 Dsymbol s
= ti
.toAlias();
8378 FuncDeclaration f
= s
.isFuncDeclaration();
8381 exp
.e1
= new VarExp(exp
.e1
.loc
, f
);
8382 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
8386 /* https://issues.dlang.org/show_bug.cgi?id=809
8388 * If the address of a lazy variable is taken,
8389 * the expression is rewritten so that the type
8390 * of it is the delegate type. This means that
8391 * the symbol is not going to represent a call
8392 * to the delegate anymore, but rather, the
8395 if (auto ve
= exp
.e1
.isVarExp())
8397 if (ve
.var
.storage_class
& STC
.lazy_
)
8399 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
8400 exp
.e1
= resolveProperties(sc
, exp
.e1
);
8401 if (auto callExp
= exp
.e1
.isCallExp())
8403 if (callExp
.e1
.type
.toBasetype().ty
== Tdelegate
)
8405 /* https://issues.dlang.org/show_bug.cgi?id=20551
8407 * Cannot take address of lazy parameter in @safe code
8408 * because it might end up being a pointer to undefined
8413 if (sc
.setUnsafe(false, exp
.loc
,
8414 "cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve
, sc
.func
))
8420 VarExp ve2
= callExp
.e1
.isVarExp();
8421 ve2
.delegateWasExtracted
= true;
8422 ve2
.var
.storage_class |
= STC
.scope_
;
8430 exp
.e1
= exp
.e1
.toLvalue(sc
, "take address of");
8431 if (exp
.e1
.op
== EXP
.error
)
8436 if (checkNonAssignmentArrayOp(exp
.e1
))
8441 error(exp
.loc
, "cannot take address of `%s`", exp
.e1
.toChars());
8444 if (!checkAddressable(exp
, sc
))
8448 if (auto f
= isFuncAddress(exp
, &hasOverloads
))
8450 if (!hasOverloads
&& f
.checkForwardRef(exp
.loc
))
8453 else if (!exp
.e1
.type
.deco
)
8455 // try to resolve the type
8456 exp
.e1
.type
= exp
.e1
.type
.typeSemantic(exp
.e1
.loc
, sc
);
8457 if (!exp
.e1
.type
.deco
) // still couldn't resolve it
8459 if (auto ve
= exp
.e1
.isVarExp())
8461 Declaration d
= ve
.var
;
8462 error(exp
.loc
, "forward reference to %s `%s`", d
.kind(), d
.toChars());
8465 error(exp
.loc
, "forward reference to type `%s` of expression `%s`", exp
.e1
.type
.toChars(), exp
.e1
.toChars());
8470 exp
.type
= exp
.e1
.type
.pointerTo();
8472 // See if this should really be a delegate
8473 if (exp
.e1
.op
== EXP
.dotVariable
)
8475 DotVarExp dve
= cast(DotVarExp
)exp
.e1
;
8476 FuncDeclaration f
= dve
.var
.isFuncDeclaration();
8479 f
= f
.toAliasFunc(); // FIXME, should see overloads
8480 // https://issues.dlang.org/show_bug.cgi?id=1983
8481 if (!dve
.hasOverloads
)
8486 e
= new DelegateExp(exp
.loc
, dve
.e1
, f
, dve
.hasOverloads
);
8487 else // It is a function pointer. Convert &v.f() --> (v, &V.f())
8488 e
= new CommaExp(exp
.loc
, dve
.e1
, new AddrExp(exp
.loc
, new VarExp(exp
.loc
, f
, dve
.hasOverloads
)));
8489 e
= e
.expressionSemantic(sc
);
8494 // Look for misaligned pointer in @safe mode
8495 if (checkUnsafeAccess(sc
, dve
, !exp
.type
.isMutable(), true))
8498 else if (exp
.e1
.op
== EXP
.variable
)
8500 VarExp ve
= cast(VarExp
)exp
.e1
;
8501 VarDeclaration v
= ve
.var
.isVarDeclaration();
8504 if (!checkAddressVar(sc
, exp
.e1
, v
))
8507 v
.checkPurity(ve
.loc
, sc
);
8509 FuncDeclaration f
= ve
.var
.isFuncDeclaration();
8512 /* Because nested functions cannot be overloaded,
8513 * mark here that we took its address because castTo()
8514 * may not be called with an exact match.
8516 * https://issues.dlang.org/show_bug.cgi?id=19285 :
8517 * We also need to make sure we aren't inside a typeof. Ideally the compiler
8518 * would do typeof(...) semantic analysis speculatively then collect information
8519 * about what it used rather than relying on what are effectively semantically-global
8520 * variables but it doesn't.
8522 if (!sc
.isFromSpeculativeSemanticContext() && (!ve
.hasOverloads ||
(f
.isNested() && !f
.needThis())))
8524 // TODO: Refactor to use a proper interface that can keep track of causes.
8528 if (f
.isNested() && !f
.needThis())
8530 if (f
.isFuncLiteralDeclaration())
8532 if (!f
.FuncDeclaration
.isNested())
8534 /* Supply a 'null' for a this pointer if no this is available
8536 Expression e
= new DelegateExp(exp
.loc
, new NullExp(exp
.loc
, Type
.tnull
), f
, ve
.hasOverloads
);
8537 e
= e
.expressionSemantic(sc
);
8542 Expression e
= new DelegateExp(exp
.loc
, exp
.e1
, f
, ve
.hasOverloads
);
8543 e
= e
.expressionSemantic(sc
);
8549 auto memberFunc
= hasThis(sc
);
8550 if (memberFunc
&& haveSameThis(memberFunc
, f
))
8552 /* Should probably supply 'this' after overload resolution,
8555 Expression ethis
= new ThisExp(exp
.loc
);
8556 Expression e
= new DelegateExp(exp
.loc
, ethis
, f
, ve
.hasOverloads
);
8557 e
= e
.expressionSemantic(sc
);
8561 if (sc
.func
&& !sc
.intypeof
&& !(sc
.flags
& SCOPE
.debug_
))
8563 sc
.setUnsafe(false, exp
.loc
,
8564 "`this` reference necessary to take address of member `%s` in `@safe` function `%s`",
8570 else if (exp
.e1
.op
== EXP
.index
)
8575 * check 'a' the same as for a regular variable
8577 if (VarDeclaration v
= expToVariable(exp
.e1
))
8579 v
.checkPurity(exp
.e1
.loc
, sc
);
8584 /* a ? b : c was transformed to *(a ? &b : &c), but we still
8585 * need to do safety checks
8587 assert(exp
.e1
.op
== EXP
.star
);
8588 PtrExp pe
= cast(PtrExp
)exp
.e1
;
8589 assert(pe
.e1
.op
== EXP
.question
);
8590 CondExp ce
= cast(CondExp
)pe
.e1
;
8591 assert(ce
.e1
.op
== EXP
.address
);
8592 assert(ce
.e2
.op
== EXP
.address
);
8594 // Re-run semantic on the address expressions only
8596 ce
.e1
= ce
.e1
.expressionSemantic(sc
);
8598 ce
.e2
= ce
.e2
.expressionSemantic(sc
);
8600 result
= exp
.optimize(WANTvalue
);
8603 override void visit(PtrExp exp
)
8605 static if (LOGSEMANTIC
)
8607 printf("PtrExp::semantic('%s')\n", exp
.toChars());
8615 Expression e
= exp
.op_overload(sc
);
8622 exp
.e1
= exp
.e1
.arrayFuncConv(sc
);
8624 Type tb
= exp
.e1
.type
.toBasetype();
8628 exp
.type
= (cast(TypePointer
)tb
).next
;
8633 if (isNonAssignmentArrayOp(exp
.e1
))
8635 error(exp
.loc
, "using `*` on an array is no longer supported; use `*(%s).ptr` instead", exp
.e1
.toChars());
8636 exp
.type
= (cast(TypeArray
)tb
).next
;
8637 exp
.e1
= exp
.e1
.castTo(sc
, exp
.type
.pointerTo());
8644 exp
.type
= Type
.tnoreturn
; // typeof(*null) is bottom type
8648 error(exp
.loc
, "can only `*` a pointer, not a `%s`", exp
.e1
.type
.toChars());
8652 if (sc
.flags
& SCOPE
.Cfile
&& exp
.type
&& exp
.type
.toBasetype().ty
== Tvoid
)
8654 // https://issues.dlang.org/show_bug.cgi?id=23752
8655 // `&*((void*)(0))` is allowed in C
8660 if (exp
.checkValue())
8666 override void visit(NegExp exp
)
8668 static if (LOGSEMANTIC
)
8670 printf("NegExp::semantic('%s')\n", exp
.toChars());
8678 Expression e
= exp
.op_overload(sc
);
8686 exp
.type
= exp
.e1
.type
;
8687 Type tb
= exp
.type
.toBasetype();
8688 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
8690 if (!isArrayOpValid(exp
.e1
))
8692 result
= arrayOpInvalidError(exp
);
8698 if (!target
.isVectorOpSupported(tb
, exp
.op
))
8700 result
= exp
.incompatibleTypes();
8703 if (exp
.e1
.checkNoBool())
8705 if (exp
.e1
.checkArithmetic(exp
.op
) ||
8706 exp
.e1
.checkSharedAccess(sc
))
8712 override void visit(UAddExp exp
)
8714 static if (LOGSEMANTIC
)
8716 printf("UAddExp::semantic('%s')\n", exp
.toChars());
8720 Expression e
= exp
.op_overload(sc
);
8728 if (!target
.isVectorOpSupported(exp
.e1
.type
.toBasetype(), exp
.op
))
8730 result
= exp
.incompatibleTypes();
8733 if (exp
.e1
.checkNoBool())
8735 if (exp
.e1
.checkArithmetic(exp
.op
))
8737 if (exp
.e1
.checkSharedAccess(sc
))
8743 override void visit(ComExp exp
)
8751 Expression e
= exp
.op_overload(sc
);
8759 exp
.type
= exp
.e1
.type
;
8760 Type tb
= exp
.type
.toBasetype();
8761 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
8763 if (!isArrayOpValid(exp
.e1
))
8765 result
= arrayOpInvalidError(exp
);
8771 if (!target
.isVectorOpSupported(tb
, exp
.op
))
8773 result
= exp
.incompatibleTypes();
8776 if (exp
.e1
.checkNoBool())
8778 if (exp
.e1
.checkIntegral() ||
8779 exp
.e1
.checkSharedAccess(sc
))
8785 override void visit(NotExp e
)
8793 e
.setNoderefOperand();
8795 // Note there is no operator overload
8796 if (Expression ex
= unaSemantic(e
, sc
))
8802 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
8803 if (e
.e1
.op
== EXP
.type
)
8804 e
.e1
= resolveAliasThis(sc
, e
.e1
);
8806 e
.e1
= resolveProperties(sc
, e
.e1
);
8807 e
.e1
= e
.e1
.toBoolean(sc
);
8808 if (e
.e1
.type
== Type
.terror
)
8814 if (!target
.isVectorOpSupported(e
.e1
.type
.toBasetype(), e
.op
))
8816 result
= e
.incompatibleTypes();
8818 // https://issues.dlang.org/show_bug.cgi?id=13910
8819 // Today NotExp can take an array as its operand.
8820 if (checkNonAssignmentArrayOp(e
.e1
))
8823 e
.type
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? Type
.tint32
: Type
.tbool
;
8827 override void visit(DeleteExp exp
)
8829 // @@@DEPRECATED_2.109@@@
8830 // 1. Deprecated since 2.079
8831 // 2. Error since 2.099
8832 // 3. Removal of keyword, "delete" can be used for other identities
8835 error(exp
.loc
, "the `delete` keyword is obsolete");
8836 errorSupplemental(exp
.loc
, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead");
8842 if (Expression ex
= unaSemantic(exp
, sc
))
8847 exp
.e1
= resolveProperties(sc
, exp
.e1
);
8848 exp
.e1
= exp
.e1
.modifiableLvalue(sc
);
8849 if (exp
.e1
.op
== EXP
.error
)
8854 exp
.type
= Type
.tvoid
;
8856 Type tb
= exp
.e1
.type
.toBasetype();
8858 /* Now that `delete` in user code is an error, we only get here when
8859 * `isRAII` has been set to true for the deletion of a `scope class`. */
8860 if (tb
.ty
!= Tclass
)
8862 error(exp
.loc
, "cannot delete type `%s`", exp
.e1
.type
.toChars());
8866 ClassDeclaration cd
= (cast(TypeClass
)tb
).sym
;
8867 if (cd
.isCOMinterface())
8869 /* Because COM classes are deleted by IUnknown.Release()
8871 error(exp
.loc
, "cannot `delete` instance of COM interface `%s`", cd
.toChars());
8878 err |
= !cd
.dtor
.functionSemantic();
8879 err |
= cd
.dtor
.checkPurity(exp
.loc
, sc
);
8880 err |
= cd
.dtor
.checkSafety(exp
.loc
, sc
);
8881 err |
= cd
.dtor
.checkNogc(exp
.loc
, sc
);
8889 override void visit(CastExp exp
)
8891 static if (LOGSEMANTIC
)
8893 printf("CastExp::semantic('%s')\n", exp
.toChars());
8895 //static int x; assert(++x < 10);
8902 if ((sc
&& sc
.flags
& SCOPE
.Cfile
) &&
8903 exp
.to
&& (exp
.to
.ty
== Tident || exp
.to
.ty
== Tsarray
) &&
8904 (exp
.e1
.op
== EXP
.address || exp
.e1
.op
== EXP
.star ||
8905 exp
.e1
.op
== EXP
.uadd || exp
.e1
.op
== EXP
.negate
))
8907 /* Ambiguous cases arise from CParser if type-name is just an identifier.
8908 * ( identifier ) cast-expression
8909 * ( identifier [expression]) cast-expression
8910 * If we determine that `identifier` is a variable, and cast-expression
8911 * is one of the unary operators (& * + -), then rewrite this cast
8912 * as a binary expression.
8918 exp
.to
.resolve(loc
, sc
, e
, t
, s
);
8921 if (auto ex
= exp
.e1
.isAddrExp()) // (ident) &exp -> (ident & exp)
8922 result
= new AndExp(loc
, e
, ex
.e1
);
8923 else if (auto ex
= exp
.e1
.isPtrExp()) // (ident) *exp -> (ident * exp)
8924 result
= new MulExp(loc
, e
, ex
.e1
);
8925 else if (auto ex
= exp
.e1
.isUAddExp()) // (ident) +exp -> (ident + exp)
8926 result
= new AddExp(loc
, e
, ex
.e1
);
8927 else if (auto ex
= exp
.e1
.isNegExp()) // (ident) -exp -> (ident - exp)
8928 result
= new MinExp(loc
, e
, ex
.e1
);
8931 result
= result
.expressionSemantic(sc
);
8938 exp
.to
= exp
.to
.typeSemantic(exp
.loc
, sc
);
8939 if (exp
.to
== Type
.terror
)
8942 if (!exp
.to
.hasPointers())
8943 exp
.setNoderefOperand();
8945 // When e1 is a template lambda, this cast may instantiate it with
8947 exp
.e1
= inferType(exp
.e1
, exp
.to
);
8950 if (auto e
= unaSemantic(exp
, sc
))
8956 if (exp
.to
&& !exp
.to
.isTypeSArray() && !exp
.to
.isTypeFunction())
8957 exp
.e1
= exp
.e1
.arrayFuncConv(sc
);
8959 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
8960 if (exp
.e1
.op
== EXP
.type
)
8961 exp
.e1
= resolveAliasThis(sc
, exp
.e1
);
8963 auto e1x
= resolveProperties(sc
, exp
.e1
);
8964 if (e1x
.op
== EXP
.error
)
8969 if (e1x
.checkType())
8975 error(exp
.loc
, "cannot cast `%s`", exp
.e1
.toChars());
8979 // https://issues.dlang.org/show_bug.cgi?id=19954
8980 if (exp
.e1
.type
.ty
== Ttuple
)
8984 if (TypeTuple tt
= exp
.to
.isTypeTuple())
8986 if (exp
.e1
.type
.implicitConvTo(tt
))
8988 result
= exp
.e1
.castTo(sc
, tt
);
8993 TupleExp te
= exp
.e1
.isTupleExp();
8994 if (te
.exps
.length
== 1)
8995 exp
.e1
= (*te
.exps
)[0];
8998 // only allow S(x) rewrite if cast specified S explicitly.
8999 // See https://issues.dlang.org/show_bug.cgi?id=18545
9000 const bool allowImplicitConstruction
= exp
.to
!is null;
9002 if (!exp
.to
) // Handle cast(const) and cast(immutable), etc.
9004 exp
.to
= exp
.e1
.type
.castMod(exp
.mod
);
9005 exp
.to
= exp
.to
.typeSemantic(exp
.loc
, sc
);
9007 if (exp
.to
== Type
.terror
)
9011 if (exp
.to
.ty
== Ttuple
)
9013 error(exp
.loc
, "cannot cast `%s` of type `%s` to type sequence `%s`", exp
.e1
.toChars(), exp
.e1
.type
.toChars(), exp
.to
.toChars());
9017 // cast(void) is used to mark e1 as unused, so it is safe
9018 if (exp
.to
.ty
== Tvoid
)
9025 if (!exp
.to
.equals(exp
.e1
.type
) && exp
.mod
== cast(ubyte)~0)
9027 if (Expression e
= exp
.op_overload(sc
))
9029 result
= e
.implicitCastTo(sc
, exp
.to
);
9034 Type t1b
= exp
.e1
.type
.toBasetype();
9035 Type tob
= exp
.to
.toBasetype();
9037 if (allowImplicitConstruction
&& tob
.ty
== Tstruct
&& !tob
.equals(t1b
))
9045 // Rewrite as to.call(e1)
9046 Expression e
= new TypeExp(exp
.loc
, exp
.to
);
9047 e
= new CallExp(exp
.loc
, e
, exp
.e1
);
9048 e
= e
.trySemantic(sc
);
9056 if (!t1b
.equals(tob
) && (t1b
.ty
== Tarray || t1b
.ty
== Tsarray
))
9058 if (checkNonAssignmentArrayOp(exp
.e1
))
9062 Expression ex
= exp
.e1
.castTo(sc
, exp
.to
);
9063 if (ex
.op
== EXP
.error
)
9069 // Check for unsafe casts
9070 if (!isSafeCast(ex
, t1b
, tob
))
9072 if (sc
.setUnsafe(false, exp
.loc
, "cast from `%s` to `%s` not allowed in safe code", exp
.e1
.type
, exp
.to
))
9078 // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built
9079 // to handle certain casts. Those casts which `object.__ArrayCast` does not support are filtered out.
9080 // See `e2ir.toElemCast` for other types of casts. If `object.__ArrayCast` is improved to support more
9081 // casts these conditions and potentially some logic in `e2ir.toElemCast` can be removed.
9082 if (tob
.ty
== Tarray
)
9084 // https://issues.dlang.org/show_bug.cgi?id=19840
9085 if (auto ad
= isAggregate(t1b
))
9089 Expression e
= resolveAliasThis(sc
, exp
.e1
);
9090 e
= new CastExp(exp
.loc
, e
, exp
.to
);
9091 result
= e
.expressionSemantic(sc
);
9096 if(t1b
.ty
== Tarray
&& exp
.e1
.op
!= EXP
.arrayLiteral
&& sc
.needsCodegen())
9098 auto tFrom
= t1b
.nextOf();
9099 auto tTo
= tob
.nextOf();
9101 // https://issues.dlang.org/show_bug.cgi?id=20130
9102 if (exp
.e1
.op
!= EXP
.string_ ||
!ex
.isStringExp
)
9104 const uint fromSize
= cast(uint)tFrom
.size();
9105 const uint toSize
= cast(uint)tTo
.size();
9106 if (fromSize
== SIZE_INVALID || toSize
== SIZE_INVALID
)
9109 // If array element sizes do not match, we must adjust the dimensions
9110 if (fromSize
!= toSize
)
9112 if (!verifyHookExist(exp
.loc
, *sc
, Id
.__ArrayCast
, "casting array of structs"))
9115 // A runtime check is needed in case arrays don't line up. That check should
9116 // be done in the implementation of `object.__ArrayCast`
9117 if (toSize
== 0 ||
(fromSize
% toSize
) != 0)
9119 // lower to `object.__ArrayCast!(TFrom, TTo)(from)`
9121 // fully qualify as `object.__ArrayCast`
9122 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
9123 auto dotid
= new DotIdExp(exp
.loc
, id
, Id
.object
);
9125 auto tiargs
= new Objects();
9128 auto dt = new DotTemplateInstanceExp(exp
.loc
, dotid
, Id
.__ArrayCast
, tiargs
);
9130 auto arguments
= new Expressions();
9131 arguments
.push(exp
.e1
);
9132 Expression ce
= new CallExp(exp
.loc
, dt, arguments
);
9134 result
= expressionSemantic(ce
, sc
);
9142 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
9144 /* C11 6.5.4-5: A cast does not yield an lvalue.
9145 * So ensure that castTo does not strip away the cast so that this
9146 * can be enforced in other semantic visitor methods.
9148 if (!ex
.isCastExp())
9150 ex
= new CastExp(exp
.loc
, ex
, exp
.to
);
9157 override void visit(VectorExp exp
)
9159 static if (LOGSEMANTIC
)
9161 printf("VectorExp::semantic('%s')\n", exp
.toChars());
9169 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
9170 exp
.type
= exp
.to
.typeSemantic(exp
.loc
, sc
);
9171 if (exp
.e1
.op
== EXP
.error || exp
.type
.ty
== Terror
)
9177 Type tb
= exp
.type
.toBasetype();
9178 assert(tb
.ty
== Tvector
);
9179 TypeVector tv
= cast(TypeVector
)tb
;
9180 Type te
= tv
.elementType();
9181 exp
.dim
= cast(int)(tv
.size(exp
.loc
) / te
.size(exp
.loc
));
9183 bool checkElem(Expression elem
)
9185 if (elem
.isConst() == 1)
9188 error(exp
.loc
, "constant expression expected, not `%s`", elem
.toChars());
9192 exp
.e1
= exp
.e1
.optimize(WANTvalue
);
9194 if (exp
.e1
.op
== EXP
.arrayLiteral
)
9196 foreach (i
; 0 .. exp
.dim
)
9198 // Do not stop on first error - check all AST nodes even if error found
9199 res |
= checkElem(exp
.e1
.isArrayLiteralExp()[i
]);
9202 else if (exp
.e1
.type
.ty
== Tvoid
)
9205 result
= res ? ErrorExp
.get() : exp
;
9208 override void visit(VectorArrayExp e
)
9210 static if (LOGSEMANTIC
)
9212 printf("VectorArrayExp::semantic('%s')\n", e
.toChars());
9217 e
.e1
= resolveProperties(sc
, e
.e1
);
9219 if (e
.e1
.op
== EXP
.error
)
9224 assert(e
.e1
.type
.ty
== Tvector
);
9225 e
.type
= e
.e1
.type
.isTypeVector().basetype
;
9230 override void visit(SliceExp exp
)
9232 static if (LOGSEMANTIC
)
9234 printf("SliceExp::semantic('%s')\n", exp
.toChars());
9242 // operator overloading should be handled in ArrayExp already.
9243 if (Expression ex
= unaSemantic(exp
, sc
))
9248 exp
.e1
= resolveProperties(sc
, exp
.e1
);
9249 if (exp
.e1
.op
== EXP
.type
&& exp
.e1
.type
.ty
!= Ttuple
)
9251 if (exp
.lwr || exp
.upr
)
9253 error(exp
.loc
, "cannot slice type `%s`", exp
.e1
.toChars());
9256 Expression e
= new TypeExp(exp
.loc
, exp
.e1
.type
.arrayOf());
9257 result
= e
.expressionSemantic(sc
);
9260 if (!exp
.lwr
&& !exp
.upr
)
9262 if (exp
.e1
.op
== EXP
.arrayLiteral
)
9264 // Convert [a,b,c][] to [a,b,c]
9265 Type t1b
= exp
.e1
.type
.toBasetype();
9266 Expression e
= exp
.e1
;
9267 if (t1b
.ty
== Tsarray
)
9270 e
.type
= t1b
.nextOf().arrayOf();
9275 if (exp
.e1
.op
== EXP
.slice
)
9277 // Convert e[][] to e[]
9278 SliceExp se
= cast(SliceExp
)exp
.e1
;
9279 if (!se
.lwr
&& !se
.upr
)
9285 if (isArrayOpOperand(exp
.e1
))
9287 // Convert (a[]+b[])[] to a[]+b[]
9292 if (exp
.e1
.op
== EXP
.error
)
9297 if (exp
.e1
.type
.ty
== Terror
)
9300 Type t1b
= exp
.e1
.type
.toBasetype();
9301 if (auto tp
= t1b
.isTypePointer())
9303 if (t1b
.isPtrToFunction())
9305 error(exp
.loc
, "cannot slice function pointer `%s`", exp
.e1
.toChars());
9308 if (!exp
.lwr ||
!exp
.upr
)
9310 error(exp
.loc
, "upper and lower bounds are needed to slice a pointer");
9311 if (auto ad
= isAggregate(tp
.next
.toBasetype()))
9313 auto s
= search_function(ad
, Id
.index
);
9314 if (!s
) s
= search_function(ad
, Id
.slice
);
9317 auto fd
= s
.isFuncDeclaration();
9318 if ((fd
&& !fd
.getParameterList().length
) || s
.isTemplateDeclaration())
9320 errorSupplemental(exp
.loc
,
9321 "pointer `%s` points to an aggregate that defines an `%s`, perhaps you meant `(*%s)[]`",
9333 if (sc
.setUnsafe(false, exp
.loc
, "pointer slicing not allowed in safe functions"))
9336 else if (t1b
.ty
== Tarray
)
9339 else if (t1b
.ty
== Tsarray
)
9342 else if (t1b
.ty
== Ttuple
)
9344 if (!exp
.lwr
&& !exp
.upr
)
9349 if (!exp
.lwr ||
!exp
.upr
)
9351 error(exp
.loc
, "need upper and lower bound to slice a sequence");
9355 else if (t1b
.ty
== Tvector
&& exp
.e1
.isLvalue())
9357 // Convert e1 to corresponding static array
9358 TypeVector tv1
= cast(TypeVector
)t1b
;
9360 t1b
= t1b
.castMod(tv1
.mod
);
9365 error(exp
.loc
, "`%s` cannot be sliced with `[]`", t1b
.ty
== Tvoid ? exp
.e1
.toChars() : t1b
.toChars());
9369 /* Run semantic on lwr and upr.
9372 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray || t1b
.ty
== Ttuple
)
9374 // Create scope for 'length' variable
9375 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, exp
);
9376 sym
.parent
= sc
.scopesym
;
9381 if (t1b
.ty
== Ttuple
)
9382 sc
= sc
.startCTFE();
9383 exp
.lwr
= exp
.lwr
.expressionSemantic(sc
);
9384 exp
.lwr
= resolveProperties(sc
, exp
.lwr
);
9385 if (t1b
.ty
== Ttuple
)
9387 exp
.lwr
= exp
.lwr
.implicitCastTo(sc
, Type
.tsize_t
);
9391 if (t1b
.ty
== Ttuple
)
9392 sc
= sc
.startCTFE();
9393 exp
.upr
= exp
.upr
.expressionSemantic(sc
);
9394 exp
.upr
= resolveProperties(sc
, exp
.upr
);
9395 if (t1b
.ty
== Ttuple
)
9397 exp
.upr
= exp
.upr
.implicitCastTo(sc
, Type
.tsize_t
);
9401 if (exp
.lwr
&& exp
.lwr
.type
== Type
.terror || exp
.upr
&& exp
.upr
.type
== Type
.terror
)
9404 if (t1b
.ty
== Ttuple
)
9406 exp
.lwr
= exp
.lwr
.ctfeInterpret();
9407 exp
.upr
= exp
.upr
.ctfeInterpret();
9408 uinteger_t i1
= exp
.lwr
.toUInteger();
9409 uinteger_t i2
= exp
.upr
.toUInteger();
9414 if (exp
.e1
.op
== EXP
.tuple
) // slicing an expression tuple
9416 te
= cast(TupleExp
)exp
.e1
;
9418 length
= te
.exps
.length
;
9420 else if (exp
.e1
.op
== EXP
.type
) // slicing a type tuple
9423 tup
= cast(TypeTuple
)t1b
;
9424 length
= Parameter
.dim(tup
.arguments
);
9429 if (i2
< i1 || length
< i2
)
9431 error(exp
.loc
, "string slice `[%llu .. %llu]` is out of bounds", i1
, i2
);
9435 size_t j1
= cast(size_t
)i1
;
9436 size_t j2
= cast(size_t
)i2
;
9438 if (exp
.e1
.op
== EXP
.tuple
)
9440 auto exps
= new Expressions(j2
- j1
);
9441 for (size_t i
= 0; i
< j2
- j1
; i
++)
9443 (*exps
)[i
] = (*te
.exps
)[j1
+ i
];
9445 e
= new TupleExp(exp
.loc
, te
.e0
, exps
);
9449 auto args
= new Parameters();
9450 args
.reserve(j2
- j1
);
9451 for (size_t i
= j1
; i
< j2
; i
++)
9453 Parameter arg
= Parameter
.getNth(tup
.arguments
, i
);
9456 e
= new TypeExp(exp
.e1
.loc
, new TypeTuple(args
));
9458 e
= e
.expressionSemantic(sc
);
9463 exp
.type
= t1b
.nextOf().arrayOf();
9464 // Allow typedef[] -> typedef[]
9465 if (exp
.type
.equals(t1b
))
9466 exp
.type
= exp
.e1
.type
;
9468 // We might know $ now
9469 setLengthVarIfKnown(exp
.lengthVar
, t1b
);
9471 if (exp
.lwr
&& exp
.upr
)
9473 exp
.lwr
= exp
.lwr
.optimize(WANTvalue
);
9474 exp
.upr
= exp
.upr
.optimize(WANTvalue
);
9476 IntRange lwrRange
= getIntRange(exp
.lwr
);
9477 IntRange uprRange
= getIntRange(exp
.upr
);
9479 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray
)
9481 Expression el
= new ArrayLengthExp(exp
.loc
, exp
.e1
);
9482 el
= el
.expressionSemantic(sc
);
9483 el
= el
.optimize(WANTvalue
);
9484 if (el
.op
== EXP
.int64
)
9486 // Array length is known at compile-time. Upper is in bounds if it fits length.
9487 dinteger_t length
= el
.toInteger();
9488 auto bounds
= IntRange(SignExtendedNumber(0), SignExtendedNumber(length
));
9489 exp
.upperIsInBounds
= bounds
.contains(uprRange
);
9491 else if (exp
.upr
.op
== EXP
.int64
&& exp
.upr
.toInteger() == 0)
9493 // Upper slice expression is '0'. Value is always in bounds.
9494 exp
.upperIsInBounds
= true;
9496 else if (exp
.upr
.op
== EXP
.variable
&& (cast(VarExp
)exp
.upr
).var
.ident
== Id
.dollar
)
9498 // Upper slice expression is '$'. Value is always in bounds.
9499 exp
.upperIsInBounds
= true;
9502 else if (t1b
.ty
== Tpointer
)
9504 exp
.upperIsInBounds
= true;
9509 exp
.lowerIsLessThanUpper
= (lwrRange
.imax
<= uprRange
.imin
);
9511 //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", exp.upperIsInBounds, exp.lowerIsLessThanUpper);
9517 override void visit(ArrayLengthExp e
)
9519 static if (LOGSEMANTIC
)
9521 printf("ArrayLengthExp::semantic('%s')\n", e
.toChars());
9529 if (Expression ex
= unaSemantic(e
, sc
))
9534 e
.e1
= resolveProperties(sc
, e
.e1
);
9536 e
.type
= Type
.tsize_t
;
9540 override void visit(ArrayExp exp
)
9542 static if (LOGSEMANTIC
)
9544 printf("ArrayExp::semantic('%s')\n", exp
.toChars());
9548 if (sc
.flags
& SCOPE
.Cfile
)
9550 /* See if need to rewrite the AST because of cast/call ambiguity
9552 if (auto e
= castCallAmbiguity(exp
, sc
))
9554 result
= expressionSemantic(e
, sc
);
9559 result
= exp
.carraySemantic(sc
); // C semantics
9563 Expression e
= exp
.op_overload(sc
);
9570 if (isAggregate(exp
.e1
.type
))
9571 error(exp
.loc
, "no `[]` operator overload for type `%s`", exp
.e1
.type
.toChars());
9572 else if (exp
.e1
.op
== EXP
.type
&& exp
.e1
.type
.ty
!= Ttuple
)
9573 error(exp
.loc
, "static array of `%s` with multiple lengths not allowed", exp
.e1
.type
.toChars());
9574 else if (isIndexableNonAggregate(exp
.e1
.type
))
9575 error(exp
.loc
, "only one index allowed to index `%s`", exp
.e1
.type
.toChars());
9577 error(exp
.loc
, "cannot use `[]` operator on expression of type `%s`", exp
.e1
.type
.toChars());
9579 result
= ErrorExp
.get();
9582 override void visit(DotExp exp
)
9584 static if (LOGSEMANTIC
)
9586 printf("DotExp::semantic('%s')\n", exp
.toChars());
9588 printf("\ttype = %s\n", exp
.type
.toChars());
9590 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
9591 exp
.e2
= exp
.e2
.expressionSemantic(sc
);
9593 if (exp
.e1
.op
== EXP
.type
)
9598 if (exp
.e2
.op
== EXP
.type
)
9603 if (auto te
= exp
.e2
.isTemplateExp())
9605 Expression e
= new DotTemplateExp(exp
.loc
, exp
.e1
, te
.td
);
9606 result
= e
.expressionSemantic(sc
);
9610 exp
.type
= exp
.e2
.type
;
9614 override void visit(CommaExp e
)
9616 //printf("Semantic.CommaExp() %s\n", e.toChars());
9623 // Allow `((a,b),(x,y))`
9624 if (e
.allowCommaExp
)
9626 CommaExp
.allow(e
.e1
);
9627 CommaExp
.allow(e
.e2
);
9630 if (Expression ex
= binSemanticProp(e
, sc
))
9635 e
.e1
= e
.e1
.addDtorHook(sc
);
9637 if (checkNonAssignmentArrayOp(e
.e1
))
9640 // Comma expressions trigger this conversion
9641 e
.e2
= e
.e2
.arrayFuncConv(sc
);
9646 if (sc
.flags
& SCOPE
.Cfile
)
9649 if (e
.type
is Type
.tvoid
)
9651 checkMustUse(e
.e1
, sc
);
9654 else if (!e
.allowCommaExp
&& !e
.isGenerated
)
9655 error(e
.loc
, "using the result of a comma expression is not allowed");
9658 override void visit(IntervalExp e
)
9660 static if (LOGSEMANTIC
)
9662 printf("IntervalExp::semantic('%s')\n", e
.toChars());
9670 Expression le
= e
.lwr
;
9671 le
= le
.expressionSemantic(sc
);
9672 le
= resolveProperties(sc
, le
);
9674 Expression ue
= e
.upr
;
9675 ue
= ue
.expressionSemantic(sc
);
9676 ue
= resolveProperties(sc
, ue
);
9678 if (le
.op
== EXP
.error
)
9683 if (ue
.op
== EXP
.error
)
9692 e
.type
= Type
.tvoid
;
9696 override void visit(DelegatePtrExp e
)
9698 static if (LOGSEMANTIC
)
9700 printf("DelegatePtrExp::semantic('%s')\n", e
.toChars());
9705 e
.e1
= resolveProperties(sc
, e
.e1
);
9707 if (e
.e1
.op
== EXP
.error
)
9712 e
.type
= Type
.tvoidptr
;
9717 override void visit(DelegateFuncptrExp e
)
9719 static if (LOGSEMANTIC
)
9721 printf("DelegateFuncptrExp::semantic('%s')\n", e
.toChars());
9726 e
.e1
= resolveProperties(sc
, e
.e1
);
9727 if (e
.e1
.op
== EXP
.error
)
9732 e
.type
= e
.e1
.type
.nextOf().pointerTo();
9737 override void visit(IndexExp exp
)
9739 static if (LOGSEMANTIC
)
9741 printf("IndexExp::semantic('%s')\n", exp
.toChars());
9749 // operator overloading should be handled in ArrayExp already.
9751 exp
.e1
= exp
.e1
.expressionSemantic(sc
).arrayFuncConv(sc
);
9752 assert(exp
.e1
.type
); // semantic() should already be run on it
9753 if (exp
.e1
.op
== EXP
.type
&& exp
.e1
.type
.ty
!= Ttuple
)
9755 exp
.e2
= exp
.e2
.expressionSemantic(sc
);
9756 exp
.e2
= resolveProperties(sc
, exp
.e2
);
9758 if (exp
.e2
.op
== EXP
.type
)
9759 nt
= new TypeAArray(exp
.e1
.type
, exp
.e2
.type
);
9761 nt
= new TypeSArray(exp
.e1
.type
, exp
.e2
);
9762 Expression e
= new TypeExp(exp
.loc
, nt
);
9763 result
= e
.expressionSemantic(sc
);
9766 if (exp
.e1
.op
== EXP
.error
)
9771 if (exp
.e1
.type
.ty
== Terror
)
9774 // Note that unlike C we do not implement the int[ptr]
9776 Type t1b
= exp
.e1
.type
.toBasetype();
9778 if (TypeVector tv1
= t1b
.isTypeVector())
9780 // Convert e1 to corresponding static array
9782 t1b
= t1b
.castMod(tv1
.mod
);
9783 exp
.e1
= exp
.e1
.castTo(sc
, t1b
);
9785 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray
)
9787 if (!checkAddressable(exp
, sc
))
9791 /* Run semantic on e2
9794 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray || t1b
.ty
== Ttuple
)
9796 // Create scope for 'length' variable
9797 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, exp
);
9798 sym
.parent
= sc
.scopesym
;
9801 if (t1b
.ty
== Ttuple
)
9802 sc
= sc
.startCTFE();
9803 exp
.e2
= exp
.e2
.expressionSemantic(sc
).arrayFuncConv(sc
);
9804 exp
.e2
= resolveProperties(sc
, exp
.e2
);
9805 if (t1b
.ty
== Ttuple
)
9807 if (exp
.e2
.op
== EXP
.tuple
)
9809 TupleExp te
= cast(TupleExp
)exp
.e2
;
9810 if (te
.exps
&& te
.exps
.length
== 1)
9811 exp
.e2
= Expression
.combine(te
.e0
, (*te
.exps
)[0]); // bug 4444 fix
9815 if (exp
.e2
.type
== Type
.terror
)
9818 if (checkNonAssignmentArrayOp(exp
.e1
))
9824 if (t1b
.isPtrToFunction())
9826 error(exp
.loc
, "cannot index function pointer `%s`", exp
.e1
.toChars());
9829 exp
.e2
= exp
.e2
.implicitCastTo(sc
, Type
.tsize_t
);
9830 if (exp
.e2
.type
== Type
.terror
)
9832 exp
.e2
= exp
.e2
.optimize(WANTvalue
);
9833 if (exp
.e2
.op
== EXP
.int64
&& exp
.e2
.toInteger() == 0)
9836 else if (sc
.setUnsafe(false, exp
.loc
, "`@safe` function `%s` cannot index pointer `%s`", sc
.func
, exp
.e1
))
9840 exp
.type
= (cast(TypeNext
)t1b
).next
;
9844 exp
.e2
= exp
.e2
.implicitCastTo(sc
, Type
.tsize_t
);
9845 if (exp
.e2
.type
== Type
.terror
)
9847 exp
.type
= (cast(TypeNext
)t1b
).next
;
9852 exp
.e2
= exp
.e2
.implicitCastTo(sc
, Type
.tsize_t
);
9853 if (exp
.e2
.type
== Type
.terror
)
9855 exp
.type
= t1b
.nextOf();
9860 TypeAArray taa
= cast(TypeAArray
)t1b
;
9861 /* We can skip the implicit conversion if they differ only by
9863 * https://issues.dlang.org/show_bug.cgi?id=2684
9864 * see also bug https://issues.dlang.org/show_bug.cgi?id=2954 b
9866 if (!arrayTypeCompatibleWithoutCasting(exp
.e2
.type
, taa
.index
))
9868 exp
.e2
= exp
.e2
.implicitCastTo(sc
, taa
.index
); // type checking
9869 if (exp
.e2
.type
== Type
.terror
)
9873 semanticTypeInfo(sc
, taa
);
9874 checkNewEscape(sc
, exp
.e2
, false);
9876 exp
.type
= taa
.next
;
9881 exp
.e2
= exp
.e2
.implicitCastTo(sc
, Type
.tsize_t
);
9882 if (exp
.e2
.type
== Type
.terror
)
9885 exp
.e2
= exp
.e2
.ctfeInterpret();
9886 uinteger_t index
= exp
.e2
.toUInteger();
9891 if (exp
.e1
.op
== EXP
.tuple
)
9893 te
= cast(TupleExp
)exp
.e1
;
9895 length
= te
.exps
.length
;
9897 else if (exp
.e1
.op
== EXP
.type
)
9900 tup
= cast(TypeTuple
)t1b
;
9901 length
= Parameter
.dim(tup
.arguments
);
9906 if (length
<= index
)
9908 error(exp
.loc
, "array index `[%llu]` is outside array bounds `[0 .. %llu]`", index
, cast(ulong)length
);
9912 if (exp
.e1
.op
== EXP
.tuple
)
9914 e
= (*te
.exps
)[cast(size_t
)index
];
9915 e
= Expression
.combine(te
.e0
, e
);
9918 e
= new TypeExp(exp
.e1
.loc
, Parameter
.getNth(tup
.arguments
, cast(size_t
)index
).type
);
9923 error(exp
.loc
, "`%s` must be an array or pointer type, not `%s`", exp
.e1
.toChars(), exp
.e1
.type
.toChars());
9927 // We might know $ now
9928 setLengthVarIfKnown(exp
.lengthVar
, t1b
);
9930 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray
)
9932 Expression el
= new ArrayLengthExp(exp
.loc
, exp
.e1
);
9933 el
= el
.expressionSemantic(sc
);
9934 el
= el
.optimize(WANTvalue
);
9935 if (el
.op
== EXP
.int64
)
9937 exp
.e2
= exp
.e2
.optimize(WANTvalue
);
9938 dinteger_t length
= el
.toInteger();
9941 auto bounds
= IntRange(SignExtendedNumber(0), SignExtendedNumber(length
- 1));
9942 // OR it in, because it might already be set for C array indexing
9943 exp
.indexIsInBounds |
= bounds
.contains(getIntRange(exp
.e2
));
9945 else if (sc
.flags
& SCOPE
.Cfile
&& t1b
.ty
== Tsarray
)
9947 if (auto ve
= exp
.e1
.isVarExp())
9949 /* Rewrite 0-length C array ve[exp.e2] as *(ve + exp.e2)
9951 auto vp
= ve
.castTo(sc
, t1b
.isTypeSArray().next
.pointerTo());
9952 auto e
= new AddExp(exp
.loc
, vp
, exp
.e2
);
9953 auto pe
= new PtrExp(exp
.loc
, e
);
9954 result
= pe
.expressionSemantic(sc
).optimize(WANTvalue
);
9964 override void visit(PostExp exp
)
9966 static if (LOGSEMANTIC
)
9968 printf("PostExp::semantic('%s')\n", exp
.toChars());
9976 if (sc
.flags
& SCOPE
.Cfile
)
9978 /* See if need to rewrite the AST because of cast/call ambiguity
9980 if (auto e
= castCallAmbiguity(exp
, sc
))
9982 result
= expressionSemantic(e
, sc
);
9987 if (Expression ex
= binSemantic(exp
, sc
))
9992 Expression e1x
= resolveProperties(sc
, exp
.e1
);
9993 if (e1x
.op
== EXP
.error
)
10000 Expression e
= exp
.op_overload(sc
);
10007 if (exp
.e1
.checkReadModifyWrite(exp
.op
))
10010 if (exp
.e1
.op
== EXP
.slice
)
10012 const(char)* s
= exp
.op
== EXP
.plusPlus ?
"increment" : "decrement";
10013 error(exp
.loc
, "cannot post-%s array slice `%s`, use pre-%s instead", s
, exp
.e1
.toChars(), s
);
10017 Type t1
= exp
.e1
.type
.toBasetype();
10018 if (t1
.ty
== Tclass || t1
.ty
== Tstruct || exp
.e1
.op
== EXP
.arrayLength
)
10020 /* Check for operator overloading,
10021 * but rewrite in terms of ++e instead of e++
10024 /* If e1 is not trivial, take a reference to it
10026 Expression
de = null;
10027 if (exp
.e1
.op
!= EXP
.variable
&& exp
.e1
.op
!= EXP
.arrayLength
)
10030 auto v
= copyToTemp(STC
.ref_
, "__postref", exp
.e1
);
10031 de = new DeclarationExp(exp
.loc
, v
);
10032 exp
.e1
= new VarExp(exp
.e1
.loc
, v
);
10036 * auto tmp = e1; ++e1; tmp
10038 auto tmp
= copyToTemp(0, "__pitmp", exp
.e1
);
10039 Expression ea
= new DeclarationExp(exp
.loc
, tmp
);
10041 Expression eb
= exp
.e1
.syntaxCopy();
10042 eb
= new PreExp(exp
.op
== EXP
.plusPlus ? EXP
.prePlusPlus
: EXP
.preMinusMinus
, exp
.loc
, eb
);
10044 Expression ec
= new VarExp(exp
.loc
, tmp
);
10046 // Combine de,ea,eb,ec
10048 ea
= new CommaExp(exp
.loc
, de, ea
);
10049 e
= new CommaExp(exp
.loc
, ea
, eb
);
10050 e
= new CommaExp(exp
.loc
, e
, ec
);
10051 e
= e
.expressionSemantic(sc
);
10056 exp
.e1
= exp
.e1
.modifiableLvalue(sc
);
10057 exp
.e1
= exp
.e1
.optimize(WANTvalue
, /*keepLvalue*/ true);
10060 if (exp
.e1
.checkScalar() ||
10061 exp
.e1
.checkSharedAccess(sc
))
10063 if (exp
.e1
.checkNoBool())
10066 if (exp
.e1
.type
.ty
== Tpointer
)
10067 e
= scaleFactor(exp
, sc
);
10069 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
);
10070 e
.type
= exp
.e1
.type
;
10074 override void visit(PreExp exp
)
10076 Expression e
= exp
.op_overload(sc
);
10077 // printf("PreExp::semantic('%s')\n", toChars());
10084 // Rewrite as e1+=1 or e1-=1
10085 if (exp
.op
== EXP
.prePlusPlus
)
10086 e
= new AddAssignExp(exp
.loc
, exp
.e1
, IntegerExp
.literal
!1);
10088 e
= new MinAssignExp(exp
.loc
, exp
.e1
, IntegerExp
.literal
!1);
10089 result
= e
.expressionSemantic(sc
);
10093 * Get the expression initializer for a specific struct
10096 * sd = the struct for which the expression initializer is needed
10097 * loc = the location of the initializer
10098 * sc = the scope where the expression is located
10099 * t = the type of the expression
10102 * The expression initializer or error expression if any errors occured
10104 private Expression
getInitExp(StructDeclaration sd
, Loc loc
, Scope
* sc
, Type t
)
10106 if (sd
.zeroInit
&& !sd
.isNested())
10108 // https://issues.dlang.org/show_bug.cgi?id=14606
10109 // Always use BlitExp for the special expression: (struct = 0)
10110 return IntegerExp
.literal
!0;
10115 auto sle
= new StructLiteralExp(loc
, sd
, null, t
);
10116 if (!sd
.fill(loc
, *sle
.elements
, true))
10117 return ErrorExp
.get();
10118 if (checkFrameAccess(loc
, sc
, sd
, sle
.elements
.length
))
10119 return ErrorExp
.get();
10125 return t
.defaultInit(loc
);
10128 override void visit(AssignExp exp
)
10130 static if (LOGSEMANTIC
)
10132 if (exp
.op
== EXP
.blit
) printf("BlitExp.toElem('%s')\n", exp
.toChars());
10133 if (exp
.op
== EXP
.assign
) printf("AssignExp.toElem('%s')\n", exp
.toChars());
10134 if (exp
.op
== EXP
.construct
) printf("ConstructExp.toElem('%s')\n", exp
.toChars());
10137 void setResult(Expression e
, int line
= __LINE__
)
10139 //printf("line %d\n", line);
10145 return setResult(exp
);
10148 Expression e1old
= exp
.e1
;
10150 if (auto e2comma
= exp
.e2
.isCommaExp())
10152 if (!e2comma
.isGenerated
&& !(sc
.flags
& SCOPE
.Cfile
))
10153 error(exp
.loc
, "using the result of a comma expression is not allowed");
10155 /* Rewrite to get rid of the comma from rvalue
10156 * e1=(e0,e2) => e0,(e1=e2)
10159 exp
.e2
= Expression
.extractLast(e2comma
, e0
);
10160 Expression e
= Expression
.combine(e0
, exp
);
10161 return setResult(e
.expressionSemantic(sc
));
10164 /* Look for operator overloading of a[arguments] = e2.
10165 * Do it before e1.expressionSemantic() otherwise the ArrayExp will have been
10166 * converted to unary operator overloading already.
10168 if (auto ae
= exp
.e1
.isArrayExp())
10172 ae
.e1
= ae
.e1
.expressionSemantic(sc
);
10173 ae
.e1
= resolveProperties(sc
, ae
.e1
);
10174 Expression ae1old
= ae
.e1
;
10176 const(bool) maybeSlice
=
10177 (ae
.arguments
.length
== 0 ||
10178 ae
.arguments
.length
== 1 && (*ae
.arguments
)[0].op
== EXP
.interval
);
10180 IntervalExp ie
= null;
10181 if (maybeSlice
&& ae
.arguments
.length
)
10183 assert((*ae
.arguments
)[0].op
== EXP
.interval
);
10184 ie
= cast(IntervalExp
)(*ae
.arguments
)[0];
10186 Type att
= null; // first cyclic `alias this` type
10189 if (ae
.e1
.op
== EXP
.error
)
10190 return setResult(ae
.e1
);
10192 Expression e0
= null;
10193 Expression ae1save
= ae
.e1
;
10194 ae
.lengthVar
= null;
10196 Type t1b
= ae
.e1
.type
.toBasetype();
10197 AggregateDeclaration ad
= isAggregate(t1b
);
10200 if (search_function(ad
, Id
.indexass
))
10203 res
= resolveOpDollar(sc
, ae
, &e0
);
10204 if (!res
) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
10206 if (res
.op
== EXP
.error
)
10207 return setResult(res
);
10209 res
= exp
.e2
.expressionSemantic(sc
);
10210 if (res
.op
== EXP
.error
)
10211 return setResult(res
);
10214 /* Rewrite (a[arguments] = e2) as:
10215 * a.opIndexAssign(e2, arguments)
10217 Expressions
* a
= ae
.arguments
.copy();
10218 a
.insert(0, exp
.e2
);
10219 res
= new DotIdExp(exp
.loc
, ae
.e1
, Id
.indexass
);
10220 res
= new CallExp(exp
.loc
, res
, a
);
10221 if (maybeSlice
) // a[] = e2 might be: a.opSliceAssign(e2)
10222 res
= res
.trySemantic(sc
);
10224 res
= res
.expressionSemantic(sc
);
10226 return setResult(Expression
.combine(e0
, res
));
10230 if (maybeSlice
&& search_function(ad
, Id
.sliceass
))
10233 res
= resolveOpDollar(sc
, ae
, ie
, &e0
);
10234 if (res
.op
== EXP
.error
)
10235 return setResult(res
);
10237 res
= exp
.e2
.expressionSemantic(sc
);
10238 if (res
.op
== EXP
.error
)
10239 return setResult(res
);
10243 /* Rewrite (a[i..j] = e2) as:
10244 * a.opSliceAssign(e2, i, j)
10246 auto a
= new Expressions();
10253 res
= new DotIdExp(exp
.loc
, ae
.e1
, Id
.sliceass
);
10254 res
= new CallExp(exp
.loc
, res
, a
);
10255 res
= res
.expressionSemantic(sc
);
10256 return setResult(Expression
.combine(e0
, res
));
10259 // No operator overloading member function found yet, but
10260 // there might be an alias this to try.
10261 if (ad
.aliasthis
&& !isRecursiveAliasThis(att
, ae
.e1
.type
))
10263 /* Rewrite (a[arguments] op e2) as:
10264 * a.aliasthis[arguments] op e2
10266 ae
.e1
= resolveAliasThis(sc
, ae1save
, true);
10272 ae
.e1
= ae1old
; // recovery
10273 ae
.lengthVar
= null;
10276 /* Run this.e1 semantic.
10279 Expression e1x
= exp
.e1
;
10281 /* With UFCS, e.f = value
10287 if (auto dti
= e1x
.isDotTemplateInstanceExp())
10289 Expression e
= dti
.dotTemplateSemanticProp(sc
, DotExpFlag
.gag
);
10292 return setResult(resolveUFCSProperties(sc
, e1x
, exp
.e2
));
10297 else if (sc
.flags
& SCOPE
.Cfile
&& e1x
.isDotIdExp())
10299 auto die
= e1x
.isDotIdExp();
10300 e1x
= fieldLookup(die
.e1
, sc
, die
.ident
, die
.arrow
);
10302 else if (auto die
= e1x
.isDotIdExp())
10304 Expression e
= die
.dotIdSemanticProp(sc
, 1);
10305 if (e
&& isDotOpDispatch(e
))
10307 /* https://issues.dlang.org/show_bug.cgi?id=19687
10309 * On this branch, e2 is semantically analyzed in resolvePropertiesX,
10310 * but that call is done with gagged errors. That is the only time when
10311 * semantic gets ran on e2, that is why the error never gets to be printed.
10312 * In order to make sure that UFCS is tried with correct parameters, e2
10313 * needs to have semantic ran on it.
10316 exp
.e2
= exp
.e2
.expressionSemantic(sc
);
10317 uint errors
= global
.startGagging();
10318 e
= resolvePropertiesX(sc
, e
, exp
.e2
);
10319 // Any error or if 'e' is not resolved, go to UFCS
10320 if (global
.endGagging(errors
) || e
is ode
)
10321 e
= null; /* fall down to UFCS */
10323 return setResult(e
);
10326 return setResult(resolveUFCSProperties(sc
, e1x
, exp
.e2
));
10331 if (auto se
= e1x
.isSliceExp())
10334 e1x
= e1x
.expressionSemantic(sc
);
10337 /* We have f = value.
10343 if (Expression e
= resolvePropertiesX(sc
, e1x
, exp
.e2
, exp
))
10344 return setResult(e
);
10346 if (e1x
.checkRightThis(sc
))
10351 assert(exp
.e1
.type
);
10353 Type t1
= exp
.e1
.type
.isTypeEnum() ? exp
.e1
.type
: exp
.e1
.type
.toBasetype();
10355 /* Run this.e2 semantic.
10356 * Different from other binary expressions, the analysis of e2
10357 * depends on the result of e1 in assignments.
10360 Expression e2x
= inferType(exp
.e2
, t1
.baseElemOf());
10361 e2x
= e2x
.expressionSemantic(sc
);
10362 if (!t1
.isTypeSArray())
10363 e2x
= e2x
.arrayFuncConv(sc
);
10364 e2x
= resolveProperties(sc
, e2x
);
10365 if (e2x
.op
== EXP
.type
)
10366 e2x
= resolveAliasThis(sc
, e2x
); //https://issues.dlang.org/show_bug.cgi?id=17684
10367 if (e2x
.op
== EXP
.error
)
10368 return setResult(e2x
);
10369 // We delay checking the value for structs/classes as these might have
10370 // an opAssign defined.
10371 if ((t1
.ty
!= Tstruct
&& t1
.ty
!= Tclass
&& e2x
.checkValue()) ||
10372 e2x
.checkSharedAccess(sc
))
10375 auto etmp
= checkNoreturnVarAccess(e2x
);
10377 return setResult(etmp
);
10382 /* Rewrite tuple assignment as a tuple of assignments.
10385 Expression e2x
= exp
.e2
;
10388 if (exp
.e1
.op
== EXP
.tuple
&& e2x
.op
== EXP
.tuple
)
10390 TupleExp tup1
= cast(TupleExp
)exp
.e1
;
10391 TupleExp tup2
= cast(TupleExp
)e2x
;
10392 size_t dim
= tup1
.exps
.length
;
10393 Expression e
= null;
10394 if (dim
!= tup2
.exps
.length
)
10396 error(exp
.loc
, "mismatched sequence lengths, %d and %d", cast(int)dim
, cast(int)tup2
.exps
.length
);
10401 e
= IntegerExp
.literal
!0;
10402 e
= new CastExp(exp
.loc
, e
, Type
.tvoid
); // avoid "has no effect" error
10403 e
= Expression
.combine(tup1
.e0
, tup2
.e0
, e
);
10407 auto exps
= new Expressions(dim
);
10408 for (size_t i
= 0; i
< dim
; i
++)
10410 Expression ex1
= (*tup1
.exps
)[i
];
10411 Expression ex2
= (*tup2
.exps
)[i
];
10412 (*exps
)[i
] = new AssignExp(exp
.loc
, ex1
, ex2
);
10414 e
= new TupleExp(exp
.loc
, Expression
.combine(tup1
.e0
, tup2
.e0
), exps
);
10416 return setResult(e
.expressionSemantic(sc
));
10419 /* Look for form: e1 = e2.aliasthis.
10421 if (exp
.e1
.op
== EXP
.tuple
)
10423 TupleDeclaration td
= isAliasThisTuple(e2x
);
10427 assert(exp
.e1
.type
.ty
== Ttuple
);
10428 TypeTuple tt
= cast(TypeTuple
)exp
.e1
.type
;
10431 Expression ev
= extractSideEffect(sc
, "__tup", e0
, e2x
);
10433 auto iexps
= new Expressions();
10435 for (size_t u
= 0; u
< iexps
.length
; u
++)
10438 Expression e
= (*iexps
)[u
];
10440 Parameter arg
= Parameter
.getNth(tt
.arguments
, u
);
10441 //printf("[%d] iexps.length = %d, ", u, iexps.length);
10442 //printf("e = (%s %s, %s), ", Token.toChars[e.op], e.toChars(), e.type.toChars());
10443 //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
10445 if (!arg ||
!e
.type
.implicitConvTo(arg
.type
))
10447 // expand initializer to tuple
10448 if (expandAliasThisTuples(iexps
, u
) != -1)
10450 if (iexps
.length
<= u
)
10457 e2x
= new TupleExp(e2x
.loc
, e0
, iexps
);
10458 e2x
= e2x
.expressionSemantic(sc
);
10459 if (e2x
.op
== EXP
.error
)
10464 // Do not need to overwrite this.e2
10470 /* Inside constructor, if this is the first assignment of object field,
10471 * rewrite this to initializing the field.
10473 if (exp
.op
== EXP
.assign
10474 && exp
.e1
.checkModifiable(sc
) == Modifiable
.initialization
)
10476 //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars());
10478 exp
= new ConstructExp(exp
.loc
, exp
.e1
, exp
.e2
);
10481 // https://issues.dlang.org/show_bug.cgi?id=13515
10482 // set Index::modifiable flag for complex AA element initialization
10483 if (auto ie1
= exp
.e1
.isIndexExp())
10485 Expression e1x
= ie1
.markSettingAAElem();
10486 if (e1x
.op
== EXP
.error
)
10493 else if (exp
.op
== EXP
.construct
&& exp
.e1
.op
== EXP
.variable
&&
10494 (cast(VarExp
)exp
.e1
).var
.storage_class
& (STC
.out_ | STC
.ref_
))
10496 exp
.memset
= MemorySet
.referenceInit
;
10499 if (exp
.op
== EXP
.assign
) // skip EXP.blit and EXP.construct, which are initializations
10501 exp
.e1
.checkSharedAccess(sc
);
10502 checkUnsafeAccess(sc
, exp
.e1
, false, true);
10505 checkUnsafeAccess(sc
, exp
.e2
, true, true); // Initializer must always be checked
10507 /* If it is an assignment from a 'foreign' type,
10508 * check for operator overloading.
10510 if (exp
.memset
== MemorySet
.referenceInit
)
10512 // If this is an initialization of a reference,
10515 else if (t1
.ty
== Tstruct
)
10519 auto sd
= (cast(TypeStruct
)t1
).sym
;
10521 if (exp
.op
== EXP
.construct
)
10523 Type t2
= e2x
.type
.toBasetype();
10524 if (t2
.ty
== Tstruct
&& sd
== (cast(TypeStruct
)t2
).sym
)
10527 if (sd
.sizeok
!= Sizeok
.done
)
10530 sd
.ctor
= sd
.searchCtor();
10532 // https://issues.dlang.org/show_bug.cgi?id=15661
10533 // Look for the form from last of comma chain.
10534 auto e2y
= lastComma(e2x
);
10536 CallExp ce
= (e2y
.op
== EXP
.call) ?
cast(CallExp
)e2y
: null;
10537 DotVarExp dve
= (ce
&& ce
.e1
.op
== EXP
.dotVariable
)
10538 ?
cast(DotVarExp
)ce
.e1
: null;
10539 if (sd
.ctor
&& ce
&& dve
&& dve
.var
.isCtorDeclaration() &&
10540 // https://issues.dlang.org/show_bug.cgi?id=19389
10541 dve
.e1
.op
!= EXP
.dotVariable
&&
10542 e2y
.type
.implicitConvTo(t1
))
10544 /* Look for form of constructor call which is:
10545 * __ctmp.ctor(arguments...)
10548 /* Before calling the constructor, initialize
10549 * variable with a bit copy of the default
10552 Expression einit
= getInitExp(sd
, exp
.loc
, sc
, t1
);
10553 if (einit
.op
== EXP
.error
)
10559 auto ae
= new BlitExp(exp
.loc
, exp
.e1
, einit
);
10560 ae
.type
= e1x
.type
;
10562 /* Replace __ctmp being constructed with e1.
10563 * We need to copy constructor call expression,
10564 * because it may be used in other place.
10566 auto dvx
= cast(DotVarExp
)dve
.copy();
10568 auto cx
= cast(CallExp
)ce
.copy();
10570 if (checkConstructorEscape(sc
, cx
, false))
10574 Expression
.extractLast(e2x
, e0
);
10576 auto e
= Expression
.combine(e0
, ae
, cx
);
10577 e
= e
.expressionSemantic(sc
);
10581 // https://issues.dlang.org/show_bug.cgi?id=21586
10582 // Rewrite CondExp or e1 will miss direct construction, e.g.
10583 // e1 = a ? S(1) : ...; -> AST: e1 = a ? (S(0)).this(1) : ...;
10584 // a temporary created and an extra destructor call.
10585 // AST will be rewritten to:
10586 // a ? e1 = 0, e1.this(1) : ...; -> blitting plus construction
10587 if (e2x
.op
== EXP
.question
)
10590 * a ? e1 = b : e1 = c;
10592 CondExp econd
= cast(CondExp
)e2x
;
10593 Expression ea1
= new ConstructExp(econd
.e1
.loc
, e1x
, econd
.e1
);
10594 Expression ea2
= new ConstructExp(econd
.e2
.loc
, e1x
, econd
.e2
);
10595 Expression e
= new CondExp(exp
.loc
, econd
.econd
, ea1
, ea2
);
10596 result
= e
.expressionSemantic(sc
);
10599 if (sd
.postblit || sd
.hasCopyCtor
)
10601 /* We have a copy constructor for this
10604 if (e2x
.isLvalue())
10606 if (sd
.hasCopyCtor
)
10609 * e1 = init, e1.copyCtor(e2);
10611 Expression einit
= new BlitExp(exp
.loc
, exp
.e1
, getInitExp(sd
, exp
.loc
, sc
, t1
));
10612 einit
.type
= e1x
.type
;
10615 e
= new DotIdExp(exp
.loc
, e1x
, Id
.ctor
);
10616 e
= new CallExp(exp
.loc
, e
, e2x
);
10617 e
= new CommaExp(exp
.loc
, einit
, e
);
10619 //printf("e: %s\n", e.toChars());
10621 result
= e
.expressionSemantic(sc
);
10626 if (!e2x
.type
.implicitConvTo(e1x
.type
))
10628 error(exp
.loc
, "conversion error from `%s` to `%s`",
10629 e2x
.type
.toChars(), e1x
.type
.toChars());
10634 * (e1 = e2).postblit();
10636 * Blit assignment e1 = e2 returns a reference to the original e1,
10637 * then call the postblit on it.
10639 Expression e
= e1x
.copy();
10640 e
.type
= e
.type
.mutableOf();
10641 if (e
.type
.isShared
&& !sd
.type
.isShared
)
10642 e
.type
= e
.type
.unSharedOf();
10643 e
= new BlitExp(exp
.loc
, e
, e2x
);
10644 e
= new DotVarExp(exp
.loc
, e
, sd
.postblit
, false);
10645 e
= new CallExp(exp
.loc
, e
);
10646 result
= e
.expressionSemantic(sc
);
10652 /* The struct value returned from the function is transferred
10653 * so should not call the destructor on it.
10655 e2x
= valueNoDtor(e2x
);
10659 // https://issues.dlang.org/show_bug.cgi?id=19251
10660 // if e2 cannot be converted to e1.type, maybe there is an alias this
10661 if (!e2x
.implicitConvTo(t1
))
10663 AggregateDeclaration ad2
= isAggregate(e2x
.type
);
10664 if (ad2
&& ad2
.aliasthis
&& !isRecursiveAliasThis(exp
.att2
, exp
.e2
.type
))
10666 /* Rewrite (e1 op e2) as:
10667 * (e1 op e2.aliasthis)
10669 exp
.e2
= new DotIdExp(exp
.e2
.loc
, exp
.e2
, ad2
.aliasthis
.ident
);
10670 result
= exp
.expressionSemantic(sc
);
10675 else if (!e2x
.implicitConvTo(t1
))
10678 if (sd
.sizeok
!= Sizeok
.done
)
10681 sd
.ctor
= sd
.searchCtor();
10685 /* Look for implicit constructor call
10687 * e1 = init, e1.ctor(e2)
10690 /* Fix Issue 5153 : https://issues.dlang.org/show_bug.cgi?id=5153
10691 * Using `new` to initialize a struct object is a common mistake, but
10692 * the error message from the compiler is not very helpful in that
10693 * case. If exp.e2 is a NewExp and the type of new is the same as
10694 * the type as exp.e1 (struct in this case), then we know for sure
10695 * that the user wants to instantiate a struct. This is done to avoid
10696 * issuing an error when the user actually wants to call a constructor
10697 * which receives a class object.
10699 * Foo f = new Foo2(0); is a valid expression if Foo has a constructor
10700 * which receives an instance of a Foo2 class
10702 if (exp
.e2
.op
== EXP
.new_
)
10704 auto newExp
= cast(NewExp
)(exp
.e2
);
10705 if (newExp
.newtype
&& newExp
.newtype
== t1
)
10707 error(exp
.loc
, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
10708 newExp
.toChars(), newExp
.type
.toChars(), t1
.toChars());
10709 errorSupplemental(exp
.loc
, "Perhaps remove the `new` keyword?");
10714 Expression einit
= new BlitExp(exp
.loc
, e1x
, getInitExp(sd
, exp
.loc
, sc
, t1
));
10715 einit
.type
= e1x
.type
;
10718 e
= new DotIdExp(exp
.loc
, e1x
, Id
.ctor
);
10719 e
= new CallExp(exp
.loc
, e
, e2x
);
10720 e
= new CommaExp(exp
.loc
, einit
, e
);
10721 e
= e
.expressionSemantic(sc
);
10725 if (search_function(sd
, Id
.call))
10727 /* Look for static opCall
10728 * https://issues.dlang.org/show_bug.cgi?id=2702
10730 * e1 = typeof(e1).opCall(arguments)
10732 e2x
= typeDotIdExp(e2x
.loc
, e1x
.type
, Id
.call);
10733 e2x
= new CallExp(exp
.loc
, e2x
, exp
.e2
);
10735 e2x
= e2x
.expressionSemantic(sc
);
10736 e2x
= resolveProperties(sc
, e2x
);
10737 if (e2x
.op
== EXP
.error
)
10742 if (e2x
.checkValue() || e2x
.checkSharedAccess(sc
))
10746 else // https://issues.dlang.org/show_bug.cgi?id=11355
10748 AggregateDeclaration ad2
= isAggregate(e2x
.type
);
10749 if (ad2
&& ad2
.aliasthis
&& !isRecursiveAliasThis(exp
.att2
, exp
.e2
.type
))
10751 /* Rewrite (e1 op e2) as:
10752 * (e1 op e2.aliasthis)
10754 exp
.e2
= new DotIdExp(exp
.e2
.loc
, exp
.e2
, ad2
.aliasthis
.ident
);
10755 result
= exp
.expressionSemantic(sc
);
10760 else if (exp
.op
== EXP
.assign
)
10762 if (e1x
.op
== EXP
.index
&& (cast(IndexExp
)e1x
).e1
.type
.toBasetype().ty
== Taarray
)
10768 * ref __aatmp = aa;
10769 * ref __aakey = key;
10770 * ref __aaval = e2;
10771 * (__aakey in __aatmp
10772 * ? __aatmp[__aakey].opAssign(__aaval)
10773 * : ConstructExp(__aatmp[__aakey], __aaval));
10775 // ensure we keep the expr modifiable
10776 Expression esetting
= (cast(IndexExp
)e1x
).markSettingAAElem();
10777 if (esetting
.op
== EXP
.error
)
10782 assert(esetting
.op
== EXP
.index
);
10783 IndexExp ie
= cast(IndexExp
) esetting
;
10784 Type t2
= e2x
.type
.toBasetype();
10786 Expression e0
= null;
10787 Expression ea
= extractSideEffect(sc
, "__aatmp", e0
, ie
.e1
);
10788 Expression ek
= extractSideEffect(sc
, "__aakey", e0
, ie
.e2
);
10789 Expression ev
= extractSideEffect(sc
, "__aaval", e0
, e2x
);
10791 AssignExp ae
= cast(AssignExp
)exp
.copy();
10792 ae
.e1
= new IndexExp(exp
.loc
, ea
, ek
);
10793 ae
.e1
= ae
.e1
.expressionSemantic(sc
);
10794 ae
.e1
= ae
.e1
.optimize(WANTvalue
);
10796 Expression e
= ae
.op_overload(sc
);
10799 Expression ey
= null;
10800 if (t2
.ty
== Tstruct
&& sd
== t2
.toDsymbol(sc
))
10804 else if (!ev
.implicitConvTo(ie
.type
) && sd
.ctor
)
10806 // Look for implicit constructor call
10807 // Rewrite as S().ctor(e2)
10808 ey
= new StructLiteralExp(exp
.loc
, sd
, null);
10809 ey
= new DotIdExp(exp
.loc
, ey
, Id
.ctor
);
10810 ey
= new CallExp(exp
.loc
, ey
, ev
);
10811 ey
= ey
.trySemantic(sc
);
10816 ex
= new IndexExp(exp
.loc
, ea
, ek
);
10817 ex
= ex
.expressionSemantic(sc
);
10818 ex
= ex
.modifiableLvalue(sc
); // allocate new slot
10819 ex
= ex
.optimize(WANTvalue
);
10821 ey
= new ConstructExp(exp
.loc
, ex
, ey
);
10822 ey
= ey
.expressionSemantic(sc
);
10823 if (ey
.op
== EXP
.error
)
10830 // https://issues.dlang.org/show_bug.cgi?id=14144
10831 // The whole expression should have the common type
10832 // of opAssign() return and assigned AA entry.
10833 // Even if there's no common type, expression should be typed as void.
10834 if (!typeMerge(sc
, EXP
.question
, ex
, ey
))
10836 ex
= new CastExp(ex
.loc
, ex
, Type
.tvoid
);
10837 ey
= new CastExp(ey
.loc
, ey
, Type
.tvoid
);
10839 e
= new CondExp(exp
.loc
, new InExp(exp
.loc
, ek
, ea
), ex
, ey
);
10841 e
= Expression
.combine(e0
, e
);
10842 e
= e
.expressionSemantic(sc
);
10849 Expression e
= exp
.op_overload(sc
);
10858 assert(exp
.op
== EXP
.blit
);
10860 if (e2x
.checkValue())
10866 else if (t1
.ty
== Tclass
)
10868 // Disallow assignment operator overloads for same type
10869 if (exp
.op
== EXP
.assign
&& !exp
.e2
.implicitConvTo(exp
.e1
.type
))
10871 Expression e
= exp
.op_overload(sc
);
10878 if (exp
.e2
.checkValue())
10881 else if (t1
.ty
== Tsarray
)
10883 // SliceExp cannot have static array type without context inference.
10884 assert(exp
.e1
.op
!= EXP
.slice
);
10885 Expression e1x
= exp
.e1
;
10886 Expression e2x
= exp
.e2
;
10888 /* C strings come through as static arrays. May need to adjust the size of the
10889 * string to match the size of e1.
10891 Type t2
= e2x
.type
.toBasetype();
10892 if (sc
.flags
& SCOPE
.Cfile
&& e2x
.isStringExp() && t2
.isTypeSArray())
10894 uinteger_t dim1
= t1
.isTypeSArray().dim
.toInteger();
10895 uinteger_t dim2
= t2
.isTypeSArray().dim
.toInteger();
10896 if (dim1
+ 1 == dim2 || dim2
< dim1
)
10898 auto tsa2
= t2
.isTypeSArray();
10899 auto newt
= tsa2
.next
.sarrayOf(dim1
).immutableOf();
10900 e2x
= castTo(e2x
, sc
, newt
);
10905 if (e2x
.implicitConvTo(e1x
.type
))
10907 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()))
10909 if (t1
.checkPostblit(e1x
.loc
, sc
))
10913 // e2 matches to t1 because of the implicit length match, so
10914 if (isUnaArrayOp(e2x
.op
) ||
isBinArrayOp(e2x
.op
))
10916 // convert e1 to e1[]
10917 // e.g. e1[] = a[] + b[];
10918 auto sle
= new SliceExp(e1x
.loc
, e1x
, null, null);
10919 sle
.arrayop
= true;
10920 e1x
= sle
.expressionSemantic(sc
);
10924 // convert e2 to t1 later
10925 // e.g. e1 = [1, 2, 3];
10930 if (e2x
.implicitConvTo(t1
.nextOf().arrayOf()) > MATCH
.nomatch
)
10932 uinteger_t dim1
= (cast(TypeSArray
)t1
).dim
.toInteger();
10933 uinteger_t dim2
= dim1
;
10934 if (auto ale
= e2x
.isArrayLiteralExp())
10936 dim2
= ale
.elements ? ale
.elements
.length
: 0;
10938 else if (auto se
= e2x
.isSliceExp())
10940 Type tx
= toStaticArrayType(se
);
10942 dim2
= (cast(TypeSArray
)tx
).dim
.toInteger();
10946 error(exp
.loc
, "mismatched array lengths, %d and %d", cast(int)dim1
, cast(int)dim2
);
10951 // May be block or element-wise assignment, so
10952 // convert e1 to e1[]
10953 if (exp
.op
!= EXP
.assign
)
10955 // If multidimensional static array, treat as one large array
10957 // Find the appropriate array type depending on the assignment, e.g.
10958 // int[3] = int => int[3]
10959 // int[3][2] = int => int[6]
10960 // int[3][2] = int[] => int[3][2]
10961 // int[3][2][4] + int => int[24]
10962 // int[3][2][4] + int[] => int[3][8]
10963 ulong dim
= t1
.isTypeSArray().dim
.toUInteger();
10964 auto type
= t1
.nextOf();
10966 for (TypeSArray tsa
; (tsa
= type
.isTypeSArray()) !is null; )
10968 import core
.checkedint
: mulu
;
10970 // Accumulate skipped dimensions
10971 bool overflow
= false;
10972 dim
= mulu(dim
, tsa
.dim
.toUInteger(), overflow
);
10973 if (overflow || dim
>= uint.max
)
10975 // dym exceeds maximum array size
10976 error(exp
.loc
, "static array `%s` size overflowed to %llu",
10977 e1x
.type
.toChars(), cast(ulong) dim
);
10981 // Move to the element type
10982 type
= tsa
.nextOf().toBasetype();
10984 // Rewrite ex1 as a static array if a matching type was found
10985 if (e2x
.implicitConvTo(type
) > MATCH
.nomatch
)
10987 e1x
.type
= type
.sarrayOf(dim
);
10992 auto sle
= new SliceExp(e1x
.loc
, e1x
, null, null);
10993 sle
.arrayop
= true;
10994 e1x
= sle
.expressionSemantic(sc
);
10996 if (e1x
.op
== EXP
.error
)
10997 return setResult(e1x
);
10998 if (e2x
.op
== EXP
.error
)
10999 return setResult(e2x
);
11003 t1
= e1x
.type
.toBasetype();
11005 /* Check the mutability of e1.
11007 if (auto ale
= exp
.e1
.isArrayLengthExp())
11009 // e1 is not an lvalue, but we let code generator handle it
11011 auto ale1x
= ale
.e1
.modifiableLvalueImpl(sc
, exp
.e1
);
11012 if (ale1x
.op
== EXP
.error
)
11013 return setResult(ale1x
);
11016 Type tn
= ale
.e1
.type
.toBasetype().nextOf();
11017 checkDefCtor(ale
.loc
, tn
);
11019 Identifier hook
= global
.params
.tracegc ? Id
._d_arraysetlengthTTrace
: Id
._d_arraysetlengthT
;
11020 if (!verifyHookExist(exp
.loc
, *sc
, Id
._d_arraysetlengthTImpl
, "resizing arrays"))
11023 exp
.e2
= exp
.e2
.expressionSemantic(sc
);
11024 auto lc
= lastComma(exp
.e2
);
11025 lc
= lc
.optimize(WANTvalue
);
11026 // use slice expression when arr.length = 0 to avoid runtime call
11027 if(lc
.op
== EXP
.int64
&& lc
.toInteger() == 0)
11029 Expression se
= new SliceExp(ale
.loc
, ale
.e1
, lc
, lc
);
11030 Expression as
= new AssignExp(ale
.loc
, ale
.e1
, se
);
11031 as
= as
.expressionSemantic(sc
);
11032 auto res
= Expression
.combine(as
, exp
.e2
);
11033 res
.type
= ale
.type
;
11034 return setResult(res
);
11037 if (!sc
.needsCodegen()) // if compile time creature only
11039 exp
.type
= Type
.tsize_t
;
11040 return setResult(exp
);
11043 // Lower to object._d_arraysetlengthTImpl!(typeof(e1))._d_arraysetlengthT{,Trace}(e1, e2)
11044 Expression id
= new IdentifierExp(ale
.loc
, Id
.empty
);
11045 id
= new DotIdExp(ale
.loc
, id
, Id
.object
);
11046 auto tiargs
= new Objects();
11047 tiargs
.push(ale
.e1
.type
);
11048 id
= new DotTemplateInstanceExp(ale
.loc
, id
, Id
._d_arraysetlengthTImpl
, tiargs
);
11049 id
= new DotIdExp(ale
.loc
, id
, hook
);
11050 id
= id
.expressionSemantic(sc
);
11052 auto arguments
= new Expressions();
11053 arguments
.reserve(5);
11054 if (global
.params
.tracegc
)
11056 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ? sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
11057 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
11058 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
11059 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
11061 arguments
.push(ale
.e1
);
11062 arguments
.push(exp
.e2
);
11064 Expression ce
= new CallExp(ale
.loc
, id
, arguments
).expressionSemantic(sc
);
11065 auto res
= new LoweredAssignExp(exp
, ce
);
11066 // if (global.params.verbose)
11067 // message("lowered %s =>\n %s", exp.toChars(), res.toChars());
11068 res
.type
= Type
.tsize_t
;
11069 return setResult(res
);
11071 else if (auto se
= exp
.e1
.isSliceExp())
11073 Type tn
= se
.type
.nextOf();
11074 const fun
= sc
.func
;
11075 if (exp
.op
== EXP
.assign
&& !tn
.isMutable() &&
11076 // allow modifiation in module ctor, see
11077 // https://issues.dlang.org/show_bug.cgi?id=9884
11078 (!fun ||
(fun
&& !fun
.isStaticCtorDeclaration())))
11080 error(exp
.loc
, "slice `%s` is not mutable", se
.toChars());
11084 if (exp
.op
== EXP
.assign
&& !tn
.baseElemOf().isAssignable())
11086 error(exp
.loc
, "slice `%s` is not mutable, struct `%s` has immutable members",
11087 exp
.e1
.toChars(), tn
.baseElemOf().toChars());
11088 result
= ErrorExp
.get();
11092 // For conditional operator, both branches need conversion.
11093 while (se
.e1
.op
== EXP
.slice
)
11094 se
= cast(SliceExp
)se
.e1
;
11095 if (se
.e1
.op
== EXP
.question
&& se
.e1
.type
.toBasetype().ty
== Tsarray
)
11097 se
.e1
= se
.e1
.modifiableLvalueImpl(sc
, exp
.e1
);
11098 if (se
.e1
.op
== EXP
.error
)
11099 return setResult(se
.e1
);
11104 if (t1
.ty
== Tsarray
&& exp
.op
== EXP
.assign
)
11106 Type tn
= exp
.e1
.type
.nextOf();
11107 if (tn
&& !tn
.baseElemOf().isAssignable())
11109 error(exp
.loc
, "array `%s` is not mutable, struct `%s` has immutable members",
11110 exp
.e1
.toChars(), tn
.baseElemOf().toChars());
11111 result
= ErrorExp
.get();
11116 Expression e1x
= exp
.e1
;
11118 // Try to do a decent error message with the expression
11119 // before it gets constant folded
11120 if (exp
.op
== EXP
.assign
)
11121 e1x
= e1x
.modifiableLvalueImpl(sc
, e1old
);
11123 e1x
= e1x
.optimize(WANTvalue
, /*keepLvalue*/ true);
11125 if (e1x
.op
== EXP
.error
)
11133 /* Tweak e2 based on the type of e1.
11135 Expression e2x
= exp
.e2
;
11136 Type t2
= e2x
.type
.toBasetype();
11138 // If it is a array, get the element type. Note that it may be
11139 // multi-dimensional.
11141 while (telem
.ty
== Tarray
)
11142 telem
= telem
.nextOf();
11144 if (exp
.e1
.op
== EXP
.slice
&& t1
.nextOf() &&
11145 (telem
.ty
!= Tvoid || e2x
.op
== EXP
.null_
) &&
11146 e2x
.implicitConvTo(t1
.nextOf()))
11148 // Check for block assignment. If it is of type void[], void[][], etc,
11149 // '= null' is the only allowable block assignment (Bug 7493)
11150 exp
.memset
= MemorySet
.blockAssign
; // make it easy for back end to tell what this is
11151 e2x
= e2x
.implicitCastTo(sc
, t1
.nextOf());
11152 if (exp
.op
!= EXP
.blit
&& e2x
.isLvalue() && t1
.nextOf
.checkPostblit(exp
.e1
.loc
, sc
))
11155 else if (exp
.e1
.op
== EXP
.slice
&&
11156 (t2
.ty
== Tarray || t2
.ty
== Tsarray
) &&
11157 t2
.nextOf().implicitConvTo(t1
.nextOf()))
11159 // Check element-wise assignment.
11161 /* If assigned elements number is known at compile time,
11162 * check the mismatch.
11164 SliceExp se1
= cast(SliceExp
)exp
.e1
;
11165 TypeSArray tsa1
= cast(TypeSArray
)toStaticArrayType(se1
);
11166 TypeSArray tsa2
= null;
11167 if (auto ale
= e2x
.isArrayLiteralExp())
11168 tsa2
= cast(TypeSArray
)t2
.nextOf().sarrayOf(ale
.elements
.length
);
11169 else if (auto se
= e2x
.isSliceExp())
11170 tsa2
= cast(TypeSArray
)toStaticArrayType(se
);
11172 tsa2
= t2
.isTypeSArray();
11176 uinteger_t dim1
= tsa1
.dim
.toInteger();
11177 uinteger_t dim2
= tsa2
.dim
.toInteger();
11180 error(exp
.loc
, "mismatched array lengths %d and %d for assignment `%s`", cast(int)dim1
, cast(int)dim2
, exp
.toChars());
11185 if (exp
.op
!= EXP
.blit
&&
11186 (e2x
.op
== EXP
.slice
&& (cast(UnaExp
)e2x
).e1
.isLvalue() ||
11187 e2x
.op
== EXP
.cast_
&& (cast(UnaExp
)e2x
).e1
.isLvalue() ||
11188 e2x
.op
!= EXP
.slice
&& e2x
.isLvalue()))
11190 if (t1
.nextOf().checkPostblit(exp
.e1
.loc
, sc
))
11194 Type t2n
= t2
.nextOf();
11195 Type t1n
= t1
.nextOf();
11197 if (t2n
.equivalent(t1n
) ||
11198 t1n
.isBaseOf(t2n
, &offset
) && offset
== 0)
11200 /* Allow copy of distinct qualifier elements.
11202 * char[] dst; const(char)[] src;
11205 * class C {} class D : C {}
11209 if (isArrayOpValid(e2x
))
11211 // Don't add CastExp to keep AST for array operations
11213 e2x
.type
= exp
.e1
.type
.constOf();
11216 e2x
= e2x
.castTo(sc
, exp
.e1
.type
.constOf());
11220 /* https://issues.dlang.org/show_bug.cgi?id=15778
11221 * A string literal has an array type of immutable
11222 * elements by default, and normally it cannot be convertible to
11223 * array type of mutable elements. But for element-wise assignment,
11224 * elements need to be const at best. So we should give a chance
11225 * to change code unit size for polysemous string literal.
11227 if (e2x
.op
== EXP
.string_
)
11228 e2x
= e2x
.implicitCastTo(sc
, exp
.e1
.type
.constOf());
11230 e2x
= e2x
.implicitCastTo(sc
, exp
.e1
.type
);
11232 if (t1n
.toBasetype
.ty
== Tvoid
&& t2n
.toBasetype
.ty
== Tvoid
)
11234 if (sc
.setUnsafe(false, exp
.loc
, "cannot copy `void[]` to `void[]` in `@safe` code"))
11240 if (exp
.op
== EXP
.blit
)
11241 e2x
= e2x
.castTo(sc
, exp
.e1
.type
);
11244 e2x
= e2x
.implicitCastTo(sc
, exp
.e1
.type
);
11246 // Fix Issue 13435: https://issues.dlang.org/show_bug.cgi?id=13435
11248 // If the implicit cast has failed and the assign expression is
11249 // the initialization of a struct member field
11250 if (e2x
.op
== EXP
.error
&& exp
.op
== EXP
.construct
&& t1
.ty
== Tstruct
)
11252 scope sd
= (cast(TypeStruct
)t1
).sym
;
11253 Dsymbol opAssign
= search_function(sd
, Id
.assign
);
11255 // and the struct defines an opAssign
11258 // offer more information about the cause of the problem
11259 errorSupplemental(exp
.loc
,
11260 "`%s` is the first assignment of `%s` therefore it represents its initialization",
11261 exp
.toChars(), exp
.e1
.toChars());
11262 errorSupplemental(exp
.loc
,
11263 "`opAssign` methods are not used for initialization, but for subsequent assignments");
11268 if (e2x
.op
== EXP
.error
)
11274 t2
= exp
.e2
.type
.toBasetype();
11276 /* Look for array operations
11278 if ((t2
.ty
== Tarray || t2
.ty
== Tsarray
) && isArrayOpValid(exp
.e2
))
11280 // Look for valid array operations
11281 if (exp
.memset
!= MemorySet
.blockAssign
&&
11282 exp
.e1
.op
== EXP
.slice
&&
11283 (isUnaArrayOp(exp
.e2
.op
) ||
isBinArrayOp(exp
.e2
.op
)))
11285 exp
.type
= exp
.e1
.type
;
11286 if (exp
.op
== EXP
.construct
) // https://issues.dlang.org/show_bug.cgi?id=10282
11287 // tweak mutability of e1 element
11288 exp
.e1
.type
= exp
.e1
.type
.nextOf().mutableOf().arrayOf();
11289 result
= arrayOp(exp
, sc
);
11293 // Drop invalid array operations in e2
11294 // d = a[] + b[], d = (a[] + b[])[0..2], etc
11295 if (checkNonAssignmentArrayOp(exp
.e2
, exp
.memset
!= MemorySet
.blockAssign
&& exp
.op
== EXP
.assign
))
11298 // Remains valid array assignments
11299 // d = d[], d = [1,2,3], etc
11302 /* Don't allow assignment to classes that were allocated on the stack with:
11303 * scope Class c = new Class();
11305 if (exp
.e1
.op
== EXP
.variable
&& exp
.op
== EXP
.assign
)
11307 VarExp ve
= cast(VarExp
)exp
.e1
;
11308 VarDeclaration vd
= ve
.var
.isVarDeclaration();
11309 if (vd
&& vd
.onstack
)
11311 assert(t1
.ty
== Tclass
);
11312 error(exp
.loc
, "cannot rebind scope variables");
11316 if (exp
.e1
.op
== EXP
.variable
&& (cast(VarExp
)exp
.e1
).var
.ident
== Id
.ctfe
)
11318 error(exp
.loc
, "cannot modify compiler-generated variable `__ctfe`");
11321 exp
.type
= exp
.e1
.type
;
11323 auto assignElem
= exp
.e2
;
11324 auto res
= exp
.op
== EXP
.assign ? exp
.reorderSettingAAElem(sc
) : exp
;
11325 /* https://issues.dlang.org/show_bug.cgi?id=22366
11327 * `reorderSettingAAElem` creates a tree of comma expressions, however,
11328 * `checkAssignExp` expects only AssignExps.
11330 if (res
== exp
) // no `AA[k] = v` rewrite was performed
11331 checkAssignEscape(sc
, res
, false, false);
11333 checkNewEscape(sc
, assignElem
, false); // assigning to AA puts it on heap
11335 if (auto ae
= res
.isConstructExp())
11337 Type t1b
= ae
.e1
.type
.toBasetype();
11338 if (t1b
.ty
!= Tsarray
&& t1b
.ty
!= Tarray
)
11339 return setResult(res
);
11341 // only non-trivial array constructions may need to be lowered (non-POD elements basically)
11342 Type t1e
= t1b
.nextOf();
11343 TypeStruct ts
= t1e
.baseElemOf().isTypeStruct();
11344 if (!ts ||
(!ts
.sym
.postblit
&& !ts
.sym
.hasCopyCtor
&& !ts
.sym
.dtor
))
11345 return setResult(res
);
11347 // don't lower ref-constructions etc.
11348 if (!(t1b
.ty
== Tsarray || ae
.e1
.isSliceExp
) ||
11349 (ae
.e1
.isVarExp
&& ae
.e1
.isVarExp
.var
.isVarDeclaration
.isReference
))
11350 return setResult(res
);
11352 // Construction from an equivalent other array?
11353 // Only lower with lvalue RHS elements; let the glue layer move rvalue elements.
11354 Type t2b
= ae
.e2
.type
.toBasetype();
11355 // skip over a (possibly implicit) cast of a static array RHS to a slice
11356 Expression rhs
= ae
.e2
;
11357 Type rhsType
= t2b
;
11358 if (t2b
.ty
== Tarray
)
11360 if (auto ce
= rhs
.isCastExp())
11362 auto ct
= ce
.e1
.type
.toBasetype();
11363 if (ct
.ty
== Tsarray
)
11371 if (!sc
.needsCodegen()) // interpreter can handle these
11372 return setResult(res
);
11374 const lowerToArrayCtor
=
11375 ( (rhsType
.ty
== Tarray
&& !rhs
.isArrayLiteralExp
) ||
11376 (rhsType
.ty
== Tsarray
&& rhs
.isLvalue
) ) &&
11377 t1e
.equivalent(t2b
.nextOf
);
11379 // Construction from a single element?
11380 // If the RHS is an rvalue, then we'll need to make a temporary for it (copied multiple times).
11381 const lowerToArraySetCtor
= !lowerToArrayCtor
&& t1e
.equivalent(t2b
);
11383 if (lowerToArrayCtor || lowerToArraySetCtor
)
11385 auto func
= lowerToArrayCtor ? Id
._d_arrayctor
: Id
._d_arraysetctor
;
11386 const other
= lowerToArrayCtor ?
"other array" : "value";
11387 if (!verifyHookExist(exp
.loc
, *sc
, func
, "construct array with " ~ other
, Id
.object
))
11390 // Lower to object._d_array{,set}ctor(e1, e2)
11391 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
11392 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
11393 id
= new DotIdExp(exp
.loc
, id
, func
);
11395 auto arguments
= new Expressions();
11396 arguments
.push(new CastExp(ae
.loc
, ae
.e1
, t1e
.arrayOf
).expressionSemantic(sc
));
11397 if (lowerToArrayCtor
)
11399 arguments
.push(new CastExp(ae
.loc
, rhs
, t2b
.nextOf
.arrayOf
).expressionSemantic(sc
));
11400 Expression ce
= new CallExp(exp
.loc
, id
, arguments
);
11401 res
= ce
.expressionSemantic(sc
);
11406 // promote an rvalue RHS element to a temporary, it's passed by ref to _d_arraysetctor
11407 if (!ae
.e2
.isLvalue
)
11409 auto vd
= copyToTemp(STC
.scope_
, "__setctor", ae
.e2
);
11410 e0
= new DeclarationExp(vd
.loc
, vd
).expressionSemantic(sc
);
11411 arguments
.push(new VarExp(vd
.loc
, vd
).expressionSemantic(sc
));
11414 arguments
.push(ae
.e2
);
11416 Expression ce
= new CallExp(exp
.loc
, id
, arguments
);
11417 res
= Expression
.combine(e0
, ce
).expressionSemantic(sc
);
11420 if (global
.params
.v
.verbose
)
11421 message("lowered %s =>\n %s", exp
.toChars(), res
.toChars());
11424 else if (auto ae
= res
.isAssignExp())
11425 res
= lowerArrayAssign(ae
);
11426 else if (auto ce
= res
.isCommaExp())
11428 if (auto ae1
= ce
.e1
.isAssignExp())
11429 ce
.e1
= lowerArrayAssign(ae1
, true);
11430 if (auto ae2
= ce
.e2
.isAssignExp())
11431 ce
.e2
= lowerArrayAssign(ae2
, true);
11434 return setResult(res
);
11437 /***************************************
11438 * Lower AssignExp to `_d_array{setassign,assign_l,assign_r}` if needed.
11441 * ae = the AssignExp to be lowered
11442 * fromCommaExp = indicates whether `ae` is part of a CommaExp or not,
11443 * so no unnecessary temporay variable is created.
11445 * a CommaExp contiaining call a to `_d_array{setassign,assign_l,assign_r}`
11446 * if needed or `ae` otherwise
11448 private Expression
lowerArrayAssign(AssignExp ae
, bool fromCommaExp
= false)
11450 Type t1b
= ae
.e1
.type
.toBasetype();
11451 if (t1b
.ty
!= Tsarray
&& t1b
.ty
!= Tarray
)
11454 const isArrayAssign
= (ae
.e1
.isSliceExp() || ae
.e1
.type
.ty
== Tsarray
) &&
11455 (ae
.e2
.type
.ty
== Tsarray || ae
.e2
.type
.ty
== Tarray
) &&
11456 (ae
.e1
.type
.nextOf() && ae
.e2
.type
.nextOf() && ae
.e1
.type
.nextOf
.mutableOf
.equals(ae
.e2
.type
.nextOf
.mutableOf()));
11458 const isArraySetAssign
= (ae
.e1
.isSliceExp() || ae
.e1
.type
.ty
== Tsarray
) &&
11459 (ae
.e1
.type
.nextOf() && ae
.e2
.type
.implicitConvTo(ae
.e1
.type
.nextOf()));
11461 if (!isArrayAssign
&& !isArraySetAssign
)
11464 const ts
= t1b
.nextOf().baseElemOf().isTypeStruct();
11465 if (!ts ||
(!ts
.sym
.postblit
&& !ts
.sym
.dtor
))
11469 Identifier func
= isArraySetAssign ? Id
._d_arraysetassign
:
11470 ae
.e2
.isLvalue() || ae
.e2
.isSliceExp() ? Id
._d_arrayassign_l
: Id
._d_arrayassign_r
;
11472 // Lower to `.object._d_array{setassign,assign_l,assign_r}(e1, e2)``
11473 Expression id
= new IdentifierExp(ae
.loc
, Id
.empty
);
11474 id
= new DotIdExp(ae
.loc
, id
, Id
.object
);
11475 id
= new DotIdExp(ae
.loc
, id
, func
);
11477 auto arguments
= new Expressions();
11478 arguments
.push(new CastExp(ae
.loc
, ae
.e1
, ae
.e1
.type
.nextOf
.arrayOf
)
11479 .expressionSemantic(sc
));
11481 Expression eValue2
, value2
= ae
.e2
;
11482 if (isArrayAssign
&& value2
.isLvalue())
11483 value2
= new CastExp(ae
.loc
, ae
.e2
, ae
.e2
.type
.nextOf
.arrayOf())
11484 .expressionSemantic(sc
);
11485 else if (!fromCommaExp
&&
11486 (isArrayAssign ||
(isArraySetAssign
&& !value2
.isLvalue())))
11488 // Rvalues from CommaExps were introduced in `visit(AssignExp)`
11489 // and are temporary variables themselves. Rvalues from trivial
11490 // SliceExps are simply passed by reference without any copying.
11492 // `__assigntmp` will be destroyed together with the array `ae.e1`.
11493 // When `ae.e2` is a variadic arg array, it is also `scope`, so
11494 // `__assigntmp` may also be scope.
11495 StorageClass
stc = STC
.nodtor
;
11497 stc |
= STC
.rvalue | STC
.scope_
;
11499 auto vd
= copyToTemp(stc, "__assigntmp", ae
.e2
);
11500 eValue2
= new DeclarationExp(vd
.loc
, vd
).expressionSemantic(sc
);
11501 value2
= new VarExp(vd
.loc
, vd
).expressionSemantic(sc
);
11503 arguments
.push(value2
);
11505 Expression ce
= new CallExp(ae
.loc
, id
, arguments
);
11506 res
= Expression
.combine(eValue2
, ce
).expressionSemantic(sc
);
11508 res
= Expression
.combine(res
, ae
.e1
).expressionSemantic(sc
);
11510 if (global
.params
.v
.verbose
)
11511 message("lowered %s =>\n %s", ae
.toChars(), res
.toChars());
11513 res
= new LoweredAssignExp(ae
, res
);
11514 res
.type
= ae
.type
;
11519 override void visit(PowAssignExp exp
)
11527 Expression e
= exp
.op_overload(sc
);
11534 if (exp
.e1
.checkReadModifyWrite(exp
.op
, exp
.e2
))
11537 assert(exp
.e1
.type
&& exp
.e2
.type
);
11538 if (exp
.e1
.op
== EXP
.slice || exp
.e1
.type
.ty
== Tarray || exp
.e1
.type
.ty
== Tsarray
)
11540 if (checkNonAssignmentArrayOp(exp
.e1
))
11544 if (exp
.e2
.implicitConvTo(exp
.e1
.type
.nextOf()))
11547 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
.nextOf());
11549 else if (Expression ex
= typeCombine(exp
, sc
))
11555 // Check element types are arithmetic
11556 Type tb1
= exp
.e1
.type
.nextOf().toBasetype();
11557 Type tb2
= exp
.e2
.type
.toBasetype();
11558 if (tb2
.ty
== Tarray || tb2
.ty
== Tsarray
)
11559 tb2
= tb2
.nextOf().toBasetype();
11560 if ((tb1
.isintegral() || tb1
.isfloating()) && (tb2
.isintegral() || tb2
.isfloating()))
11562 exp
.type
= exp
.e1
.type
;
11563 result
= arrayOp(exp
, sc
);
11569 exp
.e1
= exp
.e1
.modifiableLvalue(sc
);
11572 if ((exp
.e1
.type
.isintegral() || exp
.e1
.type
.isfloating()) && (exp
.e2
.type
.isintegral() || exp
.e2
.type
.isfloating()))
11574 Expression e0
= null;
11575 e
= exp
.reorderSettingAAElem(sc
);
11576 e
= Expression
.extractLast(e
, e0
);
11579 if (exp
.e1
.op
== EXP
.variable
)
11581 // Rewrite: e1 = e1 ^^ e2
11582 e
= new PowExp(exp
.loc
, exp
.e1
.syntaxCopy(), exp
.e2
);
11583 e
= new AssignExp(exp
.loc
, exp
.e1
, e
);
11587 // Rewrite: ref tmp = e1; tmp = tmp ^^ e2
11588 auto v
= copyToTemp(STC
.ref_
, "__powtmp", exp
.e1
);
11589 auto de = new DeclarationExp(exp
.e1
.loc
, v
);
11590 auto ve
= new VarExp(exp
.e1
.loc
, v
);
11591 e
= new PowExp(exp
.loc
, ve
, exp
.e2
);
11592 e
= new AssignExp(exp
.loc
, new VarExp(exp
.e1
.loc
, v
), e
);
11593 e
= new CommaExp(exp
.loc
, de, e
);
11595 e
= Expression
.combine(e0
, e
);
11596 e
= e
.expressionSemantic(sc
);
11600 result
= exp
.incompatibleTypes();
11603 override void visit(CatAssignExp exp
)
11611 //printf("CatAssignExp::semantic() %s\n", exp.toChars());
11612 Expression e
= exp
.op_overload(sc
);
11619 if (SliceExp se
= exp
.e1
.isSliceExp())
11621 if (se
.e1
.type
.toBasetype().ty
== Tsarray
)
11623 error(exp
.loc
, "cannot append to static array `%s`", se
.e1
.type
.toChars());
11628 exp
.e1
= exp
.e1
.modifiableLvalue(sc
);
11629 if (exp
.e1
.op
== EXP
.error
)
11634 if (exp
.e2
.op
== EXP
.error
)
11640 if (checkNonAssignmentArrayOp(exp
.e2
))
11643 Type tb1
= exp
.e1
.type
.toBasetype();
11644 Type tb1next
= tb1
.nextOf();
11645 Type tb2
= exp
.e2
.type
.toBasetype();
11648 * EXP.concatenateAssign: appending T[] to T[]
11649 * EXP.concatenateElemAssign: appending T to T[]
11650 * EXP.concatenateDcharAssign: appending dchar to T[]
11652 if ((tb1
.ty
== Tarray
) &&
11653 (tb2
.ty
== Tarray || tb2
.ty
== Tsarray
) &&
11654 (exp
.e2
.implicitConvTo(exp
.e1
.type
) ||
11655 (tb2
.nextOf().implicitConvTo(tb1next
) &&
11656 (tb2
.nextOf().size(Loc
.initial
) == tb1next
.size(Loc
.initial
)))))
11658 // EXP.concatenateAssign
11659 assert(exp
.op
== EXP
.concatenateAssign
);
11660 if (tb1next
.checkPostblit(exp
.e1
.loc
, sc
))
11663 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
);
11665 else if ((tb1
.ty
== Tarray
) && exp
.e2
.implicitConvTo(tb1next
))
11667 /* https://issues.dlang.org/show_bug.cgi?id=19782
11669 * If e2 is implicitly convertible to tb1next, the conversion
11670 * might be done through alias this, in which case, e2 needs to
11671 * be modified accordingly (e2 => e2.aliasthis).
11673 if (tb2
.ty
== Tstruct
&& (cast(TypeStruct
)tb2
).implicitConvToThroughAliasThis(tb1next
))
11675 if (tb2
.ty
== Tclass
&& (cast(TypeClass
)tb2
).implicitConvToThroughAliasThis(tb1next
))
11678 if (tb2
.checkPostblit(exp
.e2
.loc
, sc
))
11681 if (checkNewEscape(sc
, exp
.e2
, false))
11684 exp
= new CatElemAssignExp(exp
.loc
, exp
.type
, exp
.e1
, exp
.e2
.castTo(sc
, tb1next
));
11685 exp
.e2
= doCopyOrMove(sc
, exp
.e2
);
11687 else if (tb1
.ty
== Tarray
&&
11688 (tb1next
.ty
== Tchar || tb1next
.ty
== Twchar
) &&
11689 exp
.e2
.type
.ty
!= tb1next
.ty
&&
11690 exp
.e2
.implicitConvTo(Type
.tdchar
))
11692 // Append dchar to char[] or wchar[]
11693 exp
= new CatDcharAssignExp(exp
.loc
, exp
.type
, exp
.e1
, exp
.e2
.castTo(sc
, Type
.tdchar
));
11695 /* Do not allow appending wchar to char[] because if wchar happens
11696 * to be a surrogate pair, nothing good can result.
11701 // Try alias this on first operand
11702 static Expression
tryAliasThisForLhs(BinAssignExp exp
, Scope
* sc
)
11704 AggregateDeclaration ad1
= isAggregate(exp
.e1
.type
);
11705 if (!ad1 ||
!ad1
.aliasthis
)
11708 /* Rewrite (e1 op e2) as:
11709 * (e1.aliasthis op e2)
11711 if (isRecursiveAliasThis(exp
.att1
, exp
.e1
.type
))
11713 //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
11714 Expression e1
= new DotIdExp(exp
.loc
, exp
.e1
, ad1
.aliasthis
.ident
);
11715 BinExp be
= cast(BinExp
)exp
.copy();
11717 return be
.trySemantic(sc
);
11720 // Try alias this on second operand
11721 static Expression
tryAliasThisForRhs(BinAssignExp exp
, Scope
* sc
)
11723 AggregateDeclaration ad2
= isAggregate(exp
.e2
.type
);
11724 if (!ad2 ||
!ad2
.aliasthis
)
11726 /* Rewrite (e1 op e2) as:
11727 * (e1 op e2.aliasthis)
11729 if (isRecursiveAliasThis(exp
.att2
, exp
.e2
.type
))
11731 //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
11732 Expression e2
= new DotIdExp(exp
.loc
, exp
.e2
, ad2
.aliasthis
.ident
);
11733 BinExp be
= cast(BinExp
)exp
.copy();
11735 return be
.trySemantic(sc
);
11739 result
= tryAliasThisForLhs(exp
, sc
);
11743 result
= tryAliasThisForRhs(exp
, sc
);
11747 error(exp
.loc
, "cannot append type `%s` to type `%s`", tb2
.toChars(), tb1
.toChars());
11751 if (exp
.e2
.checkValue() || exp
.e2
.checkSharedAccess(sc
))
11754 exp
.type
= exp
.e1
.type
;
11755 auto assignElem
= exp
.e2
;
11756 auto res
= exp
.reorderSettingAAElem(sc
);
11757 if (res
!= exp
) // `AA[k] = v` rewrite was performed
11758 checkNewEscape(sc
, assignElem
, false);
11759 else if (exp
.op
== EXP
.concatenateElemAssign || exp
.op
== EXP
.concatenateDcharAssign
)
11760 checkAssignEscape(sc
, res
, false, false);
11764 if ((exp
.op
== EXP
.concatenateAssign || exp
.op
== EXP
.concatenateElemAssign
) && sc
.needsCodegen())
11766 // if aa ordering is triggered, `res` will be a CommaExp
11767 // and `.e2` will be the rewritten original expression.
11769 // `output` will point to the expression that the lowering will overwrite
11770 Expression
* output
;
11771 if (auto comma
= res
.isCommaExp())
11773 output
= &comma
.e2
;
11774 // manual cast because it could be either CatAssignExp or CatElemAssignExp
11775 exp
= cast(CatAssignExp
)comma
.e2
;
11780 exp
= cast(CatAssignExp
)result
;
11783 if (exp
.op
== EXP
.concatenateAssign
)
11785 Identifier hook
= global
.params
.tracegc ? Id
._d_arrayappendTTrace
: Id
._d_arrayappendT
;
11787 if (!verifyHookExist(exp
.loc
, *sc
, hook
, "appending array to arrays", Id
.object
))
11790 // Lower to object._d_arrayappendT{,Trace}({file, line, funcname}, e1, e2)
11791 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
11792 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
11793 id
= new DotIdExp(exp
.loc
, id
, hook
);
11795 auto arguments
= new Expressions();
11796 arguments
.reserve(5);
11797 if (global
.params
.tracegc
)
11799 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ? sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
11800 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
11801 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
11802 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
11805 arguments
.push(exp
.e1
);
11806 arguments
.push(exp
.e2
);
11807 Expression ce
= new CallExp(exp
.loc
, id
, arguments
);
11809 exp
.lowering
= ce
.expressionSemantic(sc
);
11812 else if (exp
.op
== EXP
.concatenateElemAssign
)
11814 /* Do not lower concats to the indices array returned by
11815 *`static foreach`, as this array is only used at compile-time.
11817 if (auto ve
= exp
.e1
.isVarExp
)
11819 import core
.stdc
.ctype
: isdigit
;
11820 // The name of the indices array that static foreach loops uses.
11821 // See dmd.cond.lowerNonArrayAggregate
11822 enum varName
= "__res";
11823 const(char)[] id
= ve
.var
.ident
.toString
;
11824 if (ve
.var
.storage_class
& STC
.temp
&& id
.length
> varName
.length
&&
11825 id
[0 .. varName
.length
] == varName
&& id
[varName
.length
].isdigit
)
11829 Identifier hook
= global
.params
.tracegc ? Id
._d_arrayappendcTXTrace
: Id
._d_arrayappendcTX
;
11830 if (!verifyHookExist(exp
.loc
, *sc
, hook
, "appending element to arrays", Id
.object
))
11833 // Lower to object._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2
11834 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
11835 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
11836 id
= new DotIdExp(exp
.loc
, id
, hook
);
11838 auto arguments
= new Expressions();
11839 arguments
.reserve(5);
11840 if (global
.params
.tracegc
)
11842 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ? sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
11843 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
11844 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
11845 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
11848 Expression eValue1
;
11849 Expression value1
= extractSideEffect(sc
, "__appendtmp", eValue1
, exp
.e1
);
11851 arguments
.push(value1
);
11852 arguments
.push(new IntegerExp(exp
.loc
, 1, Type
.tsize_t
));
11854 Expression ce
= new CallExp(exp
.loc
, id
, arguments
);
11856 Expression eValue2
;
11857 Expression value2
= exp
.e2
;
11858 if (!value2
.isVarExp() && !value2
.isConst())
11860 /* Before the template hook, this check was performed in e2ir.d
11861 * for expressions like `a ~= a[$-1]`. Here, $ will be modified
11862 * by calling `_d_arrayappendcTX`, so we need to save `a[$-1]` in
11863 * a temporary variable.
11865 value2
= extractSideEffect(sc
, "__appendtmp", eValue2
, value2
, true);
11867 // `__appendtmp*` will be destroyed together with the array `exp.e1`.
11868 auto vd
= eValue2
.isDeclarationExp().declaration
.isVarDeclaration();
11869 vd
.storage_class |
= STC
.nodtor
;
11870 // Be more explicit that this "declaration" is local to the expression
11871 vd
.storage_class |
= STC
.exptemp
;
11874 auto ale
= new ArrayLengthExp(exp
.loc
, value1
);
11875 auto elem
= new IndexExp(exp
.loc
, value1
, new MinExp(exp
.loc
, ale
, IntegerExp
.literal
!1));
11876 auto ae
= new ConstructExp(exp
.loc
, elem
, value2
);
11878 auto e0
= Expression
.combine(ce
, ae
).expressionSemantic(sc
);
11879 e0
= Expression
.combine(e0
, value1
);
11880 e0
= Expression
.combine(eValue1
, e0
);
11881 e0
= Expression
.combine(eValue2
, e0
);
11883 exp
.lowering
= e0
.expressionSemantic(sc
);
11889 override void visit(AddExp exp
)
11891 static if (LOGSEMANTIC
)
11893 printf("AddExp::semantic('%s')\n", exp
.toChars());
11901 if (Expression ex
= binSemanticProp(exp
, sc
))
11906 Expression e
= exp
.op_overload(sc
);
11913 /* ImportC: convert arrays to pointers, functions to pointers to functions
11915 exp
.e1
= exp
.e1
.arrayFuncConv(sc
);
11916 exp
.e2
= exp
.e2
.arrayFuncConv(sc
);
11918 Type tb1
= exp
.e1
.type
.toBasetype();
11919 Type tb2
= exp
.e2
.type
.toBasetype();
11922 if (tb1
.ty
== Tdelegate || tb1
.isPtrToFunction())
11924 err |
= exp
.e1
.checkArithmetic(exp
.op
) || exp
.e1
.checkSharedAccess(sc
);
11926 if (tb2
.ty
== Tdelegate || tb2
.isPtrToFunction())
11928 err |
= exp
.e2
.checkArithmetic(exp
.op
) || exp
.e2
.checkSharedAccess(sc
);
11933 if (tb1
.ty
== Tpointer
&& exp
.e2
.type
.isintegral() || tb2
.ty
== Tpointer
&& exp
.e1
.type
.isintegral())
11935 result
= scaleFactor(exp
, sc
);
11939 if (tb1
.ty
== Tpointer
&& tb2
.ty
== Tpointer
)
11941 result
= exp
.incompatibleTypes();
11945 if (Expression ex
= typeCombine(exp
, sc
))
11951 Type tb
= exp
.type
.toBasetype();
11952 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
11954 if (!isArrayOpValid(exp
))
11956 result
= arrayOpInvalidError(exp
);
11963 tb1
= exp
.e1
.type
.toBasetype();
11964 if (!target
.isVectorOpSupported(tb1
, exp
.op
, tb2
))
11966 result
= exp
.incompatibleTypes();
11969 if ((tb1
.isreal() && exp
.e2
.type
.isimaginary()) ||
(tb1
.isimaginary() && exp
.e2
.type
.isreal()))
11971 switch (exp
.type
.toBasetype().ty
)
11975 exp
.type
= Type
.tcomplex32
;
11980 exp
.type
= Type
.tcomplex64
;
11985 exp
.type
= Type
.tcomplex80
;
11995 override void visit(MinExp exp
)
11997 static if (LOGSEMANTIC
)
11999 printf("MinExp::semantic('%s')\n", exp
.toChars());
12007 if (Expression ex
= binSemanticProp(exp
, sc
))
12012 Expression e
= exp
.op_overload(sc
);
12019 /* ImportC: convert arrays to pointers, functions to pointers to functions
12021 exp
.e1
= exp
.e1
.arrayFuncConv(sc
);
12022 exp
.e2
= exp
.e2
.arrayFuncConv(sc
);
12024 Type t1
= exp
.e1
.type
.toBasetype();
12025 Type t2
= exp
.e2
.type
.toBasetype();
12028 if (t1
.ty
== Tdelegate || t1
.isPtrToFunction())
12030 err |
= exp
.e1
.checkArithmetic(exp
.op
) || exp
.e1
.checkSharedAccess(sc
);
12032 if (t2
.ty
== Tdelegate || t2
.isPtrToFunction())
12034 err |
= exp
.e2
.checkArithmetic(exp
.op
) || exp
.e2
.checkSharedAccess(sc
);
12039 if (t1
.ty
== Tpointer
)
12041 if (t2
.ty
== Tpointer
)
12043 // https://dlang.org/spec/expression.html#add_expressions
12044 // "If both operands are pointers, and the operator is -, the pointers are
12045 // subtracted and the result is divided by the size of the type pointed to
12046 // by the operands. It is an error if the pointers point to different types."
12047 Type p1
= t1
.nextOf();
12048 Type p2
= t2
.nextOf();
12050 if (!p1
.equivalent(p2
))
12052 // Deprecation to remain for at least a year, after which this should be
12053 // changed to an error
12054 // See https://github.com/dlang/dmd/pull/7332
12055 deprecation(exp
.loc
,
12056 "cannot subtract pointers to different types: `%s` and `%s`.",
12057 t1
.toChars(), t2
.toChars());
12060 // Need to divide the result by the stride
12061 // Replace (ptr - ptr) with (ptr - ptr) / stride
12064 // make sure pointer types are compatible
12065 if (Expression ex
= typeCombine(exp
, sc
))
12071 exp
.type
= Type
.tptrdiff_t
;
12072 stride
= t2
.nextOf().size();
12075 e
= new IntegerExp(exp
.loc
, 0, Type
.tptrdiff_t
);
12077 else if (stride
== cast(long)SIZE_INVALID
)
12078 e
= ErrorExp
.get();
12081 e
= new DivExp(exp
.loc
, exp
, new IntegerExp(Loc
.initial
, stride
, Type
.tptrdiff_t
));
12082 e
.type
= Type
.tptrdiff_t
;
12085 else if (t2
.isintegral())
12086 e
= scaleFactor(exp
, sc
);
12089 error(exp
.loc
, "can't subtract `%s` from pointer", t2
.toChars());
12090 e
= ErrorExp
.get();
12095 if (t2
.ty
== Tpointer
)
12097 exp
.type
= exp
.e2
.type
;
12098 error(exp
.loc
, "can't subtract pointer from `%s`", exp
.e1
.type
.toChars());
12102 if (Expression ex
= typeCombine(exp
, sc
))
12108 Type tb
= exp
.type
.toBasetype();
12109 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
12111 if (!isArrayOpValid(exp
))
12113 result
= arrayOpInvalidError(exp
);
12120 t1
= exp
.e1
.type
.toBasetype();
12121 t2
= exp
.e2
.type
.toBasetype();
12122 if (!target
.isVectorOpSupported(t1
, exp
.op
, t2
))
12124 result
= exp
.incompatibleTypes();
12127 if ((t1
.isreal() && t2
.isimaginary()) ||
(t1
.isimaginary() && t2
.isreal()))
12129 switch (exp
.type
.ty
)
12133 exp
.type
= Type
.tcomplex32
;
12138 exp
.type
= Type
.tcomplex64
;
12143 exp
.type
= Type
.tcomplex80
;
12155 * If the given expression is a `CatExp`, the function tries to lower it to
12156 * `_d_arraycatnTX`.
12159 * ee = the `CatExp` to lower
12161 * `_d_arraycatnTX(e1, e2, ..., en)` if `ee` is `e1 ~ e2 ~ ... en`
12164 private Expression
lowerToArrayCat(CatExp exp
)
12166 // String literals are concatenated by the compiler. No lowering is needed.
12167 if ((exp
.e1
.isStringExp() && (exp
.e2
.isIntegerExp() || exp
.e2
.isStringExp())) ||
12168 (exp
.e2
.isStringExp() && (exp
.e1
.isIntegerExp() || exp
.e1
.isStringExp())))
12171 bool useTraceGCHook
= global
.params
.tracegc
&& sc
.needsCodegen();
12173 Identifier hook
= useTraceGCHook ? Id
._d_arraycatnTXTrace
: Id
._d_arraycatnTX
;
12174 if (!verifyHookExist(exp
.loc
, *sc
, hook
, "concatenating arrays"))
12180 void handleCatArgument(Expressions
*arguments
, Expression e
)
12182 if (auto ce
= e
.isCatExp())
12184 Expression lowering
= ce
.lowering
;
12186 /* Skip `file`, `line`, and `funcname` if the hook of the parent
12187 * `CatExp` is `_d_arraycatnTXTrace`.
12189 if (auto callExp
= isRuntimeHook(lowering
, hook
))
12191 if (hook
== Id
._d_arraycatnTX
)
12192 arguments
.pushSlice((*callExp
.arguments
)[]);
12194 arguments
.pushSlice((*callExp
.arguments
)[3 .. $]);
12201 auto arguments
= new Expressions();
12202 if (useTraceGCHook
)
12204 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ?
12205 sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
12206 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
12207 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
12208 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
12211 handleCatArgument(arguments
, exp
.e1
);
12212 handleCatArgument(arguments
, exp
.e2
);
12214 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
12215 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
12217 auto tiargs
= new Objects();
12218 tiargs
.push(exp
.type
);
12219 id
= new DotTemplateInstanceExp(exp
.loc
, id
, hook
, tiargs
);
12220 id
= new CallExp(exp
.loc
, id
, arguments
);
12221 return id
.expressionSemantic(sc
);
12224 void trySetCatExpLowering(Expression exp
)
12226 /* `_d_arraycatnTX` canot be used with `-betterC`, but `CatExp`s may be
12227 * used with `-betterC`, but only during CTFE.
12229 if (!global
.params
.useGC
)
12232 if (auto ce
= exp
.isCatExp())
12233 ce
.lowering
= lowerToArrayCat(ce
);
12236 override void visit(CatExp exp
)
12238 // https://dlang.org/spec/expression.html#cat_expressions
12239 //printf("CatExp.semantic() %s\n", toChars());
12246 if (Expression ex
= binSemanticProp(exp
, sc
))
12251 Expression e
= exp
.op_overload(sc
);
12258 Type tb1
= exp
.e1
.type
.toBasetype();
12259 Type tb2
= exp
.e2
.type
.toBasetype();
12261 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
12262 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
12266 Type tb1next
= tb1
.nextOf();
12267 Type tb2next
= tb2
.nextOf();
12269 // Check for: array ~ array
12270 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
)))
12272 /* https://issues.dlang.org/show_bug.cgi?id=9248
12273 * Here to avoid the case of:
12274 * void*[] a = [cast(void*)1];
12275 * void*[] b = [cast(void*)2];
12278 * a ~ [cast(void*)b];
12281 /* https://issues.dlang.org/show_bug.cgi?id=14682
12282 * Also to avoid the case of:
12286 * a ~ cast(int[])[];
12291 // Check for: array ~ element
12292 if ((tb1
.ty
== Tsarray || tb1
.ty
== Tarray
) && tb2
.ty
!= Tvoid
)
12294 if (exp
.e1
.op
== EXP
.arrayLiteral
)
12296 exp
.e2
= doCopyOrMove(sc
, exp
.e2
);
12297 // https://issues.dlang.org/show_bug.cgi?id=14686
12298 // Postblit call appears in AST, and this is
12299 // finally translated to an ArrayLiteralExp in below optimize().
12301 else if (exp
.e1
.op
== EXP
.string_
)
12303 // No postblit call exists on character (integer) value.
12307 if (tb2
.checkPostblit(exp
.e2
.loc
, sc
))
12309 // Postblit call will be done in runtime helper function
12312 if (exp
.e1
.op
== EXP
.arrayLiteral
&& exp
.e1
.implicitConvTo(tb2
.arrayOf()))
12314 exp
.e1
= exp
.e1
.implicitCastTo(sc
, tb2
.arrayOf());
12315 exp
.type
= tb2
.arrayOf();
12318 if (exp
.e2
.implicitConvTo(tb1next
) >= MATCH
.convert
)
12320 exp
.e2
= exp
.e2
.implicitCastTo(sc
, tb1next
);
12321 exp
.type
= tb1next
.arrayOf();
12323 if (checkNewEscape(sc
, exp
.e2
, false))
12325 result
= exp
.optimize(WANTvalue
);
12326 trySetCatExpLowering(result
);
12330 // Check for: element ~ array
12331 if ((tb2
.ty
== Tsarray || tb2
.ty
== Tarray
) && tb1
.ty
!= Tvoid
)
12333 if (exp
.e2
.op
== EXP
.arrayLiteral
)
12335 exp
.e1
= doCopyOrMove(sc
, exp
.e1
);
12337 else if (exp
.e2
.op
== EXP
.string_
)
12342 if (tb1
.checkPostblit(exp
.e1
.loc
, sc
))
12346 if (exp
.e2
.op
== EXP
.arrayLiteral
&& exp
.e2
.implicitConvTo(tb1
.arrayOf()))
12348 exp
.e2
= exp
.e2
.implicitCastTo(sc
, tb1
.arrayOf());
12349 exp
.type
= tb1
.arrayOf();
12352 if (exp
.e1
.implicitConvTo(tb2next
) >= MATCH
.convert
)
12354 exp
.e1
= exp
.e1
.implicitCastTo(sc
, tb2next
);
12355 exp
.type
= tb2next
.arrayOf();
12357 if (checkNewEscape(sc
, exp
.e1
, false))
12359 result
= exp
.optimize(WANTvalue
);
12360 trySetCatExpLowering(result
);
12366 if ((tb1
.ty
== Tsarray || tb1
.ty
== Tarray
) && (tb2
.ty
== Tsarray || tb2
.ty
== Tarray
) && (tb1next
.mod || tb2next
.mod
) && (tb1next
.mod
!= tb2next
.mod
))
12368 Type t1
= tb1next
.mutableOf().constOf().arrayOf();
12369 Type t2
= tb2next
.mutableOf().constOf().arrayOf();
12370 if (exp
.e1
.op
== EXP
.string_
&& !(cast(StringExp
)exp
.e1
).committed
)
12373 exp
.e1
= exp
.e1
.castTo(sc
, t1
);
12374 if (exp
.e2
.op
== EXP
.string_
&& !(cast(StringExp
)exp
.e2
).committed
)
12377 exp
.e2
= exp
.e2
.castTo(sc
, t2
);
12380 if (Expression ex
= typeCombine(exp
, sc
))
12383 trySetCatExpLowering(result
);
12386 exp
.type
= exp
.type
.toHeadMutable();
12388 Type tb
= exp
.type
.toBasetype();
12389 if (tb
.ty
== Tsarray
)
12390 exp
.type
= tb
.nextOf().arrayOf();
12391 if (exp
.type
.ty
== Tarray
&& tb1next
&& tb2next
&& tb1next
.mod
!= tb2next
.mod
)
12393 exp
.type
= exp
.type
.nextOf().toHeadMutable().arrayOf();
12395 if (Type tbn
= tb
.nextOf())
12397 if (tbn
.checkPostblit(exp
.loc
, sc
))
12400 Type t1
= exp
.e1
.type
.toBasetype();
12401 Type t2
= exp
.e2
.type
.toBasetype();
12402 if ((t1
.ty
== Tarray || t1
.ty
== Tsarray
) &&
12403 (t2
.ty
== Tarray || t2
.ty
== Tsarray
))
12405 // Normalize to ArrayLiteralExp or StringExp as far as possible
12406 e
= exp
.optimize(WANTvalue
);
12410 //printf("(%s) ~ (%s)\n", e1.toChars(), e2.toChars());
12411 result
= exp
.incompatibleTypes();
12416 trySetCatExpLowering(result
);
12419 override void visit(MulExp exp
)
12423 printf("MulExp::semantic() %s\n", exp
.toChars());
12431 if (Expression ex
= binSemanticProp(exp
, sc
))
12436 Expression e
= exp
.op_overload(sc
);
12443 if (Expression ex
= typeCombine(exp
, sc
))
12449 Type tb
= exp
.type
.toBasetype();
12450 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
12452 if (!isArrayOpValid(exp
))
12454 result
= arrayOpInvalidError(exp
);
12461 if (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
))
12464 if (exp
.type
.isfloating())
12466 Type t1
= exp
.e1
.type
;
12467 Type t2
= exp
.e2
.type
;
12473 else if (t2
.isreal())
12477 else if (t1
.isimaginary())
12479 if (t2
.isimaginary())
12481 switch (t1
.toBasetype().ty
)
12484 exp
.type
= Type
.tfloat32
;
12488 exp
.type
= Type
.tfloat64
;
12492 exp
.type
= Type
.tfloat80
;
12500 exp
.e1
.type
= exp
.type
;
12501 exp
.e2
.type
= exp
.type
;
12502 e
= new NegExp(exp
.loc
, exp
);
12503 e
= e
.expressionSemantic(sc
);
12508 exp
.type
= t2
; // t2 is complex
12510 else if (t2
.isimaginary())
12512 exp
.type
= t1
; // t1 is complex
12515 else if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
12517 result
= exp
.incompatibleTypes();
12523 override void visit(DivExp exp
)
12531 if (Expression ex
= binSemanticProp(exp
, sc
))
12536 Expression e
= exp
.op_overload(sc
);
12543 if (Expression ex
= typeCombine(exp
, sc
))
12549 Type tb
= exp
.type
.toBasetype();
12550 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
12552 if (!isArrayOpValid(exp
))
12554 result
= arrayOpInvalidError(exp
);
12561 if (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
))
12564 if (exp
.type
.isfloating())
12566 Type t1
= exp
.e1
.type
;
12567 Type t2
= exp
.e2
.type
;
12572 if (t2
.isimaginary())
12576 e
= new NegExp(exp
.loc
, exp
);
12577 e
= e
.expressionSemantic(sc
);
12582 else if (t2
.isreal())
12586 else if (t1
.isimaginary())
12588 if (t2
.isimaginary())
12590 switch (t1
.toBasetype().ty
)
12593 exp
.type
= Type
.tfloat32
;
12597 exp
.type
= Type
.tfloat64
;
12601 exp
.type
= Type
.tfloat80
;
12609 exp
.type
= t2
; // t2 is complex
12611 else if (t2
.isimaginary())
12613 exp
.type
= t1
; // t1 is complex
12616 else if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
12618 result
= exp
.incompatibleTypes();
12624 override void visit(ModExp exp
)
12632 if (Expression ex
= binSemanticProp(exp
, sc
))
12637 Expression e
= exp
.op_overload(sc
);
12644 if (Expression ex
= typeCombine(exp
, sc
))
12650 Type tb
= exp
.type
.toBasetype();
12651 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
12653 if (!isArrayOpValid(exp
))
12655 result
= arrayOpInvalidError(exp
);
12661 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
12663 result
= exp
.incompatibleTypes();
12667 if (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
))
12670 if (exp
.type
.isfloating())
12672 exp
.type
= exp
.e1
.type
;
12673 if (exp
.e2
.type
.iscomplex())
12675 error(exp
.loc
, "cannot perform modulo complex arithmetic");
12682 override void visit(PowExp exp
)
12690 //printf("PowExp::semantic() %s\n", toChars());
12691 if (Expression ex
= binSemanticProp(exp
, sc
))
12696 Expression e
= exp
.op_overload(sc
);
12703 if (Expression ex
= typeCombine(exp
, sc
))
12709 Type tb
= exp
.type
.toBasetype();
12710 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
12712 if (!isArrayOpValid(exp
))
12714 result
= arrayOpInvalidError(exp
);
12721 if (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
))
12724 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
12726 result
= exp
.incompatibleTypes();
12730 // First, attempt to fold the expression.
12731 e
= exp
.optimize(WANTvalue
);
12732 if (e
.op
!= EXP
.pow
)
12734 e
= e
.expressionSemantic(sc
);
12739 Module mmath
= Module
.loadStdMath();
12742 error(e
.loc
, "`%s` requires `std.math` for `^^` operators", e
.toChars());
12745 e
= new ScopeExp(exp
.loc
, mmath
);
12747 if (exp
.e2
.op
== EXP
.float64
&& exp
.e2
.toReal() == CTFloat
.half
)
12749 // Replace e1 ^^ 0.5 with .std.math.sqrt(e1)
12750 e
= new CallExp(exp
.loc
, new DotIdExp(exp
.loc
, e
, Id
._sqrt
), exp
.e1
);
12754 // Replace e1 ^^ e2 with .std.math.pow(e1, e2)
12755 e
= new CallExp(exp
.loc
, new DotIdExp(exp
.loc
, e
, Id
._pow
), exp
.e1
, exp
.e2
);
12757 e
= e
.expressionSemantic(sc
);
12762 override void visit(ShlExp exp
)
12764 //printf("ShlExp::semantic(), type = %p\n", type);
12771 if (Expression ex
= binSemanticProp(exp
, sc
))
12776 Expression e
= exp
.op_overload(sc
);
12783 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
12786 if (!target
.isVectorOpSupported(exp
.e1
.type
.toBasetype(), exp
.op
, exp
.e2
.type
.toBasetype()))
12788 result
= exp
.incompatibleTypes();
12791 exp
.e1
= integralPromotions(exp
.e1
, sc
);
12792 if (exp
.e2
.type
.toBasetype().ty
!= Tvector
)
12793 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tshiftcnt
);
12795 exp
.type
= exp
.e1
.type
;
12799 override void visit(ShrExp exp
)
12807 if (Expression ex
= binSemanticProp(exp
, sc
))
12812 Expression e
= exp
.op_overload(sc
);
12819 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
12822 if (!target
.isVectorOpSupported(exp
.e1
.type
.toBasetype(), exp
.op
, exp
.e2
.type
.toBasetype()))
12824 result
= exp
.incompatibleTypes();
12827 exp
.e1
= integralPromotions(exp
.e1
, sc
);
12828 if (exp
.e2
.type
.toBasetype().ty
!= Tvector
)
12829 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tshiftcnt
);
12831 exp
.type
= exp
.e1
.type
;
12835 override void visit(UshrExp exp
)
12843 if (Expression ex
= binSemanticProp(exp
, sc
))
12848 Expression e
= exp
.op_overload(sc
);
12855 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
12858 if (!target
.isVectorOpSupported(exp
.e1
.type
.toBasetype(), exp
.op
, exp
.e2
.type
.toBasetype()))
12860 result
= exp
.incompatibleTypes();
12863 exp
.e1
= integralPromotions(exp
.e1
, sc
);
12864 if (exp
.e2
.type
.toBasetype().ty
!= Tvector
)
12865 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tshiftcnt
);
12867 exp
.type
= exp
.e1
.type
;
12871 override void visit(AndExp exp
)
12879 if (Expression ex
= binSemanticProp(exp
, sc
))
12884 Expression e
= exp
.op_overload(sc
);
12891 if (exp
.e1
.type
.toBasetype().ty
== Tbool
&& exp
.e2
.type
.toBasetype().ty
== Tbool
)
12893 exp
.type
= exp
.e1
.type
;
12898 if (Expression ex
= typeCombine(exp
, sc
))
12904 Type tb
= exp
.type
.toBasetype();
12905 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
12907 if (!isArrayOpValid(exp
))
12909 result
= arrayOpInvalidError(exp
);
12915 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
12917 result
= exp
.incompatibleTypes();
12920 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
12926 override void visit(OrExp exp
)
12934 if (Expression ex
= binSemanticProp(exp
, sc
))
12939 Expression e
= exp
.op_overload(sc
);
12946 if (exp
.e1
.type
.toBasetype().ty
== Tbool
&& exp
.e2
.type
.toBasetype().ty
== Tbool
)
12948 exp
.type
= exp
.e1
.type
;
12953 if (Expression ex
= typeCombine(exp
, sc
))
12959 Type tb
= exp
.type
.toBasetype();
12960 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
12962 if (!isArrayOpValid(exp
))
12964 result
= arrayOpInvalidError(exp
);
12970 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
12972 result
= exp
.incompatibleTypes();
12975 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
12981 override void visit(XorExp exp
)
12989 if (Expression ex
= binSemanticProp(exp
, sc
))
12994 Expression e
= exp
.op_overload(sc
);
13001 if (exp
.e1
.type
.toBasetype().ty
== Tbool
&& exp
.e2
.type
.toBasetype().ty
== Tbool
)
13003 exp
.type
= exp
.e1
.type
;
13008 if (Expression ex
= typeCombine(exp
, sc
))
13014 Type tb
= exp
.type
.toBasetype();
13015 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
13017 if (!isArrayOpValid(exp
))
13019 result
= arrayOpInvalidError(exp
);
13025 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
13027 result
= exp
.incompatibleTypes();
13030 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
13036 override void visit(LogicalExp exp
)
13038 static if (LOGSEMANTIC
)
13040 printf("LogicalExp::semantic() %s\n", exp
.toChars());
13049 exp
.setNoderefOperands();
13051 Expression e1x
= exp
.e1
.expressionSemantic(sc
);
13053 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
13054 if (e1x
.op
== EXP
.type
)
13055 e1x
= resolveAliasThis(sc
, e1x
);
13057 e1x
= resolveProperties(sc
, e1x
);
13058 e1x
= e1x
.toBoolean(sc
);
13060 if (sc
.flags
& SCOPE
.condition
)
13062 /* If in static if, don't evaluate e2 if we don't have to.
13064 e1x
= e1x
.optimize(WANTvalue
);
13065 if (e1x
.toBool().hasValue(exp
.op
== EXP
.orOr
))
13067 if (sc
.flags
& SCOPE
.Cfile
)
13068 result
= new IntegerExp(exp
.op
== EXP
.orOr
);
13070 result
= IntegerExp
.createBool(exp
.op
== EXP
.orOr
);
13075 CtorFlow ctorflow
= sc
.ctorflow
.clone();
13076 Expression e2x
= exp
.e2
.expressionSemantic(sc
);
13077 sc
.merge(exp
.loc
, ctorflow
);
13078 ctorflow
.freeFieldinit();
13080 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
13081 if (e2x
.op
== EXP
.type
)
13082 e2x
= resolveAliasThis(sc
, e2x
);
13084 e2x
= resolveProperties(sc
, e2x
);
13086 auto f1
= checkNonAssignmentArrayOp(e1x
);
13087 auto f2
= checkNonAssignmentArrayOp(e2x
);
13091 // Unless the right operand is 'void', the expression is converted to 'bool'.
13092 if (e2x
.type
.ty
!= Tvoid
)
13093 e2x
= e2x
.toBoolean(sc
);
13095 if (e2x
.op
== EXP
.type || e2x
.op
== EXP
.scope_
)
13097 error(exp
.loc
, "`%s` is not an expression", exp
.e2
.toChars());
13100 if (e1x
.op
== EXP
.error || e1x
.type
.ty
== Tnoreturn
)
13105 if (e2x
.op
== EXP
.error
)
13111 // The result type is 'bool', unless the right operand has type 'void'.
13112 if (e2x
.type
.ty
== Tvoid
)
13113 exp
.type
= Type
.tvoid
;
13115 exp
.type
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? Type
.tint32
: Type
.tbool
;
13123 override void visit(CmpExp exp
)
13125 static if (LOGSEMANTIC
)
13127 printf("CmpExp::semantic('%s')\n", exp
.toChars());
13135 exp
.setNoderefOperands();
13137 if (Expression ex
= binSemanticProp(exp
, sc
))
13142 Type t1
= exp
.e1
.type
.toBasetype();
13143 Type t2
= exp
.e2
.type
.toBasetype();
13144 if (t1
.ty
== Tclass
&& exp
.e2
.op
== EXP
.null_ || t2
.ty
== Tclass
&& exp
.e1
.op
== EXP
.null_
)
13146 error(exp
.loc
, "do not use `null` when comparing class types");
13151 EXP cmpop
= exp
.op
;
13152 if (auto e
= exp
.op_overload(sc
, &cmpop
))
13154 if (!e
.type
.isscalar() && e
.type
.equals(exp
.e1
.type
))
13156 error(exp
.loc
, "recursive `opCmp` expansion");
13159 if (e
.op
== EXP
.call)
13162 if (t1
.ty
== Tclass
&& t2
.ty
== Tclass
)
13164 // Lower to object.__cmp(e1, e2)
13165 Expression cl
= new IdentifierExp(exp
.loc
, Id
.empty
);
13166 cl
= new DotIdExp(exp
.loc
, cl
, Id
.object
);
13167 cl
= new DotIdExp(exp
.loc
, cl
, Id
.__cmp
);
13168 cl
= cl
.expressionSemantic(sc
);
13170 auto arguments
= new Expressions();
13171 // Check if op_overload found a better match by calling e2.opCmp(e1)
13172 // If the operands were swapped, then the result must be reversed
13173 // e1.opCmp(e2) == -e2.opCmp(e1)
13174 // cmpop takes care of this
13175 if (exp
.op
== cmpop
)
13177 arguments
.push(exp
.e1
);
13178 arguments
.push(exp
.e2
);
13182 // Use better match found by op_overload
13183 arguments
.push(exp
.e2
);
13184 arguments
.push(exp
.e1
);
13187 cl
= new CallExp(exp
.loc
, cl
, arguments
);
13188 cl
= new CmpExp(cmpop
, exp
.loc
, cl
, new IntegerExp(0));
13189 result
= cl
.expressionSemantic(sc
);
13193 e
= new CmpExp(cmpop
, exp
.loc
, e
, IntegerExp
.literal
!0);
13194 e
= e
.expressionSemantic(sc
);
13201 if (Expression ex
= typeCombine(exp
, sc
))
13207 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
13208 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
13212 exp
.type
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? Type
.tint32
: Type
.tbool
;
13214 // Special handling for array comparisons
13215 Expression arrayLowering
= null;
13216 t1
= exp
.e1
.type
.toBasetype();
13217 t2
= exp
.e2
.type
.toBasetype();
13218 if ((t1
.ty
== Tarray || t1
.ty
== Tsarray || t1
.ty
== Tpointer
) && (t2
.ty
== Tarray || t2
.ty
== Tsarray || t2
.ty
== Tpointer
))
13220 Type t1next
= t1
.nextOf();
13221 Type t2next
= t2
.nextOf();
13222 if (t1next
.implicitConvTo(t2next
) < MATCH
.constant
&& t2next
.implicitConvTo(t1next
) < MATCH
.constant
&& (t1next
.ty
!= Tvoid
&& t2next
.ty
!= Tvoid
))
13224 error(exp
.loc
, "array comparison type mismatch, `%s` vs `%s`", t1next
.toChars(), t2next
.toChars());
13228 if ((t1
.ty
== Tarray || t1
.ty
== Tsarray
) &&
13229 (t2
.ty
== Tarray || t2
.ty
== Tsarray
))
13231 if (!verifyHookExist(exp
.loc
, *sc
, Id
.__cmp
, "comparing arrays"))
13234 // Lower to object.__cmp(e1, e2)
13235 Expression al
= new IdentifierExp(exp
.loc
, Id
.empty
);
13236 al
= new DotIdExp(exp
.loc
, al
, Id
.object
);
13237 al
= new DotIdExp(exp
.loc
, al
, Id
.__cmp
);
13238 al
= al
.expressionSemantic(sc
);
13240 auto arguments
= new Expressions(2);
13241 (*arguments
)[0] = exp
.e1
;
13242 (*arguments
)[1] = exp
.e2
;
13244 al
= new CallExp(exp
.loc
, al
, arguments
);
13245 al
= new CmpExp(exp
.op
, exp
.loc
, al
, IntegerExp
.literal
!0);
13247 arrayLowering
= al
;
13250 else if (t1
.ty
== Tstruct || t2
.ty
== Tstruct ||
(t1
.ty
== Tclass
&& t2
.ty
== Tclass
))
13252 if (t2
.ty
== Tstruct
)
13253 error(exp
.loc
, "need member function `opCmp()` for %s `%s` to compare", t2
.toDsymbol(sc
).kind(), t2
.toChars());
13255 error(exp
.loc
, "need member function `opCmp()` for %s `%s` to compare", t1
.toDsymbol(sc
).kind(), t1
.toChars());
13258 else if (t1
.iscomplex() || t2
.iscomplex())
13260 error(exp
.loc
, "compare not defined for complex operands");
13263 else if (t1
.ty
== Taarray || t2
.ty
== Taarray
)
13265 error(exp
.loc
, "`%s` is not defined for associative arrays", EXPtoString(exp
.op
).ptr
);
13268 else if (!target
.isVectorOpSupported(t1
, exp
.op
, t2
))
13270 result
= exp
.incompatibleTypes();
13275 bool r1
= exp
.e1
.checkValue() || exp
.e1
.checkSharedAccess(sc
);
13276 bool r2
= exp
.e2
.checkValue() || exp
.e2
.checkSharedAccess(sc
);
13281 //printf("CmpExp: %s, type = %s\n", e.toChars(), e.type.toChars());
13284 arrayLowering
= arrayLowering
.expressionSemantic(sc
);
13285 result
= arrayLowering
;
13289 if (auto tv
= t1
.isTypeVector())
13290 exp
.type
= tv
.toBooleanVector();
13296 override void visit(InExp exp
)
13304 if (Expression ex
= binSemanticProp(exp
, sc
))
13309 Expression e
= exp
.op_overload(sc
);
13316 Type t2b
= exp
.e2
.type
.toBasetype();
13321 TypeAArray ta
= cast(TypeAArray
)t2b
;
13323 // Special handling for array keys
13324 if (!arrayTypeCompatibleWithoutCasting(exp
.e1
.type
, ta
.index
))
13326 // Convert key to type of key
13327 exp
.e1
= exp
.e1
.implicitCastTo(sc
, ta
.index
);
13330 semanticTypeInfo(sc
, ta
.index
);
13332 // Return type is pointer to value
13333 exp
.type
= ta
.nextOf().pointerTo();
13340 case Tarray
, Tsarray
:
13341 result
= exp
.incompatibleTypes();
13342 errorSupplemental(exp
.loc
, "`in` is only allowed on associative arrays");
13343 const(char)* slice
= (t2b
.ty
== Tsarray
) ?
"[]" : "";
13344 errorSupplemental(exp
.loc
, "perhaps use `std.algorithm.find(%s, %s%s)` instead",
13345 exp
.e1
.toChars(), exp
.e2
.toChars(), slice
);
13349 result
= exp
.incompatibleTypes();
13355 override void visit(RemoveExp e
)
13357 if (Expression ex
= binSemantic(e
, sc
))
13365 override void visit(EqualExp exp
)
13367 //printf("EqualExp::semantic('%s')\n", exp.toChars());
13374 exp
.setNoderefOperands();
13376 if (auto e
= binSemanticProp(exp
, sc
))
13381 if (exp
.e1
.op
== EXP
.type || exp
.e2
.op
== EXP
.type
)
13383 /* https://issues.dlang.org/show_bug.cgi?id=12520
13384 * empty tuples are represented as types so special cases are added
13385 * so that they can be compared for equality with tuples of values.
13387 static auto extractTypeTupAndExpTup(Expression e
)
13389 static struct Result
{ bool ttEmpty
; bool te
; }
13390 auto tt
= e
.op
== EXP
.type ? e
.isTypeExp().type
.isTypeTuple() : null;
13391 return Result(tt
&& (!tt
.arguments ||
!tt
.arguments
.length
), e
.isTupleExp() !is null);
13393 auto tups1
= extractTypeTupAndExpTup(exp
.e1
);
13394 auto tups2
= extractTypeTupAndExpTup(exp
.e2
);
13395 // AliasSeq!() == AliasSeq!(<at least a value>)
13396 if (tups1
.ttEmpty
&& tups2
.te
)
13398 result
= IntegerExp
.createBool(exp
.op
!= EXP
.equal
);
13401 // AliasSeq!(<at least a value>) == AliasSeq!()
13402 else if (tups1
.te
&& tups2
.ttEmpty
)
13404 result
= IntegerExp
.createBool(exp
.op
!= EXP
.equal
);
13407 // AliasSeq!() == AliasSeq!()
13408 else if (tups1
.ttEmpty
&& tups2
.ttEmpty
)
13410 result
= IntegerExp
.createBool(exp
.op
== EXP
.equal
);
13413 // otherwise, two types are really not comparable
13414 result
= exp
.incompatibleTypes();
13419 auto t1
= exp
.e1
.type
;
13420 auto t2
= exp
.e2
.type
;
13421 if (t1
.ty
== Tenum
&& t2
.ty
== Tenum
&& !t1
.equivalent(t2
))
13422 error(exp
.loc
, "comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`",
13423 t1
.toChars(), t2
.toChars());
13426 /* Before checking for operator overloading, check to see if we're
13427 * comparing the addresses of two statics. If so, we can just see
13428 * if they are the same symbol.
13430 if (exp
.e1
.op
== EXP
.address
&& exp
.e2
.op
== EXP
.address
)
13432 AddrExp ae1
= cast(AddrExp
)exp
.e1
;
13433 AddrExp ae2
= cast(AddrExp
)exp
.e2
;
13434 if (ae1
.e1
.op
== EXP
.variable
&& ae2
.e1
.op
== EXP
.variable
)
13436 VarExp ve1
= cast(VarExp
)ae1
.e1
;
13437 VarExp ve2
= cast(VarExp
)ae2
.e1
;
13438 if (ve1
.var
== ve2
.var
)
13440 // They are the same, result is 'true' for ==, 'false' for !=
13441 result
= IntegerExp
.createBool(exp
.op
== EXP
.equal
);
13447 Type t1
= exp
.e1
.type
.toBasetype();
13448 Type t2
= exp
.e2
.type
.toBasetype();
13450 // Indicates whether the comparison of the 2 specified array types
13451 // requires an object.__equals() lowering.
13452 static bool needsDirectEq(Type t1
, Type t2
, Scope
* sc
)
13454 Type t1n
= t1
.nextOf().toBasetype();
13455 Type t2n
= t2
.nextOf().toBasetype();
13456 if ((t1n
.ty
.isSomeChar
&& t2n
.ty
.isSomeChar
) ||
13457 (t1n
.ty
== Tvoid || t2n
.ty
== Tvoid
))
13461 if (t1n
.constOf() != t2n
.constOf())
13465 while (t
.toBasetype().nextOf())
13466 t
= t
.nextOf().toBasetype();
13467 if (auto ts
= t
.isTypeStruct())
13469 // semanticTypeInfo() makes sure hasIdentityEquals has been computed
13470 if (global
.params
.useTypeInfo
&& Type
.dtypeinfo
)
13471 semanticTypeInfo(sc
, ts
);
13473 return ts
.sym
.hasIdentityEquals
; // has custom opEquals
13479 if (auto e
= exp
.op_overload(sc
))
13486 const isArrayComparison
= (t1
.ty
== Tarray || t1
.ty
== Tsarray
) &&
13487 (t2
.ty
== Tarray || t2
.ty
== Tsarray
);
13488 const needsArrayLowering
= isArrayComparison
&& needsDirectEq(t1
, t2
, sc
);
13490 if (!needsArrayLowering
)
13492 // https://issues.dlang.org/show_bug.cgi?id=23783
13493 if (exp
.e1
.checkSharedAccess(sc
) || exp
.e2
.checkSharedAccess(sc
))
13495 if (auto e
= typeCombine(exp
, sc
))
13502 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
13503 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
13507 exp
.type
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? Type
.tint32
: Type
.tbool
;
13509 if (!isArrayComparison
)
13511 if (exp
.e1
.type
!= exp
.e2
.type
&& exp
.e1
.type
.isfloating() && exp
.e2
.type
.isfloating())
13513 // Cast both to complex
13514 exp
.e1
= exp
.e1
.castTo(sc
, Type
.tcomplex80
);
13515 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tcomplex80
);
13519 // lower some array comparisons to object.__equals(e1, e2)
13520 if (needsArrayLowering ||
(t1
.ty
== Tarray
&& t2
.ty
== Tarray
))
13522 //printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars());
13524 // https://issues.dlang.org/show_bug.cgi?id=22390
13525 // Equality comparison between array of noreturns simply lowers to length equality comparison
13526 if (t1
.nextOf
.isTypeNoreturn() && t2
.nextOf
.isTypeNoreturn())
13528 Expression exp_l1
= new DotIdExp(exp
.e1
.loc
, exp
.e1
, Id
.length
);
13529 Expression exp_l2
= new DotIdExp(exp
.e2
.loc
, exp
.e2
, Id
.length
);
13530 auto e
= new EqualExp(EXP
.equal
, exp
.loc
, exp_l1
, exp_l2
);
13531 result
= e
.expressionSemantic(sc
);
13535 if (!verifyHookExist(exp
.loc
, *sc
, Id
.__equals
, "equal checks on arrays"))
13538 Expression __equals
= new IdentifierExp(exp
.loc
, Id
.empty
);
13539 Identifier id
= Identifier
.idPool("__equals");
13540 __equals
= new DotIdExp(exp
.loc
, __equals
, Id
.object
);
13541 __equals
= new DotIdExp(exp
.loc
, __equals
, id
);
13543 /* https://issues.dlang.org/show_bug.cgi?id=23674
13545 * Optimize before creating the call expression to the
13546 * druntime hook as the optimizer may output errors
13547 * that will get swallowed otherwise.
13549 exp
.e1
= exp
.e1
.optimize(WANTvalue
);
13550 exp
.e2
= exp
.e2
.optimize(WANTvalue
);
13552 auto arguments
= new Expressions(2);
13553 (*arguments
)[0] = exp
.e1
;
13554 (*arguments
)[1] = exp
.e2
;
13556 __equals
= new CallExp(exp
.loc
, __equals
, arguments
);
13557 if (exp
.op
== EXP
.notEqual
)
13559 __equals
= new NotExp(exp
.loc
, __equals
);
13561 __equals
= __equals
.trySemantic(sc
); // for better error message
13564 error(exp
.loc
, "incompatible types for array comparison: `%s` and `%s`",
13565 exp
.e1
.type
.toChars(), exp
.e2
.type
.toChars());
13566 __equals
= ErrorExp
.get();
13573 if (exp
.e1
.type
.toBasetype().ty
== Taarray
)
13574 semanticTypeInfo(sc
, exp
.e1
.type
.toBasetype());
13577 if (!target
.isVectorOpSupported(t1
, exp
.op
, t2
))
13579 result
= exp
.incompatibleTypes();
13583 if (auto tv
= t1
.isTypeVector())
13584 exp
.type
= tv
.toBooleanVector();
13589 override void visit(IdentityExp exp
)
13597 exp
.setNoderefOperands();
13599 if (auto e
= binSemanticProp(exp
, sc
))
13605 if (auto e
= typeCombine(exp
, sc
))
13611 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
13612 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
13616 if (exp
.e1
.op
== EXP
.type || exp
.e2
.op
== EXP
.type
)
13618 result
= exp
.incompatibleTypes();
13622 exp
.type
= Type
.tbool
;
13624 if (exp
.e1
.type
!= exp
.e2
.type
&& exp
.e1
.type
.isfloating() && exp
.e2
.type
.isfloating())
13626 // Cast both to complex
13627 exp
.e1
= exp
.e1
.castTo(sc
, Type
.tcomplex80
);
13628 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tcomplex80
);
13631 auto tb1
= exp
.e1
.type
.toBasetype();
13632 auto tb2
= exp
.e2
.type
.toBasetype();
13633 if (!target
.isVectorOpSupported(tb1
, exp
.op
, tb2
))
13635 result
= exp
.incompatibleTypes();
13639 if (exp
.e1
.op
== EXP
.call)
13640 exp
.e1
= (cast(CallExp
)exp
.e1
).addDtorHook(sc
);
13641 if (exp
.e2
.op
== EXP
.call)
13642 exp
.e2
= (cast(CallExp
)exp
.e2
).addDtorHook(sc
);
13644 if (exp
.e1
.type
.toBasetype().ty
== Tsarray ||
13645 exp
.e2
.type
.toBasetype().ty
== Tsarray
)
13646 deprecation(exp
.loc
, "identity comparison of static arrays "
13647 ~ "implicitly coerces them to slices, "
13648 ~ "which are compared by reference");
13653 override void visit(CondExp exp
)
13655 static if (LOGSEMANTIC
)
13657 printf("CondExp::semantic('%s')\n", exp
.toChars());
13665 if (auto die
= exp
.econd
.isDotIdExp())
13666 die
.noderef
= true;
13668 Expression ec
= exp
.econd
.expressionSemantic(sc
);
13669 ec
= resolveProperties(sc
, ec
);
13670 ec
= ec
.toBoolean(sc
);
13672 CtorFlow ctorflow_root
= sc
.ctorflow
.clone();
13673 Expression e1x
= exp
.e1
.expressionSemantic(sc
).arrayFuncConv(sc
);
13674 e1x
= resolveProperties(sc
, e1x
);
13676 CtorFlow ctorflow1
= sc
.ctorflow
;
13677 sc
.ctorflow
= ctorflow_root
;
13678 Expression e2x
= exp
.e2
.expressionSemantic(sc
).arrayFuncConv(sc
);
13679 e2x
= resolveProperties(sc
, e2x
);
13681 sc
.merge(exp
.loc
, ctorflow1
);
13682 ctorflow1
.freeFieldinit();
13684 if (ec
.op
== EXP
.error
)
13689 if (ec
.type
== Type
.terror
)
13693 if (e1x
.op
== EXP
.error
)
13698 if (e1x
.type
== Type
.terror
)
13702 if (e2x
.op
== EXP
.error
)
13707 if (e2x
.type
== Type
.terror
)
13711 auto f0
= checkNonAssignmentArrayOp(exp
.econd
);
13712 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
13713 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
13714 if (f0 || f1 || f2
)
13717 Type t1
= exp
.e1
.type
;
13718 Type t2
= exp
.e2
.type
;
13720 // https://issues.dlang.org/show_bug.cgi?id=23767
13721 // `cast(void*) 0` should be treated as `null` so the ternary expression
13722 // gets the pointer type of the other branch
13723 if (sc
.flags
& SCOPE
.Cfile
)
13725 static void rewriteCNull(ref Expression e
, ref Type t
)
13727 if (!t
.isTypePointer())
13729 if (auto ie
= e
.optimize(WANTvalue
).isIntegerExp())
13731 if (ie
.getInteger() == 0)
13733 e
= new NullExp(e
.loc
, Type
.tnull
);
13738 rewriteCNull(exp
.e1
, t1
);
13739 rewriteCNull(exp
.e2
, t2
);
13742 if (t1
.ty
== Tnoreturn
)
13745 exp
.e1
= specialNoreturnCast(exp
.e1
, exp
.type
);
13747 else if (t2
.ty
== Tnoreturn
)
13750 exp
.e2
= specialNoreturnCast(exp
.e2
, exp
.type
);
13752 // If either operand is void the result is void, we have to cast both
13753 // the expression to void so that we explicitly discard the expression
13755 // https://issues.dlang.org/show_bug.cgi?id=16598
13756 else if (t1
.ty
== Tvoid || t2
.ty
== Tvoid
)
13758 exp
.type
= Type
.tvoid
;
13759 exp
.e1
= exp
.e1
.castTo(sc
, exp
.type
);
13760 exp
.e2
= exp
.e2
.castTo(sc
, exp
.type
);
13766 if (Expression ex
= typeCombine(exp
, sc
))
13772 switch (exp
.e1
.type
.toBasetype().ty
)
13777 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
);
13782 switch (exp
.e2
.type
.toBasetype().ty
)
13787 exp
.e1
= exp
.e1
.castTo(sc
, exp
.e2
.type
);
13792 if (exp
.type
.toBasetype().ty
== Tarray
)
13794 exp
.e1
= exp
.e1
.castTo(sc
, exp
.type
);
13795 exp
.e2
= exp
.e2
.castTo(sc
, exp
.type
);
13798 exp
.type
= exp
.type
.merge2();
13801 printf("res: %s\n", exp
.type
.toChars());
13802 printf("e1 : %s\n", exp
.e1
.type
.toChars());
13803 printf("e2 : %s\n", exp
.e2
.type
.toChars());
13806 /* https://issues.dlang.org/show_bug.cgi?id=14696
13807 * If either e1 or e2 contain temporaries which need dtor,
13808 * make them conditional.
13810 * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2)
13812 * (auto __cond = cond) ? (... __tmp1) : (... __tmp2)
13813 * and replace edtors of __tmp1 and __tmp2 with:
13814 * __tmp1.edtor --> __cond && __tmp1.dtor()
13815 * __tmp2.edtor --> __cond || __tmp2.dtor()
13822 override void visit(GenericExp exp
)
13824 static if (LOGSEMANTIC
)
13826 printf("GenericExp::semantic('%s')\n", exp
.toChars());
13828 // C11 6.5.1.1 Generic Selection
13830 auto ec
= exp
.cntlExp
.expressionSemantic(sc
).arrayFuncConv(sc
);
13831 bool errors
= ec
.isErrorExp() !is null;
13834 auto types
= (*exp
.types
)[];
13835 foreach (i
, ref t
; types
)
13838 continue; // `default:` case
13839 t
= t
.typeSemantic(ec
.loc
, sc
);
13840 if (t
.isTypeError())
13846 /* C11 6.5.1-2 duplicate check
13848 /* C11 distinguishes int, long, and long long. But D doesn't, so depending on the
13849 * C target, a long may have the same type as `int` in the D type system.
13850 * So, skip checks when this may be the case. Later pick the first match
13853 (t
.ty
== Tint32 || t
.ty
== Tuns32
) && target
.c
.longsize
== 4 ||
13854 (t
.ty
== Tint64 || t
.ty
== Tuns64
) && target
.c
.longsize
== 8 ||
13855 (t
.ty
== Tfloat64 || t
.ty
== Timaginary64 || t
.ty
== Tcomplex64
) && target
.c
.long_doublesize
== 8
13859 foreach (t2
; types
[0 .. i
])
13861 if (t2
&& t2
.equals(t
))
13863 error(ec
.loc
, "generic association type `%s` can only appear once", t
.toChars());
13870 auto exps
= (*exp
.exps
)[];
13871 foreach (ref e
; exps
)
13873 e
= e
.expressionSemantic(sc
);
13874 if (e
.isErrorExp())
13881 enum size_t None
= ~0;
13882 size_t imatch
= None
;
13883 size_t idefault
= None
;
13884 foreach (const i
, t
; types
)
13888 /* if tc is compatible with t, it's a match
13889 * C11 6.2.7 defines a compatible type as being the same type, including qualifiers
13893 assert(imatch
== None
);
13895 break; // pick first match
13899 idefault
= i
; // multiple defaults are not allowed, and are caught by cparse
13902 if (imatch
== None
)
13904 if (imatch
== None
)
13906 error(exp
.loc
, "no compatible generic association type for controlling expression type `%s`", tc
.toChars());
13910 result
= exps
[imatch
];
13913 override void visit(FileInitExp e
)
13915 //printf("FileInitExp::semantic()\n");
13916 e
.type
= Type
.tstring
;
13920 override void visit(LineInitExp e
)
13922 e
.type
= Type
.tint32
;
13926 override void visit(ModuleInitExp e
)
13928 //printf("ModuleInitExp::semantic()\n");
13929 e
.type
= Type
.tstring
;
13933 override void visit(FuncInitExp e
)
13935 //printf("FuncInitExp::semantic()\n");
13936 e
.type
= Type
.tstring
;
13939 result
= e
.resolveLoc(Loc
.initial
, sc
);
13945 override void visit(PrettyFuncInitExp e
)
13947 //printf("PrettyFuncInitExp::semantic()\n");
13948 e
.type
= Type
.tstring
;
13951 result
= e
.resolveLoc(Loc
.initial
, sc
);
13959 /**********************************
13960 * Try to run semantic routines.
13961 * If they fail, return NULL.
13963 Expression
trySemantic(Expression exp
, Scope
* sc
)
13965 //printf("+trySemantic(%s)\n", exp.toChars());
13966 uint errors
= global
.startGagging();
13967 Expression e
= expressionSemantic(exp
, sc
);
13968 if (global
.endGagging(errors
))
13972 //printf("-trySemantic(%s)\n", exp.toChars());
13976 /**************************
13977 * Helper function for easy error propagation.
13978 * If error occurs, returns ErrorExp. Otherwise returns NULL.
13980 Expression
unaSemantic(UnaExp e
, Scope
* sc
)
13982 static if (LOGSEMANTIC
)
13984 printf("UnaExp::semantic('%s')\n", e
.toChars());
13986 Expression e1x
= e
.e1
.expressionSemantic(sc
);
13987 if (e1x
.op
== EXP
.error
)
13993 /**************************
13994 * Helper function for easy error propagation.
13995 * If error occurs, returns ErrorExp. Otherwise returns NULL.
13997 Expression
binSemantic(BinExp e
, Scope
* sc
)
13999 static if (LOGSEMANTIC
)
14001 printf("BinExp::semantic('%s')\n", e
.toChars());
14003 Expression e1x
= e
.e1
.expressionSemantic(sc
);
14004 Expression e2x
= e
.e2
.expressionSemantic(sc
);
14006 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
14007 if (e1x
.op
== EXP
.type
)
14008 e1x
= resolveAliasThis(sc
, e1x
);
14009 if (e2x
.op
== EXP
.type
)
14010 e2x
= resolveAliasThis(sc
, e2x
);
14012 if (e1x
.op
== EXP
.error
)
14014 if (e2x
.op
== EXP
.error
)
14021 Expression
binSemanticProp(BinExp e
, Scope
* sc
)
14023 if (Expression ex
= binSemantic(e
, sc
))
14025 Expression e1x
= resolveProperties(sc
, e
.e1
);
14026 Expression e2x
= resolveProperties(sc
, e
.e2
);
14027 if (e1x
.op
== EXP
.error
)
14029 if (e2x
.op
== EXP
.error
)
14036 // entrypoint for semantic ExpressionSemanticVisitor
14037 extern (C
++) Expression
expressionSemantic(Expression e
, Scope
* sc
)
14039 scope v
= new ExpressionSemanticVisitor(sc
);
14044 private Expression
dotIdSemanticPropX(DotIdExp exp
, Scope
* sc
)
14046 //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars());
14047 if (Expression ex
= unaSemantic(exp
, sc
))
14050 if (!(sc
.flags
& SCOPE
.Cfile
) && exp
.ident
== Id
._mangleof
)
14054 // return mangleof as an Expression
14055 static Expression
dotMangleof(const ref Loc loc
, Scope
* sc
, Dsymbol
ds)
14058 if (auto f
= ds.isFuncDeclaration())
14060 if (f
.checkForwardRef(loc
))
14061 return ErrorExp
.get();
14063 if (f
.purityInprocess || f
.safetyInprocess || f
.nothrowInprocess || f
.nogcInprocess
)
14065 error(loc
, "%s `%s` cannot retrieve its `.mangleof` while inferring attributes", f
.kind
, f
.toPrettyChars
);
14066 return ErrorExp
.get();
14070 mangleToBuffer(ds, buf
);
14071 Expression e
= new StringExp(loc
, buf
.extractSlice());
14072 return e
.expressionSemantic(sc
);
14078 case EXP
.scope_
: return dotMangleof(exp
.loc
, sc
, exp
.e1
.isScopeExp().sds
);
14079 case EXP
.variable
: return dotMangleof(exp
.loc
, sc
, exp
.e1
.isVarExp().var
);
14080 case EXP
.dotVariable
: return dotMangleof(exp
.loc
, sc
, exp
.e1
.isDotVarExp().var
);
14081 case EXP
.overloadSet
: return dotMangleof(exp
.loc
, sc
, exp
.e1
.isOverExp().vars
);
14082 case EXP
.template_
:
14084 TemplateExp te
= exp
.e1
.isTemplateExp();
14085 return dotMangleof(exp
.loc
, sc
, ds = te
.fd ? te
.fd
.isDsymbol() : te
.td
);
14093 if (exp
.e1
.isVarExp() && exp
.e1
.type
.toBasetype().isTypeSArray() && exp
.ident
== Id
.length
)
14095 // bypass checkPurity
14096 return exp
.e1
.type
.dotExp(sc
, exp
.e1
, exp
.ident
, cast(DotExpFlag
) (exp
.noderef
* DotExpFlag
.noDeref
));
14099 if (!exp
.e1
.isDotExp())
14101 exp
.e1
= resolvePropertiesX(sc
, exp
.e1
);
14104 if (auto te
= exp
.e1
.isTupleExp())
14106 if (exp
.ident
== Id
.offsetof
)
14108 /* 'distribute' the .offsetof to each of the tuple elements.
14110 auto exps
= new Expressions(te
.exps
.length
);
14111 foreach (i
, e
; (*te
.exps
)[])
14113 (*exps
)[i
] = new DotIdExp(e
.loc
, e
, Id
.offsetof
);
14115 // Don't evaluate te.e0 in runtime
14116 Expression e
= new TupleExp(exp
.loc
, null, exps
);
14117 e
= e
.expressionSemantic(sc
);
14120 if (exp
.ident
== Id
.length
)
14122 // Don't evaluate te.e0 in runtime
14123 return new IntegerExp(exp
.loc
, te
.exps
.length
, Type
.tsize_t
);
14127 // https://issues.dlang.org/show_bug.cgi?id=14416
14128 // Template has no built-in properties except for 'stringof'.
14129 if ((exp
.e1
.isDotTemplateExp() || exp
.e1
.isTemplateExp()) && exp
.ident
!= Id
.stringof
)
14131 error(exp
.loc
, "template `%s` does not have property `%s`", exp
.e1
.toChars(), exp
.ident
.toChars());
14132 return ErrorExp
.get();
14136 error(exp
.loc
, "expression `%s` does not have property `%s`", exp
.e1
.toChars(), exp
.ident
.toChars());
14137 return ErrorExp
.get();
14143 private bool checkDisabled(Dsymbol s
, ref Loc loc
, Scope
* sc
)
14145 if (auto d
= s
.isDeclaration())
14146 return d
.checkDisabled(loc
, sc
);
14151 /******************************
14152 * Resolve properties, i.e. `e1.ident`, without seeing UFCS.
14154 * exp = expression to resolve
14156 * gag = do not emit error messages, just return `null`
14158 * resolved expression, null if error
14160 Expression
dotIdSemanticProp(DotIdExp exp
, Scope
* sc
, bool gag
)
14162 //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars());
14164 //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
14166 const cfile
= (sc
.flags
& SCOPE
.Cfile
) != 0;
14168 /* Special case: rewrite this.id and super.id
14169 * to be classtype.id and baseclasstype.id
14170 * if we have no this pointer.
14172 if ((exp
.e1
.isThisExp() || exp
.e1
.isSuperExp()) && !hasThis(sc
))
14174 if (AggregateDeclaration ad
= sc
.getStructClassScope())
14176 if (exp
.e1
.isThisExp())
14178 exp
.e1
= new TypeExp(exp
.e1
.loc
, ad
.type
);
14182 if (auto cd
= ad
.isClassDeclaration())
14185 exp
.e1
= new TypeExp(exp
.e1
.loc
, cd
.baseClass
.type
);
14192 Expression e
= dotIdSemanticPropX(exp
, sc
);
14199 if (auto de = exp
.e1
.isDotExp())
14210 Type t1b
= exp
.e1
.type
.toBasetype();
14212 if (auto ie
= eright
.isScopeExp()) // also used for template alias's
14214 SearchOptFlags flags
= SearchOpt
.localsOnly
;
14215 /* Disable access to another module's private imports.
14216 * The check for 'is sds our current module' is because
14217 * the current module should have access to its own imports.
14219 if (ie
.sds
.isModule() && ie
.sds
!= sc
._module
)
14220 flags |
= SearchOpt
.ignorePrivateImports
;
14221 if (sc
.flags
& SCOPE
.ignoresymbolvisibility
)
14222 flags |
= SearchOpt
.ignoreVisibility
;
14223 Dsymbol s
= ie
.sds
.search(exp
.loc
, exp
.ident
, flags
);
14224 /* Check for visibility before resolving aliases because public
14225 * aliases to private symbols are public.
14227 if (s
&& !(sc
.flags
& SCOPE
.ignoresymbolvisibility
) && !symbolIsVisible(sc
._module
, s
))
14233 auto p
= s
.isPackage();
14234 if (p
&& checkAccess(sc
, p
))
14241 // if 's' is a tuple variable, the tuple is returned.
14244 s
.checkDeprecated(exp
.loc
, sc
);
14245 s
.checkDisabled(exp
.loc
, sc
);
14247 if (auto em
= s
.isEnumMember())
14249 return em
.getVarExp(exp
.loc
, sc
);
14251 if (auto v
= s
.isVarDeclaration())
14253 //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars());
14255 !v
.type
.deco
&& v
.inuse
)
14258 error(exp
.loc
, "circular reference to %s `%s`", v
.kind(), v
.toPrettyChars());
14260 error(exp
.loc
, "forward reference to %s `%s`", v
.kind(), v
.toPrettyChars());
14261 return ErrorExp
.get();
14263 if (v
.type
.isTypeError())
14264 return ErrorExp
.get();
14266 if ((v
.storage_class
& STC
.manifest
) && v
._init
&& !exp
.wantsym
)
14268 /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2().
14269 * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably
14270 * be reverted. `wantsym` is the hack to work around the problem.
14274 error(exp
.loc
, "circular initialization of %s `%s`", v
.kind(), v
.toPrettyChars());
14275 return ErrorExp
.get();
14277 auto e
= v
.expandInitializer(exp
.loc
);
14279 e
= e
.expressionSemantic(sc
);
14288 eleft
= new ThisExp(exp
.loc
);
14289 e
= new DotVarExp(exp
.loc
, eleft
, v
);
14290 e
= e
.expressionSemantic(sc
);
14294 e
= new VarExp(exp
.loc
, v
);
14297 e
= new CommaExp(exp
.loc
, eleft
, e
);
14302 return e
.expressionSemantic(sc
);
14305 if (auto f
= s
.isFuncDeclaration())
14307 //printf("it's a function\n");
14308 if (!f
.functionSemantic())
14309 return ErrorExp
.get();
14314 eleft
= new ThisExp(exp
.loc
);
14315 e
= new DotVarExp(exp
.loc
, eleft
, f
, true);
14316 e
= e
.expressionSemantic(sc
);
14320 e
= new VarExp(exp
.loc
, f
, true);
14323 e
= new CommaExp(exp
.loc
, eleft
, e
);
14329 if (auto td
= s
.isTemplateDeclaration())
14333 e
= new DotTemplateExp(exp
.loc
, eleft
, td
);
14335 e
= new TemplateExp(exp
.loc
, td
);
14336 e
= e
.expressionSemantic(sc
);
14339 if (OverDeclaration od
= s
.isOverDeclaration())
14341 Expression e
= new VarExp(exp
.loc
, od
, true);
14344 e
= new CommaExp(exp
.loc
, eleft
, e
);
14345 e
.type
= Type
.tvoid
; // ambiguous type?
14347 return e
.expressionSemantic(sc
);
14349 if (auto o
= s
.isOverloadSet())
14351 //printf("'%s' is an overload set\n", o.toChars());
14352 return new OverExp(exp
.loc
, o
);
14355 if (auto t
= s
.getType())
14357 return (new TypeExp(exp
.loc
, t
)).expressionSemantic(sc
);
14360 if (auto tup
= s
.isTupleDeclaration())
14364 Expression e
= new DotVarExp(exp
.loc
, eleft
, tup
);
14365 e
= e
.expressionSemantic(sc
);
14368 Expression e
= new TupleExp(exp
.loc
, tup
);
14369 e
= e
.expressionSemantic(sc
);
14373 if (auto sds
= s
.isScopeDsymbol())
14375 //printf("it's a ScopeDsymbol %s\n", ident.toChars());
14376 Expression e
= new ScopeExp(exp
.loc
, sds
);
14377 e
= e
.expressionSemantic(sc
);
14379 e
= new DotExp(exp
.loc
, eleft
, e
);
14383 if (auto imp
= s
.isImport())
14385 Expression se
= new ScopeExp(exp
.loc
, imp
.pkg
);
14386 return se
.expressionSemantic(sc
);
14389 if (auto attr
= s
.isAttribDeclaration())
14391 if (auto sm
= ie
.sds
.search(exp
.loc
, exp
.ident
, flags
))
14393 auto es
= new DsymbolExp(exp
.loc
, sm
);
14398 // BUG: handle other cases like in IdentifierExp::semantic()
14401 printf("s = %p '%s', kind = '%s'\n", s
, s
.toChars(), s
.kind());
14405 else if (exp
.ident
== Id
.stringof
)
14407 Expression e
= new StringExp(exp
.loc
, ie
.toString());
14408 e
= e
.expressionSemantic(sc
);
14411 if (ie
.sds
.isPackage() || ie
.sds
.isImport() || ie
.sds
.isModule())
14417 s
= ie
.sds
.search_correct(exp
.ident
);
14418 if (s
&& symbolIsVisible(sc
, s
))
14421 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());
14423 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());
14426 error(exp
.loc
, "undefined identifier `%s` in %s `%s`", exp
.ident
.toChars(), ie
.sds
.kind(), ie
.sds
.toPrettyChars());
14427 return ErrorExp
.get();
14429 else if (t1b
.ty
== Tpointer
&& exp
.e1
.type
.ty
!= Tenum
&&
14431 exp
.ident
== Id
.__sizeof ||
14432 exp
.ident
== Id
.__xalignof ||
14434 (exp
.ident
== Id
._mangleof ||
14435 exp
.ident
== Id
.offsetof ||
14436 exp
.ident
== Id
._init ||
14437 exp
.ident
== Id
.stringof
)
14440 Type t1bn
= t1b
.nextOf();
14443 if (AggregateDeclaration ad
= isAggregate(t1bn
))
14445 if (!ad
.members
) // https://issues.dlang.org/show_bug.cgi?id=11312
14455 if (gag
&& t1bn
.ty
== Tvoid
)
14457 Expression e
= new PtrExp(exp
.loc
, exp
.e1
);
14458 e
= e
.expressionSemantic(sc
);
14459 const newFlag
= cast(DotExpFlag
) (gag
* DotExpFlag
.gag | exp
.noderef
* DotExpFlag
.noDeref
);
14460 return e
.type
.dotExp(sc
, e
, exp
.ident
, newFlag
);
14462 else if (exp
.ident
== Id
.__xalignof
&&
14463 exp
.e1
.isVarExp() &&
14464 exp
.e1
.isVarExp().var
.isVarDeclaration() &&
14465 !exp
.e1
.isVarExp().var
.isVarDeclaration().alignment
.isUnknown())
14467 // For `x.alignof` get the alignment of the variable, not the alignment of its type
14468 const explicitAlignment
= exp
.e1
.isVarExp().var
.isVarDeclaration().alignment
;
14469 const naturalAlignment
= exp
.e1
.type
.alignsize();
14470 const actualAlignment
= explicitAlignment
.isDefault() ? naturalAlignment
: explicitAlignment
.get();
14471 Expression e
= new IntegerExp(exp
.loc
, actualAlignment
, Type
.tsize_t
);
14474 else if ((exp
.ident
== Id
.max || exp
.ident
== Id
.min
) &&
14475 exp
.e1
.isVarExp() &&
14476 exp
.e1
.isVarExp().var
.isBitFieldDeclaration())
14478 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
14479 auto bf
= exp
.e1
.isVarExp().var
.isBitFieldDeclaration();
14480 return new IntegerExp(exp
.loc
, bf
.getMinMax(exp
.ident
), bf
.type
);
14482 else if ((exp
.ident
== Id
.max || exp
.ident
== Id
.min
) &&
14483 exp
.e1
.isDotVarExp() &&
14484 exp
.e1
.isDotVarExp().var
.isBitFieldDeclaration())
14486 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
14487 auto bf
= exp
.e1
.isDotVarExp().var
.isBitFieldDeclaration();
14488 return new IntegerExp(exp
.loc
, bf
.getMinMax(exp
.ident
), bf
.type
);
14492 if (exp
.e1
.isTypeExp() || exp
.e1
.isTemplateExp())
14495 const flag
= cast(DotExpFlag
) (exp
.noderef
* DotExpFlag
.noDeref | gag
* DotExpFlag
.gag
);
14497 Expression e
= exp
.e1
.type
.dotExp(sc
, exp
.e1
, exp
.ident
, flag
);
14500 e
= e
.expressionSemantic(sc
);
14507 * Resolve `e1.ident!tiargs` without seeing UFCS.
14509 * exp = the `DotTemplateInstanceExp` to resolve
14510 * sc = the semantic scope
14511 * gag = stop "not a property" error and return `null`.
14513 * `null` if error or not found, or the resolved expression.
14515 Expression
dotTemplateSemanticProp(DotTemplateInstanceExp exp
, Scope
* sc
, bool gag
)
14517 static if (LOGSEMANTIC
)
14519 printf("DotTemplateInstanceExpY::semantic('%s')\n", exp
.toChars());
14522 static Expression
errorExp()
14524 return ErrorExp
.get();
14527 Expression e1
= exp
.e1
;
14529 if (exp
.ti
.tempdecl
&& exp
.ti
.tempdecl
.parent
&& exp
.ti
.tempdecl
.parent
.isTemplateMixin())
14531 // if 'ti.tempdecl' happens to be found in a mixin template don't lose that info
14532 // and do the symbol search in that context (Issue: 19476)
14533 auto tm
= cast(TemplateMixin
)exp
.ti
.tempdecl
.parent
;
14534 e1
= new DotExp(exp
.e1
.loc
, exp
.e1
, new ScopeExp(tm
.loc
, tm
));
14537 auto die
= new DotIdExp(exp
.loc
, e1
, exp
.ti
.name
);
14539 Expression e
= die
.dotIdSemanticPropX(sc
);
14542 exp
.e1
= die
.e1
; // take back
14543 Type t1b
= exp
.e1
.type
.toBasetype();
14544 if (t1b
.ty
== Tarray || t1b
.ty
== Tsarray || t1b
.ty
== Taarray || t1b
.ty
== Tnull ||
(t1b
.isTypeBasic() && t1b
.ty
!= Tvoid
))
14546 /* No built-in type has templatized properties, so do shortcut.
14547 * It is necessary in: 1024.max!"a < b"
14552 e
= die
.dotIdSemanticProp(sc
, gag
);
14556 isDotOpDispatch(e
))
14558 /* opDispatch!tiargs would be a function template that needs IFTI,
14559 * so it's not a template
14567 if (e
.op
== EXP
.error
)
14569 if (DotVarExp dve
= e
.isDotVarExp())
14571 if (FuncDeclaration fd
= dve
.var
.isFuncDeclaration())
14573 if (TemplateDeclaration td
= fd
.findTemplateDeclRoot())
14575 e
= new DotTemplateExp(dve
.loc
, dve
.e1
, td
);
14576 e
= e
.expressionSemantic(sc
);
14579 else if (OverDeclaration od
= dve
.var
.isOverDeclaration())
14581 exp
.e1
= dve
.e1
; // pull semantic() result
14583 if (!exp
.findTempDecl(sc
))
14585 if (exp
.ti
.needsTypeInference(sc
))
14587 exp
.ti
.dsymbolSemantic(sc
);
14588 if (!exp
.ti
.inst || exp
.ti
.errors
) // if template failed to expand
14591 if (Declaration v
= exp
.ti
.toAlias().isDeclaration())
14593 if (v
.type
&& !v
.type
.deco
)
14594 v
.type
= v
.type
.typeSemantic(v
.loc
, sc
);
14595 return new DotVarExp(exp
.loc
, exp
.e1
, v
)
14596 .expressionSemantic(sc
);
14598 return new DotExp(exp
.loc
, exp
.e1
, new ScopeExp(exp
.loc
, exp
.ti
))
14599 .expressionSemantic(sc
);
14602 else if (e
.op
== EXP
.variable
)
14604 VarExp ve
= cast(VarExp
)e
;
14605 if (FuncDeclaration fd
= ve
.var
.isFuncDeclaration())
14607 if (TemplateDeclaration td
= fd
.findTemplateDeclRoot())
14609 e
= new TemplateExp(ve
.loc
, td
)
14610 .expressionSemantic(sc
);
14613 else if (OverDeclaration od
= ve
.var
.isOverDeclaration())
14615 exp
.ti
.tempdecl
= od
;
14616 return new ScopeExp(exp
.loc
, exp
.ti
)
14617 .expressionSemantic(sc
);
14621 if (DotTemplateExp dte
= e
.isDotTemplateExp())
14623 exp
.e1
= dte
.e1
; // pull semantic() result
14625 exp
.ti
.tempdecl
= dte
.td
;
14626 if (!exp
.ti
.semanticTiargs(sc
))
14628 if (exp
.ti
.needsTypeInference(sc
))
14630 exp
.ti
.dsymbolSemantic(sc
);
14631 if (!exp
.ti
.inst || exp
.ti
.errors
) // if template failed to expand
14634 if (Declaration v
= exp
.ti
.toAlias().isDeclaration())
14636 return new DotVarExp(exp
.loc
, exp
.e1
, v
)
14637 .expressionSemantic(sc
);
14639 return new DotExp(exp
.loc
, exp
.e1
, new ScopeExp(exp
.loc
, exp
.ti
))
14640 .expressionSemantic(sc
);
14642 else if (e
.op
== EXP
.template_
)
14644 exp
.ti
.tempdecl
= (cast(TemplateExp
)e
).td
;
14645 return new ScopeExp(exp
.loc
, exp
.ti
)
14646 .expressionSemantic(sc
);
14648 else if (DotExp
de = e
.isDotExp())
14650 if (de.e2
.op
== EXP
.overloadSet
)
14652 if (!exp
.findTempDecl(sc
) ||
!exp
.ti
.semanticTiargs(sc
))
14656 if (exp
.ti
.needsTypeInference(sc
))
14658 exp
.ti
.dsymbolSemantic(sc
);
14659 if (!exp
.ti
.inst || exp
.ti
.errors
) // if template failed to expand
14662 if (Declaration v
= exp
.ti
.toAlias().isDeclaration())
14664 if (v
.type
&& !v
.type
.deco
)
14665 v
.type
= v
.type
.typeSemantic(v
.loc
, sc
);
14666 return new DotVarExp(exp
.loc
, exp
.e1
, v
)
14667 .expressionSemantic(sc
);
14669 return new DotExp(exp
.loc
, exp
.e1
, new ScopeExp(exp
.loc
, exp
.ti
))
14670 .expressionSemantic(sc
);
14673 else if (OverExp oe
= e
.isOverExp())
14675 exp
.ti
.tempdecl
= oe
.vars
;
14676 return new ScopeExp(exp
.loc
, exp
.ti
)
14677 .expressionSemantic(sc
);
14681 error(exp
.loc
, "`%s` isn't a template", e
.toChars());
14685 MATCH
matchType(FuncExp funcExp
, Type to
, Scope
* sc
, FuncExp
* presult
, ErrorSink eSink
)
14687 auto loc
= funcExp
.loc
;
14688 auto tok
= funcExp
.tok
;
14689 auto td
= funcExp
.td
;
14690 auto fd
= funcExp
.fd
;
14691 auto type
= funcExp
.type
;
14693 MATCH
cannotInfer()
14695 eSink
.error(loc
, "cannot infer parameter types from `%s`", to
.toChars());
14696 return MATCH
.nomatch
;
14699 //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars());
14703 TypeFunction tof
= null;
14704 if (to
.ty
== Tdelegate
)
14706 if (tok
== TOK
.function_
)
14708 eSink
.error(loc
, "cannot match function literal to delegate type `%s`", to
.toChars());
14709 return MATCH
.nomatch
;
14711 tof
= cast(TypeFunction
)to
.nextOf();
14713 else if (to
.ty
== Tpointer
&& (tof
= to
.nextOf().isTypeFunction()) !is null)
14715 if (tok
== TOK
.delegate_
)
14717 eSink
.error(loc
, "cannot match delegate literal to function pointer type `%s`", to
.toChars());
14718 return MATCH
.nomatch
;
14726 return cannotInfer();
14729 // Parameter types inference from 'tof'
14731 TypeFunction tf
= fd
.type
.isTypeFunction();
14732 //printf("\ttof = %s\n", tof.toChars());
14733 //printf("\ttf = %s\n", tf.toChars());
14734 const dim
= tf
.parameterList
.length
;
14736 if (tof
.parameterList
.length
!= dim || tof
.parameterList
.varargs
!= tf
.parameterList
.varargs
)
14737 return cannotInfer();
14739 auto tiargs
= new Objects();
14740 tiargs
.reserve(td
.parameters
.length
);
14742 foreach (tp
; *td
.parameters
)
14745 foreach (i
, p
; tf
.parameterList
)
14747 if (auto ti
= p
.type
.isTypeIdentifier())
14748 if (ti
&& ti
.ident
== tp
.ident
)
14754 Parameter pto
= tof
.parameterList
[u
];
14756 if (t
.ty
== Terror
)
14757 return cannotInfer();
14758 tf
.parameterList
[u
].storageClass
= tof
.parameterList
[u
].storageClass
;
14762 // Set target of return type inference
14763 if (!tf
.next
&& tof
.next
)
14766 auto ti
= new TemplateInstance(loc
, td
, tiargs
);
14767 Expression ex
= (new ScopeExp(loc
, ti
)).expressionSemantic(td
._scope
);
14769 // Reset inference target for the later re-semantic
14772 if (ex
.op
== EXP
.error
)
14773 return MATCH
.nomatch
;
14774 if (auto ef
= ex
.isFuncExp())
14775 return ef
.matchType(to
, sc
, presult
, eSink
);
14777 return cannotInfer();
14780 if (!tof ||
!tof
.next
)
14781 return MATCH
.nomatch
;
14783 assert(type
&& type
!= Type
.tvoid
);
14784 if (fd
.type
.ty
== Terror
)
14785 return MATCH
.nomatch
;
14786 auto tfx
= fd
.type
.isTypeFunction();
14787 bool convertMatch
= (type
.ty
!= to
.ty
);
14789 if (fd
.inferRetType
&& tfx
.next
.implicitConvTo(tof
.next
) == MATCH
.convert
)
14791 /* If return type is inferred and covariant return,
14792 * tweak return statements to required return type.
14795 * class C : Object, I{}
14797 * I delegate() dg = delegate() { return new class C(); }
14799 convertMatch
= true;
14801 auto tfy
= new TypeFunction(tfx
.parameterList
, tof
.next
,
14802 tfx
.linkage
, STC
.undefined_
);
14804 tfy
.trust
= tfx
.trust
;
14805 tfy
.isnothrow
= tfx
.isnothrow
;
14806 tfy
.isnogc
= tfx
.isnogc
;
14807 tfy
.purity
= tfx
.purity
;
14808 tfy
.isproperty
= tfx
.isproperty
;
14809 tfy
.isref
= tfx
.isref
;
14810 tfy
.isInOutParam
= tfx
.isInOutParam
;
14811 tfy
.isInOutQual
= tfx
.isInOutQual
;
14812 tfy
.deco
= tfy
.merge().deco
;
14817 if (tok
== TOK
.delegate_ ||
14818 tok
== TOK
.reserved
&& (type
.ty
== Tdelegate || type
.ty
== Tpointer
&& to
.ty
== Tdelegate
))
14820 // Allow conversion from implicit function pointer to delegate
14821 tx
= new TypeDelegate(tfx
);
14822 tx
.deco
= tx
.merge().deco
;
14826 assert(tok
== TOK
.function_ || tok
== TOK
.reserved
&& type
.ty
== Tpointer || fd
.errors
);
14827 tx
= tfx
.pointerTo();
14829 //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars());
14831 MATCH m
= tx
.implicitConvTo(to
);
14832 if (m
> MATCH
.nomatch
)
14834 // MATCH.exact: exact type match
14835 // MATCH.constant: covairiant type match (eg. attributes difference)
14836 // MATCH.convert: context conversion
14837 m
= convertMatch ? MATCH
.convert
: tx
.equals(to
) ? MATCH
.exact
: MATCH
.constant
;
14841 (*presult
) = cast(FuncExp
)funcExp
.copy();
14842 (*presult
).type
= to
;
14844 // https://issues.dlang.org/show_bug.cgi?id=12508
14845 // Tweak function body for covariant returns.
14846 (*presult
).fd
.modifyReturns(sc
, tof
.next
);
14849 else if (!cast(ErrorSinkNull
)eSink
)
14851 auto ts
= toAutoQualChars(tx
, to
);
14852 eSink
.error(loc
, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
14853 funcExp
.toChars(), ts
[0], ts
[1]);
14858 private bool checkSharedAccessBin(BinExp binExp
, Scope
* sc
)
14860 const r1
= binExp
.e1
.checkSharedAccess(sc
);
14861 const r2
= binExp
.e2
.checkSharedAccess(sc
);
14865 /***************************************
14866 * If expression is shared, check that we can access it.
14867 * Give error message if not.
14870 * e = expression to check
14872 * returnRef = Whether this expression is for a `return` statement
14873 * off a `ref` function, in which case a single level
14874 * of dereference is allowed (e.g. `shared(int)*`).
14878 bool checkSharedAccess(Expression e
, Scope
* sc
, bool returnRef
= false)
14880 if (global
.params
.noSharedAccess
!= FeatureState
.enabled ||
14883 sc
.flags
& SCOPE
.ctfe
)
14888 //printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef);
14890 bool check(Expression e
, bool allowRef
)
14892 bool sharedError(Expression e
)
14894 // https://dlang.org/phobos/core_atomic.html
14895 error(e
.loc
, "direct access to shared `%s` is not allowed, see `core.atomic`", e
.toChars());
14899 // Error by default
14900 bool visit(Expression e
)
14902 // https://issues.dlang.org/show_bug.cgi?id=23639
14903 // Should be able to cast(shared)
14904 if (!e
.isCastExp() && e
.type
.isShared())
14905 return sharedError(e
);
14909 bool visitNew(NewExp e
)
14912 check(e
.thisexp
, false);
14916 bool visitVar(VarExp e
)
14918 // https://issues.dlang.org/show_bug.cgi?id=20908
14919 // direct access to init symbols is ok as they
14920 // cannot be modified.
14921 if (e
.var
.isSymbolDeclaration())
14924 // https://issues.dlang.org/show_bug.cgi?id=22626
14925 // Synchronized functions don't need to use core.atomic
14926 // when accessing `this`.
14927 if (sc
.func
&& sc
.func
.isSynchronized())
14929 if (e
.var
.isThisDeclaration())
14932 return sharedError(e
);
14934 else if (!allowRef
&& e
.var
.type
.isShared())
14935 return sharedError(e
);
14940 bool visitAddr(AddrExp e
)
14942 return check(e
.e1
, true);
14945 bool visitPtr(PtrExp e
)
14947 if (!allowRef
&& e
.type
.isShared())
14948 return sharedError(e
);
14950 if (e
.e1
.type
.isShared())
14951 return sharedError(e
);
14953 return check(e
.e1
, false);
14956 bool visitDotVar(DotVarExp e
)
14958 //printf("dotvarexp = %s\n", e.toChars());
14959 if (e
.type
.isShared())
14961 if (e
.e1
.isThisExp())
14963 // https://issues.dlang.org/show_bug.cgi?id=22626
14964 if (sc
.func
&& sc
.func
.isSynchronized())
14967 // https://issues.dlang.org/show_bug.cgi?id=23790
14968 if (e
.e1
.type
.isTypeStruct())
14972 auto fd
= e
.var
.isFuncDeclaration();
14973 const sharedFunc
= fd
&& fd
.type
.isShared
;
14974 if (!allowRef
&& !sharedFunc
)
14975 return sharedError(e
);
14977 // Allow using `DotVarExp` within value types
14978 if (e
.e1
.type
.isTypeSArray() || e
.e1
.type
.isTypeStruct())
14979 return check(e
.e1
, allowRef
);
14981 // If we end up with a single `VarExp`, it might be a `ref` param
14982 // `shared ref T` param == `shared(T)*`.
14983 if (auto ve
= e
.e1
.isVarExp())
14985 return check(e
.e1
, allowRef
&& (ve
.var
.storage_class
& STC
.ref_
));
14988 return sharedError(e
);
14991 return check(e
.e1
, false);
14994 bool visitIndex(IndexExp e
)
14996 if (!allowRef
&& e
.type
.isShared())
14997 return sharedError(e
);
14999 if (e
.e1
.type
.isShared())
15000 return sharedError(e
);
15002 return check(e
.e1
, false);
15005 bool visitComma(CommaExp e
)
15007 // Cannot be `return ref` since we can't use the return,
15008 // but it's better to show that error than an unrelated `shared` one
15009 return check(e
.e2
, true);
15014 default: return visit(e
);
15016 // Those have no indirections / can be ignored
15019 case EXP
.complex80
:
15021 case EXP
.null_
: return false;
15023 case EXP
.variable
: return visitVar(e
.isVarExp());
15024 case EXP
.new_
: return visitNew(e
.isNewExp());
15025 case EXP
.address
: return visitAddr(e
.isAddrExp());
15026 case EXP
.star
: return visitPtr(e
.isPtrExp());
15027 case EXP
.dotVariable
: return visitDotVar(e
.isDotVarExp());
15028 case EXP
.index
: return visitIndex(e
.isIndexExp());
15032 return check(e
, returnRef
);
15035 /****************************************
15036 * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE_FULL_PATH__ to loc.
15038 Expression
resolveLoc(Expression exp
, const ref Loc loc
, Scope
* sc
)
15040 Expression
visit(Expression exp
)
15042 if (auto unaExp
= exp
.isUnaExp())
15044 unaExp
.e1
= unaExp
.e1
.resolveLoc(loc
, sc
);
15051 Expression
visitCat(CatExp exp
)
15053 exp
.e1
= exp
.e1
.resolveLoc(loc
, sc
);
15054 exp
.e2
= exp
.e2
.resolveLoc(loc
, sc
);
15058 Expression
visitFileInit(FileInitExp exp
)
15060 //printf("FileInitExp::resolve() %s\n", exp.toChars());
15062 if (exp
.op
== EXP
.fileFullPath
)
15063 s
= FileName
.toAbsolute(loc
.isValid() ? loc
.filename
: sc
._module
.srcfile
.toChars());
15065 s
= loc
.isValid() ? loc
.filename
: sc
._module
.ident
.toChars();
15067 Expression e
= new StringExp(loc
, s
.toDString());
15068 return e
.expressionSemantic(sc
);
15071 Expression
visitLineInit(LineInitExp _
)
15073 Expression e
= new IntegerExp(loc
, loc
.linnum
, Type
.tint32
);
15074 return e
.expressionSemantic(sc
);
15077 Expression
visitModuleInit(ModuleInitExp _
)
15079 const auto s
= (sc
.callsc ? sc
.callsc
: sc
)._module
.toPrettyChars().toDString();
15080 Expression e
= new StringExp(loc
, s
);
15081 return e
.expressionSemantic(sc
);
15084 Expression
visitFuncInit(FuncInitExp _
)
15087 if (sc
.callsc
&& sc
.callsc
.func
)
15088 s
= sc
.callsc
.func
.Dsymbol
.toPrettyChars();
15090 s
= sc
.func
.Dsymbol
.toPrettyChars();
15093 Expression e
= new StringExp(loc
, s
.toDString());
15094 return e
.expressionSemantic(sc
);
15097 Expression
visitPrettyFunc(PrettyFuncInitExp _
)
15099 FuncDeclaration fd
= (sc
.callsc
&& sc
.callsc
.func
)
15106 const funcStr
= fd
.Dsymbol
.toPrettyChars();
15108 functionToBufferWithIdent(fd
.type
.isTypeFunction(), buf
, funcStr
, fd
.isStatic
);
15109 s
= buf
.extractChars();
15116 Expression e
= new StringExp(loc
, s
.toDString());
15117 e
= e
.expressionSemantic(sc
);
15118 e
.type
= Type
.tstring
;
15124 default: return visit(exp
);
15125 case EXP
.concatenate
: return visitCat(exp
.isCatExp());
15127 case EXP
.fileFullPath
: return visitFileInit(exp
.isFileInitExp());
15128 case EXP
.line
: return visitLineInit(exp
.isLineInitExp
);
15129 case EXP
.moduleString
: return visitModuleInit(exp
.isModuleInitExp());
15130 case EXP
.functionString
: return visitFuncInit(exp
.isFuncInitExp());
15131 case EXP
.prettyFunction
: return visitPrettyFunc(exp
.isPrettyFuncInitExp());
15135 /************************************************
15136 * Destructors are attached to VarDeclarations.
15137 * Hence, if expression returns a temp that needs a destructor,
15138 * make sure and create a VarDeclaration for that temp.
15140 Expression
addDtorHook(Expression e
, Scope
* sc
)
15142 Expression
visit(Expression exp
)
15147 Expression
visitStructLiteral(StructLiteralExp exp
)
15150 /* If struct requires a destructor, rewrite as:
15151 * (S tmp = S()),tmp
15152 * so that the destructor can be hung on tmp.
15154 if (sd
.dtor
&& sc
.func
)
15156 /* Make an identifier for the temporary of the form:
15157 * __sl%s%d, where %s is the struct name
15159 char[10] buf
= void;
15160 const prefix
= "__sl";
15161 const ident
= sd
.ident
.toString
;
15162 const fullLen
= prefix
.length
+ ident
.length
;
15163 const len
= fullLen
< buf
.length ? fullLen
: buf
.length
;
15164 buf
[0 .. prefix
.length
] = prefix
;
15165 buf
[prefix
.length
.. len
] = ident
[0 .. len
- prefix
.length
];
15167 auto tmp
= copyToTemp(0, buf
[0 .. len
], exp
);
15168 Expression ae
= new DeclarationExp(exp
.loc
, tmp
);
15169 Expression e
= new CommaExp(exp
.loc
, ae
, new VarExp(exp
.loc
, tmp
));
15170 e
= e
.expressionSemantic(sc
);
15177 Expression
visitCall(CallExp exp
)
15180 auto type
= exp
.type
;
15181 /* Only need to add dtor hook if it's a type that needs destruction.
15182 * Use same logic as VarDeclaration::callScopeDtor()
15185 if (auto tf
= e1
.type
.isTypeFunction())
15191 Type tv
= type
.baseElemOf();
15192 if (auto ts
= tv
.isTypeStruct())
15194 StructDeclaration sd
= ts
.sym
;
15197 /* Type needs destruction, so declare a tmp
15198 * which the back end will recognize and call dtor on
15200 auto tmp
= copyToTemp(0, Id
.__tmpfordtor
.toString(), exp
);
15201 auto de = new DeclarationExp(exp
.loc
, tmp
);
15202 auto ve
= new VarExp(exp
.loc
, tmp
);
15203 Expression e
= new CommaExp(exp
.loc
, de, ve
);
15204 e
= e
.expressionSemantic(sc
);
15212 Expression
visitCast(CastExp exp
)
15214 if (exp
.to
.toBasetype().ty
== Tvoid
) // look past the cast(void)
15215 exp
.e1
= exp
.e1
.addDtorHook(sc
);
15219 Expression
visitComma(CommaExp exp
)
15221 exp
.e2
= exp
.e2
.addDtorHook(sc
);
15227 default: return visit(e
);
15229 case EXP
.structLiteral
: return visitStructLiteral(e
.isStructLiteralExp());
15230 case EXP
.call: return visitCall(e
.isCallExp());
15231 case EXP
.cast_
: return visitCast(e
.isCastExp());
15232 case EXP
.comma
: return visitComma(e
.isCommaExp());
15236 /*******************************
15237 * Try to convert an expression to be an lvalue.
15239 * Give error if we're not an lvalue.
15241 * _this = expression to convert
15243 * action = for error messages, what the lvalue is needed for (e.g. take address of for `&x`, modify for `x++`)
15244 * Returns: converted expression, or `ErrorExp` on error
15246 extern(C
++) Expression
toLvalue(Expression _this
, Scope
* sc
, const(char)* action
)
15248 return toLvalueImpl(_this
, sc
, action
, _this
);
15251 // e = original un-lowered expression for error messages, in case of recursive calls
15252 private Expression
toLvalueImpl(Expression _this
, Scope
* sc
, const(char)* action
, Expression e
)
15255 action
= "create lvalue of";
15258 Expression
visit(Expression _this
)
15260 // BinaryAssignExp does not have an EXP associated
15261 // so it's treated on the default path.
15262 // Lvalue-ness will be handled in glue :layer.
15263 if (_this
.isBinAssignExp())
15265 if (!_this
.loc
.isValid())
15268 if (e
.op
== EXP
.type
)
15269 error(_this
.loc
, "cannot %s type `%s`", action
, e
.type
.toChars());
15270 else if (e
.op
== EXP
.template_
)
15271 error(_this
.loc
, "cannot %s template `%s`, perhaps instantiate it first", action
, e
.toChars());
15273 error(_this
.loc
, "cannot %s expression `%s` because it is not an lvalue", action
, e
.toChars());
15275 return ErrorExp
.get();
15278 Expression
visitInteger(IntegerExp _this
)
15280 if (!_this
.loc
.isValid())
15282 error(e
.loc
, "cannot %s constant `%s`", action
, e
.toChars());
15283 return ErrorExp
.get();
15286 Expression
visitThis(ThisExp _this
)
15288 if (_this
.type
.toBasetype().ty
== Tclass
)
15290 // Class `this` is an rvalue; struct `this` is an lvalue.
15291 return visit(_this
);
15297 Expression
visitString(StringExp _this
)
15299 //printf("StringExp::toLvalue(%s) type = %s\n", _this.toChars(), _this.type ? _this.type.toChars() : NULL);
15300 return (_this
.type
&& _this
.type
.toBasetype().ty
== Tsarray
) ? _this
: visit(_this
);
15303 Expression
visitStructLiteral(StructLiteralExp _this
)
15305 if (sc
.flags
& SCOPE
.Cfile
)
15306 return _this
; // C struct literals are lvalues
15308 return visit(_this
);
15311 Expression
visitTemplate(TemplateExp _this
)
15314 return visit(_this
);
15317 return symbolToExp(_this
.fd
, _this
.loc
, sc
, true);
15321 Expression
visitVar(VarExp _this
)
15323 auto var
= _this
.var
;
15324 if (var
.storage_class
& STC
.manifest
)
15326 error(_this
.loc
, "cannot %s manifest constant `%s`", action
, var
.toChars());
15327 return ErrorExp
.get();
15329 if (var
.storage_class
& STC
.lazy_
&& !_this
.delegateWasExtracted
)
15331 error(_this
.loc
, "cannot %s lazy variable `%s`", action
, var
.toChars());
15332 return ErrorExp
.get();
15334 if (var
.ident
== Id
.ctfe
)
15336 error(_this
.loc
, "cannot %s compiler-generated variable `__ctfe`", action
);
15337 return ErrorExp
.get();
15339 if (var
.ident
== Id
.dollar
) // https://issues.dlang.org/show_bug.cgi?id=13574
15341 error(_this
.loc
, "cannot %s operator `$`", action
);
15342 return ErrorExp
.get();
15347 Expression
visitDotVar(DotVarExp _this
)
15349 auto e1
= _this
.e1
;
15350 auto var
= _this
.var
;
15351 //printf("DotVarExp::toLvalue(%s)\n", toChars());
15352 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
15354 /* C11 6.5.2.3-3: A postfix expression followed by the '.' or '->' operator
15355 * is an lvalue if the first expression is an lvalue.
15357 if (!e1
.isLvalue())
15358 return visit(_this
);
15360 if (!_this
.isLvalue())
15361 return visit(_this
);
15362 if (e1
.op
== EXP
.this_
&& sc
.ctorflow
.fieldinit
.length
&& !(sc
.ctorflow
.callSuper
& CSX
.any_ctor
))
15364 if (VarDeclaration vd
= var
.isVarDeclaration())
15366 auto ad
= vd
.isMember2();
15367 if (ad
&& ad
.fields
.length
== sc
.ctorflow
.fieldinit
.length
)
15369 foreach (i
, f
; ad
.fields
)
15373 if (!(sc
.ctorflow
.fieldinit
[i
].csx
& CSX
.this_ctor
))
15375 /* If the address of vd is taken, assume it is thereby initialized
15376 * https://issues.dlang.org/show_bug.cgi?id=15869
15378 modifyFieldVar(_this
.loc
, sc
, vd
, e1
);
15389 Expression
visitCall(CallExp _this
)
15391 if (_this
.isLvalue())
15393 return visit(_this
);
15396 Expression
visitCast(CastExp _this
)
15398 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
15400 /* C11 6.5.4-5: A cast does not yield an lvalue.
15402 return visit(_this
);
15404 if (_this
.isLvalue())
15406 return visit(_this
);
15409 Expression
visitVectorArray(VectorArrayExp _this
)
15411 _this
.e1
= _this
.e1
.toLvalueImpl(sc
, action
, e
);
15415 Expression
visitSlice(SliceExp _this
)
15417 //printf("SliceExp::toLvalue(%s) _this.type = %s\n", _this.toChars(), _this.type ? _this.type.toChars() : NULL);
15418 return (_this
.type
&& _this
.type
.toBasetype().ty
== Tsarray
) ? _this
: visit(_this
);
15421 Expression
visitArray(ArrayExp _this
)
15423 if (_this
.type
&& _this
.type
.toBasetype().ty
== Tvoid
)
15424 error(_this
.loc
, "`void`s have no value");
15428 Expression
visitComma(CommaExp _this
)
15430 _this
.e2
= _this
.e2
.toLvalue(sc
, action
);
15434 Expression
visitDelegatePointer(DelegatePtrExp _this
)
15436 _this
.e1
= _this
.e1
.toLvalueImpl(sc
, action
, e
);
15440 Expression
visitDelegateFuncptr(DelegateFuncptrExp _this
)
15442 _this
.e1
= _this
.e1
.toLvalueImpl(sc
, action
, e
);
15446 Expression
visitIndex(IndexExp _this
)
15448 if (_this
.isLvalue())
15450 return visit(_this
);
15453 Expression
visitAssign(AssignExp _this
)
15455 if (_this
.e1
.op
== EXP
.slice || _this
.e1
.op
== EXP
.arrayLength
)
15457 return visit(_this
);
15460 /* In front-end level, AssignExp should make an lvalue of e1.
15461 * Taking the address of e1 will be handled in low level layer,
15462 * so this function does nothing.
15467 Expression
visitCond(CondExp _this
)
15469 // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
15470 CondExp e
= cast(CondExp
)(_this
.copy());
15471 e
.e1
= _this
.e1
.toLvalue(sc
, action
).addressOf();
15472 e
.e2
= _this
.e2
.toLvalue(sc
, action
).addressOf();
15473 e
.type
= _this
.type
.pointerTo();
15474 return new PtrExp(_this
.loc
, e
, _this
.type
);
15480 default: return visit(_this
);
15482 case EXP
.int64
: return visitInteger(_this
.isIntegerExp());
15483 case EXP
.error
: return _this
;
15484 case EXP
.identifier
: return _this
;
15485 case EXP
.dSymbol
: return _this
;
15486 case EXP
.this_
: return visitThis(_this
.isThisExp());
15487 case EXP
.super_
: return visitThis(_this
.isSuperExp());
15488 case EXP
.string_
: return visitString(_this
.isStringExp());
15489 case EXP
.structLiteral
: return visitStructLiteral(_this
.isStructLiteralExp());
15490 case EXP
.template_
: return visitTemplate(_this
.isTemplateExp());
15491 case EXP
.variable
: return visitVar(_this
.isVarExp());
15492 case EXP
.overloadSet
: return _this
;
15493 case EXP
.dotVariable
: return visitDotVar(_this
.isDotVarExp());
15494 case EXP
.call: return visitCall(_this
.isCallExp());
15495 case EXP
.star
: return _this
;
15496 case EXP
.cast_
: return visitCast(_this
.isCastExp());
15497 case EXP
.vectorArray
: return visitVectorArray(_this
.isVectorArrayExp());
15498 case EXP
.slice
: return visitSlice(_this
.isSliceExp());
15499 case EXP
.array
: return visitArray(_this
.isArrayExp());
15500 case EXP
.comma
: return visitComma(_this
.isCommaExp());
15501 case EXP
.delegatePointer
: return visitDelegatePointer(_this
.isDelegatePtrExp());
15502 case EXP
.delegateFunctionPointer
: return visitDelegateFuncptr(_this
.isDelegateFuncptrExp());
15503 case EXP
.index
: return visitIndex(_this
.isIndexExp());
15504 case EXP
.construct
: return visitAssign(_this
.isConstructExp());
15505 case EXP
.loweredAssignExp
: return visitAssign(_this
.isLoweredAssignExp());
15506 case EXP
.blit
: return visitAssign(_this
.isBlitExp());
15507 case EXP
.assign
: return visitAssign(_this
.isAssignExp());
15508 case EXP
.question
: return visitCond(_this
.isCondExp());
15512 /***************************************
15515 * flag: 1: do not issue error message for invalid modification
15516 2: the exp is a DotVarExp and a subfield of the leftmost
15517 variable is modified
15519 * Whether the type is modifiable
15521 Modifiable
checkModifiable(Expression exp
, Scope
* sc
, ModifyFlags flag
= ModifyFlags
.none
)
15526 auto varExp
= cast(VarExp
)exp
;
15528 //printf("VarExp::checkModifiable %s", varExp.toChars());
15529 assert(varExp
.type
);
15530 return varExp
.var
.checkModify(varExp
.loc
, sc
, null, flag
);
15532 case EXP
.dotVariable
:
15533 auto dotVarExp
= cast(DotVarExp
)exp
;
15535 //printf("DotVarExp::checkModifiable %s %s\n", dotVarExp.toChars(), dotVarExp.type.toChars());
15536 if (dotVarExp
.e1
.op
== EXP
.this_
)
15537 return dotVarExp
.var
.checkModify(dotVarExp
.loc
, sc
, dotVarExp
.e1
, flag
);
15539 /* https://issues.dlang.org/show_bug.cgi?id=12764
15540 * If inside a constructor and an expression of type `this.field.var`
15541 * is encountered, where `field` is a struct declaration with
15542 * default construction disabled, we must make sure that
15543 * assigning to `var` does not imply that `field` was initialized
15545 if (sc
.func
&& sc
.func
.isCtorDeclaration())
15547 // if inside a constructor scope and e1 of this DotVarExp
15548 // is another DotVarExp, then check if the leftmost expression is a `this` identifier
15549 if (auto dve
= dotVarExp
.e1
.isDotVarExp())
15551 // Iterate the chain of DotVarExp to find `this`
15552 // Keep track whether access to fields was limited to union members
15553 // s.t. one can initialize an entire struct inside nested unions
15554 // (but not its members)
15555 bool onlyUnion
= true;
15558 auto v
= dve
.var
.isVarDeclaration();
15561 // Accessing union member?
15562 auto t
= v
.type
.isTypeStruct();
15563 if (!t ||
!t
.sym
.isUnionDeclaration())
15566 // Another DotVarExp left?
15567 if (!dve
.e1 || dve
.e1
.op
!= EXP
.dotVariable
)
15570 dve
= cast(DotVarExp
) dve
.e1
;
15573 if (dve
.e1
.op
== EXP
.this_
)
15575 scope v
= dve
.var
.isVarDeclaration();
15576 /* if v is a struct member field with no initializer, no default construction
15577 * and v wasn't intialized before
15579 if (v
&& v
.isField() && !v
._init
&& !v
.ctorinit
)
15581 if (auto ts
= v
.type
.isTypeStruct())
15583 if (ts
.sym
.noDefaultCtor
)
15585 /* checkModify will consider that this is an initialization
15586 * of v while it is actually an assignment of a field of v
15588 scope modifyLevel
= v
.checkModify(dotVarExp
.loc
, sc
, dve
.e1
, !onlyUnion ?
(flag | ModifyFlags
.fieldAssign
) : flag
);
15589 if (modifyLevel
== Modifiable
.initialization
)
15591 // https://issues.dlang.org/show_bug.cgi?id=22118
15592 // v is a union type field that was assigned
15593 // a variable, therefore it counts as initialization
15595 return Modifiable
.initialization
;
15597 return Modifiable
.yes
;
15599 return modifyLevel
;
15607 //printf("\te1 = %s\n", e1.toChars());
15608 return dotVarExp
.e1
.checkModifiable(sc
, flag
);
15611 auto ptrExp
= cast(PtrExp
)exp
;
15612 if (auto se
= ptrExp
.e1
.isSymOffExp())
15614 return se
.var
.checkModify(ptrExp
.loc
, sc
, null, flag
);
15616 else if (auto ae
= ptrExp
.e1
.isAddrExp())
15618 return ae
.e1
.checkModifiable(sc
, flag
);
15620 return Modifiable
.yes
;
15623 auto sliceExp
= cast(SliceExp
)exp
;
15625 //printf("SliceExp::checkModifiable %s\n", sliceExp.toChars());
15626 auto e1
= sliceExp
.e1
;
15627 if (e1
.type
.ty
== Tsarray ||
(e1
.op
== EXP
.index
&& e1
.type
.ty
!= Tarray
) || e1
.op
== EXP
.slice
)
15629 return e1
.checkModifiable(sc
, flag
);
15631 return Modifiable
.yes
;
15634 return (cast(CommaExp
)exp
).e2
.checkModifiable(sc
, flag
);
15637 auto indexExp
= cast(IndexExp
)exp
;
15638 auto e1
= indexExp
.e1
;
15639 if (e1
.type
.ty
== Tsarray ||
15640 e1
.type
.ty
== Taarray ||
15641 (e1
.op
== EXP
.index
&& e1
.type
.ty
!= Tarray
) ||
15642 e1
.op
== EXP
.slice
)
15644 return e1
.checkModifiable(sc
, flag
);
15646 return Modifiable
.yes
;
15649 auto condExp
= cast(CondExp
)exp
;
15650 if (condExp
.e1
.checkModifiable(sc
, flag
) != Modifiable
.no
15651 && condExp
.e2
.checkModifiable(sc
, flag
) != Modifiable
.no
)
15652 return Modifiable
.yes
;
15653 return Modifiable
.no
;
15656 return exp
.type ? Modifiable
.yes
: Modifiable
.no
; // default modifiable
15661 * Similar to `toLvalue`, but also enforce it is mutable or raise an error.
15663 * _this = Expression to convert
15665 * Returns: `_this` converted to an lvalue, or an `ErrorExp`
15667 extern(C
++) Expression
modifiableLvalue(Expression _this
, Scope
* sc
)
15669 return modifiableLvalueImpl(_this
, sc
, _this
);
15672 // e = original / un-lowered expression to print in error messages
15673 private Expression
modifiableLvalueImpl(Expression _this
, Scope
* sc
, Expression e
)
15676 Expression
visit(Expression exp
)
15678 //printf("Expression::modifiableLvalue() %s, type = %s\n", exp.toChars(), exp.type.toChars());
15679 // See if this expression is a modifiable lvalue (i.e. not const)
15680 if (exp
.isBinAssignExp())
15681 return exp
.toLvalue(sc
, "modify");
15683 auto type
= exp
.type
;
15684 if (checkModifiable(exp
, sc
) == Modifiable
.yes
)
15687 if (!type
.isMutable())
15689 if (auto dve
= exp
.isDotVarExp())
15691 if (isNeedThisScope(sc
, dve
.var
))
15692 for (Dsymbol s
= sc
.func
; s
; s
= s
.toParentLocal())
15694 FuncDeclaration ff
= s
.isFuncDeclaration();
15697 if (!ff
.type
.isMutable
)
15699 error(exp
.loc
, "cannot modify `%s` in `%s` function", exp
.toChars(), MODtoChars(type
.mod
));
15700 return ErrorExp
.get();
15704 error(exp
.loc
, "cannot modify `%s` expression `%s`", MODtoChars(type
.mod
), exp
.toChars());
15705 return ErrorExp
.get();
15707 else if (!type
.isAssignable())
15709 error(exp
.loc
, "cannot modify struct instance `%s` of type `%s` because it contains `const` or `immutable` members",
15710 exp
.toChars(), type
.toChars());
15711 return ErrorExp
.get();
15714 return exp
.toLvalueImpl(sc
, "modify", e
);
15717 Expression
visitString(StringExp exp
)
15719 error(exp
.loc
, "cannot modify string literal `%s`", exp
.toChars());
15720 return ErrorExp
.get();
15723 Expression
visitVar(VarExp exp
)
15725 //printf("VarExp::modifiableLvalue('%s')\n", exp.var.toChars());
15726 if (exp
.var
.storage_class
& STC
.manifest
)
15728 error(exp
.loc
, "cannot modify manifest constant `%s`", exp
.toChars());
15729 return ErrorExp
.get();
15731 // See if this expression is a modifiable lvalue (i.e. not const)
15735 Expression
visitPtr(PtrExp exp
)
15737 //printf("PtrExp::modifiableLvalue() %s, type %s\n", exp.toChars(), exp.type.toChars());
15740 if (auto se
= e1
.isSymOffExp())
15742 else if (auto ve
= e1
.isVarExp())
15744 if (var
&& var
.type
.isFunction_Delegate_PtrToFunction())
15746 if (var
.type
.isTypeFunction())
15747 error(exp
.loc
, "function `%s` is not an lvalue and cannot be modified", var
.toChars());
15749 error(exp
.loc
, "function pointed to by `%s` is not an lvalue and cannot be modified", var
.toChars());
15750 return ErrorExp
.get();
15755 Expression
visitSlice(SliceExp exp
)
15757 error(exp
.loc
, "slice expression `%s` is not a modifiable lvalue", exp
.toChars());
15761 Expression
visitComma(CommaExp exp
)
15763 exp
.e2
= exp
.e2
.modifiableLvalueImpl(sc
, e
);
15767 Expression
visitDelegatePtr(DelegatePtrExp exp
)
15769 if (sc
.setUnsafe(false, exp
.loc
, "cannot modify delegate pointer in `@safe` code `%s`", exp
))
15771 return ErrorExp
.get();
15776 Expression
visitDelegateFuncptr(DelegateFuncptrExp exp
)
15778 if (sc
.setUnsafe(false, exp
.loc
, "cannot modify delegate function pointer in `@safe` code `%s`", exp
))
15780 return ErrorExp
.get();
15785 Expression
visitIndex(IndexExp exp
)
15787 //printf("IndexExp::modifiableLvalue(%s)\n", exp.toChars());
15788 Expression ex
= exp
.markSettingAAElem();
15789 if (ex
.op
== EXP
.error
)
15795 Expression
visitCond(CondExp exp
)
15797 if (!exp
.e1
.isLvalue() && !exp
.e2
.isLvalue())
15799 error(exp
.loc
, "conditional expression `%s` is not a modifiable lvalue", exp
.toChars());
15800 return ErrorExp
.get();
15802 exp
.e1
= exp
.e1
.modifiableLvalue(sc
);
15803 exp
.e2
= exp
.e2
.modifiableLvalue(sc
);
15804 return exp
.toLvalue(sc
, "modify");
15809 default: return visit(_this
);
15810 case EXP
.string_
: return visitString(_this
.isStringExp());
15811 case EXP
.variable
: return visitVar(_this
.isVarExp());
15812 case EXP
.star
: return visitPtr(_this
.isPtrExp());
15813 case EXP
.slice
: return visitSlice(_this
.isSliceExp());
15814 case EXP
.comma
: return visitComma(_this
.isCommaExp());
15815 case EXP
.delegatePointer
: return visitDelegatePtr(_this
.isDelegatePtrExp());
15816 case EXP
.delegateFunctionPointer
: return visitDelegateFuncptr(_this
.isDelegateFuncptrExp());
15817 case EXP
.index
: return visitIndex(_this
.isIndexExp());
15818 case EXP
.question
: return visitCond(_this
.isCondExp());
15823 /****************************************************
15824 * Determine if `exp`, which gets its address taken, can do so safely.
15827 * exp = expression having its address taken
15828 * v = the variable getting its address taken
15830 * `true` if ok, `false` for error
15832 bool checkAddressVar(Scope
* sc
, Expression exp
, VarDeclaration v
)
15834 //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars());
15838 if (!v
.canTakeAddressOf())
15840 error(exp
.loc
, "cannot take address of `%s`", exp
.toChars());
15843 if (sc
.func
&& !sc
.intypeof
&& !v
.isDataseg())
15845 if (sc
.useDIP1000
!= FeatureState
.enabled
&&
15846 !(v
.storage_class
& STC
.temp
) &&
15847 sc
.setUnsafe(false, exp
.loc
, "cannot take address of local `%s` in `@safe` function `%s`", v
, sc
.func
))
15855 /**************************************
15856 * This check ensures that the object in `exp` can have its address taken, or
15857 * issue a diagnostic error.
15859 * e = expression to check
15862 * true if the expression is addressable
15864 bool checkAddressable(Expression e
, Scope
* sc
)
15871 case EXP
.dotVariable
:
15872 // https://issues.dlang.org/show_bug.cgi?id=22749
15873 // Error about taking address of any bit-field, regardless of
15874 // whether SCOPE.Cfile is set.
15875 if (auto bf
= ex
.isDotVarExp().var
.isBitFieldDeclaration())
15877 error(e
.loc
, "cannot take address of bit-field `%s`", bf
.toChars());
15880 goto case EXP
.cast_
;
15883 ex
= ex
.isBinExp().e1
;
15889 ex
= ex
.isUnaExp().e1
;
15893 if (sc
.flags
& SCOPE
.Cfile
)
15895 // C11 6.5.3.2: A variable that has its address taken cannot be
15896 // stored in a register.
15897 // C11 6.3.2.1: An array that has its address computed with `[]`
15898 // or cast to an lvalue pointer cannot be stored in a register.
15899 if (ex
.isVarExp().var
.storage_class
& STC
.register
)
15901 if (e
.isIndexExp())
15902 error(e
.loc
, "cannot index through register variable `%s`", ex
.toChars());
15904 error(e
.loc
, "cannot take address of register variable `%s`", ex
.toChars());
15919 /*******************************
15920 * Checks the attributes of a function.
15921 * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`)
15922 * and usage of `deprecated` and `@disabled`-ed symbols are checked.
15925 * exp = expression to check attributes for
15926 * sc = scope of the function
15927 * f = function to be checked
15928 * Returns: `true` if error occur.
15930 private bool checkFunctionAttributes(Expression exp
, Scope
* sc
, FuncDeclaration f
)
15932 bool error
= f
.checkDisabled(exp
.loc
, sc
);
15933 error |
= f
.checkDeprecated(exp
.loc
, sc
);
15934 error |
= f
.checkPurity(exp
.loc
, sc
);
15935 error |
= f
.checkSafety(exp
.loc
, sc
);
15936 error |
= f
.checkNogc(exp
.loc
, sc
);
15940 /*******************************
15941 * Helper function for `getRightThis()`.
15942 * Gets `this` of the next outer aggregate.
15944 * loc = location to use for error messages
15946 * s = the parent symbol of the existing `this`
15947 * ad = struct or class we need the correct `this` for
15948 * e1 = existing `this`
15949 * t = type of the existing `this`
15950 * var = the specific member of ad we're accessing
15951 * flag = if true, return `null` instead of throwing an error
15953 * Expression representing the `this` for the var
15955 Expression
getThisSkipNestedFuncs(const ref Loc loc
, Scope
* sc
, Dsymbol s
, AggregateDeclaration ad
, Expression e1
, Type t
, Dsymbol var
, bool flag
= false)
15958 while (s
&& s
.isFuncDeclaration())
15960 FuncDeclaration f
= s
.isFuncDeclaration();
15964 e1
= new VarExp(loc
, f
.vthis
);
15965 if (f
.hasDualContext())
15969 e1
= e1
.expressionSemantic(sc
);
15970 e1
= new PtrExp(loc
, e1
);
15971 uint i
= f
.followInstantiationContext(ad
);
15972 e1
= new IndexExp(loc
, e1
, new IntegerExp(i
));
15973 s
= f
.toParentP(ad
);
15981 error(e1
.loc
, "need `this` of type `%s` to access member `%s` from static function `%s`", ad
.toChars(), var
.toChars(), f
.toChars());
15982 e1
= ErrorExp
.get();
15987 if (n
> 1 || e1
.op
== EXP
.index
)
15988 e1
= e1
.expressionSemantic(sc
);
15989 if (s
&& e1
.type
.equivalent(Type
.tvoidptr
))
15991 if (auto sad
= s
.isAggregateDeclaration())
15993 Type ta
= sad
.handleType();
15994 if (ta
.ty
== Tstruct
)
15995 ta
= ta
.pointerTo();
15999 e1
.type
= e1
.type
.addMod(t
.mod
);
16003 /*******************************
16004 * Make a dual-context container for use as a `this` argument.
16006 * loc = location to use for error messages
16007 * sc = current scope
16008 * fd = target function that will take the `this` argument
16010 * Temporary closure variable.
16012 * The function `fd` is added to the nested references of the
16013 * newly created variable such that a closure is made for the variable when
16014 * the address of `fd` is taken.
16016 VarDeclaration
makeThis2Argument(const ref Loc loc
, Scope
* sc
, FuncDeclaration fd
)
16018 Type tthis2
= Type
.tvoidptr
.sarrayOf(2);
16019 VarDeclaration vthis2
= new VarDeclaration(loc
, tthis2
, Identifier
.generateId("__this"), null);
16020 vthis2
.storage_class |
= STC
.temp
;
16021 vthis2
.dsymbolSemantic(sc
);
16022 vthis2
.parent
= sc
.parent
;
16023 // make it a closure var
16025 sc
.func
.closureVars
.push(vthis2
);
16026 // add `fd` to the nested refs
16027 vthis2
.nestedrefs
.push(fd
);
16031 /*******************************
16032 * Make sure that the runtime hook `id` exists.
16034 * loc = location to use for error messages
16035 * sc = current scope
16036 * id = the hook identifier
16037 * description = what the hook does
16038 * module_ = what module the hook is located in
16040 * a `bool` indicating if the hook is present.
16042 bool verifyHookExist(const ref Loc loc
, ref Scope sc
, Identifier id
, string description
, Identifier module_
= Id
.object
)
16045 auto rootSymbol
= sc
.search(loc
, Id
.empty
, pscopesym
);
16046 if (auto moduleSymbol
= rootSymbol
.search(loc
, module_
))
16047 if (moduleSymbol
.search(loc
, id
))
16049 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
);
16053 /***************************************
16054 * Fit elements[] to the corresponding types of the `sd`'s fields.
16057 * sd = the struct declaration
16058 * loc = location to use for error messages
16060 * elements = explicit arguments used to construct object
16061 * stype = the constructed object type.
16063 * false if any errors occur,
16064 * otherwise true and elements[] are rewritten for the output.
16066 private bool fit(StructDeclaration sd
, const ref Loc loc
, Scope
* sc
, Expressions
* elements
, Type stype
)
16071 const nfields
= sd
.nonHiddenFields();
16073 for (size_t i
= 0; i
< elements
.length
; i
++)
16075 Expression e
= (*elements
)[i
];
16079 e
= resolveProperties(sc
, e
);
16082 if (i
< sd
.fields
.length
&& e
.op
== EXP
.null_
)
16084 // CTFE sometimes creates null as hidden pointer; we'll allow this.
16087 .error(loc
, "more initializers than fields (%llu) of `%s`", cast(ulong)nfields
, sd
.toChars());
16090 VarDeclaration v
= sd
.fields
[i
];
16091 if (v
.offset
< offset
)
16093 .error(loc
, "overlapping initialization for `%s`", v
.toChars());
16094 if (!sd
.isUnionDeclaration())
16096 enum errorMsg
= "`struct` initializers that contain anonymous unions" ~
16097 " must initialize only the first member of a `union`. All subsequent" ~
16098 " non-overlapping fields are default initialized";
16099 .errorSupplemental(loc
, errorMsg
);
16103 const vsize
= v
.type
.size();
16104 if (vsize
== SIZE_INVALID
)
16106 offset
= cast(uint)(v
.offset
+ vsize
);
16110 t
= t
.addMod(stype
.mod
);
16112 Type tb
= t
.toBasetype();
16114 const hasPointers
= tb
.hasPointers();
16117 if ((!stype
.alignment
.isDefault() && stype
.alignment
.get() < target
.ptrsize ||
16118 (v
.offset
& (target
.ptrsize
- 1))) &&
16119 (sc
.setUnsafe(false, loc
,
16120 "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd
, v
)))
16126 /* Look for case of initializing a static array with a too-short
16127 * string literal, such as:
16128 * char[5] foo = "abc";
16129 * Allow this by doing an explicit cast, which will lengthen the string
16132 if (e
.op
== EXP
.string_
&& tb
.ty
== Tsarray
)
16134 StringExp se
= cast(StringExp
)e
;
16135 Type typeb
= se
.type
.toBasetype();
16136 TY tynto
= tb
.nextOf().ty
;
16137 if (!se
.committed
&&
16138 (typeb
.ty
== Tarray || typeb
.ty
== Tsarray
) && tynto
.isSomeChar
&&
16139 se
.numberOfCodeUnits(tynto
) < (cast(TypeSArray
)tb
).dim
.toInteger())
16141 e
= se
.castTo(sc
, t
);
16146 while (!e
.implicitConvTo(t
) && tb
.ty
== Tsarray
)
16148 /* Static array initialization, as in:
16152 tb
= t
.toBasetype();
16154 if (!e
.implicitConvTo(t
))
16155 t
= origType
; // restore type for better diagnostic
16157 e
= e
.implicitCastTo(sc
, t
);
16159 if (e
.op
== EXP
.error
)
16162 (*elements
)[i
] = doCopyOrMove(sc
, e
);
16169 * Returns `em` as a VariableExp
16171 * em = the EnumMember to wrap
16172 * loc = location of use of em
16173 * sc = scope of use of em
16175 * VarExp referenceing `em` or ErrorExp if `em` if disabled/deprecated
16177 Expression
getVarExp(EnumMember em
, const ref Loc loc
, Scope
* sc
)
16179 dsymbolSemantic(em
, sc
);
16181 return ErrorExp
.get();
16182 em
.checkDisabled(loc
, sc
);
16184 if (em
.depdecl
&& !em
.depdecl
._scope
)
16185 em
.depdecl
._scope
= sc
;
16186 em
.checkDeprecated(loc
, sc
);
16189 return ErrorExp
.get();
16190 Expression e
= new VarExp(loc
, em
);
16191 e
= e
.expressionSemantic(sc
);
16192 if (!(sc
.flags
& SCOPE
.Cfile
) && em
.isCsymbol())
16194 /* C11 types them as int. But if in D file,
16195 * type qualified names as the enum
16197 e
.type
= em
.parent
.isEnumDeclaration().type
;
16204 /*****************************
16205 * Try to treat `exp` as a boolean,
16207 * exp = the expression
16208 * sc = scope to evalute `exp` in
16210 * Modified expression on success, ErrorExp on error
16212 Expression
toBoolean(Expression exp
, Scope
* sc
)
16217 error(exp
.loc
, "`delete` does not give a boolean result");
16218 return ErrorExp
.get();
16221 auto ce
= exp
.isCommaExp();
16222 auto ex2
= ce
.e2
.toBoolean(sc
);
16223 if (ex2
.op
== EXP
.error
)
16226 ce
.type
= ce
.e2
.type
;
16230 case EXP
.construct
:
16232 case EXP
.loweredAssignExp
:
16233 if (sc
.flags
& SCOPE
.Cfile
)
16237 // are usually mistakes.
16238 error(exp
.loc
, "assignment cannot be used as a condition, perhaps `==` was meant?");
16239 return ErrorExp
.get();
16244 auto le
= exp
.isLogicalExp();
16245 auto ex2
= le
.e2
.toBoolean(sc
);
16246 if (ex2
.op
== EXP
.error
)
16252 auto ce
= exp
.isCondExp();
16253 auto ex1
= ce
.e1
.toBoolean(sc
);
16254 auto ex2
= ce
.e2
.toBoolean(sc
);
16255 if (ex1
.op
== EXP
.error
)
16257 if (ex2
.op
== EXP
.error
)
16265 // Default is 'yes' - do nothing
16266 Expression e
= arrayFuncConv(exp
, sc
);
16268 Type tb
= t
.toBasetype();
16273 // Structs can be converted to bool using opCast(bool)()
16274 if (auto ts
= tb
.isTypeStruct())
16276 AggregateDeclaration ad
= ts
.sym
;
16277 /* Don't really need to check for opCast first, but by doing so we
16278 * get better error messages if it isn't there.
16280 if (Dsymbol fd
= search_function(ad
, Id
._cast
))
16282 e
= new CastExp(exp
.loc
, e
, Type
.tbool
);
16283 e
= e
.expressionSemantic(sc
);
16287 // Forward to aliasthis.
16288 if (ad
.aliasthis
&& !isRecursiveAliasThis(att
, tb
))
16290 e
= resolveAliasThis(sc
, e
);
16292 tb
= e
.type
.toBasetype();
16299 if (!t
.isBoolean())
16301 if (tb
!= Type
.terror
)
16302 error(exp
.loc
, "expression `%s` of type `%s` does not have a boolean value",
16303 exp
.toChars(), t
.toChars());
16304 return ErrorExp
.get();