2 * Semantic analysis of expressions.
4 * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions)
6 * Copyright: Copyright (C) 1999-2024 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
;
47 import dmd
.expression
;
48 import dmd
.file_manager
;
54 import dmd
.identifier
;
70 import dmd
.postordervisitor
;
71 import dmd
.root
.array
;
72 import dmd
.root
.ctfloat
;
73 import dmd
.root
.filename
;
74 import dmd
.common
.outbuffer
;
75 import dmd
.rootobject
;
76 import dmd
.root
.string
;
80 import dmd
.sideeffect
;
88 import dmd
.utils
: arrayCastBigEndian
;
91 enum LOGSEMANTIC
= false;
93 /***********************************
94 * Determine if a `this` is needed to access `d`.
97 * d = declaration to check
99 * true means a `this` is needed
101 private bool isNeedThisScope(Scope
* sc
, Declaration d
)
103 if (sc
.intypeof
== 1)
106 AggregateDeclaration ad
= d
.isThis();
109 //printf("d = %s, ad = %s\n", d.toChars(), ad.toChars());
111 for (Dsymbol s
= sc
.parent
; s
; s
= s
.toParentLocal())
113 //printf("\ts = %s %s, toParent2() = %p\n", s.kind(), s.toChars(), s.toParent2());
114 if (AggregateDeclaration ad2
= s
.isAggregateDeclaration())
118 else if (ad2
.isNested())
123 if (FuncDeclaration f
= s
.isFuncDeclaration())
125 if (f
.isMemberLocal())
133 /********************************************************
134 * Perform semantic analysis and CTFE on expressions to produce
137 * buf = append generated string to buffer
139 * exps = array of Expressions
143 bool expressionsToString(ref OutBuffer buf
, Scope
* sc
, Expressions
* exps
)
152 auto sc2
= sc
.startCTFE();
154 sc2
.minst
= null; // prevents emission of any instantiated templates to object file
155 auto e2
= ex
.expressionSemantic(sc2
);
156 auto e3
= resolveProperties(sc2
, e2
);
159 // allowed to contain types as well as expressions
160 auto e4
= ctfeInterpretForPragmaMsg(e3
);
161 if (!e4 || e4
.op
== EXP
.error
)
165 if (auto te
= e4
.isTupleExp())
167 if (expressionsToString(buf
, sc
, te
.exps
))
171 // char literals exp `.toStringExp` return `null` but we cant override it
172 // because in most contexts we don't want the conversion to succeed.
173 IntegerExp ie
= e4
.isIntegerExp();
174 const ty
= (ie
&& ie
.type
) ? ie
.type
.ty
: Terror
;
177 auto tsa
= new TypeSArray(ie
.type
, IntegerExp
.literal
!1);
178 e4
= new ArrayLiteralExp(ex
.loc
, tsa
, ie
);
181 if (StringExp se
= e4
.toStringExp())
182 buf
.writestring(se
.toUTF8(sc
).peekString());
184 buf
.writestring(e4
.toString());
189 /*****************************************
190 * Determine if `this` is available by walking up the enclosing
191 * scopes until a function is found.
194 * sc = where to start looking for the enclosing function
196 * Found function if it satisfies `isThis()`, otherwise `null`
198 FuncDeclaration
hasThis(Scope
* sc
)
200 //printf("hasThis()\n");
201 Dsymbol p
= sc
.parent
;
202 while (p
&& p
.isTemplateMixin())
204 FuncDeclaration fdthis
= p ? p
.isFuncDeclaration() : null;
205 //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis.toChars() : "");
207 // Go upwards until we find the enclosing member function
208 FuncDeclaration fd
= fdthis
;
215 if (!fd
.isNested() || fd
.isThis() ||
(fd
.hasDualContext() && fd
.isMember2()))
218 Dsymbol parent
= fd
.parent
;
223 TemplateInstance ti
= parent
.isTemplateInstance();
229 fd
= parent
.isFuncDeclaration();
232 if (!fd
.isThis() && !(fd
.hasDualContext() && fd
.isMember2()))
242 extern (D
) bool findTempDecl(DotTemplateInstanceExp exp
, Scope
* sc
)
246 static if (LOGSEMANTIC
)
248 printf("DotTemplateInstanceExp::findTempDecl('%s')\n", exp
.toChars());
253 Expression e
= new DotIdExp(exp
.loc
, e1
, ti
.name
);
254 e
= e
.expressionSemantic(sc
);
256 e
= (cast(DotExp
)e
).e2
;
261 case EXP
.overloadSet
:
262 s
= (cast(OverExp
)e
).vars
;
265 case EXP
.dotTemplateDeclaration
:
266 s
= (cast(DotTemplateExp
)e
).td
;
270 s
= (cast(ScopeExp
)e
).sds
;
273 case EXP
.dotVariable
:
274 s
= (cast(DotVarExp
)e
).var
;
278 s
= (cast(VarExp
)e
).var
;
284 return ti
.updateTempDecl(sc
, s
);
287 /***********************************************************
288 * Resolve `exp` as a compile-time known string.
291 * exp = Expression which expected as a string
292 * s = What the string is expected for, will be used in error diagnostic.
294 * String literal, or `null` if error happens.
296 StringExp
semanticString(Scope
*sc
, Expression exp
, const char* s
)
299 exp
= exp
.expressionSemantic(sc
);
300 exp
= resolveProperties(sc
, exp
);
303 if (exp
.op
== EXP
.error
)
307 if (exp
.type
.isString())
309 e
= e
.ctfeInterpret();
310 if (e
.op
== EXP
.error
)
314 auto se
= e
.toStringExp();
317 error(exp
.loc
, "`string` expected for %s, not `(%s)` of type `%s`",
318 s
, exp
.toChars(), exp
.type
.toChars());
324 /****************************************
325 * Convert string to char[].
327 StringExp
toUTF8(StringExp se
, Scope
* sc
)
331 // Convert to UTF-8 string
332 se
.committed
= false;
333 Expression e
= castTo(se
, sc
, Type
.tchar
.arrayOf());
334 e
= e
.optimize(WANTvalue
);
335 auto result
= e
.isStringExp();
336 assert(result
.sz
== 1);
342 private Expression
reorderSettingAAElem(BinExp exp
, Scope
* sc
)
346 auto ie
= be
.e1
.isIndexExp();
349 if (ie
.e1
.type
.toBasetype().ty
!= Taarray
)
352 /* Fix evaluation order of setting AA element
353 * https://issues.dlang.org/show_bug.cgi?id=3825
355 * aa[k1][k2][k3] op= val;
357 * auto ref __aatmp = aa;
358 * auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3;
359 * auto ref __aaval = val;
360 * __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval; // assignment
367 ie
.e2
= extractSideEffect(sc
, "__aakey", de, ie
.e2
);
368 e0
= Expression
.combine(de, e0
);
370 auto ie1
= ie
.e1
.isIndexExp();
372 ie1
.e1
.type
.toBasetype().ty
!= Taarray
)
378 assert(ie
.e1
.type
.toBasetype().ty
== Taarray
);
381 ie
.e1
= extractSideEffect(sc
, "__aatmp", de, ie
.e1
);
382 e0
= Expression
.combine(de, e0
);
384 be
.e2
= extractSideEffect(sc
, "__aaval", e0
, be
.e2
, true);
386 //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars());
387 return Expression
.combine(e0
, be
);
390 private Expression
checkOpAssignTypes(BinExp binExp
, Scope
* sc
)
395 auto type
= binExp
.type
;
396 auto loc
= binExp
.loc
;
398 // At that point t1 and t2 are the merged types. type is the original type of the lhs.
402 // T opAssign floating yields a floating. Prevent truncating conversions (float to int).
403 // See https://issues.dlang.org/show_bug.cgi?id=3841.
404 // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ?
405 if (op
== EXP
.addAssign || op
== EXP
.minAssign ||
406 op
== EXP
.mulAssign || op
== EXP
.divAssign || op
== EXP
.modAssign ||
409 if ((type
.isintegral() && t2
.isfloating()))
411 warning(loc
, "`%s %s %s` is performing truncating conversion", type
.toChars(), EXPtoString(op
).ptr
, t2
.toChars());
415 // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
416 if (op
== EXP
.mulAssign || op
== EXP
.divAssign || op
== EXP
.modAssign
)
418 // Any multiplication by an imaginary or complex number yields a complex result.
419 // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
420 const(char)* opstr
= EXPtoString(op
).ptr
;
421 if (t1
.isreal() && t2
.iscomplex())
423 error(loc
, "`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1
.toChars(), opstr
, t2
.toChars(), t1
.toChars(), opstr
, t2
.toChars());
424 return ErrorExp
.get();
426 else if (t1
.isimaginary() && t2
.iscomplex())
428 error(loc
, "`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1
.toChars(), opstr
, t2
.toChars(), t1
.toChars(), opstr
, t2
.toChars());
429 return ErrorExp
.get();
431 else if ((t1
.isreal() || t1
.isimaginary()) && t2
.isimaginary())
433 error(loc
, "`%s %s %s` is an undefined operation", t1
.toChars(), opstr
, t2
.toChars());
434 return ErrorExp
.get();
438 // generate an error if this is a nonsensical += or -=, eg real += imaginary
439 if (op
== EXP
.addAssign || op
== EXP
.minAssign
)
441 // Addition or subtraction of a real and an imaginary is a complex result.
442 // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
443 if ((t1
.isreal() && (t2
.isimaginary() || t2
.iscomplex())) ||
(t1
.isimaginary() && (t2
.isreal() || t2
.iscomplex())))
445 error(loc
, "`%s %s %s` is undefined (result is complex)", t1
.toChars(), EXPtoString(op
).ptr
, t2
.toChars());
446 return ErrorExp
.get();
448 if (type
.isreal() || type
.isimaginary())
450 assert(global
.errors || t2
.isfloating());
451 e2
= e2
.castTo(sc
, t1
);
454 if (op
== EXP
.mulAssign
)
460 if (t2
.isimaginary() || t2
.iscomplex())
462 e2
= e2
.castTo(sc
, t1
);
465 else if (t1
.isimaginary())
467 if (t2
.isimaginary() || t2
.iscomplex())
486 e2
= e2
.castTo(sc
, t2
);
491 else if (op
== EXP
.divAssign
)
493 if (t2
.isimaginary())
498 // Therefore, the result is 0
499 e2
= new CommaExp(loc
, e2
, new RealExp(loc
, CTFloat
.zero
, t1
));
501 Expression e
= new AssignExp(loc
, e1
, e2
);
505 else if (t1
.isimaginary())
525 e2
= e2
.castTo(sc
, t3
);
526 Expression e
= new AssignExp(loc
, e1
, e2
);
532 else if (op
== EXP
.modAssign
)
536 error(loc
, "cannot perform modulo complex arithmetic");
537 return ErrorExp
.get();
543 private Expression
extractOpDollarSideEffect(Scope
* sc
, UnaExp ue
)
546 Expression e1
= Expression
.extractLast(ue
.e1
, e0
);
547 // https://issues.dlang.org/show_bug.cgi?id=12585
548 // Extract the side effect part if ue.e1 is comma.
550 if ((sc
.flags
& SCOPE
.ctfe
) ?
hasSideEffect(e1
) : !isTrivialExp(e1
)) // match logic in extractSideEffect()
552 /* Even if opDollar is needed, 'e1' should be evaluate only once. So
554 * e1.opIndex( ... use of $ ... )
555 * e1.opSlice( ... use of $ ... )
557 * (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...)
558 * (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
560 e1
= extractSideEffect(sc
, "__dop", e0
, e1
, false);
561 assert(e1
.isVarExp());
562 e1
.isVarExp().var
.storage_class |
= STC
.exptemp
; // lifetime limited to expression
568 /****************************************
569 * Expand alias this tuples.
571 TupleDeclaration
isAliasThisTuple(Expression e
)
576 Type t
= e
.type
.toBasetype();
579 if (Dsymbol s
= t
.toDsymbol(null))
581 if (auto ad
= s
.isAggregateDeclaration())
583 s
= ad
.aliasthis ? ad
.aliasthis
.sym
: null;
584 if (s
&& s
.isVarDeclaration())
586 TupleDeclaration td
= s
.isVarDeclaration().toAlias().isTupleDeclaration();
590 if (Type att
= t
.aliasthisOf())
601 /**************************************
602 * Runs semantic on ae.arguments. Declares temporary variables
605 Expression
resolveOpDollar(Scope
* sc
, ArrayExp ae
, Expression
* pe0
)
607 assert(!ae
.lengthVar
);
609 AggregateDeclaration ad
= isAggregate(ae
.e1
.type
);
610 Dsymbol slice
= search_function(ad
, Id
.slice
);
611 //printf("slice = %s %s\n", slice.kind(), slice.toChars());
612 foreach (i
, e
; *ae
.arguments
)
615 *pe0
= extractOpDollarSideEffect(sc
, ae
);
617 if (e
.op
== EXP
.interval
&& !(slice
&& slice
.isTemplateDeclaration()))
620 if (ae
.arguments
.length
== 1)
622 error(ae
.loc
, "multi-dimensional slicing requires template `opSlice`");
623 return ErrorExp
.get();
625 //printf("[%d] e = %s\n", i, e.toChars());
627 // Create scope for '$' variable for this dimension
628 auto sym
= new ArrayScopeSymbol(sc
, ae
);
629 sym
.parent
= sc
.scopesym
;
631 ae
.lengthVar
= null; // Create it only if required
632 ae
.currentDimension
= i
; // Dimension for $, if required
634 e
= e
.expressionSemantic(sc
);
635 e
= resolveProperties(sc
, e
);
637 if (ae
.lengthVar
&& sc
.func
)
639 // If $ was used, declare it now
640 Expression
de = new DeclarationExp(ae
.loc
, ae
.lengthVar
);
641 de = de.expressionSemantic(sc
);
642 *pe0
= Expression
.combine(*pe0
, de);
646 if (auto ie
= e
.isIntervalExp())
648 auto tiargs
= new Objects();
649 Expression edim
= new IntegerExp(ae
.loc
, i
, Type
.tsize_t
);
650 edim
= edim
.expressionSemantic(sc
);
653 auto fargs
= new Expressions(2);
654 (*fargs
)[0] = ie
.lwr
;
655 (*fargs
)[1] = ie
.upr
;
657 uint xerrors
= global
.startGagging();
659 FuncDeclaration fslice
= resolveFuncCall(ae
.loc
, sc
, slice
, tiargs
, ae
.e1
.type
, ArgumentList(fargs
), FuncResolveFlag
.quiet
);
661 global
.endGagging(xerrors
);
665 e
= new DotTemplateInstanceExp(ae
.loc
, ae
.e1
, slice
.ident
, tiargs
);
666 e
= new CallExp(ae
.loc
, e
, fargs
);
667 e
= e
.expressionSemantic(sc
);
672 error(ae
.loc
, "`%s` has no value", e
.toChars());
675 if (e
.op
== EXP
.error
)
678 (*ae
.arguments
)[i
] = e
;
683 /**************************************
684 * Runs semantic on se.lwr and se.upr. Declares a temporary variable
687 * ae, or ErrorExp if errors occurred
689 Expression
resolveOpDollar(Scope
* sc
, ArrayExp ae
, IntervalExp ie
, Expression
* pe0
)
691 //assert(!ae.lengthVar);
695 VarDeclaration lengthVar
= ae
.lengthVar
;
698 // create scope for '$'
699 auto sym
= new ArrayScopeSymbol(sc
, ae
);
700 sym
.parent
= sc
.scopesym
;
703 Expression
sem(Expression e
)
705 e
= e
.expressionSemantic(sc
);
706 e
= resolveProperties(sc
, e
);
709 error(ae
.loc
, "`%s` has no value", e
.toChars());
715 ie
.lwr
= sem(ie
.lwr
);
716 ie
.upr
= sem(ie
.upr
);
718 if (ie
.lwr
.isErrorExp() || ie
.upr
.isErrorExp())
721 if (lengthVar
!= ae
.lengthVar
&& sc
.func
)
723 // If $ was used, declare it now
724 Expression
de = new DeclarationExp(ae
.loc
, ae
.lengthVar
);
725 de = de.expressionSemantic(sc
);
726 *pe0
= Expression
.combine(*pe0
, de);
731 return errors ? ErrorExp
.get() : ae
;
734 /******************************
735 * Perform semantic() on an array of Expressions.
737 extern(D
) bool arrayExpressionSemantic(
738 Expression
[] exps
, Scope
* sc
, bool preserveErrors
= false)
741 foreach (ref e
; exps
)
743 if (e
is null) continue;
744 auto e2
= e
.expressionSemantic(sc
);
745 if (e2
.op
== EXP
.error
)
747 if (preserveErrors || e2
.op
!= EXP
.error
)
753 /************************************************
754 * Handle the postblit call on lvalue, or the move of rvalue.
757 * sc = the scope where the expression is encountered
758 * e = the expression the needs to be moved or copied (source)
759 * t = if the struct defines a copy constructor, the type of the destination
762 * The expression that copy constructs or moves the value.
764 extern (D
) Expression
doCopyOrMove(Scope
*sc
, Expression e
, Type t
= null)
766 if (auto ce
= e
.isCondExp())
768 ce
.e1
= doCopyOrMove(sc
, ce
.e1
);
769 ce
.e2
= doCopyOrMove(sc
, ce
.e2
);
773 e
= e
.isLvalue() ?
callCpCtor(sc
, e
, t
) : valueNoDtor(e
);
778 /*********************************************
779 * If e is an instance of a struct, and that struct has a copy constructor,
783 * sc = just used to specify the scope of created temporary variable
784 * destinationType = the type of the object on which the copy constructor is called;
785 * may be null if the struct defines a postblit
787 private Expression
callCpCtor(Scope
* sc
, Expression e
, Type destinationType
)
789 if (auto ts
= e
.type
.baseElemOf().isTypeStruct())
791 StructDeclaration sd
= ts
.sym
;
792 if (sd
.postblit || sd
.hasCopyCtor
)
794 /* Create a variable tmp, and replace the argument e with:
796 * and let AssignExp() handle the construction.
797 * This is not the most efficient, ideally tmp would be constructed
798 * directly onto the stack.
800 auto tmp
= copyToTemp(STC
.rvalue
, "__copytmp", e
);
801 if (sd
.hasCopyCtor
&& destinationType
)
803 // https://issues.dlang.org/show_bug.cgi?id=22619
804 // If the destination type is inout we can preserve it
805 // only if inside an inout function; if we are not inside
806 // an inout function, then we will preserve the type of
808 if (destinationType
.hasWild
&& !(sc
.func
.storage_class
& STC
.wild
))
811 tmp
.type
= destinationType
;
813 tmp
.storage_class |
= STC
.nodtor
;
814 tmp
.dsymbolSemantic(sc
);
815 Expression
de = new DeclarationExp(e
.loc
, tmp
);
816 Expression ve
= new VarExp(e
.loc
, tmp
);
817 de.type
= Type
.tvoid
;
819 return Expression
.combine(de, ve
);
825 /************************************************
826 * If we want the value of this expression, but do not want to call
827 * the destructor on it.
829 Expression
valueNoDtor(Expression e
)
831 auto ex
= lastComma(e
);
833 if (auto ce
= ex
.isCallExp())
835 /* The struct value returned from the function is transferred
836 * so do not call the destructor on it.
838 * ((S _ctmp = S.init), _ctmp).this(...)
839 * and make sure the destructor is not called on _ctmp
840 * BUG: if ex is a CommaExp, we should go down the right side.
842 if (auto dve
= ce
.e1
.isDotVarExp())
844 if (dve
.var
.isCtorDeclaration())
846 // It's a constructor call
847 if (auto comma
= dve
.e1
.isCommaExp())
849 if (auto ve
= comma
.e2
.isVarExp())
851 VarDeclaration ctmp
= ve
.var
.isVarDeclaration();
854 ctmp
.storage_class |
= STC
.nodtor
;
855 assert(!ce
.isLvalue());
862 else if (auto ve
= ex
.isVarExp())
864 auto vtmp
= ve
.var
.isVarDeclaration();
865 if (vtmp
&& (vtmp
.storage_class
& STC
.rvalue
))
867 vtmp
.storage_class |
= STC
.nodtor
;
874 Checks if `exp` contains a direct access to a `noreturn`
875 variable. If that is the case, an `assert(0)` expression
876 is generated and returned. This function should be called
877 only after semantic analysis has been performed on `exp`.
880 exp = expression that is checked
883 An `assert(0)` expression if `exp` contains a `noreturn`
884 variable access, `exp` otherwise.
887 Expression
checkNoreturnVarAccess(Expression exp
)
891 Expression result
= exp
;
892 if (exp
.type
.isTypeNoreturn() && !exp
.isAssertExp() &&
893 !exp
.isThrowExp() && !exp
.isCallExp())
895 auto msg
= new StringExp(exp
.loc
, "Accessed expression of type `noreturn`");
896 msg
.type
= Type
.tstring
;
897 result
= new AssertExp(exp
.loc
, IntegerExp
.literal
!0, msg
);
898 result
.type
= exp
.type
;
904 /******************************
905 * Find symbol in accordance with the UFCS name look up rule
907 private Expression
searchUFCS(Scope
* sc
, UnaExp ue
, Identifier ident
)
909 //printf("searchUFCS(ident = %s)\n", ident.toChars());
912 // TODO: merge with Scope.search.searchScopes()
913 Dsymbol
searchScopes(SearchOptFlags flags
)
916 for (Scope
* scx
= sc
; scx
; scx
= scx
.enclosing
)
920 if (scx
.scopesym
.isModule())
921 flags |
= SearchOpt
.unqualifiedModule
; // tell Module.search() that SearchOpt.localsOnly is to be obeyed
922 s
= scx
.scopesym
.search(loc
, ident
, flags
);
925 // overload set contains only module scope symbols.
926 if (s
.isOverloadSet())
928 // selective/renamed imports also be picked up
929 if (AliasDeclaration ad
= s
.isAliasDeclaration())
934 // See only module scope symbols for UFCS target.
935 Dsymbol p
= s
.toParent2();
936 if (p
&& p
.isModule())
941 // Stop when we hit a module, but keep going if that is not just under the global scope
942 if (scx
.scopesym
.isModule() && !(scx
.enclosing
&& !scx
.enclosing
.enclosing
))
948 SearchOptFlags flags
= SearchOpt
.all
;
951 if (sc
.flags
& SCOPE
.ignoresymbolvisibility
)
952 flags |
= SearchOpt
.ignoreVisibility
;
954 // First look in local scopes
955 s
= searchScopes(flags | SearchOpt
.localsOnly
);
958 // Second look in imported modules
959 s
= searchScopes(flags | SearchOpt
.importsOnly
);
963 return ue
.e1
.type
.getProperty(sc
, loc
, ident
, 0, ue
.e1
);
965 FuncDeclaration f
= s
.isFuncDeclaration();
968 TemplateDeclaration td
= getFuncTemplateDecl(f
);
977 if (auto dti
= ue
.isDotTemplateInstanceExp())
979 // https://issues.dlang.org/show_bug.cgi?id=23968
980 // Typically, deprecated alias declarations are caught
981 // when `TemplateInstance.findTempDecl` is called,
982 // however, in this case the tempdecl field is updated
983 // therefore `findTempDecl` will return immediately
984 // and not get the chance to issue the deprecation.
985 if (s
.isAliasDeclaration())
986 s
.checkDeprecated(ue
.loc
, sc
);
988 auto ti
= new TemplateInstance(loc
, s
.ident
, dti
.ti
.tiargs
);
989 if (!ti
.updateTempDecl(sc
, s
))
990 return ErrorExp
.get();
991 return new ScopeExp(loc
, ti
);
995 //printf("-searchUFCS() %s\n", s.toChars());
996 return new DsymbolExp(loc
, s
);
1000 /******************************
1001 * check e is exp.opDispatch!(tiargs) or not
1002 * It's used to switch to UFCS the semantic analysis path
1004 private bool isDotOpDispatch(Expression e
)
1006 if (auto dtie
= e
.isDotTemplateInstanceExp())
1007 return dtie
.ti
.name
== Id
.opDispatch
;
1011 private void hookDtors(CondExp ce
, Scope
* sc
)
1013 extern (C
++) final class DtorVisitor
: StoppableVisitor
1015 alias visit
= typeof(super).visit
;
1019 VarDeclaration vcond
;
1022 extern (D
) this(Scope
* sc
, CondExp ce
) @safe
1028 override void visit(Expression e
)
1030 //printf("(e = %s)\n", e.toChars());
1033 override void visit(DeclarationExp e
)
1035 auto v
= e
.declaration
.isVarDeclaration();
1036 if (v
&& !v
.isDataseg())
1040 if (auto ei
= v
._init
.isExpInitializer())
1041 walkPostorder(ei
.exp
, this);
1045 walkPostorder(v
.edtor
, this);
1047 if (v
.needsScopeDtor())
1051 vcond
= copyToTemp(STC
.volatile_ | STC
.const_
, "__cond", ce
.econd
);
1052 vcond
.dsymbolSemantic(sc
);
1054 Expression
de = new DeclarationExp(ce
.econd
.loc
, vcond
);
1055 de = de.expressionSemantic(sc
);
1057 Expression ve
= new VarExp(ce
.econd
.loc
, vcond
);
1058 ce
.econd
= Expression
.combine(de, ve
);
1061 //printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
1062 Expression ve
= new VarExp(vcond
.loc
, vcond
);
1064 v
.edtor
= new LogicalExp(v
.edtor
.loc
, EXP
.andAnd
, ve
, v
.edtor
);
1066 v
.edtor
= new LogicalExp(v
.edtor
.loc
, EXP
.orOr
, ve
, v
.edtor
);
1067 v
.edtor
= v
.edtor
.expressionSemantic(sc
);
1068 //printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
1074 scope DtorVisitor v
= new DtorVisitor(sc
, ce
);
1075 //printf("+%s\n", toChars());
1077 walkPostorder(ce
.e1
, v
);
1079 walkPostorder(ce
.e2
, v
);
1080 //printf("-%s\n", toChars());
1084 /******************************
1085 * Pull out callable entity with UFCS.
1087 private Expression
resolveUFCS(Scope
* sc
, CallExp ce
)
1093 if (auto die
= ce
.e1
.isDotIdExp())
1095 Identifier ident
= die
.ident
;
1097 Expression ex
= die
.dotIdSemanticPropX(sc
);
1105 Type t
= eleft
.type
.toBasetype();
1106 if (t
.ty
== Tarray || t
.ty
== Tsarray || t
.ty
== Tnull ||
(t
.isTypeBasic() && t
.ty
!= Tvoid
))
1108 /* Built-in types and arrays have no callable properties, so do shortcut.
1109 * It is necessary in: e.init()
1112 else if (t
.ty
== Taarray
)
1114 if (ident
== Id
.remove
)
1117 * aa.remove(arg) into delete aa[arg]
1119 if (!ce
.arguments || ce
.arguments
.length
!= 1)
1121 error(ce
.loc
, "expected key as argument to `aa.remove()`");
1122 return ErrorExp
.get();
1124 if (!eleft
.type
.isMutable())
1126 error(ce
.loc
, "cannot remove key from `%s` associative array `%s`", MODtoChars(t
.mod
), eleft
.toChars());
1127 return ErrorExp
.get();
1129 Expression key
= (*ce
.arguments
)[0];
1130 key
= key
.expressionSemantic(sc
);
1131 key
= resolveProperties(sc
, key
);
1133 TypeAArray taa
= t
.isTypeAArray();
1134 key
= key
.implicitCastTo(sc
, taa
.index
);
1136 if (key
.checkValue() || key
.checkSharedAccess(sc
))
1137 return ErrorExp
.get();
1139 semanticTypeInfo(sc
, taa
.index
);
1141 return new RemoveExp(loc
, eleft
, key
);
1146 if (Expression ey
= die
.dotIdSemanticProp(sc
, 1))
1148 if (ey
.op
== EXP
.error
)
1151 if (isDotOpDispatch(ey
))
1153 // even opDispatch and UFCS must have valid arguments,
1154 // so now that we've seen indication of a problem,
1155 // check them for issues.
1156 Expressions
* originalArguments
= Expression
.arraySyntaxCopy(ce
.arguments
);
1158 uint errors
= global
.startGagging();
1159 e
= ce
.expressionSemantic(sc
);
1160 if (!global
.endGagging(errors
))
1163 if (arrayExpressionSemantic(originalArguments
.peekSlice(), sc
))
1164 return ErrorExp
.get();
1166 /* fall down to UFCS */
1173 /* https://issues.dlang.org/show_bug.cgi?id=13953
1175 * If a struct has an alias this to an associative array
1176 * and remove is used on a struct instance, we have to
1177 * check first if there is a remove function that can be called
1178 * on the struct. If not we must check the alias this.
1192 const errors
= global
.startGagging();
1193 e
= searchUFCS(sc
, die
, ident
);
1194 // if there were any errors and the identifier was remove
1195 if (global
.endGagging(errors
))
1197 if (ident
== Id
.remove
)
1200 Expression alias_e
= resolveAliasThis(sc
, die
.e1
, 1);
1201 if (alias_e
&& alias_e
!= die
.e1
)
1204 CallExp ce2
= ce
.syntaxCopy();
1206 e
= ce2
.isCallExp().trySemantic(sc
);
1211 // if alias this did not work out, print the initial errors
1212 searchUFCS(sc
, die
, ident
);
1215 else if (auto dti
= ce
.e1
.isDotTemplateInstanceExp())
1217 if (Expression ey
= dti
.dotTemplateSemanticProp(sc
, DotExpFlag
.gag
))
1223 e
= searchUFCS(sc
, dti
, dti
.ti
.name
);
1231 ce
.arguments
= new Expressions();
1232 ce
.arguments
.shift(eleft
);
1234 ce
.names
= new Identifiers();
1235 ce
.names
.shift(null);
1236 ce
.isUfcsRewrite
= true;
1240 int expandAliasThisTuples(Expressions
* exps
, size_t starti
= 0)
1242 if (!exps || exps
.length
== 0)
1245 for (size_t u
= starti
; u
< exps
.length
; u
++)
1247 Expression exp
= (*exps
)[u
];
1248 if (TupleDeclaration td
= exp
.isAliasThisTuple
)
1254 auto d
= s
.isDeclaration();
1255 auto e
= new DotVarExp(exp
.loc
, exp
, d
);
1258 exps
.insert(u
+ i
, e
);
1263 printf("expansion ->\n");
1266 printf("\texps[%d] e = %s %s\n", i
, EXPtoString(e
.op
), e
.toChars());
1275 /******************************
1276 * Pull out property with UFCS.
1278 private Expression
resolveUFCSProperties(Scope
* sc
, Expression e1
, Expression e2
= null)
1284 if (auto die
= e1
.isDotIdExp())
1287 e
= searchUFCS(sc
, die
, die
.ident
);
1289 else if (auto dti
= e1
.isDotTemplateInstanceExp())
1292 e
= searchUFCS(sc
, dti
, dti
.ti
.name
);
1303 // run semantic without gagging
1304 e2
= e2
.expressionSemantic(sc
);
1308 Expression ex
= e
.copy();
1309 auto a1
= new Expressions(1);
1311 ex
= new CallExp(loc
, ex
, a1
);
1312 auto e1PassSemantic
= ex
.trySemantic(sc
);
1316 auto a2
= new Expressions(2);
1319 e
= new CallExp(loc
, e
, a2
);
1320 e
= e
.trySemantic(sc
);
1321 if (!e1PassSemantic
&& !e
)
1323 /* https://issues.dlang.org/show_bug.cgi?id=20448
1325 * If both versions have failed to pass semantic,
1326 * f(e1) = e2 gets priority in error printing
1327 * because f might be a templated function that
1328 * failed to instantiate and we have to print
1329 * the instantiation errors.
1331 return e1
.expressionSemantic(sc
);
1335 ex
= new AssignExp(loc
, ex
, e2
);
1336 return ex
.expressionSemantic(sc
);
1340 // strict setter prints errors if fails
1341 e
= e
.expressionSemantic(sc
);
1349 auto arguments
= new Expressions(1);
1350 (*arguments
)[0] = eleft
;
1351 e
= new CallExp(loc
, e
, arguments
);
1353 // https://issues.dlang.org/show_bug.cgi?id=24017
1354 if (sc
.flags
& SCOPE
.debug_
)
1355 e
.isCallExp().inDebugStatement
= true;
1357 e
= e
.expressionSemantic(sc
);
1362 /******************************
1363 * If e1 is a property function (template), resolve it.
1365 Expression
resolvePropertiesOnly(Scope
* sc
, Expression e1
)
1367 //printf("e1 = %s %s\n", Token.toChars(e1.op), e1.toChars());
1369 Expression
handleOverloadSet(OverloadSet os
)
1374 auto fd
= s
.isFuncDeclaration();
1375 auto td
= s
.isTemplateDeclaration();
1378 if (fd
.type
.isTypeFunction().isproperty
)
1379 return resolveProperties(sc
, e1
);
1381 else if (td
&& td
.onemember
&& (fd
= td
.onemember
.isFuncDeclaration()) !is null)
1383 if (fd
.type
.isTypeFunction().isproperty ||
1384 (fd
.storage_class2
& STC
.property
) ||
1385 (td
._scope
.stc & STC
.property
))
1386 return resolveProperties(sc
, e1
);
1392 Expression
handleTemplateDecl(TemplateDeclaration td
)
1397 if (auto fd
= td
.onemember
.isFuncDeclaration())
1399 if (fd
.type
.isTypeFunction().isproperty ||
1400 (fd
.storage_class2
& STC
.property
) ||
1401 (td
._scope
.stc & STC
.property
))
1402 return resolveProperties(sc
, e1
);
1408 Expression
handleFuncDecl(FuncDeclaration fd
)
1411 if (fd
.type
.isTypeFunction().isproperty
)
1412 return resolveProperties(sc
, e1
);
1416 if (auto de = e1
.isDotExp())
1418 if (auto os
= de.e2
.isOverExp())
1419 return handleOverloadSet(os
.vars
);
1421 else if (auto oe
= e1
.isOverExp())
1422 return handleOverloadSet(oe
.vars
);
1423 else if (auto dti
= e1
.isDotTemplateInstanceExp())
1425 if (dti
.ti
.tempdecl
)
1426 if (auto td
= dti
.ti
.tempdecl
.isTemplateDeclaration())
1427 return handleTemplateDecl(td
);
1429 else if (auto dte
= e1
.isDotTemplateExp())
1430 return handleTemplateDecl(dte
.td
);
1431 else if (auto se
= e1
.isScopeExp())
1434 TemplateInstance ti
= s
.isTemplateInstance();
1435 if (ti
&& !ti
.semanticRun
&& ti
.tempdecl
)
1436 if (auto td
= ti
.tempdecl
.isTemplateDeclaration())
1437 return handleTemplateDecl(td
);
1439 else if (auto et
= e1
.isTemplateExp())
1440 return handleTemplateDecl(et
.td
);
1441 else if (e1
.isDotVarExp() && e1
.type
.isTypeFunction())
1443 DotVarExp dve
= e1
.isDotVarExp();
1444 return handleFuncDecl(dve
.var
.isFuncDeclaration());
1446 else if (e1
.isVarExp() && e1
.type
&& e1
.type
.isTypeFunction() && (sc
.intypeof ||
!e1
.isVarExp().var
.needThis()))
1447 return handleFuncDecl(e1
.isVarExp().var
.isFuncDeclaration());
1451 /****************************************
1452 * Turn symbol `s` into the expression it represents.
1455 * s = symbol to resolve
1456 * loc = location of use of `s`
1458 * hasOverloads = applies if `s` represents a function.
1459 * true means it's overloaded and will be resolved later,
1460 * false means it's the exact function symbol.
1462 * `s` turned into an expression, `ErrorExp` if an error occurred
1464 Expression
symbolToExp(Dsymbol s
, const ref Loc loc
, Scope
*sc
, bool hasOverloads
)
1466 static if (LOGSEMANTIC
)
1468 printf("DsymbolExp::resolve(%s %s)\n", s
.kind(), s
.toChars());
1474 //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars());
1475 //printf("s = '%s', s.kind = '%s'\n", s.toChars(), s.kind());
1477 Declaration d
= s
.isDeclaration();
1478 if (d
&& (d
.storage_class
& STC
.templateparameter
))
1484 // functions are checked after overloading
1485 // templates are checked after matching constraints
1486 if (!s
.isFuncDeclaration() && !s
.isTemplateDeclaration())
1488 s
.checkDeprecated(loc
, sc
);
1490 d
.checkDisabled(loc
, sc
);
1493 // https://issues.dlang.org/show_bug.cgi?id=12023
1494 // if 's' is a tuple variable, the tuple is returned.
1497 //printf("s = '%s', s.kind = '%s', s.needThis() = %p\n", s.toChars(), s.kind(), s.needThis());
1498 if (s
!= olds
&& !s
.isFuncDeclaration() && !s
.isTemplateDeclaration())
1500 s
.checkDeprecated(loc
, sc
);
1502 d
.checkDisabled(loc
, sc
);
1505 if (auto sd
= s
.isDeclaration())
1509 if (sc
.setUnsafePreview(global
.params
.systemVariables
, false, loc
,
1510 "cannot access `@system` variable `%s` in @safe code", sd
))
1512 if (auto v
= sd
.isVarDeclaration())
1514 if (v
.systemInferred
)
1515 errorSupplemental(v
.loc
, "`%s` is inferred to be `@system` from its initializer here", v
.toChars());
1517 errorSupplemental(v
.loc
, "`%s` is declared here", v
.toChars());
1519 return ErrorExp
.get();
1525 if (auto em
= s
.isEnumMember())
1527 return em
.getVarExp(loc
, sc
);
1529 if (auto v
= s
.isVarDeclaration())
1531 //printf("Identifier '%s' is a variable, type '%s'\n", s.toChars(), v.type.toChars());
1532 if (sc
.intypeof
== 1 && !v
.inuse
)
1533 v
.dsymbolSemantic(sc
);
1534 if (!v
.type ||
// during variable type inference
1535 !v
.type
.deco
&& v
.inuse
) // during variable type semantic
1537 if (v
.inuse
) // variable type depends on the variable itself
1538 error(loc
, "circular reference to %s `%s`", v
.kind(), v
.toPrettyChars());
1539 else // variable type cannot be determined
1540 error(loc
, "forward reference to %s `%s`", v
.kind(), v
.toPrettyChars());
1541 return ErrorExp
.get();
1543 if (v
.type
.ty
== Terror
)
1544 return ErrorExp
.get();
1546 if ((v
.storage_class
& STC
.manifest
) && v
._init
)
1550 error(loc
, "circular initialization of %s `%s`", v
.kind(), v
.toPrettyChars());
1551 return ErrorExp
.get();
1553 e
= v
.expandInitializer(loc
);
1555 e
= e
.expressionSemantic(sc
);
1560 // We need to run semantics to correctly set 'STC.field' if it is a member variable
1561 // that could be forward referenced. This is needed for 'v.needThis()' to work
1563 v
.dsymbolSemantic(sc
);
1565 // Change the ancestor lambdas to delegate before hasThis(sc) call.
1566 if (v
.checkNestedReference(sc
, loc
))
1567 return ErrorExp
.get();
1569 if (v
.needThis() && hasThis(sc
))
1570 e
= new DotVarExp(loc
, new ThisExp(loc
), v
);
1572 e
= new VarExp(loc
, v
);
1573 e
= e
.expressionSemantic(sc
);
1576 if (auto fld = s
.isFuncLiteralDeclaration())
1578 //printf("'%s' is a function literal\n", fld.toChars());
1579 e
= new FuncExp(loc
, fld);
1580 return e
.expressionSemantic(sc
);
1582 if (auto f
= s
.isFuncDeclaration())
1584 f
= f
.toAliasFunc();
1585 if (!functionSemantic(f
))
1586 return ErrorExp
.get();
1588 if (!hasOverloads
&& f
.checkForwardRef(loc
))
1589 return ErrorExp
.get();
1591 auto fd
= s
.isFuncDeclaration();
1593 return new VarExp(loc
, fd
, hasOverloads
);
1595 if (OverDeclaration od
= s
.isOverDeclaration())
1597 e
= new VarExp(loc
, od
, true);
1598 e
.type
= Type
.tvoid
;
1601 if (OverloadSet o
= s
.isOverloadSet())
1603 //printf("'%s' is an overload set\n", o.toChars());
1604 return new OverExp(loc
, o
);
1607 if (Import imp
= s
.isImport())
1611 .error(loc
, "forward reference of import `%s`", imp
.toChars());
1612 return ErrorExp
.get();
1614 auto ie
= new ScopeExp(loc
, imp
.pkg
);
1615 return ie
.expressionSemantic(sc
);
1617 if (Package pkg
= s
.isPackage())
1619 auto ie
= new ScopeExp(loc
, pkg
);
1620 return ie
.expressionSemantic(sc
);
1622 if (Module mod
= s
.isModule())
1624 auto ie
= new ScopeExp(loc
, mod
);
1625 return ie
.expressionSemantic(sc
);
1627 if (Nspace ns
= s
.isNspace())
1629 auto ie
= new ScopeExp(loc
, ns
);
1630 return ie
.expressionSemantic(sc
);
1633 if (Type t
= s
.getType())
1635 return (new TypeExp(loc
, t
)).expressionSemantic(sc
);
1638 if (TupleDeclaration tup
= s
.isTupleDeclaration())
1640 if (tup
.needThis() && hasThis(sc
))
1641 e
= new DotVarExp(loc
, new ThisExp(loc
), tup
);
1643 e
= new TupleExp(loc
, tup
);
1644 e
= e
.expressionSemantic(sc
);
1648 if (TemplateInstance ti
= s
.isTemplateInstance())
1650 ti
.dsymbolSemantic(sc
);
1651 if (!ti
.inst || ti
.errors
)
1652 return ErrorExp
.get();
1654 if (!s
.isTemplateInstance())
1656 e
= new ScopeExp(loc
, ti
);
1657 e
= e
.expressionSemantic(sc
);
1660 if (TemplateDeclaration td
= s
.isTemplateDeclaration())
1662 Dsymbol p
= td
.toParentLocal();
1663 FuncDeclaration fdthis
= hasThis(sc
);
1664 AggregateDeclaration ad
= p ? p
.isAggregateDeclaration() : null;
1665 if (fdthis
&& ad
&& fdthis
.isMemberLocal() == ad
&& (td
._scope
.stc & STC
.static_
) == 0)
1667 e
= new DotTemplateExp(loc
, new ThisExp(loc
), td
);
1670 e
= new TemplateExp(loc
, td
);
1671 e
= e
.expressionSemantic(sc
);
1675 .error(loc
, "%s `%s` is not a variable", s
.kind(), s
.toChars());
1676 return ErrorExp
.get();
1679 /*************************************************************
1680 * Given var, get the
1681 * right `this` pointer if var is in an outer class, but our
1682 * existing `this` pointer is in an inner class.
1684 * loc = location to use for error messages
1686 * ad = struct or class we need the correct `this` for
1687 * e1 = existing `this`
1688 * var = the specific member of ad we're accessing
1689 * flag = if true, return `null` instead of throwing an error
1691 * Expression representing the `this` for the var
1693 private Expression
getRightThis(const ref Loc loc
, Scope
* sc
, AggregateDeclaration ad
, Expression e1
, Dsymbol var
, int flag
= 0)
1695 //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars());
1697 Type t
= e1
.type
.toBasetype();
1698 //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars());
1700 if (e1
.op
== EXP
.objcClassReference
)
1702 // We already have an Objective-C class reference, just use that as 'this'.
1705 else if (ad
&& ad
.isClassDeclaration
&& ad
.isClassDeclaration
.classKind
== ClassKind
.objc
&&
1706 var
.isFuncDeclaration
&& var
.isFuncDeclaration
.isStatic
&&
1707 var
.isFuncDeclaration
.objc
.selector
)
1709 auto cls
= ad
.isClassDeclaration();
1710 auto classObj
= new ObjcClassReferenceExp(e1
.loc
, cls
);
1711 classObj
.type
= objc
.getRuntimeMetaclass(cls
).getType();
1715 /* Access of a member which is a template parameter in dual-scope scenario
1716 * class A { inc(alias m)() { ++m; } } // `m` needs `this` of `B`
1717 * class B {int m; inc() { new A().inc!m(); } }
1719 if (e1
.op
== EXP
.this_
)
1721 FuncDeclaration f
= hasThis(sc
);
1722 if (f
&& f
.hasDualContext())
1724 if (f
.followInstantiationContext(ad
))
1726 e1
= new VarExp(loc
, f
.vthis
);
1727 e1
= new PtrExp(loc
, e1
);
1728 e1
= new IndexExp(loc
, e1
, IntegerExp
.literal
!1);
1729 e1
= getThisSkipNestedFuncs(loc
, sc
, f
.toParent2(), ad
, e1
, t
, var
);
1730 if (e1
.op
== EXP
.error
)
1737 /* If e1 is not the 'this' pointer for ad
1740 !(t
.isTypePointer() && t
.nextOf().isTypeStruct() && t
.nextOf().isTypeStruct().sym
== ad
) &&
1741 !(t
.isTypeStruct() && t
.isTypeStruct().sym
== ad
))
1743 ClassDeclaration cd
= ad
.isClassDeclaration();
1744 ClassDeclaration tcd
= t
.isClassHandle();
1746 /* e1 is the right this if ad is a base class of e1
1748 if (!cd ||
!tcd ||
!(tcd
== cd || cd
.isBaseOf(tcd
, null)))
1750 /* Only classes can be inner classes with an 'outer'
1751 * member pointing to the enclosing class instance
1753 if (tcd
&& tcd
.isNested())
1755 /* e1 is the 'this' pointer for an inner class: tcd.
1756 * Rewrite it as the 'this' pointer for the outer class.
1758 auto vthis
= tcd
.followInstantiationContext(ad
) ? tcd
.vthis2
: tcd
.vthis
;
1759 e1
= new DotVarExp(loc
, e1
, vthis
);
1760 e1
.type
= vthis
.type
;
1761 e1
.type
= e1
.type
.addMod(t
.mod
);
1762 // Do not call ensureStaticLinkTo()
1763 //e1 = e1.semantic(sc);
1765 // Skip up over nested functions, and get the enclosing
1767 e1
= getThisSkipNestedFuncs(loc
, sc
, tcd
.toParentP(ad
), ad
, e1
, t
, var
);
1768 if (e1
.op
== EXP
.error
)
1773 /* Can't find a path from e1 to ad
1777 error(e1
.loc
, "`this` for `%s` needs to be type `%s` not type `%s`", var
.toChars(), ad
.toChars(), t
.toChars());
1778 return ErrorExp
.get();
1785 * Check whether `outerFunc` and `calledFunc` have the same `this`.
1786 * If `calledFunc` is the member of a base class of the class that contains
1787 * `outerFunc` we consider that they have the same this.
1789 * This function is used to test whether `this` needs to be prepended to
1790 * a function call or function symbol. For example:
1806 * When `fun` is called, `outerfunc` = `sun` and `calledFunc = `fun`.
1807 * `sun` is a member of `A` and `fun` is also a member of `A`, therefore
1808 * `this` can be prepended to `fun`. When `gun` is called (it will result
1809 * in an error, but that is not relevant here), which is a member of `X`,
1810 * no `this` is needed because the outer function does not have the same
1814 * `true` if outerFunc and calledFunc may use the same `this` pointer.
1815 * `false` otherwise.
1817 private bool haveSameThis(FuncDeclaration outerFunc
, FuncDeclaration calledFunc
)
1819 // https://issues.dlang.org/show_bug.cgi?id=24013
1820 // traits(getOverloads) inserts an alias to select the overload.
1821 // When searching for the right this we need to use the aliased
1822 // overload/function, not the alias.
1823 outerFunc
= outerFunc
.toAliasFunc();
1824 calledFunc
= calledFunc
.toAliasFunc();
1826 auto thisAd
= outerFunc
.isMemberLocal();
1830 auto requiredAd
= calledFunc
.isMemberLocal();
1834 if (thisAd
== requiredAd
)
1837 // if outerfunc is the member of a nested aggregate, then let
1838 // getRightThis take care of this.
1839 if (thisAd
.isNested())
1842 // outerfunc is the member of a base class that contains calledFunc,
1843 // then we consider that they have the same this.
1844 auto cd
= requiredAd
.isClassDeclaration();
1848 if (cd
.isBaseOf2(thisAd
.isClassDeclaration()))
1854 /*********************************************
1855 * Calling function f.
1856 * Check the purity, i.e. if we're in a pure function
1857 * we can only call other pure functions.
1858 * Returns true if error occurs.
1860 private bool checkPurity(FuncDeclaration f
, const ref Loc loc
, Scope
* sc
)
1866 if (sc
.intypeof
== 1)
1868 if (sc
.flags
& (SCOPE
.ctfe | SCOPE
.debug_
))
1871 // If the call has a pure parent, then the called func must be pure.
1872 if (!f
.isPure() && checkImpure(sc
, loc
, null, f
))
1874 error(loc
, "`pure` %s `%s` cannot call impure %s `%s`",
1875 sc
.func
.kind(), sc
.func
.toPrettyChars(), f
.kind(),
1878 if (!f
.isDtorDeclaration())
1879 errorSupplementalInferredAttr(f
, /*max depth*/ 10, /*deprecation*/ false, STC
.pure_
);
1881 f
.checkOverriddenDtor(sc
, loc
, dd => dd.type
.toTypeFunction().purity
!= PURE
.impure
, "impure");
1888 * Checks whether `f` is a generated `DtorDeclaration` that hides a user-defined one
1889 * which passes `check` while `f` doesn't (e.g. when the user defined dtor is pure but
1890 * the generated dtor is not).
1891 * In that case the method will identify and print all members causing the attribute
1895 * f = potential `DtorDeclaration`
1898 * check = current check (e.g. whether it's pure)
1899 * checkName = the kind of check (e.g. `"pure"`)
1901 void checkOverriddenDtor(FuncDeclaration f
, Scope
* sc
, const ref Loc loc
,
1902 scope bool function(DtorDeclaration
) check
, const string checkName
)
1904 auto dd = f
.isDtorDeclaration();
1905 if (!dd ||
!dd.isGenerated())
1908 // DtorDeclaration without parents should fail at an earlier stage
1909 auto ad
= cast(AggregateDeclaration
) f
.toParent2();
1912 if (ad
.userDtors
.length
)
1914 if (!check(ad
.userDtors
[0])) // doesn't match check (e.g. is impure as well)
1918 assert(!check(ad
.fieldDtor
));
1921 dd.loc
.errorSupplemental("%s`%s.~this` is %.*s because of the following field's destructors:",
1922 dd.isGenerated() ?
"generated " : "".ptr
,
1924 cast(int) checkName
.length
, checkName
.ptr
);
1926 // Search for the offending fields
1927 foreach (field
; ad
.fields
)
1929 // Only structs may define automatically called destructors
1930 auto ts
= field
.type
.isTypeStruct();
1933 // But they might be part of a static array
1934 auto ta
= field
.type
.isTypeSArray();
1938 ts
= ta
.baseElemOf().isTypeStruct();
1943 auto fieldSym
= ts
.toDsymbol(sc
);
1944 assert(fieldSym
); // Resolving ts must succeed because missing defs. should error before
1946 auto fieldSd
= fieldSym
.isStructDeclaration();
1947 assert(fieldSd
); // ts is a TypeStruct, this would imply a malformed ASR
1949 if (fieldSd
.dtor
&& !check(fieldSd
.dtor
))
1951 field
.loc
.errorSupplemental(" - %s %s", field
.type
.toChars(), field
.toChars());
1953 if (fieldSd
.dtor
.isGenerated())
1954 fieldSd
.dtor
.checkOverriddenDtor(sc
, loc
, check
, checkName
);
1956 fieldSd
.dtor
.loc
.errorSupplemental(" %.*s `%s.~this` is declared here",
1957 cast(int) checkName
.length
, checkName
.ptr
, fieldSd
.toChars());
1962 /*******************************************
1963 * Accessing variable v.
1964 * Check for purity and safety violations.
1965 * Returns true if error occurs.
1967 private bool checkPurity(VarDeclaration v
, const ref Loc loc
, Scope
* sc
)
1969 //printf("v = %s %s\n", v.type.toChars(), v.toChars());
1970 /* Look for purity and safety violations when accessing variable v
1971 * from current function.
1975 if (sc
.intypeof
== 1)
1976 return false; // allow violations inside typeof(expression)
1977 if (sc
.flags
& (SCOPE
.ctfe | SCOPE
.debug_
))
1978 return false; // allow violations inside compile-time evaluated expressions and debug conditionals
1979 if (v
.ident
== Id
.ctfe
)
1980 return false; // magic variable never violates pure and safe
1981 if (v
.isImmutable())
1982 return false; // always safe and pure to access immutables...
1983 if (v
.isConst() && !v
.isReference() && (v
.isDataseg() || v
.isParameter()) && v
.type
.implicitConvTo(v
.type
.immutableOf()))
1984 return false; // or const global/parameter values which have no mutable indirections
1985 if (v
.storage_class
& STC
.manifest
)
1986 return false; // ...or manifest constants
1988 // accessing empty structs is pure
1989 // https://issues.dlang.org/show_bug.cgi?id=18694
1990 // https://issues.dlang.org/show_bug.cgi?id=21464
1991 // https://issues.dlang.org/show_bug.cgi?id=23589
1992 if (v
.type
.ty
== Tstruct
)
1994 StructDeclaration sd
= (cast(TypeStruct
)v
.type
).sym
;
1995 if (sd
.members
) // not opaque
1997 if (sd
.semanticRun
>= PASS
.semanticdone
)
1998 sd
.determineSize(v
.loc
);
2007 // https://issues.dlang.org/show_bug.cgi?id=7533
2008 // Accessing implicit generated __gate is pure.
2009 if (v
.ident
== Id
.gate
)
2012 if (checkImpure(sc
, loc
, "`pure` %s `%s` cannot access mutable static data `%s`", v
))
2014 error(loc
, "`pure` %s `%s` cannot access mutable static data `%s`",
2015 sc
.func
.kind(), sc
.func
.toPrettyChars(), v
.toChars());
2026 * /+pure+/ void h() {
2028 * /+pure+/ void i() { }
2032 * i() can modify hx and gx but not fx
2035 Dsymbol vparent
= v
.toParent2();
2036 for (Dsymbol s
= sc
.func
; !err
&& s
; s
= s
.toParentP(vparent
))
2041 if (AggregateDeclaration ad
= s
.isAggregateDeclaration())
2047 FuncDeclaration ff
= s
.isFuncDeclaration();
2050 if (ff
.isNested() || ff
.isThis())
2052 if (ff
.type
.isImmutable() ||
2053 ff
.type
.isShared() && !MODimplicitConv(ff
.type
.mod
, v
.type
.mod
))
2057 MODMatchToBuffer(&ffbuf
, ff
.type
.mod
, v
.type
.mod
);
2058 MODMatchToBuffer(&vbuf
, v
.type
.mod
, ff
.type
.mod
);
2059 error(loc
, "%s%s `%s` cannot access %sdata `%s`",
2060 ffbuf
.peekChars(), ff
.kind(), ff
.toPrettyChars(), vbuf
.peekChars(), v
.toChars());
2070 /* Do not allow safe functions to access __gshared data
2072 if (v
.storage_class
& STC
.gshared
)
2074 if (sc
.setUnsafe(false, loc
,
2075 "`@safe` function `%s` cannot access `__gshared` data `%s`", sc
.func
, v
))
2085 Check if sc.func is impure or can be made impure.
2086 Returns true on error, i.e. if sc.func is pure and cannot be made impure.
2088 private bool checkImpure(Scope
* sc
, Loc loc
, const(char)* fmt
, RootObject arg0
)
2090 return sc
.func
&& (isRootTraitsCompilesScope(sc
)
2091 ? sc
.func
.isPureBypassingInference() >= PURE
.weak
2092 : sc
.func
.setImpure(loc
, fmt
, arg0
));
2095 /*********************************************
2096 * Calling function f.
2097 * Check the safety, i.e. if we're in a @safe function
2098 * we can only call @safe or @trusted functions.
2099 * Returns true if error occurs.
2101 private bool checkSafety(FuncDeclaration f
, ref Loc loc
, Scope
* sc
)
2105 if (sc
.intypeof
== 1)
2107 if (sc
.flags
& SCOPE
.debug_
)
2109 if ((sc
.flags
& SCOPE
.ctfe
) && sc
.func
)
2114 if (sc
.varDecl
&& !f
.safetyInprocess
&& !f
.isSafe() && !f
.isTrusted())
2116 if (sc
.varDecl
.storage_class
& STC
.safe
)
2118 error(loc
, "`@safe` variable `%s` cannot be initialized by calling `@system` function `%s`",
2119 sc
.varDecl
.toChars(), f
.toChars());
2124 sc
.varDecl
.storage_class |
= STC
.system
;
2125 sc
.varDecl
.systemInferred
= true;
2131 if (!f
.isSafe() && !f
.isTrusted())
2133 if (isRootTraitsCompilesScope(sc
) ? sc
.func
.isSafeBypassingInference() : sc
.func
.setUnsafeCall(f
))
2135 if (!loc
.isValid()) // e.g. implicitly generated dtor
2138 const prettyChars
= f
.toPrettyChars();
2139 error(loc
, "`@safe` %s `%s` cannot call `@system` %s `%s`",
2140 sc
.func
.kind(), sc
.func
.toPrettyChars(), f
.kind(),
2142 if (!f
.isDtorDeclaration
)
2143 errorSupplementalInferredAttr(f
, /*max depth*/ 10, /*deprecation*/ false, STC
.safe
);
2144 .errorSupplemental(f
.loc
, "`%s` is declared here", prettyChars
);
2146 f
.checkOverriddenDtor(sc
, loc
, dd => dd.type
.toTypeFunction().trust
> TRUST
.system
, "@system");
2151 else if (f
.isSafe() && f
.safetyViolation
)
2153 // for dip1000 by default transition, print deprecations for calling functions that will become `@system`
2154 if (sc
.func
.isSafeBypassingInference())
2156 .deprecation(loc
, "`@safe` function `%s` calling `%s`", sc
.func
.toChars(), f
.toChars());
2157 errorSupplementalInferredAttr(f
, 10, true, STC
.safe
);
2159 else if (!sc
.func
.safetyViolation
)
2161 import dmd
.func
: AttributeViolation
;
2162 sc
.func
.safetyViolation
= new AttributeViolation(loc
, null, f
, null, null);
2168 /*********************************************
2169 * Calling function f.
2170 * Check the @nogc-ness, i.e. if we're in a @nogc function
2171 * we can only call other @nogc functions.
2172 * Returns true if error occurs.
2174 private bool checkNogc(FuncDeclaration f
, ref Loc loc
, Scope
* sc
)
2180 if (sc
.intypeof
== 1)
2182 if (sc
.flags
& (SCOPE
.ctfe | SCOPE
.debug_
))
2184 /* The original expressions (`new S(...)` or `new S[...]``) will be
2185 * verified instead. This is to keep errors related to the original code
2186 * and not the lowering.
2188 if (f
.ident
== Id
._d_newitemT || f
.ident
== Id
._d_newarrayT || f
.ident
== Id
._d_newarraymTX
)
2193 if (isRootTraitsCompilesScope(sc
) ? sc
.func
.isNogcBypassingInference() : sc
.func
.setGCCall(f
))
2195 if (loc
.linnum
== 0) // e.g. implicitly generated dtor
2198 // Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)),
2199 // so don't print anything to avoid double error messages.
2200 if (!(f
.ident
== Id
._d_HookTraceImpl || f
.ident
== Id
._d_arraysetlengthT
2201 || f
.ident
== Id
._d_arrayappendT || f
.ident
== Id
._d_arrayappendcTX
2202 || f
.ident
== Id
._d_arraycatnTX || f
.ident
== Id
._d_newclassT
))
2204 error(loc
, "`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
2205 sc
.func
.kind(), sc
.func
.toPrettyChars(), f
.kind(), f
.toPrettyChars());
2207 if (!f
.isDtorDeclaration
)
2208 f
.errorSupplementalInferredAttr(/*max depth*/ 10, /*deprecation*/ false, STC
.nogc
);
2211 f
.checkOverriddenDtor(sc
, loc
, dd => dd.type
.toTypeFunction().isnogc
, "non-@nogc");
2219 /********************************************
2220 * Check that the postblit is callable if t is an array of structs.
2221 * Returns true if error happens.
2223 private bool checkPostblit(Type t
, ref Loc loc
, Scope
* sc
)
2225 if (auto ts
= t
.baseElemOf().isTypeStruct())
2227 if (global
.params
.useTypeInfo
&& Type
.dtypeinfo
)
2229 // https://issues.dlang.org/show_bug.cgi?id=11395
2230 // Require TypeInfo generation for array concatenation
2231 semanticTypeInfo(sc
, t
);
2234 StructDeclaration sd
= ts
.sym
;
2237 if (sd
.postblit
.checkDisabled(loc
, sc
))
2240 //checkDeprecated(sc, sd.postblit); // necessary?
2241 sd
.postblit
.checkPurity(loc
, sc
);
2242 sd
.postblit
.checkSafety(loc
, sc
);
2243 sd
.postblit
.checkNogc(loc
, sc
);
2244 //checkAccess(sd, loc, sc, sd.postblit); // necessary?
2251 /***************************************
2252 * Pull out any properties.
2254 private Expression
resolvePropertiesX(Scope
* sc
, Expression e1
, Expression e2
= null, BinExp saveAtts
= null)
2256 //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null);
2263 if (auto de = e1
.isDotExp())
2265 if (auto oe
= de.e2
.isOverExp())
2273 else if (e1
.isOverExp())
2277 os
= e1
.isOverExp().vars
;
2280 FuncDeclaration fd
= null;
2283 e2
= e2
.expressionSemantic(sc
);
2284 if (e2
.op
== EXP
.error
)
2285 return ErrorExp
.get();
2286 e2
= resolveProperties(sc
, e2
);
2288 Expressions
* a
= new Expressions();
2291 for (size_t i
= 0; i
< os
.a
.length
; i
++)
2293 if (FuncDeclaration f
= resolveFuncCall(loc
, sc
, os
.a
[i
], tiargs
, tthis
, ArgumentList(a
), FuncResolveFlag
.quiet
))
2296 return ErrorExp
.get();
2298 assert(fd
.type
.ty
== Tfunction
);
2303 Expression e
= new CallExp(loc
, e1
, e2
);
2304 return e
.expressionSemantic(sc
);
2308 for (size_t i
= 0; i
< os
.a
.length
; i
++)
2310 if (FuncDeclaration f
= resolveFuncCall(loc
, sc
, os
.a
[i
], tiargs
, tthis
, ArgumentList(), FuncResolveFlag
.quiet
))
2313 return ErrorExp
.get();
2315 assert(fd
.type
.ty
== Tfunction
);
2316 auto tf
= fd
.type
.isTypeFunction();
2317 if (!tf
.isref
&& e2
)
2319 error(loc
, "%s is not an lvalue", e1
.toChars());
2320 return ErrorExp
.get();
2326 Expression e
= new CallExp(loc
, e1
);
2329 e
= new AssignExp(loc
, e
, e2
);
2332 (cast(BinExp
)e
).att1
= saveAtts
.att1
;
2333 (cast(BinExp
)e
).att2
= saveAtts
.att2
;
2336 return e
.expressionSemantic(sc
);
2342 else if (auto dti
= e1
.isDotTemplateInstanceExp())
2344 if (!dti
.findTempDecl(sc
))
2346 if (!dti
.ti
.semanticTiargs(sc
))
2348 tiargs
= dti
.ti
.tiargs
;
2349 tthis
= dti
.e1
.type
;
2350 if ((os
= dti
.ti
.tempdecl
.isOverloadSet()) !is null)
2352 if ((s
= dti
.ti
.tempdecl
) !is null)
2355 else if (auto dte
= e1
.isDotTemplateExp())
2359 tthis
= dte
.e1
.type
;
2362 else if (auto se
= e1
.isScopeExp())
2365 TemplateInstance ti
= s
.isTemplateInstance();
2366 if (ti
&& !ti
.semanticRun
&& ti
.tempdecl
)
2368 //assert(ti.needsTypeInference(sc));
2369 if (!ti
.semanticTiargs(sc
))
2373 if ((os
= ti
.tempdecl
.isOverloadSet()) !is null)
2375 if ((s
= ti
.tempdecl
) !is null)
2379 else if (auto te
= e1
.isTemplateExp())
2386 else if (e1
.isDotVarExp() && e1
.type
&& (e1
.type
.toBasetype().isTypeFunction() || e1
.isDotVarExp().var
.isOverDeclaration()))
2388 DotVarExp dve
= e1
.isDotVarExp();
2391 tthis
= dve
.e1
.type
;
2394 else if (sc
&& sc
.flags
& SCOPE
.Cfile
&& e1
.isVarExp() && !e2
)
2396 // ImportC: do not implicitly call function if no ( ) are present
2398 else if (e1
.isVarExp() && e1
.type
&& (e1
.type
.toBasetype().isTypeFunction() || e1
.isVarExp().var
.isOverDeclaration()))
2400 s
= e1
.isVarExp().var
;
2407 e2
= e2
.expressionSemantic(sc
);
2408 if (e2
.op
== EXP
.error
)
2409 return ErrorExp
.get();
2410 e2
= resolveProperties(sc
, e2
);
2412 Expressions
* a
= new Expressions();
2415 FuncDeclaration fd
= resolveFuncCall(loc
, sc
, s
, tiargs
, tthis
, ArgumentList(a
), FuncResolveFlag
.quiet
);
2419 return ErrorExp
.get();
2420 assert(fd
.type
.ty
== Tfunction
);
2421 Expression e
= new CallExp(loc
, e1
, e2
);
2422 return e
.expressionSemantic(sc
);
2426 FuncDeclaration fd
= resolveFuncCall(loc
, sc
, s
, tiargs
, tthis
, ArgumentList(), FuncResolveFlag
.quiet
);
2430 return ErrorExp
.get();
2431 TypeFunction tf
= fd
.type
.isTypeFunction();
2432 if (!e2 || tf
.isref
)
2434 Expression e
= new CallExp(loc
, e1
);
2437 e
= new AssignExp(loc
, e
, e2
);
2440 (cast(BinExp
)e
).att1
= saveAtts
.att1
;
2441 (cast(BinExp
)e
).att2
= saveAtts
.att2
;
2444 return e
.expressionSemantic(sc
);
2448 if (FuncDeclaration fd
= s
.isFuncDeclaration())
2450 // Keep better diagnostic message for invalid property usage of functions
2451 assert(fd
.type
.ty
== Tfunction
);
2452 Expression e
= new CallExp(loc
, e1
, e2
);
2453 return e
.expressionSemantic(sc
);
2458 if (auto ve
= e1
.isVarExp())
2460 if (auto v
= ve
.var
.isVarDeclaration())
2462 if (v
.checkPurity(ve
.loc
, sc
))
2463 return ErrorExp
.get();
2469 if (e1
.type
&& !e1
.isTypeExp()) // function type is not a property
2471 /* Look for e1 being a lazy parameter; rewrite as delegate call
2472 * only if the symbol wasn't already treated as a delegate
2474 auto ve
= e1
.isVarExp();
2475 if (ve
&& ve
.var
.storage_class
& STC
.lazy_
&& !ve
.delegateWasExtracted
)
2477 Expression e
= new CallExp(loc
, e1
);
2478 return e
.expressionSemantic(sc
);
2480 else if (e1
.isDotVarExp())
2482 // Check for reading overlapped pointer field in @safe code.
2483 if (checkUnsafeAccess(sc
, e1
, true, true))
2484 return ErrorExp
.get();
2486 else if (auto ce
= e1
.isCallExp())
2488 // Check for reading overlapped pointer field in @safe code.
2489 if (checkUnsafeAccess(sc
, ce
.e1
, true, true))
2490 return ErrorExp
.get();
2496 error(loc
, "cannot resolve type for %s", e1
.toChars());
2497 e1
= ErrorExp
.get();
2502 error(loc
, "not a property %s", e1
.toChars());
2503 return ErrorExp
.get();
2506 private bool checkRightThis(Expression e
, Scope
* sc
)
2508 if (e
.op
== EXP
.error
)
2510 if (e
.op
== EXP
.variable
&& e
.type
.ty
!= Terror
)
2512 VarExp ve
= cast(VarExp
)e
;
2513 if (isNeedThisScope(sc
, ve
.var
))
2515 //printf("checkRightThis sc.intypeof = %d, ad = %p, func = %p, fdthis = %p\n",
2516 // sc.intypeof, sc.getStructClassScope(), func, fdthis);
2517 auto t
= ve
.var
.isThis();
2519 error(e
.loc
, "accessing non-static variable `%s` requires an instance of `%s`", ve
.var
.toChars(), t
.toChars());
2526 Expression
resolveProperties(Scope
* sc
, Expression e
)
2528 //printf("resolveProperties(%s)\n", e.toChars());
2529 e
= resolvePropertiesX(sc
, e
);
2530 if (e
.checkRightThis(sc
))
2531 return ErrorExp
.get();
2535 /****************************************
2536 * The common type is determined by applying ?: to each pair.
2538 * exps[] properties resolved, implicitly cast to common type, rewritten in place
2540 * The common type, or `null` if an error has occured
2542 private Type
arrayExpressionToCommonType(Scope
* sc
, ref Expressions exps
)
2544 /* Still have a problem with:
2545 * ubyte[][] = [ cast(ubyte[])"hello", [1]];
2546 * which works if the array literal is initialized top down with the ubyte[][]
2547 * type, but fails with this function doing bottom up typing.
2550 //printf("arrayExpressionToCommonType()\n");
2551 scope IntegerExp integerexp
= IntegerExp
.literal
!0;
2552 scope CondExp condexp
= new CondExp(Loc
.initial
, integerexp
, null, null);
2555 Expression e0
= null;
2558 for (size_t i
= 0; i
< exps
.length
; i
++)
2560 Expression e
= exps
[i
];
2564 e
= resolveProperties(sc
, e
);
2567 error(e
.loc
, "`%s` has no value", e
.toChars());
2571 if (e
.op
== EXP
.type
)
2573 foundType
= true; // do not break immediately, there might be more errors
2574 e
.checkValue(); // report an error "type T has no value"
2578 if (e
.type
.ty
== Tvoid
)
2580 // void expressions do not concur to the determination of the common
2584 if (checkNonAssignmentArrayOp(e
))
2590 e
= doCopyOrMove(sc
, e
);
2592 if (!foundType
&& t0
&& !t0
.equals(e
.type
))
2594 /* This applies ?: to merge the types. It's backwards;
2595 * ?: should call this function to merge types.
2597 condexp
.type
= null;
2600 condexp
.loc
= e
.loc
;
2601 Expression ex
= condexp
.expressionSemantic(sc
);
2602 if (ex
.op
== EXP
.error
)
2606 // Convert to common type
2607 exps
[i
] = condexp
.e1
.castTo(sc
, condexp
.type
);
2608 e
= condexp
.e2
.castTo(sc
, condexp
.type
);
2613 if (e
.op
!= EXP
.error
)
2617 // [] is typed as void[]
2621 // It's an error, don't do the cast
2622 if (t0
.ty
== Terror
)
2625 for (size_t i
= 0; i
< exps
.length
; i
++)
2627 Expression e
= exps
[i
];
2631 e
= e
.implicitCastTo(sc
, t0
);
2632 if (e
.op
== EXP
.error
)
2634 /* https://issues.dlang.org/show_bug.cgi?id=13024
2635 * a workaround for the bug in typeMerge -
2636 * it should paint e1 and e2 by deduced common type,
2637 * but doesn't in this particular case.
2646 private Expression
opAssignToOp(const ref Loc loc
, EXP op
, Expression e1
, Expression e2
) @safe
2652 e
= new AddExp(loc
, e1
, e2
);
2656 e
= new MinExp(loc
, e1
, e2
);
2660 e
= new MulExp(loc
, e1
, e2
);
2664 e
= new DivExp(loc
, e1
, e2
);
2668 e
= new ModExp(loc
, e1
, e2
);
2672 e
= new AndExp(loc
, e1
, e2
);
2676 e
= new OrExp(loc
, e1
, e2
);
2680 e
= new XorExp(loc
, e1
, e2
);
2683 case EXP
.leftShiftAssign
:
2684 e
= new ShlExp(loc
, e1
, e2
);
2687 case EXP
.rightShiftAssign
:
2688 e
= new ShrExp(loc
, e1
, e2
);
2691 case EXP
.unsignedRightShiftAssign
:
2692 e
= new UshrExp(loc
, e1
, e2
);
2701 /*********************
2703 * array.length op= e2
2705 private Expression
rewriteOpAssign(BinExp exp
)
2707 ArrayLengthExp ale
= exp
.e1
.isArrayLengthExp();
2708 if (ale
.e1
.isVarExp())
2710 // array.length = array.length op e2
2711 Expression e
= opAssignToOp(exp
.loc
, exp
.op
, ale
, exp
.e2
);
2712 e
= new AssignExp(exp
.loc
, ale
.syntaxCopy(), e
);
2717 // (ref tmp = array;), tmp.length = tmp.length op e2
2718 auto tmp
= copyToTemp(STC
.ref_
, "__arraylength", ale
.e1
);
2719 Expression e1
= new ArrayLengthExp(ale
.loc
, new VarExp(ale
.loc
, tmp
));
2720 Expression elvalue
= e1
.syntaxCopy();
2721 Expression e
= opAssignToOp(exp
.loc
, exp
.op
, e1
, exp
.e2
);
2722 e
= new AssignExp(exp
.loc
, elvalue
, e
);
2723 e
= new CommaExp(exp
.loc
, new DeclarationExp(ale
.loc
, tmp
), e
);
2728 /****************************************
2729 * Preprocess arguments to function.
2731 * Tuples in argumentList get expanded, properties resolved, rewritten in place
2735 * argumentList = arguments to function
2736 * reportErrors = whether or not to report errors here. Some callers are not
2737 * checking actual function params, so they'll do their own error reporting
2739 * `true` when a semantic error occurred
2741 private bool preFunctionParameters(Scope
* sc
, ArgumentList argumentList
, const bool reportErrors
= true)
2743 Expressions
* exps
= argumentList
.arguments
;
2747 expandTuples(exps
, argumentList
.names
);
2749 for (size_t i
= 0; i
< exps
.length
; i
++)
2751 Expression arg
= (*exps
)[i
];
2752 arg
= resolveProperties(sc
, arg
);
2753 arg
= arg
.arrayFuncConv(sc
);
2754 if (arg
.op
== EXP
.type
)
2756 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
2757 arg
= resolveAliasThis(sc
, arg
);
2759 if (arg
.op
== EXP
.type
)
2763 error(arg
.loc
, "cannot pass type `%s` as a function argument", arg
.toChars());
2764 arg
= ErrorExp
.get();
2769 else if (arg
.type
.toBasetype().ty
== Tfunction
)
2773 error(arg
.loc
, "cannot pass function `%s` as a function argument", arg
.toChars());
2774 arg
= ErrorExp
.get();
2778 else if (checkNonAssignmentArrayOp(arg
))
2780 arg
= ErrorExp
.get();
2789 /********************************************
2790 * Issue an error if default construction is disabled for type t.
2791 * Default construction is required for arrays and 'out' parameters.
2793 * true an error was issued
2795 private bool checkDefCtor(Loc loc
, Type t
)
2797 if (auto ts
= t
.baseElemOf().isTypeStruct())
2799 StructDeclaration sd
= ts
.sym
;
2800 if (sd
.noDefaultCtor
)
2802 .error(loc
, "%s `%s` default construction is disabled", sd
.kind
, sd
.toPrettyChars
);
2809 /****************************************
2810 * Now that we know the exact type of the function we're calling,
2811 * the arguments[] need to be adjusted:
2812 * 1. implicitly convert argument to the corresponding parameter type
2813 * 2. add default arguments for any missing arguments
2814 * 3. do default promotions on arguments corresponding to ...
2815 * 4. add hidden _arguments[] argument
2816 * 5. call copy constructor for struct value arguments
2818 * loc = location of function call
2820 * tf = type of the function
2821 * ethis = `this` argument, `null` if none or not known
2822 * tthis = type of `this` argument, `null` if no `this` argument
2823 * argumentsList = array of actual arguments to function call
2824 * fd = the function being called, `null` if called indirectly
2825 * prettype = set to return type of function
2826 * peprefix = set to expression to execute before `arguments[]` are evaluated, `null` if none
2828 * true errors happened
2830 private bool functionParameters(const ref Loc loc
, Scope
* sc
,
2831 TypeFunction tf
, Expression ethis
, Type tthis
, ArgumentList argumentList
, FuncDeclaration fd
,
2832 Type
* prettype
, Expression
* peprefix
)
2834 Expressions
* arguments
= argumentList
.arguments
;
2835 //printf("functionParameters() %s\n", fd ? fd.toChars() : "");
2837 assert(fd || tf
.next
);
2838 const size_t nparams
= tf
.parameterList
.length
;
2839 const olderrors
= global
.errors
;
2841 Expression eprefix
= null;
2844 if (argumentList
.names
)
2846 const(char)* msg
= null;
2847 auto resolvedArgs
= tf
.resolveNamedArgs(argumentList
, &msg
);
2850 // while errors are usually already caught by `tf.callMatch`,
2851 // this can happen when calling `typeof(freefunc)`
2853 error(loc
, "%s", msg
);
2856 // note: the argument list should be mutated with named arguments / default arguments,
2857 // so we can't simply change the pointer like `arguments = resolvedArgs;`
2858 arguments
.setDim(0);
2859 arguments
.pushSlice((*resolvedArgs
)[]);
2861 size_t nargs
= arguments ? arguments
.length
: 0;
2863 if (nargs
> nparams
&& tf
.parameterList
.varargs
== VarArg
.none
)
2865 error(loc
, "expected %llu arguments, not %llu for non-variadic function type `%s`", cast(ulong)nparams
, cast(ulong)nargs
, tf
.toChars());
2869 // If inferring return type, and semantic3() needs to be run if not already run
2870 if (!tf
.next
&& fd
.inferRetType
)
2872 functionSemantic(fd
);
2874 else if (fd
&& fd
.parent
)
2876 TemplateInstance ti
= fd
.parent
.isTemplateInstance();
2877 if (ti
&& ti
.tempdecl
)
2879 fd
.functionSemantic3();
2883 /* If calling a pragma(inline, true) function,
2884 * set flag to later scan for inlines.
2886 if (fd
&& fd
.inlining
== PINLINE
.always
)
2889 sc
._module
.hasAlwaysInlines
= true;
2891 sc
.func
.hasAlwaysInlines
= true;
2894 const isCtorCall
= fd
&& fd
.needThis() && fd
.isCtorDeclaration();
2896 const size_t n
= (nargs
> nparams
) ? nargs
: nparams
; // n = max(nargs, nparams)
2898 /* If the function return type has wildcards in it, we'll need to figure out the actual type
2899 * based on the actual argument types.
2900 * Start with the `this` argument, later on merge into wildmatch the mod bits of the rest
2903 MOD wildmatch
= (tthis
&& !isCtorCall
) ? tthis
.Type
.deduceWild(tf
, false) : 0;
2906 foreach (const i
; 0 .. n
)
2908 Expression arg
= (i
< nargs
) ?
(*arguments
)[i
] : null;
2914 error(loc
, "expected %llu function arguments, not %llu", cast(ulong)nparams
, cast(ulong)nargs
);
2918 Parameter p
= tf
.parameterList
[i
];
2924 if (tf
.parameterList
.varargs
== VarArg
.typesafe
&& i
+ 1 == nparams
)
2930 arg
= arg
.expressionSemantic(sc
);
2931 arg
= inlineCopy(arg
, sc
);
2932 // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
2933 arg
= arg
.resolveLoc(loc
, sc
);
2936 arguments
.push(arg
);
2940 (*arguments
)[i
] = arg
;
2944 if (arg
.isDefaultInitExp())
2946 arg
= arg
.resolveLoc(loc
, sc
);
2947 (*arguments
)[i
] = arg
;
2952 if (tf
.parameterList
.varargs
== VarArg
.typesafe
&& i
+ 1 == nparams
) // https://dlang.org/spec/function.html#variadic
2954 //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars());
2957 if ((m
= arg
.implicitConvTo(p
.type
)) > MATCH
.nomatch
)
2959 if (p
.type
.nextOf() && arg
.implicitConvTo(p
.type
.nextOf()) >= m
)
2961 else if (nargs
!= nparams
)
2967 Type tb
= p
.type
.toBasetype();
2973 /* Create a static array variable v of type arg.type:
2974 * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
2976 * The array literal in the initializer of the hidden variable
2978 * https://issues.dlang.org/show_bug.cgi?id=2356
2980 Type tbn
= (cast(TypeArray
)tb
).next
; // array element type
2981 Type tret
= p
.isLazyArray();
2983 auto elements
= new Expressions(nargs
- i
);
2984 foreach (u
; 0 .. elements
.length
)
2986 Expression a
= (*arguments
)[i
+ u
];
2988 if (tret
&& a
.implicitConvTo(tret
))
2990 // p is a lazy array of delegates, tret is return type of the delegates
2991 a
= a
.implicitCastTo(sc
, tret
)
2992 .optimize(WANTvalue
)
2993 .toDelegate(tret
, sc
);
2996 a
= a
.implicitCastTo(sc
, tbn
);
2997 a
= a
.addDtorHook(sc
);
3000 // https://issues.dlang.org/show_bug.cgi?id=14395
3001 // Convert to a static array literal, or its slice.
3002 arg
= new ArrayLiteralExp(loc
, tbn
.sarrayOf(nargs
- i
), elements
);
3003 if (tb
.ty
== Tarray
)
3005 arg
= new SliceExp(loc
, arg
, null, null);
3013 * new Tclass(arg0, arg1, ..., argn)
3015 auto args
= new Expressions(nargs
- i
);
3016 foreach (u
; i
.. nargs
)
3017 (*args
)[u
- i
] = (*arguments
)[u
];
3018 arg
= new NewExp(loc
, null, p
.type
, args
);
3024 error(loc
, "not enough arguments");
3029 arg
= arg
.expressionSemantic(sc
);
3030 //printf("\targ = '%s'\n", arg.toChars());
3031 arguments
.setDim(i
+ 1);
3032 (*arguments
)[i
] = arg
;
3038 if (!(p
.isLazy() && p
.type
.ty
== Tvoid
))
3040 if (ubyte wm
= arg
.type
.deduceWild(p
.type
, p
.isReference()))
3042 wildmatch
= wildmatch ?
MODmerge(wildmatch
, wm
) : wm
;
3043 //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p.type.toChars(), arg.type.toChars(), wm, wildmatch);
3050 if ((wildmatch
== MODFlags
.mutable || wildmatch
== MODFlags
.immutable_
) &&
3051 tf
.next
&& tf
.next
.hasWild() &&
3052 (tf
.isref ||
!tf
.next
.implicitConvTo(tf
.next
.immutableOf())))
3054 bool errorInout(MOD wildmatch
)
3056 const(char)* s
= wildmatch
== MODFlags
.mutable ?
"mutable" : MODtoChars(wildmatch
);
3057 error(loc
, "modify `inout` to `%s` is not allowed inside `inout` function", s
);
3063 /* If the called function may return the reference to
3064 * outer inout data, it should be rejected.
3066 * void foo(ref inout(int) x) {
3067 * ref inout(int) bar(inout(int)) { return x; }
3069 * ref inout(int) bar() inout { return x; }
3070 * ref inout(int) baz(alias a)() inout { return x; }
3072 * bar(int.init) = 1; // bad!
3073 * S().bar() = 1; // bad!
3078 * s.baz!a() = 1; // bad!
3082 bool checkEnclosingWild(Dsymbol s
)
3084 bool checkWild(Dsymbol s
)
3088 if (auto ad
= s
.isAggregateDeclaration())
3091 return checkEnclosingWild(s
);
3093 else if (auto ff
= s
.isFuncDeclaration())
3095 if (ff
.type
.isTypeFunction().iswild
)
3096 return errorInout(wildmatch
);
3098 if (ff
.isNested() || ff
.isThis())
3099 return checkEnclosingWild(s
);
3104 Dsymbol ctx0
= s
.toParent2();
3105 Dsymbol ctx1
= s
.toParentLocal();
3106 if (checkWild(ctx0
))
3109 return checkWild(ctx1
);
3112 if ((fd
.isThis() || fd
.isNested()) && checkEnclosingWild(fd
))
3115 else if (tf
.isWild())
3116 return errorInout(wildmatch
);
3119 Expression firstArg
= null;
3120 final switch (returnParamDest(tf
, tthis
))
3122 case ReturnParamDest
.returnVal
:
3124 case ReturnParamDest
.firstArg
:
3125 firstArg
= nargs
> 0 ?
(*arguments
)[0] : null;
3127 case ReturnParamDest
.this_
:
3132 assert(nargs
>= nparams
);
3133 foreach (const i
, arg
; (*arguments
)[0 .. nargs
])
3138 Parameter p
= tf
.parameterList
[i
];
3139 Type targ
= arg
.type
; // keep original type for isCopyable() because alias this
3140 // resolution may hide an uncopyable type
3142 if (!(p
.isLazy() && p
.type
.ty
== Tvoid
))
3144 Type tprm
= p
.type
.hasWild()
3145 ? p
.type
.substWildTo(wildmatch
)
3148 const hasCopyCtor
= arg
.type
.isTypeStruct() && arg
.type
.isTypeStruct().sym
.hasCopyCtor
;
3149 const typesMatch
= arg
.type
.mutableOf().unSharedOf().equals(tprm
.mutableOf().unSharedOf());
3150 if (!((hasCopyCtor
&& typesMatch
) || tprm
.equals(arg
.type
)))
3152 //printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars());
3153 arg
= arg
.implicitCastTo(sc
, tprm
);
3154 arg
= arg
.optimize(WANTvalue
, p
.isReference());
3158 // Support passing rvalue to `in` parameters
3159 if ((p
.storageClass
& (STC
.in_ | STC
.ref_
)) == (STC
.in_ | STC
.ref_
))
3161 if (!arg
.isLvalue())
3163 auto v
= copyToTemp(STC
.exptemp
, "__rvalue", arg
);
3164 Expression ev
= new DeclarationExp(arg
.loc
, v
);
3165 ev
= new CommaExp(arg
.loc
, ev
, new VarExp(arg
.loc
, v
));
3166 arg
= ev
.expressionSemantic(sc
);
3168 arg
= arg
.toLvalue(sc
, "create `in` parameter from");
3170 // Look for mutable misaligned pointer, etc., in @safe mode
3171 err |
= checkUnsafeAccess(sc
, arg
, false, true);
3173 else if (p
.storageClass
& STC
.ref_
)
3175 if (global
.params
.rvalueRefParam
== FeatureState
.enabled
&&
3178 { /* allow rvalues to be passed to ref parameters by copying
3179 * them to a temp, then pass the temp as the argument
3181 auto v
= copyToTemp(0, "__rvalue", arg
);
3182 Expression ev
= new DeclarationExp(arg
.loc
, v
);
3183 ev
= new CommaExp(arg
.loc
, ev
, new VarExp(arg
.loc
, v
));
3184 arg
= ev
.expressionSemantic(sc
);
3186 arg
= arg
.toLvalue(sc
, "create `ref` parameter from");
3188 // Look for mutable misaligned pointer, etc., in @safe mode
3189 err |
= checkUnsafeAccess(sc
, arg
, false, true);
3191 else if (p
.storageClass
& STC
.out_
)
3194 if (!t
.isMutable() ||
!t
.isAssignable()) // check blit assignable
3196 error(arg
.loc
, "cannot modify struct `%s` with immutable members", arg
.toChars());
3201 // Look for misaligned pointer, etc., in @safe mode
3202 err |
= checkUnsafeAccess(sc
, arg
, false, true);
3203 err |
= checkDefCtor(arg
.loc
, t
); // t must be default constructible
3205 arg
= arg
.toLvalue(sc
, "create `out` parameter from");
3207 else if (p
.isLazy())
3209 // Convert lazy argument to a delegate
3210 auto t
= (p
.type
.ty
== Tvoid
) ? p
.type
: arg
.type
;
3211 arg
= toDelegate(arg
, t
, sc
);
3213 //printf("arg: %s\n", arg.toChars());
3214 //printf("type: %s\n", arg.type.toChars());
3215 //printf("param: %s\n", p.toChars());
3217 const indirect
= (fd
is null) ||
(fd
.isVirtual() && !fd
.isFinal());
3218 const pStc
= tf
.parameterStorageClass(tthis
, p
, fd ?
&fd
.outerVars
: null, indirect
);
3220 if (firstArg
&& (pStc
& STC
.return_
))
3222 /* Argument value can be assigned to firstArg.
3223 * Check arg to see if it matters.
3225 err |
= checkParamArgumentReturn(sc
, firstArg
, arg
, p
, false);
3227 // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along
3228 // as lazy parameters to the next function, but that isn't escaping.
3229 // The arguments of `_d_arraycatnTX` are already handled in
3230 // expressionsem.d, via `checkNewEscape`. Without `-dip1000`, the
3231 // check does not return an error, so the lowering of `a ~ b` to
3232 // `_d_arraycatnTX(a, b)` still occurs.
3233 else if (!(pStc
& STC
.lazy_
) && (!fd || fd
.ident
!= Id
._d_arraycatnTX
))
3235 /* Argument value can escape from the called function.
3236 * Check arg to see if it matters.
3238 VarDeclaration vPar
= fd ?
(fd
.parameters ?
(*fd
.parameters
)[i
] : null) : null;
3239 err |
= checkParamArgumentEscape(sc
, fd
, p
.ident
, vPar
, cast(STC
) pStc
, arg
, false, false);
3242 // Turning heap allocations into stack allocations is dangerous without dip1000, since `scope` inference
3243 // may be unreliable when scope violations only manifest as deprecation warnings.
3244 // However, existing `@nogc` code may rely on it, so still do it when the parameter is explicitly marked `scope`
3245 const explicitScope
= p
.isLazy() ||
3246 ((p
.storageClass
& STC
.scope_
) && !(p
.storageClass
& STC
.scopeinferred
));
3247 if ((pStc
& (STC
.scope_ | STC
.lazy_
)) &&
3248 ((sc
.useDIP1000
== FeatureState
.enabled
) || explicitScope
) &&
3249 !(pStc
& STC
.return_
))
3251 /* Argument value cannot escape from the called function.
3254 if (auto ce
= a
.isCastExp())
3257 ArrayLiteralExp ale
;
3258 if (p
.type
.toBasetype().ty
== Tarray
&&
3259 (ale
= a
.isArrayLiteralExp()) !is null && ale
.elements
&& ale
.elements
.length
> 0)
3261 // allocate the array literal as temporary static array on the stack
3262 ale
.type
= ale
.type
.nextOf().sarrayOf(ale
.elements
.length
);
3263 auto tmp
= copyToTemp(0, "__arrayliteral_on_stack", ale
);
3264 tmp
.storage_class |
= STC
.exptemp
;
3265 auto declareTmp
= new DeclarationExp(ale
.loc
, tmp
);
3266 auto castToSlice
= new CastExp(ale
.loc
, new VarExp(ale
.loc
, tmp
),
3267 p
.type
.substWildTo(MODFlags
.mutable
));
3268 arg
= CommaExp
.combine(declareTmp
, castToSlice
);
3269 arg
= arg
.expressionSemantic(sc
);
3271 else if (auto fe
= a
.isFuncExp())
3273 /* Function literals can only appear once, so if this
3274 * appearance was scoped, there cannot be any others.
3276 fe
.fd
.tookAddressOf
= 0;
3278 else if (auto de = a
.isDelegateExp())
3280 /* For passing a delegate to a scoped parameter,
3281 * this doesn't count as taking the address of it.
3282 * We only worry about 'escaping' references to the function.
3284 if (auto ve
= de.e1
.isVarExp())
3286 if (auto f
= ve
.var
.isFuncDeclaration())
3288 if (f
.tookAddressOf
)
3290 //printf("--tookAddressOf = %d\n", f.tookAddressOf);
3295 if (!p
.isReference())
3296 err |
= arg
.checkSharedAccess(sc
);
3298 arg
= arg
.optimize(WANTvalue
, p
.isReference());
3302 // These will be the trailing ... arguments
3303 // If not D linkage, do promotions
3304 if (tf
.linkage
!= LINK
.d
)
3306 // Promote bytes, words, etc., to ints
3307 arg
= integralPromotions(arg
, sc
);
3309 // Promote floats to doubles
3310 switch (arg
.type
.ty
)
3313 arg
= arg
.castTo(sc
, Type
.tfloat64
);
3317 arg
= arg
.castTo(sc
, Type
.timaginary64
);
3323 if (tf
.parameterList
.varargs
== VarArg
.variadic ||
3324 tf
.parameterList
.varargs
== VarArg
.KRvariadic
)
3326 const(char)* p
= tf
.linkage
== LINK
.c ?
"extern(C)" : "extern(C++)";
3327 if (arg
.type
.ty
== Tarray
)
3329 error(arg
.loc
, "cannot pass dynamic arrays to `%s` vararg functions", p
);
3332 if (arg
.type
.ty
== Tsarray
)
3334 error(arg
.loc
, "cannot pass static arrays to `%s` vararg functions", p
);
3340 // Do not allow types that need destructors or copy constructors.
3341 if (arg
.type
.needsDestruction())
3343 error(arg
.loc
, "cannot pass types that need destruction as variadic arguments");
3346 if (arg
.type
.needsCopyOrPostblit())
3348 error(arg
.loc
, "cannot pass types with postblits or copy constructors as variadic arguments");
3352 // Convert static arrays to dynamic arrays
3353 // BUG: I don't think this is right for D2
3354 Type tb
= arg
.type
.toBasetype();
3355 if (auto ts
= tb
.isTypeSArray())
3357 Type ta
= ts
.next
.arrayOf();
3358 if (ts
.size(arg
.loc
) == 0)
3359 arg
= new NullExp(arg
.loc
, ta
);
3361 arg
= arg
.castTo(sc
, ta
);
3363 if (tb
.ty
== Tstruct
)
3365 //arg = callCpCtor(sc, arg);
3367 // Give error for overloaded function addresses
3368 if (auto se
= arg
.isSymOffExp())
3370 if (se
.hasOverloads
&& !se
.var
.isFuncDeclaration().isUnique())
3372 error(arg
.loc
, "function `%s` is overloaded", arg
.toChars());
3376 err |
= arg
.checkValue();
3377 err |
= arg
.checkSharedAccess(sc
);
3378 err |
= checkParamArgumentEscape(sc
, fd
, Id
.dotdotdot
, null, cast(STC
) tf
.parameterList
.stc, arg
, false, false);
3379 arg
= arg
.optimize(WANTvalue
);
3381 (*arguments
)[i
] = arg
;
3384 /* If calling C scanf(), printf(), or any variants, check the format string against the arguments
3386 const isVa_list
= tf
.parameterList
.varargs
== VarArg
.none
;
3387 if (fd
&& fd
.printf
)
3389 if (auto se
= (*arguments
)[nparams
- 1 - isVa_list
].isStringExp())
3391 checkPrintfFormat(se
.loc
, se
.peekString(), (*arguments
)[nparams
.. nargs
], isVa_list
, sc
.eSink
);
3394 else if (fd
&& fd
.scanf
)
3396 if (auto se
= (*arguments
)[nparams
- 1 - isVa_list
].isStringExp())
3398 checkScanfFormat(se
.loc
, se
.peekString(), (*arguments
)[nparams
.. nargs
], isVa_list
, sc
.eSink
);
3403 // TODO: not checking the "v" functions yet (for those, check format string only, not args)
3406 /* Remaining problems:
3407 * 1. value structs (or static arrays of them) that need to be copy constructed
3408 * 2. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
3409 * function gets called.
3410 * 3. value structs need to be destructed after the function call for platforms where the caller destroys the arguments.
3411 * Those are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
3412 * up properly. Pushing arguments on the stack then cannot fail.
3415 /* Does Problem (3) apply?
3417 const bool callerDestroysArgs
= !target
.isCalleeDestroyingArgs(tf
);
3419 /* Compute indices of last throwing argument and first arg needing destruction.
3420 * Used to not set up destructors unless an arg needs destruction on a throw
3421 * in a later argument.
3423 ptrdiff_t lastthrow
= -1; // last argument that may throw
3424 ptrdiff_t firstdtor
= -1; // first argument that needs destruction
3425 ptrdiff_t lastdtor
= -1; // last argument that needs destruction
3426 for (ptrdiff_t i
= 0; i
!= nargs
; i
++)
3428 Expression arg
= (*arguments
)[i
];
3429 if (canThrow(arg
, sc
.func
, null))
3431 if (arg
.type
.needsDestruction())
3433 Parameter p
= (i
>= nparams ?
null : tf
.parameterList
[i
]);
3434 if (!(p
&& (p
.isLazy() || p
.isReference())))
3436 if (firstdtor
== -1)
3443 /* Do we need 'eprefix' for problems 2 or 3?
3445 const bool needsPrefix
= callerDestroysArgs
3446 ? firstdtor
>= 0 // true if any argument needs destruction
3447 : firstdtor
>= 0 && lastthrow
>= 0 &&
3448 (lastthrow
- firstdtor
) > 0; // last throw after first destruction
3449 const ptrdiff_t lastPrefix
= callerDestroysArgs
3450 ? lastdtor
// up to last argument requiring destruction
3451 : lastthrow
; // up to last potentially throwing argument
3453 /* Problem 3: initialize 'eprefix' by declaring the gate
3455 VarDeclaration gate
;
3456 if (needsPrefix
&& !callerDestroysArgs
)
3458 // eprefix => bool __gate [= false]
3459 Identifier idtmp
= Identifier
.generateId("__gate");
3460 gate
= new VarDeclaration(loc
, Type
.tbool
, idtmp
, null);
3461 gate
.storage_class |
= STC
.temp | STC
.ctfe | STC
.volatile_
;
3462 gate
.dsymbolSemantic(sc
);
3464 auto ae
= new DeclarationExp(loc
, gate
);
3465 eprefix
= ae
.expressionSemantic(sc
);
3468 foreach (ptrdiff_t i
; 0 .. nargs
)
3470 Expression arg
= (*arguments
)[i
];
3471 //printf("arg[%d]: %s\n", cast(int)i, arg.toChars());
3473 Parameter parameter
= i
< nparams ? tf
.parameterList
[i
] : null;
3474 const bool isRef
= parameter
&& parameter
.isReference();
3475 const bool isLazy
= parameter
&& parameter
.isLazy();
3477 /* Skip lazy parameters
3482 /* Do we have 'eprefix' and aren't past 'lastPrefix' yet?
3483 * Then declare a temporary variable for this arg and append that declaration
3484 * to 'eprefix', which will implicitly take care of potential problem 1) for
3486 * 'eprefix' will therefore finally contain all args up to and including 'lastPrefix',
3487 * excluding all lazy parameters.
3489 if (needsPrefix
&& i
<= lastPrefix
)
3491 const bool needsDtor
= !isRef
&& arg
.type
.needsDestruction() &&
3492 // Problem 3: last throwing arg doesn't require dtor patching
3493 (callerDestroysArgs || i
!= lastPrefix
);
3495 /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
3497 auto tmp
= copyToTemp(
3498 (parameter ? parameter
.storageClass
: tf
.parameterList
.stc) & (STC
.return_ | STC
.scope_
),
3499 needsDtor ?
"__pfx" : "__pfy",
3500 isRef ? arg
.addressOf() : arg
);
3501 tmp
.dsymbolSemantic(sc
);
3503 if (callerDestroysArgs
)
3505 /* Problem 4: Normal temporary, destructed after the call
3508 tmp
.isArgDtorVar
= true; // mark it so that the backend passes it by ref to the function being called
3512 /* Problem 2: Modify the destructor so it only runs if gate==false,
3513 * i.e., only if there was a throw while constructing the args
3517 // edtor => (__gate || edtor)
3519 Expression e
= tmp
.edtor
;
3520 e
= new LogicalExp(e
.loc
, EXP
.orOr
, new VarExp(e
.loc
, gate
), e
);
3521 tmp
.edtor
= e
.expressionSemantic(sc
);
3522 //printf("edtor: %s\n", tmp.edtor.toChars());
3528 assert(i
== lastPrefix
);
3534 // eprefix => (eprefix, auto __pfx/y = arg)
3535 auto ae
= new DeclarationExp(loc
, tmp
);
3536 eprefix
= Expression
.combine(eprefix
, ae
.expressionSemantic(sc
));
3539 arg
= new VarExp(loc
, tmp
);
3540 arg
= arg
.expressionSemantic(sc
);
3543 arg
= new PtrExp(loc
, arg
);
3544 arg
= arg
.expressionSemantic(sc
);
3547 /* Problem 2: Last throwing arg?
3548 * Then finalize eprefix => (eprefix, gate = true), i.e., disable the
3549 * dtors right after constructing the last throwing arg.
3550 * From now on, the callee will take care of destructing the args because
3551 * the args are implicitly moved into function parameters.
3553 if (!callerDestroysArgs
&& i
== lastPrefix
)
3555 auto e
= new AssignExp(gate
.loc
, new VarExp(gate
.loc
, gate
), IntegerExp
.createBool(true));
3556 eprefix
= Expression
.combine(eprefix
, e
.expressionSemantic(sc
));
3559 else // not part of 'eprefix'
3561 /* Handle problem 1) by calling the copy constructor for value structs
3562 * (or static arrays of them) if appropriate.
3564 Type tv
= arg
.type
.baseElemOf();
3565 if (!isRef
&& tv
.ty
== Tstruct
)
3566 arg
= doCopyOrMove(sc
, arg
, parameter ? parameter
.type
: null);
3569 (*arguments
)[i
] = arg
;
3572 //if (eprefix) printf("eprefix: %s\n", eprefix.toChars());
3574 /* Test compliance with DIP1021 Argument Ownership and Function Calls
3576 if (global
.params
.useDIP1021
&& (tf
.trust
== TRUST
.safe || tf
.trust
== TRUST
.default_
) ||
3578 err |
= checkMutableArguments(sc
, fd
, tf
, ethis
, arguments
, false);
3580 // If D linkage and variadic, add _arguments[] as first argument
3581 if (tf
.isDstyleVariadic())
3583 assert(arguments
.length
>= nparams
);
3585 auto args
= new Parameters(arguments
.length
- nparams
);
3586 for (size_t i
= 0; i
< arguments
.length
- nparams
; i
++)
3588 Expression earg
= (*arguments
)[nparams
+ i
];
3589 auto arg
= new Parameter(earg
.loc
, STC
.in_
, earg
.type
, null, null, null);
3592 auto tup
= new TypeTuple(args
);
3593 Expression e
= (new TypeidExp(loc
, tup
)).expressionSemantic(sc
);
3594 arguments
.insert(0, e
);
3597 /* Determine function return type: tret
3599 Type tret
= tf
.next
;
3602 //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd.toChars(), fd.type.toChars(),
3603 // wildmatch, tf.isWild(), fd.isReturnIsolated());
3606 assert(sc
.intypeof || global
.errors
);
3607 tthis
= fd
.isThis().type
.addMod(fd
.type
.mod
);
3609 if (tf
.isWild() && !fd
.isReturnIsolated())
3612 tret
= tret
.substWildTo(wildmatch
);
3614 if (!tret
.implicitConvTo(tthis
) && !(MODimplicitConv(tret
.mod
, tthis
.mod
) && tret
.isBaseOf(tthis
, &offset
) && offset
== 0))
3616 const(char)* s1
= tret
.isNaked() ?
" mutable" : tret
.modToChars();
3617 const(char)* s2
= tthis
.isNaked() ?
" mutable" : tthis
.modToChars();
3618 .error(loc
, "`inout` constructor `%s` creates%s object, not%s", fd
.toPrettyChars(), s1
, s2
);
3624 else if (wildmatch
&& tret
)
3626 /* Adjust function return type based on wildmatch
3628 //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret.toChars());
3629 tret
= tret
.substWildTo(wildmatch
);
3633 *peprefix
= eprefix
;
3634 return (err || olderrors
!= global
.errors
);
3638 * Determines whether a symbol represents a module or package
3639 * (Used as a helper for is(type == module) and is(type == package))
3642 * sym = the symbol to be checked
3645 * the symbol which `sym` represents (or `null` if it doesn't represent a `Package`)
3647 Package
resolveIsPackage(Dsymbol sym
)
3650 if (Import imp
= sym
.isImport())
3652 if (imp
.pkg
is null)
3654 .error(sym
.loc
, "internal compiler error: unable to process forward-referenced import `%s`",
3660 else if (auto mod
= sym
.isModule())
3661 pkg
= mod
.isPackageFile ? mod
.pkg
: sym
.isPackage();
3663 pkg
= sym
.isPackage();
3665 pkg
.resolvePKGunknown();
3670 private extern (C
++) final class ExpressionSemanticVisitor
: Visitor
3672 alias visit
= Visitor
.visit
;
3677 this(Scope
* sc
) scope @safe
3682 private void setError()
3684 result
= ErrorExp
.get();
3687 private void needThisError(Loc loc
, FuncDeclaration f
)
3689 auto t
= f
.isThis();
3691 .error(loc
, "calling non-static function `%s` requires an instance of type `%s`", f
.toChars(), t
.toChars());
3695 /**************************
3696 * Semantically analyze Expression.
3697 * Determine types, fold constants, etc.
3699 override void visit(Expression e
)
3701 static if (LOGSEMANTIC
)
3703 printf("Expression::semantic() %s\n", e
.toChars());
3706 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
3708 e
.type
= Type
.tvoid
;
3712 override void visit(IntegerExp e
)
3715 if (e
.type
.ty
== Terror
)
3718 assert(e
.type
.deco
);
3719 e
.setInteger(e
.getInteger());
3723 override void visit(RealExp e
)
3726 e
.type
= Type
.tfloat64
;
3727 else if (e
.type
.isimaginary
&& sc
.flags
& SCOPE
.Cfile
)
3729 /* Convert to core.stdc.config.complex
3731 Type t
= getComplexLibraryType(e
.loc
, sc
, e
.type
.ty
);
3738 case Timaginary32
: tf
= Type
.tfloat32
; break;
3739 case Timaginary64
: tf
= Type
.tfloat64
; break;
3740 case Timaginary80
: tf
= Type
.tfloat80
; break;
3745 /* Construct ts{re : 0.0, im : e}
3747 TypeStruct ts
= t
.isTypeStruct
;
3748 Expressions
* elements
= new Expressions(2);
3749 (*elements
)[0] = new RealExp(e
.loc
, CTFloat
.zero
, tf
);
3750 (*elements
)[1] = new RealExp(e
.loc
, e
.toImaginary(), tf
);
3751 Expression sle
= new StructLiteralExp(e
.loc
, ts
.sym
, elements
);
3752 result
= sle
.expressionSemantic(sc
);
3756 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
3760 override void visit(ComplexExp e
)
3763 e
.type
= Type
.tcomplex80
;
3765 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
3769 override void visit(IdentifierExp exp
)
3771 static if (LOGSEMANTIC
)
3773 printf("IdentifierExp::semantic('%s')\n", exp
.ident
.toChars());
3775 if (exp
.type
) // This is used as the dummy expression
3782 Dsymbol s
= sc
.search(exp
.loc
, exp
.ident
, scopesym
);
3790 /* See if the symbol was a member of an enclosing 'with'
3792 WithScopeSymbol withsym
= scopesym
.isWithScopeSymbol();
3793 if (withsym
&& withsym
.withstate
.wthis
&& symbolIsVisible(sc
, s
))
3795 /* Disallow shadowing
3797 // First find the scope of the with
3799 while (scwith
.scopesym
!= scopesym
)
3801 scwith
= scwith
.enclosing
;
3804 // Look at enclosing scopes for symbols with the same name,
3805 // in the same function
3806 for (Scope
* scx
= scwith
; scx
&& scx
.func
== scwith
.func
; scx
= scx
.enclosing
)
3809 if (scx
.scopesym
&& scx
.scopesym
.symtab
&& (s2
= scx
.scopesym
.symtab
.lookup(s
.ident
)) !is null && s
!= s2
)
3811 error(exp
.loc
, "with symbol `%s` is shadowing local symbol `%s`", s
.toPrettyChars(), s2
.toPrettyChars());
3817 // Same as wthis.ident
3818 // TODO: DotIdExp.semantic will find 'ident' from 'wthis' again.
3819 // The redudancy should be removed.
3820 e
= new VarExp(exp
.loc
, withsym
.withstate
.wthis
);
3821 e
= new DotIdExp(exp
.loc
, e
, exp
.ident
);
3822 e
= e
.expressionSemantic(sc
);
3828 if (withsym
.withstate
.exp
.type
.ty
!= Tvoid
)
3830 // 'with (exp)' is a type expression
3831 // or 's' is not visible there (for error message)
3832 e
= new TypeExp(exp
.loc
, withsym
.withstate
.exp
.type
);
3836 // 'with (exp)' is a Package/Module
3837 e
= withsym
.withstate
.exp
;
3839 e
= new DotIdExp(exp
.loc
, e
, exp
.ident
);
3840 result
= e
.expressionSemantic(sc
);
3844 /* If f is really a function template,
3845 * then replace f with the function template declaration.
3847 FuncDeclaration f
= s
.isFuncDeclaration();
3850 TemplateDeclaration td
= getFuncTemplateDecl(f
);
3853 if (td
.overroot
) // if not start of overloaded list of TemplateDeclaration's
3854 td
= td
.overroot
; // then get the start
3855 e
= new TemplateExp(exp
.loc
, td
, f
);
3856 e
= e
.expressionSemantic(sc
);
3862 if (global
.params
.fixAliasThis
)
3864 ExpressionDsymbol expDsym
= scopesym
.isExpressionDsymbol();
3867 //printf("expDsym = %s\n", expDsym.exp.toChars());
3868 result
= expDsym
.exp
.expressionSemantic(sc
);
3872 // Haven't done overload resolution yet, so pass 1
3873 e
= symbolToExp(s
, exp
.loc
, sc
, true);
3879 if (!global
.params
.fixAliasThis
&& hasThis(sc
))
3881 for (AggregateDeclaration ad
= sc
.getStructClassScope(); ad
;)
3886 e
= new ThisExp(exp
.loc
);
3887 e
= new DotIdExp(exp
.loc
, e
, ad
.aliasthis
.ident
);
3888 e
= new DotIdExp(exp
.loc
, e
, exp
.ident
);
3889 e
= e
.trySemantic(sc
);
3897 auto cd
= ad
.isClassDeclaration();
3898 if (cd
&& cd
.baseClass
&& cd
.baseClass
!= ClassDeclaration
.object
)
3907 if (exp
.ident
== Id
.ctfe
)
3909 if (sc
.flags
& SCOPE
.ctfe
)
3911 error(exp
.loc
, "variable `__ctfe` cannot be read at compile time");
3915 // Create the magic __ctfe bool variable
3916 auto vd
= new VarDeclaration(exp
.loc
, Type
.tbool
, Id
.ctfe
, null);
3917 vd
.storage_class |
= STC
.temp
;
3918 vd
.semanticRun
= PASS
.semanticdone
;
3919 Expression e
= new VarExp(exp
.loc
, vd
);
3920 e
= e
.expressionSemantic(sc
);
3925 // If we've reached this point and are inside a with() scope then we may
3926 // try one last attempt by checking whether the 'wthis' object supports
3927 // dynamic dispatching via opDispatch.
3928 // This is done by rewriting this expression as wthis.ident.
3929 // The innermost with() scope of the hierarchy to satisfy the condition
3931 // https://issues.dlang.org/show_bug.cgi?id=6400
3932 for (Scope
* sc2
= sc
; sc2
; sc2
= sc2
.enclosing
)
3937 if (auto ss
= sc2
.scopesym
.isWithScopeSymbol())
3939 if (ss
.withstate
.wthis
)
3942 e
= new VarExp(exp
.loc
, ss
.withstate
.wthis
);
3943 e
= new DotIdExp(exp
.loc
, e
, exp
.ident
);
3944 e
= e
.trySemantic(sc
);
3951 // Try Type.opDispatch (so the static version)
3952 else if (ss
.withstate
.exp
&& ss
.withstate
.exp
.op
== EXP
.type
)
3954 if (Type t
= ss
.withstate
.exp
.isTypeExp().type
)
3957 e
= new TypeExp(exp
.loc
, t
);
3958 e
= new DotIdExp(exp
.loc
, e
, exp
.ident
);
3959 e
= e
.trySemantic(sc
);
3970 /* Look for what user might have meant
3972 if (const n
= importHint(exp
.ident
.toString()))
3973 error(exp
.loc
, "`%s` is not defined, perhaps `import %.*s;` is needed?", exp
.ident
.toChars(), cast(int)n
.length
, n
.ptr
);
3974 else if (auto s2
= sc
.search_correct(exp
.ident
))
3975 error(exp
.loc
, "undefined identifier `%s`, did you mean %s `%s`?", exp
.ident
.toChars(), s2
.kind(), s2
.toChars());
3976 else if (const p
= Scope
.search_correct_C(exp
.ident
))
3977 error(exp
.loc
, "undefined identifier `%s`, did you mean `%s`?", exp
.ident
.toChars(), p
);
3978 else if (exp
.ident
== Id
.dollar
)
3979 error(exp
.loc
, "undefined identifier `$`");
3981 error(exp
.loc
, "undefined identifier `%s`", exp
.ident
.toChars());
3983 result
= ErrorExp
.get();
3986 override void visit(DsymbolExp e
)
3988 result
= symbolToExp(e
.s
, e
.loc
, sc
, e
.hasOverloads
);
3991 override void visit(ThisExp e
)
3993 static if (LOGSEMANTIC
)
3995 printf("ThisExp::semantic()\n");
4003 FuncDeclaration fd
= hasThis(sc
); // fd is the uplevel function with the 'this' variable
4004 AggregateDeclaration ad
;
4006 /* Special case for typeof(this) and typeof(super) since both
4007 * should work even if they are not inside a non-static member function
4009 if (!fd
&& sc
.intypeof
== 1)
4011 // Find enclosing struct or class
4012 for (Dsymbol s
= sc
.getStructClassScope(); 1; s
= s
.parent
)
4016 error(e
.loc
, "`%s` is not in a class or struct scope", e
.toChars());
4019 ClassDeclaration cd
= s
.isClassDeclaration();
4026 StructDeclaration sd
= s
.isStructDeclaration();
4037 error(e
.loc
, "`this` is only defined in non-static member functions, not `%s`", sc
.parent
.toChars());
4043 assert(e
.var
.parent
);
4044 ad
= fd
.isMemberLocal();
4046 ad
= fd
.isMember2();
4048 e
.type
= ad
.type
.addMod(e
.var
.type
.mod
);
4050 if (e
.var
.checkNestedReference(sc
, e
.loc
))
4056 override void visit(SuperExp e
)
4058 static if (LOGSEMANTIC
)
4060 printf("SuperExp::semantic('%s')\n", e
.toChars());
4068 FuncDeclaration fd
= hasThis(sc
);
4069 ClassDeclaration cd
;
4072 /* Special case for typeof(this) and typeof(super) since both
4073 * should work even if they are not inside a non-static member function
4075 if (!fd
&& sc
.intypeof
== 1)
4077 // Find enclosing class
4078 for (s
= sc
.getStructClassScope(); 1; s
= s
.parent
)
4082 error(e
.loc
, "`%s` is not in a class scope", e
.toChars());
4085 cd
= s
.isClassDeclaration();
4091 error(e
.loc
, "class `%s` has no `super`", s
.toChars());
4104 assert(e
.var
&& e
.var
.parent
);
4106 s
= fd
.toParentDecl();
4107 if (s
.isTemplateDeclaration()) // allow inside template constraint
4110 cd
= s
.isClassDeclaration();
4111 //printf("parent is %s %s\n", fd.toParent().kind(), fd.toParent().toChars());
4116 error(e
.loc
, "no base class for `%s`", cd
.toChars());
4117 e
.type
= cd
.type
.addMod(e
.var
.type
.mod
);
4121 e
.type
= cd
.baseClass
.type
;
4122 e
.type
= e
.type
.castMod(e
.var
.type
.mod
);
4125 if (e
.var
.checkNestedReference(sc
, e
.loc
))
4132 error(e
.loc
, "`super` is only allowed in non-static class member functions");
4133 result
= ErrorExp
.get();
4136 override void visit(NullExp e
)
4138 static if (LOGSEMANTIC
)
4140 printf("NullExp::semantic('%s')\n", e
.toChars());
4142 // NULL is the same as (void *)0
4148 e
.type
= Type
.tnull
;
4152 override void visit(InterpExp e
)
4154 // the lexer breaks up into an odd/even array of literals and expression code
4155 // we need to turn that into:
4158 .object.imported!"core.interpolation".InterpolationHeader(),
4160 .object.imported!"core.interpolation".InterpolationFooter()
4163 There the ... loops through them all, making the even ones
4164 .object.imported!"core.interpolation".InterpolatedLiteral!str()
4165 and making the odd ones
4166 .object.imported!"core.interpolation".InterpolatedExpression!str(),
4167 the code represented by str
4169 Empty string literals are skipped as they provide no additional information.
4173 error(e
.loc
, "String postfixes on interpolated expression sequences are not allowed.");
4175 Expression
makeNonTemplateItem(Identifier which
) {
4176 Expression id
= new IdentifierExp(e
.loc
, Id
.empty
);
4177 id
= new DotIdExp(e
.loc
, id
, Id
.object
);
4178 auto moduleNameArgs
= new Objects();
4179 moduleNameArgs
.push(new StringExp(e
.loc
, "core.interpolation"));
4180 id
= new DotTemplateInstanceExp(e
.loc
, id
, Id
.imported
, moduleNameArgs
);
4181 id
= new DotIdExp(e
.loc
, id
, which
);
4182 id
= new CallExp(e
.loc
, id
, new Expressions());
4186 Expression
makeTemplateItem(Identifier which
, string arg
) {
4187 Expression id
= new IdentifierExp(e
.loc
, Id
.empty
);
4188 id
= new DotIdExp(e
.loc
, id
, Id
.object
);
4189 auto moduleNameArgs
= new Objects();
4190 moduleNameArgs
.push(new StringExp(e
.loc
, "core.interpolation"));
4191 id
= new DotTemplateInstanceExp(e
.loc
, id
, Id
.imported
, moduleNameArgs
);
4192 auto tiargs
= new Objects();
4193 auto templateStringArg
= new StringExp(e
.loc
, arg
);
4194 // banning those instead of forwarding them
4195 // templateStringArg.postfix = e.postfix; // forward the postfix to these literals
4196 tiargs
.push(templateStringArg
);
4197 id
= new DotTemplateInstanceExp(e
.loc
, id
, which
, tiargs
);
4198 id
= new CallExp(e
.loc
, id
, new Expressions());
4202 auto arguments
= new Expressions();
4203 arguments
.push(makeNonTemplateItem(Id
.InterpolationHeader
));
4205 foreach (idx
, str; e
.interpolatedSet
.parts
)
4210 arguments
.push(makeTemplateItem(Id
.InterpolatedLiteral
, str));
4214 arguments
.push(makeTemplateItem(Id
.InterpolatedExpression
, str));
4215 Expressions
* mix
= new Expressions();
4216 mix
.push(new StringExp(e
.loc
, str));
4217 // FIXME: i'd rather not use MixinExp but idk how to do it lol
4218 arguments
.push(new MixinExp(e
.loc
, mix
));
4222 arguments
.push(makeNonTemplateItem(Id
.InterpolationFooter
));
4224 auto loweredTo
= new TupleExp(e
.loc
, arguments
);
4230 override void visit(StringExp e
)
4232 static if (LOGSEMANTIC
)
4234 printf("StringExp::semantic() %s\n", e
.toChars());
4254 e
.type
= Type
.tdstring
;
4259 e
.type
= Type
.twstring
;
4265 e
.type
= Type
.tstring
;
4269 if ((e
.len
% e
.sz
) != 0)
4270 error(e
.loc
, "hex string with `%s` type needs to be multiple of %d bytes, not %d",
4271 e
.type
.toChars(), e
.sz
, cast(int) e
.len
);
4273 e
.setData(arrayCastBigEndian(e
.peekData(), e
.sz
).ptr
, e
.len
/ e
.sz
, e
.sz
);
4275 else switch (e
.postfix
)
4278 for (u
= 0; u
< e
.len
;)
4280 if (const p
= utf_decodeChar(e
.peekString(), u
, c
))
4282 error(e
.loc
, "%.*s", cast(int)p
.length
, p
.ptr
);
4292 e
.setData(buffer
.extractData(), newlen
, 4);
4293 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
4294 e
.type
= Type
.tuns32
.sarrayOf(e
.len
+ 1);
4296 e
.type
= Type
.tdchar
.immutableOf().arrayOf();
4301 for (u
= 0; u
< e
.len
;)
4303 if (const p
= utf_decodeChar(e
.peekString(), u
, c
))
4305 error(e
.loc
, "%.*s", cast(int)p
.length
, p
.ptr
);
4310 buffer
.writeUTF16(c
);
4316 buffer
.writeUTF16(0);
4317 e
.setData(buffer
.extractData(), newlen
, 2);
4318 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
4319 e
.type
= Type
.tuns16
.sarrayOf(e
.len
+ 1);
4321 e
.type
= Type
.twchar
.immutableOf().arrayOf();
4330 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
4331 e
.type
= Type
.tchar
.sarrayOf(e
.len
+ 1);
4333 e
.type
= Type
.tchar
.immutableOf().arrayOf();
4336 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
4337 //type = type.immutableOf();
4338 //printf("type = %s\n", type.toChars());
4343 override void visit(TupleExp exp
)
4345 static if (LOGSEMANTIC
)
4347 printf("+TupleExp::semantic(%s)\n", exp
.toChars());
4356 exp
.e0
= exp
.e0
.expressionSemantic(sc
);
4358 // Run semantic() on each argument
4360 for (size_t i
= 0; i
< exp
.exps
.length
; i
++)
4362 Expression e
= (*exp
.exps
)[i
];
4363 e
= e
.expressionSemantic(sc
);
4366 error(exp
.loc
, "`%s` has no value", e
.toChars());
4369 else if (e
.op
== EXP
.error
)
4377 expandTuples(exp
.exps
);
4379 exp
.type
= new TypeTuple(exp
.exps
);
4380 exp
.type
= exp
.type
.typeSemantic(exp
.loc
, sc
);
4381 //printf("-TupleExp::semantic(%s)\n", toChars());
4385 override void visit(ArrayLiteralExp e
)
4387 static if (LOGSEMANTIC
)
4389 printf("ArrayLiteralExp::semantic('%s')\n", e
.toChars());
4397 /* Perhaps an empty array literal [ ] should be rewritten as null?
4401 e
.basis
= e
.basis
.expressionSemantic(sc
);
4402 if (arrayExpressionSemantic(e
.elements
.peekSlice(), sc
) ||
(e
.basis
&& e
.basis
.op
== EXP
.error
))
4405 expandTuples(e
.elements
);
4408 e
.elements
.push(e
.basis
);
4409 Type t0
= arrayExpressionToCommonType(sc
, *e
.elements
);
4411 e
.basis
= e
.elements
.pop();
4415 e
.type
= t0
.arrayOf();
4416 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
4418 /* Disallow array literals of type void being used.
4420 if (e
.elements
.length
> 0 && t0
.ty
== Tvoid
)
4422 error(e
.loc
, "`%s` of type `%s` has no value", e
.toChars(), e
.type
.toChars());
4426 if (global
.params
.useTypeInfo
&& Type
.dtypeinfo
)
4427 semanticTypeInfo(sc
, e
.type
);
4432 override void visit(AssocArrayLiteralExp e
)
4434 static if (LOGSEMANTIC
)
4436 printf("AssocArrayLiteralExp::semantic('%s')\n", e
.toChars());
4444 // Run semantic() on each element
4445 bool err_keys
= arrayExpressionSemantic(e
.keys
.peekSlice(), sc
);
4446 bool err_vals
= arrayExpressionSemantic(e
.values
.peekSlice(), sc
);
4447 if (err_keys || err_vals
)
4450 expandTuples(e
.keys
);
4451 expandTuples(e
.values
);
4452 if (e
.keys
.length
!= e
.values
.length
)
4454 error(e
.loc
, "number of keys is %llu, must match number of values %llu",
4455 cast(ulong) e
.keys
.length
, cast(ulong) e
.values
.length
);
4459 Type tkey
= arrayExpressionToCommonType(sc
, *e
.keys
);
4460 Type tvalue
= arrayExpressionToCommonType(sc
, *e
.values
);
4461 if (tkey
is null || tvalue
is null)
4464 e
.type
= new TypeAArray(tvalue
, tkey
);
4465 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
4467 semanticTypeInfo(sc
, e
.type
);
4469 if (checkAssocArrayLiteralEscape(sc
, e
, false))
4475 override void visit(StructLiteralExp e
)
4477 static if (LOGSEMANTIC
)
4479 printf("StructLiteralExp::semantic('%s')\n", e
.toChars());
4488 if (e
.sd
.sizeok
!= Sizeok
.done
)
4491 // run semantic() on each element
4492 if (arrayExpressionSemantic(e
.elements
.peekSlice(), sc
))
4495 expandTuples(e
.elements
);
4497 /* Fit elements[] to the corresponding type of field[].
4499 if (!e
.sd
.fit(e
.loc
, sc
, e
.elements
, e
.stype
))
4502 /* Fill out remainder of elements[] with default initializers for fields[]
4504 if (!e
.sd
.fill(e
.loc
, *e
.elements
, false))
4506 /* An error in the initializer needs to be recorded as an error
4507 * in the enclosing function or template, since the initializer
4508 * will be part of the stuct declaration.
4510 global
.increaseErrorCount();
4514 if (checkFrameAccess(e
.loc
, sc
, e
.sd
, e
.elements
.length
))
4517 e
.type
= e
.stype ? e
.stype
: e
.sd
.type
;
4521 override void visit(CompoundLiteralExp cle
)
4523 static if (LOGSEMANTIC
)
4525 printf("CompoundLiteralExp::semantic('%s')\n", cle
.toChars());
4527 Type t
= cle
.type
.typeSemantic(cle
.loc
, sc
);
4528 auto init
= initializerSemantic(cle
.initializer
, sc
, t
, INITnointerpret
);
4529 auto e
= initializerToExpression(init
, t
, (sc
.flags
& SCOPE
.Cfile
) != 0);
4532 error(cle
.loc
, "cannot convert initializer `%s` to expression", toChars(init
));
4539 override void visit(TypeExp exp
)
4541 if (exp
.type
.ty
== Terror
)
4544 //printf("TypeExp::semantic(%s)\n", exp.type.toChars());
4549 dmd
.typesem
.resolve(exp
.type
, exp
.loc
, sc
, e
, t
, s
, true);
4552 // `(Type)` is actually `(var)` so if `(var)` is a member requiring `this`
4553 // then rewrite as `(this.var)` in case it would be followed by a DotVar
4554 // to fix https://issues.dlang.org/show_bug.cgi?id=9490
4555 VarExp ve
= e
.isVarExp();
4556 if (ve
&& ve
.var
&& exp
.parens
&& !ve
.var
.isStatic() && !(sc
.stc & STC
.static_
) &&
4557 sc
.func
&& sc
.func
.needThis
&& ve
.var
.isMember2())
4559 // printf("apply fix for bugzilla issue 9490: add `this.` to `%s`...\n", e.toChars());
4560 e
= new DotVarExp(exp
.loc
, new ThisExp(exp
.loc
), ve
.var
, false);
4562 //printf("e = %s %s\n", Token.toChars(e.op), e.toChars());
4563 e
= e
.expressionSemantic(sc
);
4567 //printf("t = %d %s\n", t.ty, t.toChars());
4568 exp
.type
= t
.typeSemantic(exp
.loc
, sc
);
4573 //printf("s = %s %s\n", s.kind(), s.toChars());
4574 e
= symbolToExp(s
, exp
.loc
, sc
, true);
4579 exp
.type
.checkComplexTransition(exp
.loc
, sc
);
4584 override void visit(ScopeExp exp
)
4586 static if (LOGSEMANTIC
)
4588 printf("+ScopeExp::semantic(%p '%s')\n", exp
, exp
.toChars());
4596 ScopeDsymbol sds2
= exp
.sds
;
4597 TemplateInstance ti
= sds2
.isTemplateInstance();
4600 WithScopeSymbol withsym
;
4601 if (!ti
.findTempDecl(sc
, &withsym
) ||
!ti
.semanticTiargs(sc
))
4603 if (withsym
&& withsym
.withstate
.wthis
)
4605 Expression e
= new VarExp(exp
.loc
, withsym
.withstate
.wthis
);
4606 e
= new DotTemplateInstanceExp(exp
.loc
, e
, ti
);
4607 result
= e
.expressionSemantic(sc
);
4610 if (ti
.needsTypeInference(sc
))
4612 if (TemplateDeclaration td
= ti
.tempdecl
.isTemplateDeclaration())
4614 Dsymbol p
= td
.toParentLocal();
4615 FuncDeclaration fdthis
= hasThis(sc
);
4616 AggregateDeclaration ad
= p ? p
.isAggregateDeclaration() : null;
4617 if (fdthis
&& ad
&& fdthis
.isMemberLocal() == ad
&& (td
._scope
.stc & STC
.static_
) == 0)
4619 Expression e
= new DotTemplateInstanceExp(exp
.loc
, new ThisExp(exp
.loc
), ti
);
4620 result
= e
.expressionSemantic(sc
);
4624 else if (OverloadSet os
= ti
.tempdecl
.isOverloadSet())
4626 FuncDeclaration fdthis
= hasThis(sc
);
4627 AggregateDeclaration ad
= os
.parent
.isAggregateDeclaration();
4628 if (fdthis
&& ad
&& fdthis
.isMemberLocal() == ad
)
4630 Expression e
= new DotTemplateInstanceExp(exp
.loc
, new ThisExp(exp
.loc
), ti
);
4631 result
= e
.expressionSemantic(sc
);
4635 // ti is an instance which requires IFTI.
4637 exp
.type
= Type
.tvoid
;
4641 ti
.dsymbolSemantic(sc
);
4642 if (!ti
.inst || ti
.errors
)
4645 Dsymbol s
= ti
.toAlias();
4649 exp
.type
= Type
.tvoid
;
4653 sds2
= s
.isScopeDsymbol();
4656 ti
= sds2
.isTemplateInstance();
4657 //printf("+ sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
4661 if (auto v
= s
.isVarDeclaration())
4665 error(exp
.loc
, "forward reference of %s `%s`", v
.kind(), v
.toChars());
4668 if ((v
.storage_class
& STC
.manifest
) && v
._init
)
4670 /* When an instance that will be converted to a constant exists,
4671 * the instance representation "foo!tiargs" is treated like a
4672 * variable name, and its recursive appearance check (note that
4673 * it's equivalent with a recursive instantiation of foo) is done
4674 * separately from the circular initialization check for the
4675 * eponymous enum variable declaration.
4678 * enum bool foo = foo; // recursive definition check (v.inuse)
4681 * enum bool bar = bar!T; // recursive instantiation check (ti.inuse)
4686 error(exp
.loc
, "recursive expansion of %s `%s`", ti
.kind(), ti
.toPrettyChars());
4689 v
.checkDeprecated(exp
.loc
, sc
);
4690 auto e
= v
.expandInitializer(exp
.loc
);
4692 e
= e
.expressionSemantic(sc
);
4699 //printf("s = %s, '%s'\n", s.kind(), s.toChars());
4700 auto e
= symbolToExp(s
, exp
.loc
, sc
, true);
4701 //printf("-1ScopeExp::semantic()\n");
4706 //printf("sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
4707 //printf("\tparent = '%s'\n", sds2.parent.toChars());
4708 sds2
.dsymbolSemantic(sc
);
4710 // (Aggregate|Enum)Declaration
4711 if (auto t
= sds2
.getType())
4713 result
= (new TypeExp(exp
.loc
, t
)).expressionSemantic(sc
);
4717 if (auto td
= sds2
.isTemplateDeclaration())
4719 result
= (new TemplateExp(exp
.loc
, td
)).expressionSemantic(sc
);
4724 exp
.type
= Type
.tvoid
;
4725 //printf("-2ScopeExp::semantic() %s\n", toChars());
4730 * Sets the `lowering` field of a `NewExp` to a call to `_d_newitemT` unless
4731 * compiling with `-betterC` or within `__traits(compiles)`.
4734 * ne = the `NewExp` to lower
4736 private void tryLowerToNewItem(NewExp ne
)
4738 if (!global
.params
.useGC ||
!sc
.needsCodegen())
4741 auto hook
= global
.params
.tracegc ? Id
._d_newitemTTrace
: Id
._d_newitemT
;
4742 if (!verifyHookExist(ne
.loc
, *sc
, hook
, "new struct"))
4745 /* Lower the memory allocation and initialization of `new T()` to
4746 * `_d_newitemT!T()`.
4748 Expression id
= new IdentifierExp(ne
.loc
, Id
.empty
);
4749 id
= new DotIdExp(ne
.loc
, id
, Id
.object
);
4750 auto tiargs
= new Objects();
4752 * Remove `inout`, `const`, `immutable` and `shared` to reduce the
4753 * number of generated `_d_newitemT` instances.
4755 auto t
= ne
.type
.nextOf
.unqualify(MODFlags
.wild | MODFlags
.const_ |
4756 MODFlags
.immutable_ | MODFlags
.shared_
);
4758 id
= new DotTemplateInstanceExp(ne
.loc
, id
, hook
, tiargs
);
4760 auto arguments
= new Expressions();
4761 if (global
.params
.tracegc
)
4763 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ?
4764 sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
4765 arguments
.push(new StringExp(ne
.loc
, ne
.loc
.filename
.toDString()));
4766 arguments
.push(new IntegerExp(ne
.loc
, ne
.loc
.linnum
, Type
.tint32
));
4767 arguments
.push(new StringExp(ne
.loc
, funcname
.toDString()));
4769 id
= new CallExp(ne
.loc
, id
, arguments
);
4771 ne
.lowering
= id
.expressionSemantic(sc
);
4774 override void visit(NewExp exp
)
4776 static if (LOGSEMANTIC
)
4778 printf("NewExp::semantic() %s\n", exp
.toChars());
4780 printf("\tthisexp = %s\n", exp
.thisexp
.toChars());
4781 printf("\tnewtype: %s\n", exp
.newtype
.toChars());
4783 if (exp
.type
) // if semantic() already run
4789 //for error messages if the argument in [] is not convertible to size_t
4790 const originalNewtype
= exp
.newtype
;
4792 // https://issues.dlang.org/show_bug.cgi?id=11581
4793 // With the syntax `new T[edim]` or `thisexp.new T[edim]`,
4794 // T should be analyzed first and edim should go into arguments iff it's
4796 Expression edim
= null;
4797 if (!exp
.arguments
&& exp
.newtype
.isTypeSArray())
4799 auto ts
= exp
.newtype
.isTypeSArray();
4800 // check `new Value[Key]`
4801 ts
.dim
= ts
.dim
.expressionSemantic(sc
);
4802 if (ts
.dim
.op
== EXP
.type
)
4804 exp
.newtype
= new TypeAArray(ts
.next
, ts
.dim
.isTypeExp().type
);
4809 exp
.newtype
= ts
.next
;
4813 ClassDeclaration cdthis
= null;
4816 exp
.thisexp
= exp
.thisexp
.expressionSemantic(sc
);
4817 if (exp
.thisexp
.op
== EXP
.error
)
4820 cdthis
= exp
.thisexp
.type
.isClassHandle();
4823 error(exp
.loc
, "`this` for nested class must be a class type, not `%s`", exp
.thisexp
.type
.toChars());
4827 sc
= sc
.push(cdthis
);
4828 exp
.type
= exp
.newtype
.typeSemantic(exp
.loc
, sc
);
4833 exp
.type
= exp
.newtype
.typeSemantic(exp
.loc
, sc
);
4835 if (exp
.type
.ty
== Terror
)
4840 if (exp
.type
.toBasetype().ty
== Ttuple
)
4843 exp
.type
= new TypeSArray(exp
.type
, edim
);
4844 exp
.type
= exp
.type
.typeSemantic(exp
.loc
, sc
);
4845 if (exp
.type
.ty
== Terror
)
4850 // --> new T[](edim)
4851 exp
.arguments
= new Expressions();
4852 exp
.arguments
.push(edim
);
4853 exp
.type
= exp
.type
.arrayOf();
4857 exp
.newtype
= exp
.type
; // in case type gets cast to something else
4858 Type tb
= exp
.type
.toBasetype();
4859 //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco);
4860 if (arrayExpressionSemantic(exp
.arguments
.peekSlice(), sc
))
4864 if (preFunctionParameters(sc
, exp
.argumentList
))
4869 if (exp
.thisexp
&& tb
.ty
!= Tclass
)
4871 error(exp
.loc
, "`.new` is only for allocating nested classes, not `%s`", tb
.toChars());
4875 const size_t nargs
= exp
.arguments ? exp
.arguments
.length
: 0;
4876 Expression newprefix
= null;
4878 if (auto tc
= tb
.isTypeClass())
4884 if (cd
.sizeok
!= Sizeok
.done
)
4887 cd
.ctor
= cd
.searchCtor();
4888 if (cd
.noDefaultCtor
&& !nargs
&& !cd
.defaultCtor
)
4890 error(exp
.loc
, "default construction is disabled for type `%s`", cd
.type
.toChars());
4894 if (cd
.isInterfaceDeclaration())
4896 error(exp
.loc
, "cannot create instance of interface `%s`", cd
.toChars());
4900 if (cd
.isAbstract())
4902 error(exp
.loc
, "cannot create instance of abstract class `%s`", cd
.toChars());
4903 errorSupplemental(cd
.loc
, "class `%s` is declared here", cd
.toChars());
4904 for (size_t i
= 0; i
< cd
.vtbl
.length
; i
++)
4906 FuncDeclaration fd
= cd
.vtbl
[i
].isFuncDeclaration();
4907 if (fd
&& fd
.isAbstract())
4909 errorSupplemental(fd
.loc
, "function `%s` is not implemented",
4910 fd
.toFullSignature());
4915 // checkDeprecated() is already done in newtype.typeSemantic().
4919 /* We need a 'this' pointer for the nested class.
4920 * Ensure we have the right one.
4922 Dsymbol s
= cd
.toParentLocal();
4924 //printf("cd isNested, parent = %s '%s'\n", s.kind(), s.toPrettyChars());
4925 if (auto cdn
= s
.isClassDeclaration())
4929 void noReferenceToOuterClass()
4932 error(exp
.loc
, "cannot construct anonymous nested class because no implicit `this` reference to outer class is available");
4934 error(exp
.loc
, "cannot construct nested class `%s` because no implicit `this` reference to outer class `%s` is available",
4935 cd
.toChars(), cdn
.toChars());
4940 return noReferenceToOuterClass();
4942 // Supply an implicit 'this' and try again
4943 exp
.thisexp
= new ThisExp(exp
.loc
);
4944 for (Dsymbol sp
= sc
.parent
; 1; sp
= sp
.toParentLocal())
4947 return noReferenceToOuterClass();
4948 ClassDeclaration cdp
= sp
.isClassDeclaration();
4951 if (cdp
== cdn || cdn
.isBaseOf(cdp
, null))
4953 // Add a '.outer' and try again
4954 exp
.thisexp
= new DotIdExp(exp
.loc
, exp
.thisexp
, Id
.outer
);
4957 exp
.thisexp
= exp
.thisexp
.expressionSemantic(sc
);
4958 if (exp
.thisexp
.op
== EXP
.error
)
4960 cdthis
= exp
.thisexp
.type
.isClassHandle();
4962 if (cdthis
!= cdn
&& !cdn
.isBaseOf(cdthis
, null))
4964 //printf("cdthis = %s\n", cdthis.toChars());
4965 error(exp
.loc
, "`this` for nested class must be of type `%s`, not `%s`",
4966 cdn
.toChars(), exp
.thisexp
.type
.toChars());
4969 if (!MODimplicitConv(exp
.thisexp
.type
.mod
, exp
.newtype
.mod
))
4971 error(exp
.loc
, "nested type `%s` should have the same or weaker constancy as enclosing type `%s`",
4972 exp
.newtype
.toChars(), exp
.thisexp
.type
.toChars());
4976 else if (exp
.thisexp
)
4978 error(exp
.loc
, "`.new` is only for allocating nested classes");
4981 else if (auto fdn
= s
.isFuncDeclaration())
4983 // make sure the parent context fdn of cd is reachable from sc
4984 if (!ensureStaticLinkTo(sc
.parent
, fdn
))
4986 error(exp
.loc
, "outer function context of `%s` is needed to `new` nested class `%s`",
4987 fdn
.toPrettyChars(), cd
.toPrettyChars());
4994 else if (exp
.thisexp
)
4996 error(exp
.loc
, "`.new` is only for allocating nested classes");
5002 if (AggregateDeclaration ad2
= cd
.isMember2())
5004 Expression te
= new ThisExp(exp
.loc
).expressionSemantic(sc
);
5005 if (te
.op
!= EXP
.error
)
5006 te
= getRightThis(exp
.loc
, sc
, ad2
, te
, cd
);
5007 if (te
.op
== EXP
.error
)
5009 error(exp
.loc
, "need `this` of type `%s` needed to `new` nested class `%s`", ad2
.toChars(), cd
.toChars());
5015 if (cd
.disableNew
&& !exp
.onstack
)
5017 error(exp
.loc
, "cannot allocate `class %s` with `new` because it is annotated with `@disable new()`",
5018 originalNewtype
.toChars());
5024 FuncDeclaration f
= resolveFuncCall(exp
.loc
, sc
, cd
.ctor
, null, tb
, exp
.argumentList
, FuncResolveFlag
.standard
);
5028 checkFunctionAttributes(exp
, sc
, f
);
5029 if (!checkSymbolAccess(sc
, f
))
5031 error(exp
.loc
, "%s `%s` is not accessible from module `%s`",
5032 f
.kind(), f
.toPrettyChars(), sc
._module
.toChars
);
5036 TypeFunction tf
= f
.type
.isTypeFunction();
5038 exp
.arguments
= new Expressions();
5039 if (functionParameters(exp
.loc
, sc
, tf
, null, exp
.type
, exp
.argumentList
, f
, &exp
.type
, &exp
.argprefix
))
5042 exp
.member
= f
.isCtorDeclaration();
5049 error(exp
.loc
, "no constructor for `%s`", cd
.toChars());
5053 // https://issues.dlang.org/show_bug.cgi?id=19941
5054 // Run semantic on all field initializers to resolve any forward
5055 // references. This is the same as done for structs in sd.fill().
5056 for (ClassDeclaration c
= cd
; c
; c
= c
.baseClass
)
5058 foreach (v
; c
.fields
)
5060 if (v
.inuse || v
._scope
is null || v
._init
is null ||
5061 v
._init
.isVoidInitializer() || v
.semanticRun
>= PASS
.semantic2done
)
5064 v
._init
= v
._init
.initializerSemantic(v
._scope
, v
.type
, INITinterpret
);
5065 import dmd
.semantic2
: lowerStaticAAs
;
5066 lowerStaticAAs(v
, sc
);
5072 // When using `@nogc` exception handling, lower `throw new E(args)` to
5073 // `throw (__tmp = _d_newThrowable!E(), __tmp.__ctor(args), __tmp)`.
5074 if (global
.params
.ehnogc
&& exp
.thrownew
&&
5075 !cd
.isCOMclass() && !cd
.isCPPclass())
5079 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
5080 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
5082 auto tiargs
= new Objects();
5083 tiargs
.push(exp
.newtype
);
5084 id
= new DotTemplateInstanceExp(exp
.loc
, id
, Id
._d_newThrowable
, tiargs
);
5085 id
= new CallExp(exp
.loc
, id
).expressionSemantic(sc
);
5088 Expression tmp
= extractSideEffect(sc
, "__tmpThrowable", idVal
, id
, true);
5089 // auto castTmp = new CastExp(exp.loc, tmp, exp.type);
5091 auto ctor
= new DotIdExp(exp
.loc
, tmp
, Id
.ctor
).expressionSemantic(sc
);
5092 auto ctorCall
= new CallExp(exp
.loc
, ctor
, exp
.arguments
);
5094 id
= Expression
.combine(idVal
, exp
.argprefix
).expressionSemantic(sc
);
5095 id
= Expression
.combine(id
, ctorCall
).expressionSemantic(sc
);
5096 // id = Expression.combine(id, castTmp).expressionSemantic(sc);
5098 result
= id
.expressionSemantic(sc
);
5101 else if (sc
.needsCodegen() && // interpreter doesn't need this lowered
5102 !exp
.onstack
&& !exp
.type
.isscope()) // these won't use the GC
5104 /* replace `new T(arguments)` with `core.lifetime._d_newclassT!T(arguments)`
5105 * or `_d_newclassTTrace`
5107 auto hook
= global
.params
.tracegc ? Id
._d_newclassTTrace
: Id
._d_newclassT
;
5108 if (!verifyHookExist(exp
.loc
, *sc
, hook
, "new class"))
5111 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
5112 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
5114 auto tiargs
= new Objects();
5115 auto t
= exp
.newtype
.unqualify(MODFlags
.wild
); // remove `inout`
5117 id
= new DotTemplateInstanceExp(exp
.loc
, id
, hook
, tiargs
);
5118 auto arguments
= new Expressions();
5119 if (global
.params
.tracegc
)
5121 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ?
5122 sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
5123 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
5124 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
5125 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
5127 id
= new CallExp(exp
.loc
, id
, arguments
);
5129 exp
.lowering
= id
.expressionSemantic(sc
);
5132 else if (auto ts
= tb
.isTypeStruct())
5136 if (sd
.sizeok
!= Sizeok
.done
)
5139 sd
.ctor
= sd
.searchCtor();
5140 if (sd
.noDefaultCtor
&& !nargs
)
5142 error(exp
.loc
, "default construction is disabled for type `%s`", sd
.type
.toChars());
5145 // checkDeprecated() is already done in newtype.typeSemantic().
5149 error(exp
.loc
, "cannot allocate `struct %s` with `new` because it is annotated with `@disable new()`",
5150 originalNewtype
.toChars());
5154 // https://issues.dlang.org/show_bug.cgi?id=22639
5155 // If the new expression has arguments, we either should call a
5156 // regular constructor of a copy constructor if the first argument
5157 // is the same type as the struct
5158 if (nargs
&& (sd
.hasRegularCtor() ||
(sd
.ctor
&& (*exp
.arguments
)[0].type
.mutableOf() == sd
.type
.mutableOf())))
5160 FuncDeclaration f
= resolveFuncCall(exp
.loc
, sc
, sd
.ctor
, null, tb
, exp
.argumentList
, FuncResolveFlag
.standard
);
5164 checkFunctionAttributes(exp
, sc
, f
);
5165 checkAccess(sd
, exp
.loc
, sc
, f
);
5167 TypeFunction tf
= f
.type
.isTypeFunction();
5169 exp
.arguments
= new Expressions();
5170 if (functionParameters(exp
.loc
, sc
, tf
, null, exp
.type
, exp
.argumentList
, f
, &exp
.type
, &exp
.argprefix
))
5173 exp
.member
= f
.isCtorDeclaration();
5176 if (checkFrameAccess(exp
.loc
, sc
, sd
, sd
.fields
.length
))
5183 exp
.arguments
= resolveStructLiteralNamedArgs(sd
, exp
.type
, sc
, exp
.loc
,
5184 exp
.names ?
(*exp
.names
)[] : null,
5185 (size_t i
, Type t
) => (*exp
.arguments
)[i
],
5186 i
=> (*exp
.arguments
)[i
].loc
5191 else if (!exp
.arguments
)
5193 exp
.arguments
= new Expressions();
5196 if (!sd
.fit(exp
.loc
, sc
, exp
.arguments
, tb
))
5199 if (!sd
.fill(exp
.loc
, *exp
.arguments
, false))
5202 if (checkFrameAccess(exp
.loc
, sc
, sd
, exp
.arguments ? exp
.arguments
.length
: 0))
5205 /* Since a `new` allocation may escape, check each of the arguments for escaping
5207 foreach (arg
; *exp
.arguments
)
5209 if (arg
&& checkNewEscape(sc
, arg
, false))
5214 exp
.type
= exp
.type
.pointerTo();
5215 tryLowerToNewItem(exp
);
5217 else if (tb
.ty
== Tarray
)
5221 // https://issues.dlang.org/show_bug.cgi?id=20422
5222 // Without this check the compiler would give a misleading error
5223 error(exp
.loc
, "missing length argument for array");
5227 Type tn
= tb
.nextOf().baseElemOf();
5228 Dsymbol s
= tn
.toDsymbol(sc
);
5229 AggregateDeclaration ad
= s ? s
.isAggregateDeclaration() : null;
5230 if (ad
&& ad
.noDefaultCtor
)
5232 error(exp
.loc
, "default construction is disabled for type `%s`", tb
.nextOf().toChars());
5235 for (size_t i
= 0; i
< nargs
; i
++)
5237 if (tb
.ty
!= Tarray
)
5239 error(exp
.loc
, "too many arguments for array");
5243 Expression arg
= (*exp
.arguments
)[i
];
5244 if (exp
.names
&& (*exp
.names
)[i
])
5246 error(exp
.loc
, "no named argument `%s` allowed for array dimension", (*exp
.names
)[i
].toChars());
5250 arg
= resolveProperties(sc
, arg
);
5251 arg
= arg
.implicitCastTo(sc
, Type
.tsize_t
);
5252 if (arg
.op
== EXP
.error
)
5254 arg
= arg
.optimize(WANTvalue
);
5255 if (arg
.op
== EXP
.int64
&& (target
.isLP64 ?
5256 cast(sinteger_t
)arg
.toInteger() : cast(int)arg
.toInteger()) < 0)
5258 error(exp
.loc
, "negative array dimension `%s`", (*exp
.arguments
)[i
].toChars());
5261 (*exp
.arguments
)[i
] = arg
;
5262 tb
= tb
.isTypeDArray().next
.toBasetype();
5265 if (!global
.params
.useGC
&& sc
.needsCodegen())
5268 error(exp
.loc
, "expression `%s` allocates with the GC and cannot be used with switch `-fno-rtti`", exp
.toChars());
5270 error(exp
.loc
, "expression `%s` allocates with the GC and cannot be used with switch `-betterC`", exp
.toChars());
5274 if (!sc
.needsCodegen())
5275 goto LskipNewArrayLowering
;
5277 /* Class types may inherit base classes that have errors.
5278 * This may leak errors from the base class to the derived one
5279 * and then to the hook. Semantic analysis is performed eagerly
5282 if (auto tc
= exp
.type
.nextOf
.isTypeClass())
5284 tc
.sym
.dsymbolSemantic(sc
);
5286 goto LskipNewArrayLowering
;
5291 auto hook
= global
.params
.tracegc ? Id
._d_newarrayTTrace
: Id
._d_newarrayT
;
5292 if (!verifyHookExist(exp
.loc
, *sc
, hook
, "new array"))
5293 goto LskipNewArrayLowering
;
5295 /* Lower the memory allocation and initialization of `new T[n]`
5296 * to `_d_newarrayT!T(n)`.
5298 Expression lowering
= new IdentifierExp(exp
.loc
, Id
.empty
);
5299 lowering
= new DotIdExp(exp
.loc
, lowering
, Id
.object
);
5300 auto tiargs
= new Objects();
5301 /* Remove `inout`, `const`, `immutable` and `shared` to reduce
5302 * the number of generated `_d_newarrayT` instances.
5304 const isShared
= exp
.type
.nextOf
.isShared();
5305 auto t
= exp
.type
.nextOf
.unqualify(MODFlags
.wild | MODFlags
.const_ |
5306 MODFlags
.immutable_ | MODFlags
.shared_
);
5308 lowering
= new DotTemplateInstanceExp(exp
.loc
, lowering
, hook
, tiargs
);
5310 auto arguments
= new Expressions();
5311 if (global
.params
.tracegc
)
5313 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ?
5314 sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
5315 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
5316 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
5317 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
5319 arguments
.push((*exp
.arguments
)[0]);
5320 arguments
.push(new IntegerExp(exp
.loc
, isShared
, Type
.tbool
));
5322 lowering
= new CallExp(exp
.loc
, lowering
, arguments
);
5323 exp
.lowering
= lowering
.expressionSemantic(sc
);
5327 auto hook
= global
.params
.tracegc ? Id
._d_newarraymTXTrace
: Id
._d_newarraymTX
;
5328 if (!verifyHookExist(exp
.loc
, *sc
, hook
, "new multi-dimensional array"))
5329 goto LskipNewArrayLowering
;
5331 /* Lower the memory allocation and initialization of `new T[][]...[](n1, n2, ...)`
5332 * to `_d_newarraymTX!(T[][]...[], T)([n1, n2, ...])`.
5334 Expression lowering
= new IdentifierExp(exp
.loc
, Id
.empty
);
5335 lowering
= new DotIdExp(exp
.loc
, lowering
, Id
.object
);
5337 auto tbn
= exp
.type
.nextOf();
5338 while (tbn
.ty
== Tarray
)
5340 auto unqualTbn
= tbn
.unqualify(MODFlags
.wild | MODFlags
.const_ |
5341 MODFlags
.immutable_ | MODFlags
.shared_
);
5343 auto tiargs
= new Objects();
5344 tiargs
.push(exp
.type
);
5345 tiargs
.push(unqualTbn
);
5346 lowering
= new DotTemplateInstanceExp(exp
.loc
, lowering
, hook
, tiargs
);
5348 auto arguments
= new Expressions();
5349 if (global
.params
.tracegc
)
5351 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ?
5352 sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
5353 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
5354 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
5355 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
5358 arguments
.push(new ArrayLiteralExp(exp
.loc
, Type
.tsize_t
.sarrayOf(nargs
), exp
.arguments
));
5359 arguments
.push(new IntegerExp(exp
.loc
, tbn
.isShared(), Type
.tbool
));
5361 lowering
= new CallExp(exp
.loc
, lowering
, arguments
);
5362 exp
.lowering
= lowering
.expressionSemantic(sc
);
5365 else if (tb
.isscalar())
5370 else if (nargs
== 1)
5372 if (exp
.names
&& (*exp
.names
)[0])
5374 error(exp
.loc
, "no named argument `%s` allowed for scalar", (*exp
.names
)[0].toChars());
5377 Expression e
= (*exp
.arguments
)[0];
5378 e
= e
.implicitCastTo(sc
, tb
);
5379 (*exp
.arguments
)[0] = e
;
5383 error(exp
.loc
, "more than one argument for construction of `%s`", exp
.type
.toChars());
5387 exp
.type
= exp
.type
.pointerTo();
5388 tryLowerToNewItem(exp
);
5390 else if (tb
.ty
== Taarray
)
5392 // e.g. `new Alias(args)`
5395 error(exp
.loc
, "`new` cannot take arguments for an associative array");
5401 error(exp
.loc
, "cannot create a `%s` with `new`", exp
.type
.toChars());
5405 LskipNewArrayLowering
:
5406 //printf("NewExp: '%s'\n", toChars());
5407 //printf("NewExp:type '%s'\n", type.toChars());
5408 semanticTypeInfo(sc
, exp
.type
);
5412 result
= Expression
.combine(newprefix
, exp
);
5418 override void visit(NewAnonClassExp e
)
5420 static if (LOGSEMANTIC
)
5422 printf("NewAnonClassExp::semantic() %s\n", e
.toChars());
5423 //printf("thisexp = %p\n", thisexp);
5424 //printf("type: %s\n", type.toChars());
5427 Expression d
= new DeclarationExp(e
.loc
, e
.cd
);
5428 sc
= sc
.push(); // just create new scope
5429 sc
.flags
&= ~SCOPE
.ctfe
; // temporary stop CTFE
5430 d
= d
.expressionSemantic(sc
);
5433 if (!e
.cd
.errors
&& sc
.intypeof
&& !sc
.parent
.inNonRoot())
5435 ScopeDsymbol sds
= sc
.tinst ?
cast(ScopeDsymbol
)sc
.tinst
: sc
._module
;
5437 sds
.members
= new Dsymbols();
5438 sds
.members
.push(e
.cd
);
5441 Expression n
= new NewExp(e
.loc
, e
.thisexp
, e
.cd
.type
, e
.arguments
);
5443 Expression c
= new CommaExp(e
.loc
, d
, n
);
5444 result
= c
.expressionSemantic(sc
);
5447 override void visit(SymOffExp e
)
5449 static if (LOGSEMANTIC
)
5451 printf("SymOffExp::semantic('%s')\n", e
.toChars());
5453 //var.dsymbolSemantic(sc);
5455 e
.type
= e
.var
.type
.pointerTo();
5457 if (auto v
= e
.var
.isVarDeclaration())
5459 if (v
.checkNestedReference(sc
, e
.loc
))
5462 else if (auto f
= e
.var
.isFuncDeclaration())
5464 if (f
.checkNestedReference(sc
, e
.loc
))
5471 override void visit(VarExp e
)
5473 static if (LOGSEMANTIC
)
5475 printf("VarExp::semantic(%s)\n", e
.toChars());
5478 auto vd
= e
.var
.isVarDeclaration();
5479 auto fd
= e
.var
.isFuncDeclaration();
5483 //printf("L%d fd = %s\n", __LINE__, f.toChars());
5484 if (!functionSemantic(fd
))
5489 e
.type
= e
.var
.type
;
5490 if (e
.type
&& !e
.type
.deco
)
5492 auto decl
= e
.var
.isDeclaration();
5495 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
5500 /* Fix for 1161 doesn't work because it causes visibility
5501 * problems when instantiating imported templates passing private
5502 * variables as alias template parameters.
5504 //checkAccess(loc, sc, NULL, var);
5508 if (vd
.checkNestedReference(sc
, e
.loc
))
5511 // https://issues.dlang.org/show_bug.cgi?id=12025
5512 // If the variable is not actually used in runtime code,
5513 // the purity violation error is redundant.
5514 //checkPurity(sc, vd);
5518 // TODO: If fd isn't yet resolved its overload, the checkNestedReference
5519 // call would cause incorrect validation.
5520 // Maybe here should be moved in CallExp, or AddrExp for functions.
5521 if (fd
.checkNestedReference(sc
, e
.loc
))
5524 else if (auto od
= e
.var
.isOverDeclaration())
5526 e
.type
= Type
.tvoid
; // ambiguous type?
5532 private void genIdent(FuncExp exp
, Scope
* sc
)
5534 if (exp
.fd
.ident
== Id
.empty
)
5538 s
= "__foreachbody";
5539 else if (exp
.fd
.tok
== TOK
.reserved
)
5541 else if (exp
.fd
.tok
== TOK
.delegate_
)
5544 s
= "__funcliteral";
5546 DsymbolTable symtab
;
5547 if (FuncDeclaration func
= sc
.parent
.isFuncDeclaration())
5549 if (func
.localsymtab
is null)
5551 // Inside template constraint, symtab is not set yet.
5552 // Initialize it lazily.
5553 func
.localsymtab
= new DsymbolTable();
5555 symtab
= func
.localsymtab
;
5559 ScopeDsymbol sds
= sc
.parent
.isScopeDsymbol();
5562 // Inside template constraint, symtab may not be set yet.
5563 // Initialize it lazily.
5564 assert(sds
.isTemplateInstance());
5565 sds
.symtab
= new DsymbolTable();
5567 symtab
= sds
.symtab
;
5570 Identifier id
= Identifier
.generateId(s
, symtab
.length() + 1);
5574 symtab
.insert(exp
.td ?
cast(Dsymbol
)exp
.td
: cast(Dsymbol
)exp
.fd
);
5578 override void visit(FuncExp exp
)
5580 static if (LOGSEMANTIC
)
5582 printf("FuncExp::semantic(%s)\n", exp
.toChars());
5584 printf(" treq = %s\n", exp
.fd
.treq
.toChars());
5596 sc
= sc
.push(); // just create new scope
5597 sc
.flags
&= ~SCOPE
.ctfe
; // temporary stop CTFE
5598 sc
.visibility
= Visibility(Visibility
.Kind
.public_
); // https://issues.dlang.org/show_bug.cgi?id=12506
5600 /* fd.treq might be incomplete type,
5601 * so should not semantic it.
5602 * void foo(T)(T delegate(int) dg){}
5603 * foo(a=>a); // in IFTI, treq == T delegate(int)
5606 // fd.treq = fd.treq.dsymbolSemantic(loc, sc);
5610 // Set target of return type inference
5611 if (exp
.fd
.treq
&& !exp
.fd
.type
.nextOf())
5613 TypeFunction tfv
= null;
5614 if (exp
.fd
.treq
.ty
== Tdelegate || exp
.fd
.treq
.isPtrToFunction())
5615 tfv
= cast(TypeFunction
)exp
.fd
.treq
.nextOf();
5618 TypeFunction tfl
= cast(TypeFunction
)exp
.fd
.type
;
5619 tfl
.next
= tfv
.nextOf();
5623 //printf("td = %p, treq = %p\n", td, fd.treq);
5626 assert(exp
.td
.parameters
&& exp
.td
.parameters
.length
);
5627 exp
.td
.dsymbolSemantic(sc
);
5628 exp
.type
= Type
.tvoid
; // temporary type
5630 if (exp
.fd
.treq
) // defer type determination
5633 if (exp
.matchType(exp
.fd
.treq
, sc
, &fe
, sc
.eSink
) > MATCH
.nomatch
)
5641 olderrors
= global
.errors
;
5642 exp
.fd
.dsymbolSemantic(sc
);
5643 if (olderrors
== global
.errors
)
5645 exp
.fd
.semantic2(sc
);
5646 if (olderrors
== global
.errors
)
5647 exp
.fd
.semantic3(sc
);
5649 if (olderrors
!= global
.errors
)
5651 if (exp
.fd
.type
&& exp
.fd
.type
.ty
== Tfunction
&& !exp
.fd
.type
.nextOf())
5652 (cast(TypeFunction
)exp
.fd
.type
).next
= Type
.terror
;
5657 // Type is a "delegate to" or "pointer to" the function literal
5658 if ((exp
.fd
.isNested() && exp
.fd
.tok
== TOK
.delegate_
) ||
(exp
.tok
== TOK
.reserved
&& exp
.fd
.treq
&& exp
.fd
.treq
.ty
== Tdelegate
))
5660 // https://issues.dlang.org/show_bug.cgi?id=22686
5661 // if the delegate return type is an error
5662 // abort semantic of the FuncExp and propagate
5664 if (exp
.fd
.type
.isTypeError())
5669 exp
.type
= new TypeDelegate(exp
.fd
.type
.isTypeFunction());
5670 exp
.type
= exp
.type
.typeSemantic(exp
.loc
, sc
);
5672 exp
.fd
.tok
= TOK
.delegate_
;
5676 exp
.type
= new TypePointer(exp
.fd
.type
);
5677 exp
.type
= exp
.type
.typeSemantic(exp
.loc
, sc
);
5678 //type = fd.type.pointerTo();
5680 /* A lambda expression deduced to function pointer might become
5681 * to a delegate literal implicitly.
5683 * auto foo(void function() fp) { return 1; }
5684 * assert(foo({}) == 1);
5686 * So, should keep fd.tok == TOK.reserve if fd.treq == NULL.
5688 if (exp
.fd
.treq
&& exp
.fd
.treq
.ty
== Tpointer
)
5690 // change to non-nested
5691 exp
.fd
.tok
= TOK
.function_
;
5692 exp
.fd
.vthis
= null;
5695 exp
.fd
.tookAddressOf
++;
5703 * Perform semantic analysis on function literals
5705 * Test the following construct:
5707 * (x, y, z) { return x + y + z; }(42, 84, 1992);
5710 Expression
callExpSemantic(FuncExp exp
, Scope
* sc
, Expressions
* arguments
)
5712 if ((!exp
.type || exp
.type
== Type
.tvoid
) && exp
.td
&& arguments
&& arguments
.length
)
5714 for (size_t k
= 0; k
< arguments
.length
; k
++)
5716 Expression checkarg
= (*arguments
)[k
];
5717 if (checkarg
.op
== EXP
.error
)
5723 assert(exp
.td
.parameters
&& exp
.td
.parameters
.length
);
5724 exp
.td
.dsymbolSemantic(sc
);
5726 TypeFunction tfl
= cast(TypeFunction
)exp
.fd
.type
;
5727 size_t dim
= tfl
.parameterList
.length
;
5728 if (arguments
.length
< dim
)
5730 // Default arguments are always typed, so they don't need inference.
5731 Parameter p
= tfl
.parameterList
[arguments
.length
];
5733 dim
= arguments
.length
;
5736 if ((tfl
.parameterList
.varargs
== VarArg
.none
&& arguments
.length
> dim
) ||
5737 arguments
.length
< dim
)
5740 foreach (idx
, ref arg
; *arguments
)
5741 buf
.printf("%s%s", (idx ?
", ".ptr
: "".ptr
), arg
.type
.toChars());
5742 error(exp
.loc
, "function literal `%s%s` is not callable using argument types `(%s)`",
5743 exp
.fd
.toChars(), parametersTypeToChars(tfl
.parameterList
),
5745 errorSupplemental(exp
.loc
, "too %s arguments, expected %d, got %d",
5746 arguments
.length
< dim ?
"few".ptr
: "many".ptr
,
5747 cast(int)dim
, cast(int)arguments
.length
);
5748 return ErrorExp
.get();
5751 auto tiargs
= new Objects();
5752 tiargs
.reserve(exp
.td
.parameters
.length
);
5754 for (size_t i
= 0; i
< exp
.td
.parameters
.length
; i
++)
5756 TemplateParameter tp
= (*exp
.td
.parameters
)[i
];
5757 assert(dim
<= tfl
.parameterList
.length
);
5758 foreach (u
, p
; tfl
.parameterList
)
5763 if (p
.type
.ty
== Tident
&& (cast(TypeIdentifier
)p
.type
).ident
== tp
.ident
)
5765 Expression e
= (*arguments
)[u
];
5766 tiargs
.push(e
.type
);
5772 auto ti
= new TemplateInstance(exp
.loc
, exp
.td
, tiargs
);
5773 return (new ScopeExp(exp
.loc
, ti
)).expressionSemantic(sc
);
5775 return exp
.expressionSemantic(sc
);
5778 override void visit(CallExp exp
)
5780 static if (LOGSEMANTIC
)
5782 printf("CallExp::semantic() %s\n", exp
.toChars());
5787 return; // semantic() already run
5790 Objects
* tiargs
= null; // initial list of template arguments
5791 Expression ethis
= null;
5793 Expression e1org
= exp
.e1
;
5795 if (auto ce
= exp
.e1
.isCommaExp())
5797 /* Rewrite (a,b)(args) as (a,(b(args)))
5801 result
= ce
.expressionSemantic(sc
);
5804 if (DelegateExp
de = exp
.e1
.isDelegateExp())
5806 exp
.e1
= new DotVarExp(de.loc
, de.e1
, de.func
, de.hasOverloads
);
5810 if (FuncExp fe
= exp
.e1
.isFuncExp())
5812 if (arrayExpressionSemantic(exp
.arguments
.peekSlice(), sc
) ||
5813 preFunctionParameters(sc
, exp
.argumentList
))
5816 // Run e1 semantic even if arguments have any errors
5817 exp
.e1
= callExpSemantic(fe
, sc
, exp
.arguments
);
5818 if (exp
.e1
.op
== EXP
.error
)
5824 if (sc
.flags
& SCOPE
.Cfile
)
5826 /* See if need to rewrite the AST because of cast/call ambiguity
5828 if (auto e
= castCallAmbiguity(exp
, sc
))
5830 result
= expressionSemantic(e
, sc
);
5835 if (Expression ex
= resolveUFCS(sc
, exp
))
5842 * foo!(tiargs)(funcargs)
5844 if (ScopeExp se
= exp
.e1
.isScopeExp())
5846 TemplateInstance ti
= se
.sds
.isTemplateInstance();
5849 /* Attempt to instantiate ti. If that works, go with it.
5850 * If not, go with partial explicit specialization.
5852 WithScopeSymbol withsym
;
5853 if (!ti
.findTempDecl(sc
, &withsym
) ||
!ti
.semanticTiargs(sc
))
5855 if (withsym
&& withsym
.withstate
.wthis
)
5857 exp
.e1
= new VarExp(exp
.e1
.loc
, withsym
.withstate
.wthis
);
5858 exp
.e1
= new DotTemplateInstanceExp(exp
.e1
.loc
, exp
.e1
, ti
);
5861 if (ti
.needsTypeInference(sc
, 1))
5863 /* Go with partial explicit specialization
5866 assert(ti
.tempdecl
);
5867 if (TemplateDeclaration td
= ti
.tempdecl
.isTemplateDeclaration())
5868 exp
.e1
= new TemplateExp(exp
.loc
, td
);
5869 else if (OverDeclaration od
= ti
.tempdecl
.isOverDeclaration())
5870 exp
.e1
= new VarExp(exp
.loc
, od
);
5872 exp
.e1
= new OverExp(exp
.loc
, ti
.tempdecl
.isOverloadSet());
5876 Expression e1x
= exp
.e1
.expressionSemantic(sc
);
5877 if (e1x
.op
== EXP
.error
)
5888 * expr.foo!(tiargs)(funcargs)
5891 if (DotTemplateInstanceExp se
= exp
.e1
.isDotTemplateInstanceExp())
5893 TemplateInstance ti
= se
.ti
;
5895 /* Attempt to instantiate ti. If that works, go with it.
5896 * If not, go with partial explicit specialization.
5898 if (!se
.findTempDecl(sc
) ||
!ti
.semanticTiargs(sc
))
5900 if (ti
.needsTypeInference(sc
, 1))
5902 /* Go with partial explicit specialization
5905 assert(ti
.tempdecl
);
5906 if (TemplateDeclaration td
= ti
.tempdecl
.isTemplateDeclaration())
5907 exp
.e1
= new DotTemplateExp(exp
.loc
, se
.e1
, td
);
5908 else if (OverDeclaration od
= ti
.tempdecl
.isOverDeclaration())
5910 exp
.e1
= new DotVarExp(exp
.loc
, se
.e1
, od
, true);
5913 exp
.e1
= new DotExp(exp
.loc
, se
.e1
, new OverExp(exp
.loc
, ti
.tempdecl
.isOverloadSet()));
5917 Expression e1x
= exp
.e1
.expressionSemantic(sc
);
5918 if (e1x
.op
== EXP
.error
)
5930 //printf("Lagain: %s\n", toChars());
5932 if (exp
.e1
.op
== EXP
.this_ || exp
.e1
.op
== EXP
.super_
)
5934 // semantic() run later for these
5938 if (DotIdExp die
= exp
.e1
.isDotIdExp())
5940 exp
.e1
= die
.expressionSemantic(sc
);
5941 /* Look for e1 having been rewritten to expr.opDispatch!(string)
5942 * We handle such earlier, so go back.
5943 * Note that in the rewrite, we carefully did not run semantic() on e1
5945 if (exp
.e1
.op
== EXP
.dotTemplateInstance
)
5953 if (++nest
> global
.recursionLimit
)
5955 error(exp
.loc
, "recursive evaluation of `%s`", exp
.toChars());
5959 Expression ex
= unaSemantic(exp
, sc
);
5968 /* Look for e1 being a lazy parameter
5970 if (VarExp ve
= exp
.e1
.isVarExp())
5972 if (ve
.var
.storage_class
& STC
.lazy_
)
5974 // lazy parameters can be called without violating purity and safety
5975 Type tw
= ve
.var
.type
;
5976 Type tc
= ve
.var
.type
.substWildTo(MODFlags
.const_
);
5977 auto tf
= new TypeFunction(ParameterList(), tc
, LINK
.d
, STC
.safe | STC
.pure_
);
5978 (tf
= cast(TypeFunction
)tf
.typeSemantic(exp
.loc
, sc
)).next
= tw
; // hack for bug7757
5979 auto t
= new TypeDelegate(tf
);
5980 ve
.type
= t
.typeSemantic(exp
.loc
, sc
);
5982 VarDeclaration v
= ve
.var
.isVarDeclaration();
5983 if (v
&& v
.checkPurity(ve
.loc
, sc
))
5987 if (exp
.e1
.op
== EXP
.symbolOffset
&& (cast(SymOffExp
)exp
.e1
).hasOverloads
)
5989 SymOffExp se
= cast(SymOffExp
)exp
.e1
;
5990 exp
.e1
= new VarExp(se
.loc
, se
.var
, true);
5991 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
5993 else if (DotExp
de = exp
.e1
.isDotExp())
5995 if (de.e2
.op
== EXP
.overloadSet
)
6002 else if (exp
.e1
.op
== EXP
.star
&& exp
.e1
.type
.ty
== Tfunction
)
6004 // Rewrite (*fp)(arguments) to fp(arguments)
6005 exp
.e1
= (cast(PtrExp
)exp
.e1
).e1
;
6007 else if (exp
.e1
.op
== EXP
.type
&& (sc
&& sc
.flags
& SCOPE
.Cfile
))
6009 const numArgs
= exp
.arguments ? exp
.arguments
.length
: 0;
6011 /* Ambiguous cases arise from CParser where there is not enough
6012 * information to determine if we have a function call or declaration.
6013 * type-name ( identifier ) ;
6014 * identifier ( identifier ) ;
6015 * If exp.e1 is a type-name, then this is a declaration. C11 does not
6016 * have type construction syntax, so don't convert this to a cast().
6020 Expression arg
= (*exp
.arguments
)[0];
6021 if (auto ie
= (*exp
.arguments
)[0].isIdentifierExp())
6023 TypeExp te
= cast(TypeExp
)exp
.e1
;
6024 auto initializer
= new VoidInitializer(ie
.loc
);
6025 Dsymbol s
= new VarDeclaration(ie
.loc
, te
.type
, ie
.ident
, initializer
);
6026 auto decls
= new Dsymbols(1);
6028 s
= new LinkDeclaration(s
.loc
, LINK
.c
, decls
);
6029 result
= new DeclarationExp(exp
.loc
, s
);
6030 result
= result
.expressionSemantic(sc
);
6034 error(arg
.loc
, "identifier or `(` expected");
6035 result
= ErrorExp
.get();
6039 error(exp
.loc
, "identifier or `(` expected before `)`");
6040 result
= ErrorExp
.get();
6045 Type t1
= exp
.e1
.type ? exp
.e1
.type
.toBasetype() : null;
6047 if (exp
.e1
.op
== EXP
.error
)
6052 if (arrayExpressionSemantic(exp
.arguments
.peekSlice(), sc
) ||
6053 preFunctionParameters(sc
, exp
.argumentList
))
6056 // Check for call operator overload
6059 if (t1
.ty
== Tstruct
)
6061 auto sd
= (cast(TypeStruct
)t1
).sym
;
6062 sd
.size(exp
.loc
); // Resolve forward references to construct object
6063 if (sd
.sizeok
!= Sizeok
.done
)
6066 sd
.ctor
= sd
.searchCtor();
6067 /* If `sd.ctor` is a generated copy constructor, this means that it
6068 is the single constructor that this struct has. In order to not
6069 disable default construction, the ctor is nullified. The side effect
6070 of this is that the generated copy constructor cannot be called
6071 explicitly, but that is ok, because when calling a constructor the
6072 default constructor should have priority over the generated copy
6077 auto ctor
= sd
.ctor
.isCtorDeclaration();
6078 if (ctor
&& ctor
.isCpCtor
&& ctor
.isGenerated())
6082 // First look for constructor
6083 if (exp
.e1
.op
== EXP
.type
&& sd
.ctor
)
6085 if (!sd
.noDefaultCtor
&& !(exp
.arguments
&& exp
.arguments
.length
))
6088 /* https://issues.dlang.org/show_bug.cgi?id=20695
6089 If all constructors are copy constructors, then
6090 try default construction.
6092 if (!sd
.hasRegularCtor
&&
6093 // https://issues.dlang.org/show_bug.cgi?id=22639
6094 // we might still have a copy constructor that could be called
6095 (*exp
.arguments
)[0].type
.mutableOf
!= sd
.type
.mutableOf())
6098 auto sle
= new StructLiteralExp(exp
.loc
, sd
, null, exp
.e1
.type
);
6099 if (!sd
.fill(exp
.loc
, *sle
.elements
, true))
6101 if (checkFrameAccess(exp
.loc
, sc
, sd
, sle
.elements
.length
))
6104 // https://issues.dlang.org/show_bug.cgi?id=14556
6105 // Set concrete type to avoid further redundant semantic().
6106 sle
.type
= exp
.e1
.type
;
6108 /* Constructor takes a mutable object, so don't use
6109 * the immutable initializer symbol.
6111 sle
.useStaticInit
= false;
6114 if (auto cf
= sd
.ctor
.isCtorDeclaration())
6116 e
= new DotVarExp(exp
.loc
, e
, cf
, true);
6118 else if (auto td
= sd
.ctor
.isTemplateDeclaration())
6120 e
= new DotIdExp(exp
.loc
, e
, td
.ident
);
6122 else if (auto os
= sd
.ctor
.isOverloadSet())
6124 e
= new DotExp(exp
.loc
, e
, new OverExp(exp
.loc
, os
));
6128 e
= new CallExp(exp
.loc
, e
, exp
.arguments
, exp
.names
);
6129 e
= e
.expressionSemantic(sc
);
6133 // No constructor, look for overload of opCall
6134 if (search_function(sd
, Id
.call))
6136 // overload of opCall, therefore it's a call
6137 if (exp
.e1
.op
!= EXP
.type
)
6139 if (sd
.aliasthis
&& !isRecursiveAliasThis(att
, exp
.e1
.type
))
6141 exp
.e1
= resolveAliasThis(sc
, exp
.e1
);
6144 error(exp
.loc
, "%s `%s` does not overload ()", sd
.kind(), sd
.toChars());
6148 /* It's a struct literal
6151 Expressions
* resolvedArgs
= exp
.arguments
;
6154 resolvedArgs
= resolveStructLiteralNamedArgs(sd
, exp
.e1
.type
, sc
, exp
.loc
,
6156 (size_t i
, Type t
) => (*exp
.arguments
)[i
],
6157 i
=> (*exp
.arguments
)[i
].loc
6161 result
= ErrorExp
.get();
6166 Expression e
= new StructLiteralExp(exp
.loc
, sd
, resolvedArgs
, exp
.e1
.type
);
6167 e
= e
.expressionSemantic(sc
);
6171 else if (t1
.ty
== Tclass
)
6174 // Rewrite as e1.call(arguments)
6175 Expression e
= new DotIdExp(exp
.loc
, exp
.e1
, Id
.call);
6176 e
= new CallExp(exp
.loc
, e
, exp
.arguments
, exp
.names
);
6177 e
= e
.expressionSemantic(sc
);
6181 else if (exp
.e1
.op
== EXP
.type
&& t1
.isscalar())
6185 // Make sure to use the enum type itself rather than its
6187 // https://issues.dlang.org/show_bug.cgi?id=16346
6188 if (exp
.e1
.type
.ty
== Tenum
)
6193 if (!exp
.arguments || exp
.arguments
.length
== 0)
6195 e
= t1
.defaultInitLiteral(exp
.loc
);
6197 else if (exp
.arguments
.length
== 1)
6199 e
= (*exp
.arguments
)[0];
6200 e
= e
.implicitCastTo(sc
, t1
);
6201 e
= new CastExp(exp
.loc
, e
, t1
);
6205 error(exp
.loc
, "more than one argument for construction of `%s`", t1
.toChars());
6208 e
= e
.expressionSemantic(sc
);
6214 FuncDeclaration
resolveOverloadSet(Loc loc
, Scope
* sc
,
6215 OverloadSet os
, Objects
* tiargs
, Type tthis
, ArgumentList argumentList
)
6217 FuncDeclaration f
= null;
6220 if (tiargs
&& s
.isFuncDeclaration())
6222 if (auto f2
= resolveFuncCall(loc
, sc
, s
, tiargs
, tthis
, argumentList
, FuncResolveFlag
.quiet
))
6228 /* Match in more than one overload set,
6229 * even if one is a 'better' match than the other.
6231 if (f
.isCsymbol() && f2
.isCsymbol())
6233 /* C has global name space, so just pick one, such as f.
6234 * If f and f2 are not compatible, that's how C rolls.
6238 ScopeDsymbol
.multiplyDefined(loc
, f
, f2
); // issue error
6246 .error(loc
, "no overload matches for `%s`", exp
.toChars());
6247 errorSupplemental(loc
, "Candidates are:");
6250 overloadApply(s
, (ds){
6251 if (auto fd
= ds.isFuncDeclaration())
6252 .errorSupplemental(ds.loc
, "%s%s", fd
.toChars(),
6253 fd
.type
.toTypeFunction().parameterList
.parametersTypeToChars());
6255 .errorSupplemental(ds.loc
, "%s", ds.toChars());
6265 bool isSuper
= false;
6266 if (exp
.e1
.op
== EXP
.dotVariable
&& t1
.ty
== Tfunction || exp
.e1
.op
== EXP
.dotTemplateDeclaration
)
6268 UnaExp ue
= cast(UnaExp
)exp
.e1
;
6270 Expression ue1old
= ue
.e1
; // need for 'right this' check
6274 if (exp
.e1
.op
== EXP
.dotVariable
)
6276 dve
= cast(DotVarExp
)exp
.e1
;
6284 dte
= cast(DotTemplateExp
)exp
.e1
;
6288 // Do overload resolution
6289 exp
.f
= resolveFuncCall(exp
.loc
, sc
, s
, tiargs
, ue
.e1
.type
, exp
.argumentList
, FuncResolveFlag
.standard
);
6290 if (!exp
.f || exp
.f
.errors || exp
.f
.type
.ty
== Terror
)
6293 if (exp
.f
.interfaceVirtual
)
6295 /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent
6297 auto b
= exp
.f
.interfaceVirtual
;
6299 ue
.e1
= ue
.e1
.castTo(sc
, ad2
.type
.addMod(ue
.e1
.type
.mod
));
6300 ue
.e1
= ue
.e1
.expressionSemantic(sc
);
6301 auto vi
= findVtblIndex(exp
.f
, ad2
.vtbl
[]);
6303 exp
.f
= ad2
.vtbl
[vi
].isFuncDeclaration();
6306 if (exp
.f
.needThis())
6308 AggregateDeclaration ad
= exp
.f
.isMemberLocal();
6309 ue
.e1
= getRightThis(exp
.loc
, sc
, ad
, ue
.e1
, exp
.f
);
6310 if (ue
.e1
.op
== EXP
.error
)
6317 if (!(exp
.f
.type
.ty
== Tfunction
&& (cast(TypeFunction
)exp
.f
.type
).isScopeQual
))
6319 if (checkParamArgumentEscape(sc
, exp
.f
, Id
.This
, exp
.f
.vthis
, STC
.undefined_
, ethis
, false, false))
6324 /* Cannot call public functions from inside invariant
6325 * (because then the invariant would have infinite recursion)
6327 if (sc
.func
&& sc
.func
.isInvariantDeclaration() && ue
.e1
.op
== EXP
.this_
&& exp
.f
.addPostInvariant())
6329 error(exp
.loc
, "cannot call `public`/`export` function `%s` from invariant", exp
.f
.toChars());
6333 if (!exp
.ignoreAttributes
)
6334 checkFunctionAttributes(exp
, sc
, exp
.f
);
6336 // Cut-down version of checkAccess() that doesn't use the "most visible" version of exp.f.
6337 // We've already selected an overload here.
6338 const parent
= exp
.f
.toParent();
6339 if (parent
&& parent
.isTemplateInstance())
6341 // already a deprecation
6343 else if (!checkSymbolAccess(sc
, exp
.f
))
6345 error(exp
.loc
, "%s `%s` of type `%s` is not accessible from module `%s`",
6346 exp
.f
.kind(), exp
.f
.toPrettyChars(), exp
.f
.type
.toChars(), sc
._module
.toChars
);
6350 if (!exp
.f
.needThis())
6352 exp
.e1
= Expression
.combine(ue
.e1
, new VarExp(exp
.loc
, exp
.f
, false));
6356 if (ue1old
.checkRightThis(sc
))
6358 if (exp
.e1
.op
== EXP
.dotVariable
)
6361 exp
.e1
.type
= exp
.f
.type
;
6365 exp
.e1
= new DotVarExp(exp
.loc
, dte
.e1
, exp
.f
, false);
6366 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
6367 if (exp
.e1
.op
== EXP
.error
)
6369 ue
= cast(UnaExp
)exp
.e1
;
6373 printf("ue.e1 = %s\n", ue
.e1
.toChars());
6374 printf("f = %s\n", exp
.f
.toChars());
6375 printf("t1 = %s\n", t1
.toChars());
6376 printf("e1 = %s\n", exp
.e1
.toChars());
6377 printf("e1.type = %s\n", exp
.e1
.type
.toChars());
6380 // See if we need to adjust the 'this' pointer
6381 AggregateDeclaration ad
= exp
.f
.isThis();
6382 ClassDeclaration cd
= ue
.e1
.type
.isClassHandle();
6383 if (ad
&& cd
&& ad
.isClassDeclaration())
6385 if (ue
.e1
.op
== EXP
.dotType
)
6387 ue
.e1
= (cast(DotTypeExp
)ue
.e1
).e1
;
6388 exp
.directcall
= true;
6390 else if (ue
.e1
.op
== EXP
.super_
)
6391 exp
.directcall
= true;
6392 else if ((cd
.storage_class
& STC
.final_
) != 0) // https://issues.dlang.org/show_bug.cgi?id=14211
6393 exp
.directcall
= true;
6397 ue
.e1
= ue
.e1
.castTo(sc
, ad
.type
.addMod(ue
.e1
.type
.mod
));
6398 ue
.e1
= ue
.e1
.expressionSemantic(sc
);
6402 // If we've got a pointer to a function then deference it
6403 // https://issues.dlang.org/show_bug.cgi?id=16483
6404 if (exp
.e1
.type
.isPtrToFunction())
6406 Expression e
= new PtrExp(exp
.loc
, exp
.e1
);
6407 e
.type
= exp
.e1
.type
.nextOf();
6412 else if (exp
.e1
.op
== EXP
.super_ || exp
.e1
.op
== EXP
.this_
)
6414 auto ad
= sc
.func ? sc
.func
.isThis() : null;
6415 auto cd
= ad ? ad
.isClassDeclaration() : null;
6417 isSuper
= exp
.e1
.op
== EXP
.super_
;
6420 // Base class constructor call
6421 if (!cd ||
!cd
.baseClass ||
!sc
.func
.isCtorDeclaration())
6423 error(exp
.loc
, "super class constructor call must be in a constructor");
6426 if (!cd
.baseClass
.ctor
)
6428 error(exp
.loc
, "no super class constructor for `%s`", cd
.baseClass
.toChars());
6434 // `this` call expression must be inside a
6436 if (!ad ||
!sc
.func
.isCtorDeclaration())
6438 error(exp
.loc
, "constructor call must be in a constructor");
6442 // https://issues.dlang.org/show_bug.cgi?id=18719
6443 // If `exp` is a call expression to another constructor
6444 // then it means that all struct/class fields will be
6445 // initialized after this call.
6446 foreach (ref field
; sc
.ctorflow
.fieldinit
)
6448 field
.csx |
= CSX
.this_ctor
;
6452 if (!sc
.intypeof
&& !(sc
.ctorflow
.callSuper
& CSX
.halt
))
6454 if (sc
.inLoop || sc
.ctorflow
.callSuper
& CSX
.label
)
6455 error(exp
.loc
, "constructor calls not allowed in loops or after labels");
6456 if (sc
.ctorflow
.callSuper
& (CSX
.super_ctor | CSX
.this_ctor
))
6457 error(exp
.loc
, "multiple constructor calls");
6458 if ((sc
.ctorflow
.callSuper
& CSX
.return_
) && !(sc
.ctorflow
.callSuper
& CSX
.any_ctor
))
6459 error(exp
.loc
, "an earlier `return` statement skips constructor");
6460 sc
.ctorflow
.callSuper |
= CSX
.any_ctor |
(isSuper ? CSX
.super_ctor
: CSX
.this_ctor
);
6463 tthis
= ad
.type
.addMod(sc
.func
.type
.mod
);
6464 auto ctor
= isSuper ? cd
.baseClass
.ctor
: ad
.ctor
;
6465 if (auto os
= ctor
.isOverloadSet())
6466 exp
.f
= resolveOverloadSet(exp
.loc
, sc
, os
, null, tthis
, exp
.argumentList
);
6468 exp
.f
= resolveFuncCall(exp
.loc
, sc
, ctor
, null, tthis
, exp
.argumentList
, FuncResolveFlag
.standard
);
6470 if (!exp
.f || exp
.f
.errors
)
6473 checkFunctionAttributes(exp
, sc
, exp
.f
);
6474 if (!checkSymbolAccess(sc
, exp
.f
))
6476 error(exp
.loc
, "%s `%s` is not accessible from module `%s`",
6477 exp
.f
.kind(), exp
.f
.toPrettyChars(), sc
._module
.toChars
);
6481 exp
.e1
= new DotVarExp(exp
.e1
.loc
, exp
.e1
, exp
.f
, false);
6482 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
6483 // https://issues.dlang.org/show_bug.cgi?id=21095
6484 if (exp
.e1
.op
== EXP
.error
)
6488 // BUG: this should really be done by checking the static
6490 if (exp
.f
== sc
.func
)
6492 error(exp
.loc
, "cyclic constructor call");
6496 else if (auto oe
= exp
.e1
.isOverExp())
6498 exp
.f
= resolveOverloadSet(exp
.loc
, sc
, oe
.vars
, tiargs
, tthis
, exp
.argumentList
);
6502 exp
.e1
= new DotVarExp(exp
.loc
, ethis
, exp
.f
, false);
6504 exp
.e1
= new VarExp(exp
.loc
, exp
.f
, false);
6509 error(exp
.loc
, "function expected before `()`, not `%s`", exp
.e1
.toChars());
6512 else if (t1
.ty
== Terror
)
6516 else if (t1
.ty
!= Tfunction
)
6522 if (auto fe
= exp
.e1
.isFuncExp())
6524 // function literal that direct called is always inferred.
6527 tf
= cast(TypeFunction
)exp
.f
.type
;
6528 p
= "function literal";
6530 else if (t1
.ty
== Tdelegate
)
6532 TypeDelegate td
= cast(TypeDelegate
)t1
;
6533 assert(td
.next
.ty
== Tfunction
);
6534 tf
= cast(TypeFunction
)td
.next
;
6537 else if (auto tfx
= t1
.isPtrToFunction())
6540 p
= "function pointer";
6542 else if (exp
.e1
.op
== EXP
.dotVariable
&& (cast(DotVarExp
)exp
.e1
).var
.isOverDeclaration())
6544 DotVarExp dve
= cast(DotVarExp
)exp
.e1
;
6545 exp
.f
= resolveFuncCall(exp
.loc
, sc
, dve
.var
, tiargs
, dve
.e1
.type
, exp
.argumentList
, FuncResolveFlag
.overloadOnly
);
6548 if (exp
.f
.needThis())
6551 dve
.type
= exp
.f
.type
;
6552 dve
.hasOverloads
= false;
6555 exp
.e1
= new VarExp(dve
.loc
, exp
.f
, false);
6556 Expression e
= new CommaExp(exp
.loc
, dve
.e1
, exp
);
6557 result
= e
.expressionSemantic(sc
);
6560 else if (exp
.e1
.op
== EXP
.variable
&& (cast(VarExp
)exp
.e1
).var
.isOverDeclaration())
6562 s
= (cast(VarExp
)exp
.e1
).var
;
6565 else if (exp
.e1
.op
== EXP
.template_
)
6567 s
= (cast(TemplateExp
)exp
.e1
).td
;
6569 exp
.f
= resolveFuncCall(exp
.loc
, sc
, s
, tiargs
, null, exp
.argumentList
,
6570 exp
.isUfcsRewrite ? FuncResolveFlag
.ufcs
: FuncResolveFlag
.standard
);
6571 if (!exp
.f || exp
.f
.errors
)
6573 if (exp
.f
.needThis())
6577 // Supply an implicit 'this', as in
6579 exp
.e1
= new DotVarExp(exp
.loc
, (new ThisExp(exp
.loc
)).expressionSemantic(sc
), exp
.f
, false);
6582 else if (isNeedThisScope(sc
, exp
.f
))
6584 return needThisError(exp
.loc
, exp
.f
);
6587 exp
.e1
= new VarExp(exp
.e1
.loc
, exp
.f
, false);
6592 error(exp
.loc
, "function expected before `()`, not `%s` of type `%s`", exp
.e1
.toChars(), exp
.e1
.type
.toChars());
6596 void errorHelper(const(char)* failMessage
) scope
6600 argExpTypesToCBuffer(buf
, exp
.arguments
);
6603 tthis
.modToBuffer(buf
);
6605 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
6606 .error(exp
.loc
, "%s `%s%s` is not callable using argument types `%s`",
6607 p
, exp
.e1
.toChars(), parametersTypeToChars(tf
.parameterList
), buf
.peekChars());
6609 errorSupplemental(exp
.loc
, "%s", failMessage
);
6612 if (tf
.callMatch(null, exp
.argumentList
, 0, &errorHelper
, sc
) == MATCH
.nomatch
)
6615 // Purity and safety check should run after testing arguments matching
6618 exp
.f
.checkPurity(exp
.loc
, sc
);
6619 exp
.f
.checkSafety(exp
.loc
, sc
);
6620 exp
.f
.checkNogc(exp
.loc
, sc
);
6621 if (exp
.f
.checkNestedReference(sc
, exp
.loc
))
6624 else if (sc
.func
&& sc
.intypeof
!= 1 && !(sc
.flags
& (SCOPE
.ctfe | SCOPE
.debug_
)))
6627 if (!tf
.purity
&& sc
.func
.setImpure(exp
.loc
, "`pure` %s `%s` cannot call impure `%s`", exp
.e1
))
6629 error(exp
.loc
, "`pure` %s `%s` cannot call impure %s `%s`",
6630 sc
.func
.kind(), sc
.func
.toPrettyChars(), p
, exp
.e1
.toChars());
6633 if (!tf
.isnogc
&& sc
.func
.setGC(exp
.loc
, "`@nogc` %s `%s` cannot call non-@nogc `%s`", exp
.e1
))
6635 error(exp
.loc
, "`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
6636 sc
.func
.kind(), sc
.func
.toPrettyChars(), p
, exp
.e1
.toChars());
6639 if (tf
.trust
<= TRUST
.system
&& sc
.setUnsafe(true, exp
.loc
,
6640 "`@safe` function `%s` cannot call `@system` `%s`", sc
.func
, exp
.e1
))
6642 error(exp
.loc
, "`@safe` %s `%s` cannot call `@system` %s `%s`",
6643 sc
.func
.kind(), sc
.func
.toPrettyChars(), p
, exp
.e1
.toChars());
6650 if (t1
.ty
== Tpointer
)
6652 Expression e
= new PtrExp(exp
.loc
, exp
.e1
);
6658 else if (VarExp ve
= exp
.e1
.isVarExp())
6660 // Do overload resolution
6661 exp
.f
= ve
.var
.isFuncDeclaration();
6665 if (ve
.hasOverloads
&& exp
.f
.overnext
)
6666 exp
.f
= resolveFuncCall(exp
.loc
, sc
, exp
.f
, tiargs
, null, exp
.argumentList
, FuncResolveFlag
.overloadOnly
);
6669 exp
.f
= exp
.f
.toAliasFunc();
6670 TypeFunction tf
= cast(TypeFunction
)exp
.f
.type
;
6672 void errorHelper2(const(char)* failMessage
) scope
6676 argExpTypesToCBuffer(buf
, exp
.arguments
);
6679 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
6680 if (exp
.isUfcsRewrite
)
6682 const arg
= (*exp
.argumentList
.arguments
)[0];
6683 .error(exp
.loc
, "no property `%s` for `%s` of type `%s`", exp
.f
.ident
.toChars(), arg
.toChars(), arg
.type
.toChars());
6684 .errorSupplemental(exp
.loc
, "the following error occured while looking for a UFCS match");
6687 .error(exp
.loc
, "%s `%s` is not callable using argument types `%s`",
6688 exp
.f
.kind(), exp
.f
.toChars(), buf
.peekChars());
6690 errorSupplemental(exp
.loc
, "%s", failMessage
);
6691 .errorSupplemental(exp
.f
.loc
, "`%s%s` declared here", exp
.f
.toPrettyChars(), parametersTypeToChars(tf
.parameterList
));
6695 if (tf
.callMatch(null, exp
.argumentList
, 0, &errorHelper2
, sc
) == MATCH
.nomatch
)
6698 if (!exp
.f || exp
.f
.errors
)
6701 if (exp
.f
.needThis())
6703 // Change the ancestor lambdas to delegate before hasThis(sc) call.
6704 if (exp
.f
.checkNestedReference(sc
, exp
.loc
))
6707 auto memberFunc
= hasThis(sc
);
6708 if (memberFunc
&& haveSameThis(memberFunc
, exp
.f
))
6710 // Supply an implicit 'this', as in
6712 exp
.e1
= new DotVarExp(exp
.loc
, (new ThisExp(exp
.loc
)).expressionSemantic(sc
), ve
.var
);
6713 // Note: we cannot use f directly, because further overload resolution
6714 // through the supplied 'this' may cause different result.
6717 else if (isNeedThisScope(sc
, exp
.f
))
6719 // At this point it is possible that `exp.f` had an ambiguity error that was
6720 // silenced because the previous call to `resolveFuncCall` was done using
6721 // `FuncResolveFlag.overloadOnly`. To make sure that a proper error message
6722 // is printed, redo the call with `FuncResolveFlag.standard`.
6724 // https://issues.dlang.org/show_bug.cgi?id=22157
6726 exp
.f
= resolveFuncCall(exp
.loc
, sc
, exp
.f
, tiargs
, null, exp
.argumentList
, FuncResolveFlag
.standard
);
6728 if (!exp
.f || exp
.f
.errors
)
6731 // If no error is printed, it means that `f` is the single matching overload
6732 // and it needs `this`.
6733 return needThisError(exp
.loc
, exp
.f
);
6737 checkFunctionAttributes(exp
, sc
, exp
.f
);
6738 checkAccess(exp
.loc
, sc
, null, exp
.f
);
6739 if (exp
.f
.checkNestedReference(sc
, exp
.loc
))
6745 if (ve
.hasOverloads
)
6747 exp
.e1
= new VarExp(ve
.loc
, exp
.f
, false);
6748 exp
.e1
.type
= exp
.f
.type
;
6752 assert(t1
.ty
== Tfunction
);
6754 Expression argprefix
;
6756 exp
.arguments
= new Expressions();
6757 if (functionParameters(exp
.loc
, sc
, cast(TypeFunction
)t1
, ethis
, tthis
, exp
.argumentList
, exp
.f
, &exp
.type
, &argprefix
))
6762 exp
.e1
= e1org
; // https://issues.dlang.org/show_bug.cgi?id=10922
6763 // avoid recursive expression printing
6764 error(exp
.loc
, "forward reference to inferred return type of function call `%s`", exp
.toChars());
6768 if (exp
.f
&& exp
.f
.tintro
)
6772 TypeFunction tf
= cast(TypeFunction
)exp
.f
.tintro
;
6773 if (tf
.next
.isBaseOf(t
, &offset
) && offset
)
6776 result
= Expression
.combine(argprefix
, exp
.castTo(sc
, t
));
6781 // Handle the case of a direct lambda call
6782 if (exp
.f
&& exp
.f
.isFuncLiteralDeclaration() && sc
.func
&& !sc
.intypeof
)
6784 exp
.f
.tookAddressOf
= 0;
6787 result
= Expression
.combine(argprefix
, exp
);
6791 auto ad
= sc
.func ? sc
.func
.isThis() : null;
6792 auto cd
= ad ? ad
.isClassDeclaration() : null;
6793 if (cd
&& cd
.classKind
== ClassKind
.cpp
&& exp
.f
&& !exp
.f
.fbody
)
6795 // if super is defined in C++, it sets the vtable pointer to the base class
6796 // so we have to restore it, but still return 'this' from super() call:
6797 // (auto __vptrTmp = this.__vptr, auto __superTmp = super()), (this.__vptr = __vptrTmp, __superTmp)
6800 auto vptr
= new DotIdExp(loc
, new ThisExp(loc
), Id
.__vptr
);
6801 auto vptrTmpDecl
= copyToTemp(0, "__vptrTmp", vptr
);
6802 auto declareVptrTmp
= new DeclarationExp(loc
, vptrTmpDecl
);
6804 auto superTmpDecl
= copyToTemp(0, "__superTmp", result
);
6805 auto declareSuperTmp
= new DeclarationExp(loc
, superTmpDecl
);
6807 auto declareTmps
= new CommaExp(loc
, declareVptrTmp
, declareSuperTmp
);
6809 auto restoreVptr
= new AssignExp(loc
, vptr
.syntaxCopy(), new VarExp(loc
, vptrTmpDecl
));
6811 Expression e
= new CommaExp(loc
, declareTmps
, new CommaExp(loc
, restoreVptr
, new VarExp(loc
, superTmpDecl
)));
6812 result
= e
.expressionSemantic(sc
);
6816 // `super.fun()` with fun being abstract and unimplemented
6817 auto supDotFun
= exp
.e1
.isDotVarExp();
6818 if (supDotFun
&& supDotFun
.e1
.isSuperExp() && exp
.f
&& exp
.f
.isAbstract() && !exp
.f
.fbody
)
6820 error(exp
.loc
, "call to unimplemented abstract function `%s`", exp
.f
.toFullSignature());
6821 errorSupplemental(exp
.loc
, "declared here: %s", exp
.f
.loc
.toChars());
6824 // declare dual-context container
6825 if (exp
.f
&& exp
.f
.hasDualContext() && !sc
.intypeof
&& sc
.func
)
6827 // check access to second `this`
6828 if (AggregateDeclaration ad2
= exp
.f
.isMember2())
6830 Expression te
= new ThisExp(exp
.loc
).expressionSemantic(sc
);
6831 if (te
.op
!= EXP
.error
)
6832 te
= getRightThis(exp
.loc
, sc
, ad2
, te
, exp
.f
);
6833 if (te
.op
== EXP
.error
)
6835 error(exp
.loc
, "need `this` of type `%s` to call function `%s`", ad2
.toChars(), exp
.f
.toChars());
6839 exp
.vthis2
= makeThis2Argument(exp
.loc
, sc
, exp
.f
);
6840 Expression
de = new DeclarationExp(exp
.loc
, exp
.vthis2
);
6841 result
= Expression
.combine(de, result
);
6842 result
= result
.expressionSemantic(sc
);
6846 override void visit(DeclarationExp e
)
6853 static if (LOGSEMANTIC
)
6855 printf("DeclarationExp::semantic() %s\n", e
.toChars());
6858 uint olderrors
= global
.errors
;
6860 /* This is here to support extern(linkage) declaration,
6861 * where the extern(linkage) winds up being an AttribDeclaration
6864 Dsymbol s
= e
.declaration
;
6868 AttribDeclaration ad
= s
.isAttribDeclaration();
6871 if (ad
.decl
&& ad
.decl
.length
== 1)
6880 //printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc);
6881 // Insert into both local scope and function scope.
6882 // Must be unique in both.
6885 VarDeclaration v
= s
.isVarDeclaration();
6888 if (sc
.flags
& SCOPE
.Cfile
)
6890 /* Do semantic() on the type before inserting v into the symbol table
6892 if (!v
.originalType
)
6893 v
.originalType
= v
.type
.syntaxCopy();
6894 Scope
* sc2
= sc
.push();
6895 sc2
.stc |
= v
.storage_class
& STC
.FUNCATTR
;
6896 sc2
.linkage
= LINK
.c
; // account for the extern(C) in front of the declaration
6898 v
.type
= v
.type
.typeSemantic(v
.loc
, sc2
);
6904 /* Do semantic() on initializer first so this will be illegal:
6907 e
.declaration
.dsymbolSemantic(sc
);
6908 s
.parent
= sc
.parent
;
6915 auto conflict
= sc
.search(Loc
.initial
, s
.ident
, pscopesym
);
6916 error(e
.loc
, "declaration `%s` is already defined", s
.toPrettyChars());
6917 errorSupplemental(conflict
.loc
, "`%s` `%s` is defined here",
6918 conflict
.kind(), conflict
.toChars());
6922 if (v
&& (sc
.flags
& SCOPE
.Cfile
))
6924 /* Do semantic() on initializer last so this will be legal:
6927 e
.declaration
.dsymbolSemantic(sc
);
6928 s
.parent
= sc
.parent
;
6933 // https://issues.dlang.org/show_bug.cgi?id=11720
6934 if ((s
.isFuncDeclaration() ||
6935 s
.isAggregateDeclaration() ||
6936 s
.isEnumDeclaration() ||
6937 s
.isTemplateDeclaration() ||
6939 ) && !sc
.func
.localsymtab
.insert(s
))
6941 // Get the previous symbol
6942 Dsymbol originalSymbol
= sc
.func
.localsymtab
.lookup(s
.ident
);
6944 // Perturb the name mangling so that the symbols can co-exist
6945 // instead of colliding
6946 s
.localNum
= cast(ushort)(originalSymbol
.localNum
+ 1);
6947 // 65535 should be enough for anyone
6950 error(e
.loc
, "more than 65535 symbols with name `%s` generated", s
.ident
.toChars());
6954 // Replace originalSymbol with s, which updates the localCount
6955 sc
.func
.localsymtab
.update(s
);
6957 // The mangling change only works for D mangling
6960 if (!(sc
.flags
& SCOPE
.Cfile
))
6962 /* https://issues.dlang.org/show_bug.cgi?id=21272
6963 * If we are in a foreach body we need to extract the
6964 * function containing the foreach
6966 FuncDeclaration fes_enclosing_func
;
6967 if (sc
.func
&& sc
.func
.fes
)
6968 fes_enclosing_func
= sc
.enclosing
.enclosing
.func
;
6970 // Disallow shadowing
6971 for (Scope
* scx
= sc
.enclosing
; scx
&& (scx
.func
== sc
.func ||
(fes_enclosing_func
&& scx
.func
== fes_enclosing_func
)); scx
= scx
.enclosing
)
6974 if (scx
.scopesym
&& scx
.scopesym
.symtab
&& (s2
= scx
.scopesym
.symtab
.lookup(s
.ident
)) !is null && s
!= s2
)
6976 // allow STC.local symbols to be shadowed
6977 // TODO: not really an optimal design
6978 auto decl
= s2
.isDeclaration();
6979 if (!decl ||
!(decl
.storage_class
& STC
.local
))
6983 deprecation(e
.loc
, "%s `%s` is shadowing %s `%s`", s
.kind(), s
.ident
.toChars(), s2
.kind(), s2
.toPrettyChars());
6984 deprecationSupplemental(s2
.loc
, "declared here");
6989 error(e
.loc
, "%s `%s` is shadowing %s `%s`", s
.kind(), s
.ident
.toChars(), s2
.kind(), s2
.toPrettyChars());
6990 errorSupplemental(s2
.loc
, "declared here");
6999 if (!s
.isVarDeclaration())
7002 if (sc2
.stc & (STC
.pure_ | STC
.nothrow_ | STC
.nogc
))
7004 sc2
.stc &= ~(STC
.pure_ | STC
.nothrow_ | STC
.nogc
);
7005 e
.declaration
.dsymbolSemantic(sc2
);
7008 s
.parent
= sc
.parent
;
7010 if (global
.errors
== olderrors
)
7012 e
.declaration
.semantic2(sc
);
7013 if (global
.errors
== olderrors
)
7015 e
.declaration
.semantic3(sc
);
7018 // todo: error in declaration should be propagated.
7020 e
.type
= Type
.tvoid
;
7024 override void visit(TypeidExp exp
)
7026 static if (LOGSEMANTIC
)
7028 printf("TypeidExp::semantic() %s\n", exp
.toChars());
7030 Type ta
= isType(exp
.obj
);
7031 Expression ea
= isExpression(exp
.obj
);
7032 Dsymbol sa
= isDsymbol(exp
.obj
);
7033 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
7037 dmd
.typesem
.resolve(ta
, exp
.loc
, sc
, ea
, ta
, sa
, true);
7042 if (auto sym
= getDsymbol(ea
))
7043 ea
= symbolToExp(sym
, exp
.loc
, sc
, false);
7045 ea
= ea
.expressionSemantic(sc
);
7046 ea
= resolveProperties(sc
, ea
);
7048 if (ea
.op
== EXP
.type
)
7054 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
7055 error(exp
.loc
, "no type for `typeid(%s)`", ea ? ea
.toChars() : (sa ? sa
.toChars() : ""));
7059 ta
.checkComplexTransition(exp
.loc
, sc
);
7062 auto tb
= ta
.toBasetype();
7063 if (ea
&& tb
.ty
== Tclass
)
7065 if (tb
.toDsymbol(sc
).isClassDeclaration().classKind
== ClassKind
.cpp
)
7067 error(exp
.loc
, "runtime type information is not supported for `extern(C++)` classes");
7070 else if (!Type
.typeinfoclass
)
7072 error(exp
.loc
, "`object.TypeInfo_Class` could not be found, but is implicitly used");
7077 /* Get the dynamic type, which is .classinfo
7079 ea
= ea
.expressionSemantic(sc
);
7080 e
= new TypeidExp(ea
.loc
, ea
);
7081 e
.type
= Type
.typeinfoclass
.type
;
7084 else if (ta
.ty
== Terror
)
7090 // Handle this in the glue layer
7091 e
= new TypeidExp(exp
.loc
, ta
);
7093 bool genObjCode
= true;
7095 // https://issues.dlang.org/show_bug.cgi?id=23650
7096 // We generate object code for typeinfo, required
7097 // by typeid, only if in non-speculative context
7098 if (sc
.flags
& SCOPE
.compile
)
7103 e
.type
= getTypeInfoType(exp
.loc
, ta
, sc
, genObjCode
);
7104 semanticTypeInfo(sc
, ta
);
7108 e
= new CommaExp(exp
.loc
, ea
, e
); // execute ea
7109 e
= e
.expressionSemantic(sc
);
7115 override void visit(TraitsExp e
)
7117 result
= semanticTraits(e
, sc
);
7120 override void visit(HaltExp e
)
7122 static if (LOGSEMANTIC
)
7124 printf("HaltExp::semantic()\n");
7126 e
.type
= Type
.tnoreturn
;
7130 override void visit(IsExp e
)
7132 /* is(targ id tok tspec)
7133 * is(targ id : tok2)
7134 * is(targ id == tok2)
7143 result
= IntegerExp
.createBool(true);
7148 Tuple tup
= isTuple(tded
);
7150 s
= new TupleDeclaration(e
.loc
, e
.id
, &tup
.objects
);
7152 s
= new AliasDeclaration(e
.loc
, e
.id
, tded
);
7153 s
.dsymbolSemantic(sc
);
7155 /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there.
7156 * More investigation is needed.
7158 if (!tup
&& !sc
.insert(s
))
7161 auto conflict
= sc
.search(Loc
.initial
, s
.ident
, pscopesym
);
7162 error(e
.loc
, "declaration `%s` is already defined", s
.toPrettyChars());
7163 errorSupplemental(conflict
.loc
, "`%s` `%s` is defined here",
7164 conflict
.kind(), conflict
.toChars());
7167 unSpeculative(sc
, s
);
7169 result
= IntegerExp
.createBool(true);
7173 result
= IntegerExp
.createBool(false);
7177 static if (LOGSEMANTIC
)
7179 printf("IsExp::semantic(%s)\n", e
.toChars());
7181 if (e
.id
&& !(sc
.flags
& SCOPE
.condition
))
7183 error(e
.loc
, "can only declare type aliases within `static if` conditionals or `static assert`s");
7187 if (e
.tok2
== TOK
.package_ || e
.tok2
== TOK
.module_
) // These is() expressions are special because they can work on modules, not just types.
7189 const oldErrors
= global
.startGagging();
7190 Dsymbol sym
= e
.targ
.toDsymbol(sc
);
7191 global
.endGagging(oldErrors
);
7195 Package p
= resolveIsPackage(sym
);
7198 if (e
.tok2
== TOK
.package_
&& p
.isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module.
7200 else if(e
.tok2
== TOK
.module_
&& !(p
.isModule() || p
.isPackageMod()))
7207 Scope
* sc2
= sc
.copy(); // keep sc.flags
7210 sc2
.flags |
= SCOPE
.fullinst
;
7211 Type t
= dmd
.typesem
.trySemantic(e
.targ
, e
.loc
, sc2
);
7213 if (!t
) // errors, so condition is false
7218 if (e
.tok2
!= TOK
.reserved
)
7223 if (e
.targ
.ty
!= Tstruct
)
7225 if ((cast(TypeStruct
)e
.targ
).sym
.isUnionDeclaration())
7231 if (e
.targ
.ty
!= Tstruct
)
7233 if (!(cast(TypeStruct
)e
.targ
).sym
.isUnionDeclaration())
7239 if (e
.targ
.ty
!= Tclass
)
7241 if ((cast(TypeClass
)e
.targ
).sym
.isInterfaceDeclaration())
7246 case TOK
.interface_
:
7247 if (e
.targ
.ty
!= Tclass
)
7249 if (!(cast(TypeClass
)e
.targ
).sym
.isInterfaceDeclaration())
7255 if (!e
.targ
.isConst())
7260 case TOK
.immutable_
:
7261 if (!e
.targ
.isImmutable())
7267 if (!e
.targ
.isShared())
7273 if (!e
.targ
.isWild())
7279 // If class or interface, get the base class and interfaces
7280 if (e
.targ
.ty
!= Tclass
)
7284 ClassDeclaration cd
= (cast(TypeClass
)e
.targ
).sym
;
7285 auto args
= new Parameters();
7286 args
.reserve(cd
.baseclasses
.length
);
7287 if (cd
.semanticRun
< PASS
.semanticdone
)
7288 cd
.dsymbolSemantic(null);
7289 for (size_t i
= 0; i
< cd
.baseclasses
.length
; i
++)
7291 BaseClass
* b
= (*cd
.baseclasses
)[i
];
7292 args
.push(new Parameter(Loc
.initial
, STC
.in_
, b
.type
, null, null, null));
7294 tded
= new TypeTuple(args
);
7299 if (e
.targ
.ty
!= Tenum
)
7302 tded
= (cast(TypeEnum
)e
.targ
).sym
.getMemtype(e
.loc
);
7306 if (tded
.ty
== Terror
)
7311 if (e
.targ
.ty
!= Tdelegate
)
7313 tded
= (cast(TypeDelegate
)e
.targ
).next
; // the underlying function type
7317 if (e
.targ
.ty
!= Tfunction
)
7320 case TOK
.parameters
:
7322 if (auto tf
= e
.targ
.isFunction_Delegate_PtrToFunction())
7327 /* Generate tuple from function parameter types.
7329 auto args
= new Parameters();
7330 foreach (i
, arg
; tded
.isTypeFunction().parameterList
)
7332 assert(arg
&& arg
.type
);
7333 /* If one of the default arguments was an error,
7334 don't return an invalid tuple
7336 if (e
.tok2
== TOK
.parameters
&& arg
.defaultArg
&& arg
.defaultArg
.op
== EXP
.error
)
7338 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
));
7340 tded
= new TypeTuple(args
);
7344 /* Get the 'return type' for the function,
7345 * delegate, or pointer to function.
7347 if (auto tf
= e
.targ
.isFunction_Delegate_PtrToFunction())
7353 case TOK
.argumentTypes
:
7354 /* Generate a type tuple of the equivalent types used to determine if a
7355 * function argument of this type can be passed in registers.
7356 * The results of this are highly platform dependent, and intended
7357 * primarly for use in implementing va_arg().
7359 tded
= target
.toArgTypes(e
.targ
);
7362 // not valid for a parameter
7366 if (e
.targ
.ty
!= Tvector
)
7368 tded
= (cast(TypeVector
)e
.targ
).basetype
;
7375 // https://issues.dlang.org/show_bug.cgi?id=18753
7380 else if (e
.tspec
&& !e
.id
&& !(e
.parameters
&& e
.parameters
.length
))
7382 /* Evaluate to true if targ matches tspec
7386 e
.tspec
= e
.tspec
.typeSemantic(e
.loc
, sc
);
7387 //printf("targ = %s, %s\n", e.targ.toChars(), e.targ.deco);
7388 //printf("tspec = %s, %s\n", e.tspec.toChars(), e.tspec.deco);
7390 if (e
.tok
== TOK
.colon
)
7392 // current scope is itself deprecated, or deprecations are not errors
7393 const bool deprecationAllowed
= sc
.isDeprecated
7394 || global
.params
.useDeprecated
!= DiagnosticReporting
.error
;
7395 const bool preventAliasThis
= e
.targ
.hasDeprecatedAliasThis
&& !deprecationAllowed
;
7397 if (preventAliasThis
&& e
.targ
.ty
== Tstruct
)
7399 if ((cast(TypeStruct
) e
.targ
).implicitConvToWithoutAliasThis(e
.tspec
))
7404 else if (preventAliasThis
&& e
.targ
.ty
== Tclass
)
7406 if ((cast(TypeClass
) e
.targ
).implicitConvToWithoutAliasThis(e
.tspec
))
7411 else if (e
.targ
.implicitConvTo(e
.tspec
))
7418 if (e
.targ
.equals(e
.tspec
))
7426 /* Evaluate to true if targ matches tspec.
7427 * If true, declare id as an alias for the specialized type.
7428 * is(targ == tspec, tpl)
7429 * is(targ : tspec, tpl)
7430 * is(targ id == tspec)
7431 * is(targ id : tspec)
7432 * is(targ id == tspec, tpl)
7433 * is(targ id : tspec, tpl)
7435 Identifier tid
= e
.id ? e
.id
: Identifier
.generateId("__isexp_id");
7436 e
.parameters
.insert(0, new TemplateTypeParameter(e
.loc
, tid
, null, null));
7438 Objects dedtypes
= Objects(e
.parameters
.length
);
7441 MATCH m
= deduceType(e
.targ
, sc
, e
.tspec
, *e
.parameters
, dedtypes
, null, 0, e
.tok
== TOK
.equal
);
7443 if (m
== MATCH
.nomatch ||
(m
!= MATCH
.exact
&& e
.tok
== TOK
.equal
))
7449 tded
= cast(Type
)dedtypes
[0];
7452 Objects tiargs
= Objects(1);
7455 /* Declare trailing parameters
7457 for (size_t i
= 1; i
< e
.parameters
.length
; i
++)
7459 TemplateParameter tp
= (*e
.parameters
)[i
];
7460 Declaration s
= null;
7462 m
= tp
.matchArg(e
.loc
, sc
, &tiargs
, i
, e
.parameters
, dedtypes
, &s
);
7463 if (m
== MATCH
.nomatch
)
7465 s
.dsymbolSemantic(sc
);
7469 auto conflict
= sc
.search(Loc
.initial
, s
.ident
, pscopesym
);
7470 error(e
.loc
, "declaration `%s` is already defined", s
.toPrettyChars());
7471 errorSupplemental(conflict
.loc
, "`%s` `%s` is defined here",
7472 conflict
.kind(), conflict
.toChars());
7475 unSpeculative(sc
, s
);
7482 /* Declare id as an alias for type targ. Evaluate to true
7490 override void visit(BinAssignExp exp
)
7498 Expression e
= exp
.op_overload(sc
);
7505 if (exp
.e1
.op
== EXP
.arrayLength
)
7507 // arr.length op= e2;
7508 e
= rewriteOpAssign(exp
);
7509 e
= e
.expressionSemantic(sc
);
7513 if (exp
.e1
.op
== EXP
.slice || exp
.e1
.type
.ty
== Tarray || exp
.e1
.type
.ty
== Tsarray
)
7515 if (checkNonAssignmentArrayOp(exp
.e1
))
7518 if (exp
.e1
.op
== EXP
.slice
)
7519 (cast(SliceExp
)exp
.e1
).arrayop
= true;
7522 if (exp
.e2
.implicitConvTo(exp
.e1
.type
.nextOf()))
7525 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
.nextOf());
7527 else if (Expression ex
= typeCombine(exp
, sc
))
7532 exp
.type
= exp
.e1
.type
;
7533 result
= arrayOp(exp
, sc
);
7537 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
7538 exp
.e1
= exp
.e1
.modifiableLvalue(sc
);
7539 exp
.e1
= exp
.e1
.optimize(WANTvalue
, /*keepLvalue*/ true);
7540 exp
.type
= exp
.e1
.type
;
7542 if (auto ad
= isAggregate(exp
.e1
.type
))
7544 if (const s
= search_function(ad
, Id
.opOpAssign
))
7546 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());
7550 if (exp
.e1
.checkScalar() ||
7551 exp
.e1
.checkReadModifyWrite(exp
.op
, exp
.e2
) ||
7552 exp
.e1
.checkSharedAccess(sc
))
7555 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
);
7556 int bitwise
= (exp
.op
== EXP
.andAssign || exp
.op
== EXP
.orAssign || exp
.op
== EXP
.xorAssign
);
7557 int shift
= (exp
.op
== EXP
.leftShiftAssign || exp
.op
== EXP
.rightShiftAssign || exp
.op
== EXP
.unsignedRightShiftAssign
);
7559 if (bitwise
&& exp
.type
.toBasetype().ty
== Tbool
)
7560 exp
.e2
= exp
.e2
.implicitCastTo(sc
, exp
.type
);
7561 else if (exp
.checkNoBool())
7564 if ((exp
.op
== EXP
.addAssign || exp
.op
== EXP
.minAssign
) && exp
.e1
.type
.toBasetype().ty
== Tpointer
&& exp
.e2
.type
.toBasetype().isintegral())
7566 result
= scaleFactor(exp
, sc
);
7570 if (Expression ex
= typeCombine(exp
, sc
))
7576 if (arith
&& (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
)))
7578 if ((bitwise || shift
) && (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
)))
7583 if (exp
.e2
.type
.toBasetype().ty
!= Tvector
)
7584 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tshiftcnt
);
7587 if (!target
.isVectorOpSupported(exp
.type
.toBasetype(), exp
.op
, exp
.e2
.type
.toBasetype()))
7589 result
= exp
.incompatibleTypes();
7593 if (exp
.e1
.op
== EXP
.error || exp
.e2
.op
== EXP
.error
)
7596 e
= exp
.checkOpAssignTypes(sc
);
7597 if (e
.op
== EXP
.error
)
7603 assert(e
.op
== EXP
.assign || e
== exp
);
7604 result
= (cast(BinExp
)e
).reorderSettingAAElem(sc
);
7607 private Expression
compileIt(MixinExp exp
, Scope
*sc
)
7610 if (expressionsToString(buf
, sc
, exp
.exps
))
7613 uint errors
= global
.errors
;
7614 const len
= buf
.length
;
7615 const str = buf
.extractChars()[0 .. len
];
7616 const bool doUnittests
= global
.params
.parsingUnittestsRequired();
7617 auto loc
= adjustLocForMixin(str, exp
.loc
, global
.params
.mixinOut
);
7618 scope p
= new Parser
!ASTCodegen(loc
, sc
._module
, str, false, global
.errorSink
, &global
.compileEnv
, doUnittests
);
7619 p
.transitionIn
= global
.params
.v
.vin
;
7621 //printf("p.loc.linnum = %d\n", p.loc.linnum);
7623 Expression e
= p
.parseExpression();
7624 if (global
.errors
!= errors
)
7627 if (p
.token
.value
!= TOK
.endOfFile
)
7629 error(e
.loc
, "unexpected token `%s` after %s expression",
7630 p
.token
.toChars(), EXPtoString(e
.op
).ptr
);
7631 errorSupplemental(e
.loc
, "while parsing string mixin expression `%s`",
7638 override void visit(MixinExp exp
)
7640 /* https://dlang.org/spec/expression.html#mixin_expressions
7643 static if (LOGSEMANTIC
)
7645 printf("MixinExp::semantic('%s')\n", exp
.toChars());
7648 // The expression is not treated as part of a default argument,
7649 // because it is evaluated at compile time.
7650 Scope
* sc2
= sc
.push();
7651 sc2
.inDefaultArg
= false;
7653 auto e
= compileIt(exp
, sc2
);
7657 result
= e
.expressionSemantic(sc
);
7660 override void visit(ImportExp e
)
7662 static if (LOGSEMANTIC
)
7664 printf("ImportExp::semantic('%s')\n", e
.toChars());
7667 auto se
= semanticString(sc
, e
.e1
, "file name argument");
7672 auto namez
= se
.toStringz();
7673 if (!global
.filePath
.length
)
7675 error(e
.loc
, "need `-J` switch to import text file `%s`", namez
.ptr
);
7679 /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
7680 * ('Path Traversal') attacks.
7681 * https://cwe.mitre.org/data/definitions/22.html
7684 if (FileName
.absolute(namez
))
7686 error(e
.loc
, "absolute path is not allowed in import expression: `%s`", se
.toChars());
7690 auto idxReserved
= FileName
.findReservedChar(namez
);
7691 if (idxReserved
!= size_t
.max
)
7693 error(e
.loc
, "`%s` is not a valid filename on this platform", se
.toChars());
7694 errorSupplemental(e
.loc
, "Character `'%c'` is reserved and cannot be used", namez
[idxReserved
]);
7698 if (FileName
.refersToParentDir(namez
))
7700 error(e
.loc
, "path refers to parent (`..`) directory: `%s`", se
.toChars());
7704 auto resolvedNamez
= FileName
.searchPath(global
.filePath
[], namez
, false);
7707 error(e
.loc
, "file `%s` cannot be found or not in a path specified with `-J`", se
.toChars());
7708 errorSupplemental(e
.loc
, "Path(s) searched (as provided by `-J`):");
7709 foreach (idx
, path
; global
.filePath
[])
7711 const attr
= FileName
.exists(path
);
7712 const(char)* err
= attr
== 2 ?
"" :
7713 (attr
== 1 ?
" (not a directory)" : " (path not found)");
7714 errorSupplemental(e
.loc
, "[%llu]: `%s`%s", cast(ulong)idx
, path
, err
);
7719 sc
._module
.contentImportedFiles
.push(resolvedNamez
.ptr
);
7720 if (global
.params
.v
.verbose
)
7722 const slice
= se
.peekString();
7723 message("file %.*s\t(%s)", cast(int)slice
.length
, slice
.ptr
, resolvedNamez
.ptr
);
7725 if (global
.params
.moduleDeps
.buffer
!is null)
7727 OutBuffer
* ob
= global
.params
.moduleDeps
.buffer
;
7728 Module imod
= sc
._module
;
7730 if (!global
.params
.moduleDeps
.name
)
7731 ob
.writestring("depsFile ");
7732 ob
.writestring(imod
.toPrettyChars());
7733 ob
.writestring(" (");
7734 escapePath(ob
, imod
.srcfile
.toChars());
7735 ob
.writestring(") : ");
7736 if (global
.params
.moduleDeps
.name
)
7737 ob
.writestring("string : ");
7738 ob
.write(se
.peekString());
7739 ob
.writestring(" (");
7740 escapePath(ob
, resolvedNamez
.ptr
);
7741 ob
.writestring(")");
7744 if (global
.params
.makeDeps
.doOutput
)
7746 global
.params
.makeDeps
.files
.push(resolvedNamez
.ptr
);
7750 auto fileName
= FileName(resolvedNamez
);
7751 if (auto fmResult
= global
.fileManager
.getFileContents(fileName
))
7753 se
= new StringExp(e
.loc
, fmResult
);
7757 error(e
.loc
, "cannot read file `%s`", resolvedNamez
.ptr
);
7761 result
= se
.expressionSemantic(sc
);
7764 override void visit(AssertExp exp
)
7766 // https://dlang.org/spec/expression.html#assert_expressions
7767 static if (LOGSEMANTIC
)
7769 printf("AssertExp::semantic('%s')\n", exp
.toChars());
7771 if (auto e
= exp
.e1
.isStringExp())
7773 // deprecated in 2.107
7774 deprecation(e
.loc
, "assert condition cannot be a string literal");
7775 deprecationSupplemental(e
.loc
, "If intentional, use `%s !is null` instead to preserve behaviour",
7779 const generateMsg
= !exp
.msg
&&
7780 sc
.needsCodegen() && // let ctfe interpreter handle the error message
7781 global
.params
.checkAction
== CHECKACTION
.context
&&
7782 global
.params
.useAssert
== CHECKENABLE
.on
&&
7783 !((exp
.e1
.isIntegerExp() && (exp
.e1
.toInteger() == 0)) ||
7784 exp
.e1
.isNullExp());
7785 Expression temporariesPrefix
;
7788 // no message - use assert expression as msg
7790 if (!verifyHookExist(exp
.loc
, *sc
, Id
._d_assert_fail
, "generating assert messages"))
7795 auto a = e1, b = e2;
7796 assert(a == b, _d_assert_fail!"=="(a, b));
7801 Stores the result of an operand expression into a temporary
7802 if necessary, e.g. if it is an impure fuction call containing side
7803 effects as in https://issues.dlang.org/show_bug.cgi?id=20114
7806 op = an expression which may require a temporary (added to
7807 `temporariesPrefix`: `auto tmp = op`) and will be replaced
7808 by `tmp` if necessary
7810 Returns: (possibly replaced) `op`
7812 Expression
maybePromoteToTmp(ref Expression op
)
7814 // https://issues.dlang.org/show_bug.cgi?id=20989
7815 // Flag that _d_assert_fail will never dereference `array.ptr` to avoid safety
7816 // errors for `assert(!array.ptr)` => `_d_assert_fail!"!"(array.ptr)`
7818 auto die
= op
.isDotIdExp();
7819 if (die
&& die
.ident
== Id
.ptr
)
7823 op
= op
.expressionSemantic(sc
);
7824 op
= resolveProperties(sc
, op
);
7826 // Detect assert's using static operator overloads (e.g. `"var" in environment`)
7827 if (auto te
= op
.isTypeExp())
7829 // Replace the TypeExp with it's textual representation
7830 // Including "..." in the error message isn't quite right but
7831 // proper solutions require more drastic changes, e.g. directly
7832 // using miniFormat and combine instead of calling _d_assert_fail
7833 auto name
= new StringExp(te
.loc
, te
.toString());
7834 return name
.expressionSemantic(sc
);
7837 // Create a temporary for expressions with side effects
7838 // Defensively assume that function calls may have side effects even
7839 // though it's not detected by hasSideEffect (e.g. `debug puts("Hello")` )
7840 // Rewriting CallExp's also avoids some issues with the inliner/debug generation
7841 if (op
.hasSideEffect(true))
7843 // Don't create an invalid temporary for void-expressions
7844 // Further semantic will issue an appropriate error
7845 if (op
.type
.ty
== Tvoid
)
7848 // https://issues.dlang.org/show_bug.cgi?id=21590
7849 // Don't create unnecessary temporaries and detect `assert(a = b)`
7850 if (op
.isAssignExp() || op
.isBinAssignExp())
7852 auto left
= (cast(BinExp
) op
).e1
;
7854 // Find leftmost expression to handle other rewrites,
7855 // e.g. --(++a) => a += 1 -= 1
7856 while (left
.isAssignExp() || left
.isBinAssignExp())
7857 left
= (cast(BinExp
) left
).e1
;
7859 // Only use the assignee if it's a variable and skip
7860 // other lvalues (e.g. ref's returned by functions)
7861 if (left
.isVarExp())
7864 // Sanity check that `op` can be converted to boolean
7865 // But don't raise errors for assignments enclosed in another expression
7870 // Tuples with side-effects already receive a temporary during semantic
7871 if (op
.type
.isTypeTuple())
7873 auto te
= op
.isTupleExp();
7876 // Create a new tuple without the associated temporary
7877 auto res
= new TupleExp(op
.loc
, te
.exps
);
7878 return res
.expressionSemantic(sc
);
7881 const stc = op
.isLvalue() ? STC
.ref_
: 0;
7882 auto tmp
= copyToTemp(stc, "__assertOp", op
);
7883 tmp
.dsymbolSemantic(sc
);
7885 auto decl
= new DeclarationExp(op
.loc
, tmp
);
7886 temporariesPrefix
= Expression
.combine(temporariesPrefix
, decl
);
7888 op
= new VarExp(op
.loc
, tmp
);
7889 op
= op
.expressionSemantic(sc
);
7894 // if the assert condition is a mixin expression, try to compile it
7895 if (auto ce
= exp
.e1
.isMixinExp())
7897 if (auto e1
= compileIt(ce
, sc
))
7903 Loc loc
= exp
.e1
.loc
;
7905 const op
= exp
.e1
.op
;
7906 bool isEqualsCallExpression
;
7907 if (const callExp
= exp
.e1
.isCallExp())
7909 // https://issues.dlang.org/show_bug.cgi?id=20331
7910 // callExp.f may be null if the assert contains a call to
7911 // a function pointer or literal
7912 if (const callExpFunc
= callExp
.f
)
7914 const callExpIdent
= callExpFunc
.ident
;
7915 isEqualsCallExpression
= callExpIdent
== Id
.__equals ||
7916 callExpIdent
== Id
.eq
;
7919 if (op
== EXP
.equal || op
== EXP
.notEqual ||
7920 op
== EXP
.lessThan || op
== EXP
.greaterThan ||
7921 op
== EXP
.lessOrEqual || op
== EXP
.greaterOrEqual ||
7922 op
== EXP
.identity || op
== EXP
.notIdentity ||
7924 isEqualsCallExpression
)
7926 es
= new Expressions(3);
7927 tiargs
= new Objects(1);
7929 if (isEqualsCallExpression
)
7931 auto callExp
= cast(CallExp
) exp
.e1
;
7932 auto args
= callExp
.arguments
;
7934 // structs with opEquals get rewritten to a DotVarExp:
7936 // https://issues.dlang.org/show_bug.cgi?id=20100
7937 if (args
.length
== 1)
7939 auto dv
= callExp
.e1
.isDotVarExp();
7943 (*es
)[1] = maybePromoteToTmp(dv
.e1
);
7944 (*es
)[2] = maybePromoteToTmp((*args
)[0]);
7949 (*es
)[1] = maybePromoteToTmp((*args
)[0]);
7950 (*es
)[2] = maybePromoteToTmp((*args
)[1]);
7955 auto binExp
= cast(EqualExp
) exp
.e1
;
7958 (*es
)[1] = maybePromoteToTmp(binExp
.e1
);
7959 (*es
)[2] = maybePromoteToTmp(binExp
.e2
);
7963 Expression comp
= new StringExp(loc
, isEqualsCallExpression ?
"==" : EXPtoString(exp
.e1
.op
));
7964 comp
= comp
.expressionSemantic(sc
);
7966 (*tiargs
)[0] = (*es
)[1].type
;
7969 // Format exp.e1 before any additional boolean conversion
7970 // Ignore &&/|| because "assert(...) failed" is more informative than "false != true"
7971 else if (op
!= EXP
.andAnd
&& op
!= EXP
.orOr
)
7973 es
= new Expressions(2);
7974 tiargs
= new Objects(1);
7976 if (auto ne
= exp
.e1
.isNotExp())
7978 // Fetch the (potential non-bool) expression and fold
7979 // (n) negations into (n % 2) negations, e.g. !!a => a
7980 for (bool neg = true; ; neg = !neg)
7982 if (auto ne2
= ne
.e1
.isNotExp())
7986 (*es
)[0] = new StringExp(loc
, neg ?
"!" : "");
7987 (*es
)[1] = maybePromoteToTmp(ne
.e1
);
7993 { // Simply format exp.e1
7994 (*es
)[0] = new StringExp(loc
, "");
7995 (*es
)[1] = maybePromoteToTmp(exp
.e1
);
7998 (*tiargs
)[0] = (*es
)[1].type
;
8000 // Passing __ctfe to auto ref infers ref and aborts compilation:
8001 // "cannot modify compiler-generated variable __ctfe"
8002 auto ve
= (*es
)[1].isVarExp();
8003 if (ve
&& ve
.var
.ident
== Id
.ctfe
)
8005 exp
.msg
= new StringExp(loc
, "assert(__ctfe) failed!");
8012 buf
.printf("`%s` failed", exp
.toChars());
8013 exp
.msg
= new StringExp(Loc
.initial
, buf
.extractSlice());
8017 Expression __assertFail
= new IdentifierExp(exp
.loc
, Id
.empty
);
8018 auto assertFail
= new DotIdExp(loc
, __assertFail
, Id
.object
);
8020 auto dt = new DotTemplateInstanceExp(loc
, assertFail
, Id
._d_assert_fail
, tiargs
);
8021 auto ec
= CallExp
.create(loc
, dt, es
);
8026 if (Expression ex
= unaSemantic(exp
, sc
))
8032 exp
.e1
= resolveProperties(sc
, exp
.e1
);
8033 // BUG: see if we can do compile time elimination of the Assert
8034 exp
.e1
= exp
.e1
.optimize(WANTvalue
);
8035 exp
.e1
= exp
.e1
.toBoolean(sc
);
8037 if (exp
.e1
.op
== EXP
.error
)
8045 exp
.msg
= expressionSemantic(exp
.msg
, sc
);
8046 exp
.msg
= resolveProperties(sc
, exp
.msg
);
8047 exp
.msg
= exp
.msg
.implicitCastTo(sc
, Type
.tchar
.constOf().arrayOf());
8048 exp
.msg
= exp
.msg
.optimize(WANTvalue
);
8049 checkParamArgumentEscape(sc
, null, null, null, STC
.undefined_
, exp
.msg
, true, false);
8052 if (exp
.msg
&& exp
.msg
.op
== EXP
.error
)
8058 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
8059 auto f2
= exp
.msg
&& checkNonAssignmentArrayOp(exp
.msg
);
8063 if (exp
.e1
.toBool().hasValue(false))
8065 /* This is an `assert(0)` which means halt program execution
8067 FuncDeclaration fd
= sc
.parent
.isFuncDeclaration();
8069 fd
.hasReturnExp |
= 4;
8070 sc
.ctorflow
.orCSX(CSX
.halt
);
8072 if (global
.params
.useAssert
== CHECKENABLE
.off
)
8074 Expression e
= new HaltExp(exp
.loc
);
8075 e
= e
.expressionSemantic(sc
);
8080 // Only override the type when it isn't already some flavour of noreturn,
8081 // e.g. when this assert was generated by defaultInitLiteral
8082 if (!exp
.type ||
!exp
.type
.isTypeNoreturn())
8083 exp
.type
= Type
.tnoreturn
;
8086 exp
.type
= Type
.tvoid
;
8088 result
= !temporariesPrefix
8090 : Expression
.combine(temporariesPrefix
, exp
).expressionSemantic(sc
);
8093 override void visit(ThrowExp te
)
8095 import dmd
.statementsem
;
8097 if (throwSemantic(te
.loc
, te
.e1
, sc
))
8103 override void visit(DotIdExp exp
)
8105 static if (LOGSEMANTIC
)
8107 printf("DotIdExp::semantic(this = %p, '%s')\n", exp
, exp
.toChars());
8108 //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op));
8111 if (sc
.flags
& SCOPE
.Cfile
)
8113 /* See if need to rewrite the AST because of cast/call ambiguity
8115 if (auto e
= castCallAmbiguity(exp
, sc
))
8117 result
= expressionSemantic(e
, sc
);
8121 if (exp
.arrow
) // ImportC only
8122 exp
.e1
= exp
.e1
.expressionSemantic(sc
).arrayFuncConv(sc
);
8124 if (exp
.ident
== Id
.__xalignof
&& exp
.e1
.isTypeExp())
8126 // C11 6.5.3 says _Alignof only applies to types
8130 dmd
.typesem
.resolve(exp
.e1
.type
, exp
.e1
.loc
, sc
, e
, t
, s
, true);
8133 error(exp
.e1
.loc
, "argument to `_Alignof` must be a type");
8138 // Note similarity to getProperty() implementation of __xalignof
8139 const explicitAlignment
= t
.alignment();
8140 const naturalAlignment
= t
.alignsize();
8141 const actualAlignment
= (explicitAlignment
.isDefault() ? naturalAlignment
: explicitAlignment
.get());
8142 result
= new IntegerExp(exp
.loc
, actualAlignment
, Type
.tsize_t
);
8146 error(exp
.e1
.loc
, "argument to `_Alignof` must be a type");
8154 if (exp
.ident
!= Id
.__sizeof
)
8156 result
= fieldLookup(exp
.e1
, sc
, exp
.ident
, exp
.arrow
);
8161 Expression e
= exp
.dotIdSemanticProp(sc
, 1);
8163 if (e
&& isDotOpDispatch(e
))
8166 uint errors
= global
.startGagging();
8167 e
= resolvePropertiesX(sc
, e
);
8168 // Any error or if 'e' is not resolved, go to UFCS
8169 if (global
.endGagging(errors
) || e
is ode
)
8170 e
= null; /* fall down to UFCS */
8177 if (!e
) // if failed to find the property
8179 /* If ident is not a valid property, rewrite:
8184 e
= resolveUFCSProperties(sc
, exp
);
8189 override void visit(DotTemplateExp e
)
8196 if (Expression ex
= unaSemantic(e
, sc
))
8201 // 'void' like TemplateExp
8202 e
.type
= Type
.tvoid
;
8206 override void visit(DotVarExp exp
)
8208 static if (LOGSEMANTIC
)
8210 printf("DotVarExp::semantic('%s')\n", exp
.toChars());
8218 exp
.var
= exp
.var
.toAlias().isDeclaration();
8220 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
8222 if (auto tup
= exp
.var
.isTupleDeclaration())
8227 * tuple(e1.a, e1.b, e1.c)
8230 Expression ev
= sc
.func ?
extractSideEffect(sc
, "__tup", e0
, exp
.e1
) : exp
.e1
;
8232 auto exps
= new Expressions();
8233 exps
.reserve(tup
.objects
.length
);
8234 for (size_t i
= 0; i
< tup
.objects
.length
; i
++)
8236 RootObject o
= (*tup
.objects
)[i
];
8239 switch (o
.dyncast()) with (DYNCAST
)
8242 e
= cast(Expression
)o
;
8243 if (auto se
= e
.isDsymbolExp())
8244 var
= se
.s
.isDeclaration();
8245 else if (auto ve
= e
.isVarExp())
8246 if (!ve
.var
.isFuncDeclaration())
8247 // Exempt functions for backwards compatibility reasons.
8248 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
8252 Dsymbol s
= cast(Dsymbol
) o
;
8253 Declaration d
= s
.isDeclaration();
8254 if (!d || d
.isFuncDeclaration())
8255 // Exempt functions for backwards compatibility reasons.
8256 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
8257 e
= new DsymbolExp(exp
.loc
, s
);
8262 e
= new TypeExp(exp
.loc
, cast(Type
)o
);
8265 error(exp
.loc
, "`%s` is not an expression", o
.toChars());
8269 e
= new DotVarExp(exp
.loc
, ev
, var
);
8273 Expression e
= new TupleExp(exp
.loc
, e0
, exps
);
8274 e
= e
.expressionSemantic(sc
);
8278 else if (auto ad
= exp
.var
.isAliasDeclaration())
8280 if (auto t
= ad
.getType())
8282 result
= new TypeExp(exp
.loc
, t
).expressionSemantic(sc
);
8287 exp
.e1
= exp
.e1
.addDtorHook(sc
);
8289 Type t1
= exp
.e1
.type
;
8291 if (FuncDeclaration fd
= exp
.var
.isFuncDeclaration())
8293 // for functions, do checks after overload resolution
8294 if (!functionSemantic(fd
))
8297 /* https://issues.dlang.org/show_bug.cgi?id=13843
8298 * If fd obviously has no overloads, we should
8299 * normalize AST, and it will give a chance to wrap fd with FuncExp.
8301 if ((fd
.isNested() && !fd
.isThis()) || fd
.isFuncLiteralDeclaration())
8304 auto e
= symbolToExp(fd
, exp
.loc
, sc
, false);
8305 result
= Expression
.combine(exp
.e1
, e
);
8312 else if (OverDeclaration od
= exp
.var
.isOverDeclaration())
8314 exp
.type
= Type
.tvoid
; // ambiguous type?
8318 exp
.type
= exp
.var
.type
;
8319 if (!exp
.type
&& global
.errors
) // var is goofed up, just return error.
8323 if (t1
.ty
== Tpointer
)
8326 exp
.type
= exp
.type
.addMod(t1
.mod
);
8328 // https://issues.dlang.org/show_bug.cgi?id=23109
8329 // Run semantic on the DotVarExp type
8330 if (auto handle
= exp
.type
.isClassHandle())
8332 if (handle
.semanticRun
< PASS
.semanticdone
&& !handle
.isBaseInfoComplete())
8333 handle
.dsymbolSemantic(null);
8336 Dsymbol vparent
= exp
.var
.toParent();
8337 AggregateDeclaration ad
= vparent ? vparent
.isAggregateDeclaration() : null;
8338 if (Expression e1x
= getRightThis(exp
.loc
, sc
, ad
, exp
.e1
, exp
.var
, 1))
8342 /* Later checkRightThis will report correct error for invalid field variable access.
8344 Expression e
= new VarExp(exp
.loc
, exp
.var
);
8345 e
= e
.expressionSemantic(sc
);
8349 checkAccess(exp
.loc
, sc
, exp
.e1
, exp
.var
);
8351 VarDeclaration v
= exp
.var
.isVarDeclaration();
8352 if (v
&& (v
.isDataseg() ||
(v
.storage_class
& STC
.manifest
)))
8354 Expression e
= expandVar(WANTvalue
, v
);
8362 if (v
&& (v
.isDataseg() ||
// fix https://issues.dlang.org/show_bug.cgi?id=8238
8363 (!v
.needThis() && v
.semanticRun
> PASS
.initial
))) // fix https://issues.dlang.org/show_bug.cgi?id=17258
8366 checkAccess(exp
.loc
, sc
, exp
.e1
, v
);
8367 Expression e
= new VarExp(exp
.loc
, v
);
8368 e
= new CommaExp(exp
.loc
, exp
.e1
, e
);
8369 e
= e
.expressionSemantic(sc
);
8374 //printf("-DotVarExp::semantic('%s')\n", toChars());
8378 override void visit(DotTemplateInstanceExp exp
)
8380 static if (LOGSEMANTIC
)
8382 printf("DotTemplateInstanceExp::semantic('%s')\n", exp
.toChars());
8389 // Indicate we need to resolve by UFCS.
8390 Expression e
= exp
.dotTemplateSemanticProp(sc
, DotExpFlag
.gag
);
8392 e
= resolveUFCSProperties(sc
, exp
);
8394 e
.type
= Type
.tvoid
; // Unresolved type, because it needs inference
8398 override void visit(DelegateExp e
)
8400 static if (LOGSEMANTIC
)
8402 printf("DelegateExp::semantic('%s')\n", e
.toChars());
8410 e
.e1
= e
.e1
.expressionSemantic(sc
);
8412 e
.type
= new TypeDelegate(e
.func
.type
.isTypeFunction());
8413 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
8415 FuncDeclaration f
= e
.func
.toAliasFunc();
8416 AggregateDeclaration ad
= f
.isMemberLocal();
8418 e
.e1
= getRightThis(e
.loc
, sc
, ad
, e
.e1
, f
);
8420 if (f
.type
.ty
== Tfunction
)
8422 TypeFunction tf
= cast(TypeFunction
)f
.type
;
8423 if (!MODmethodConv(e
.e1
.type
.mod
, f
.type
.mod
))
8425 OutBuffer thisBuf
, funcBuf
;
8426 MODMatchToBuffer(&thisBuf
, e
.e1
.type
.mod
, tf
.mod
);
8427 MODMatchToBuffer(&funcBuf
, tf
.mod
, e
.e1
.type
.mod
);
8428 error(e
.loc
, "%smethod `%s` is not callable using a %s`%s`",
8429 funcBuf
.peekChars(), f
.toPrettyChars(), thisBuf
.peekChars(), e
.e1
.toChars());
8433 if (ad
&& ad
.isClassDeclaration() && ad
.type
!= e
.e1
.type
)
8435 // A downcast is required for interfaces
8436 // https://issues.dlang.org/show_bug.cgi?id=3706
8437 e
.e1
= new CastExp(e
.loc
, e
.e1
, ad
.type
);
8438 e
.e1
= e
.e1
.expressionSemantic(sc
);
8441 // declare dual-context container
8442 if (f
.hasDualContext() && !sc
.intypeof
&& sc
.func
)
8444 // check access to second `this`
8445 if (AggregateDeclaration ad2
= f
.isMember2())
8447 Expression te
= new ThisExp(e
.loc
).expressionSemantic(sc
);
8448 if (te
.op
!= EXP
.error
)
8449 te
= getRightThis(e
.loc
, sc
, ad2
, te
, f
);
8450 if (te
.op
== EXP
.error
)
8452 error(e
.loc
, "need `this` of type `%s` to make delegate from function `%s`", ad2
.toChars(), f
.toChars());
8456 VarDeclaration vthis2
= makeThis2Argument(e
.loc
, sc
, f
);
8458 Expression
de = new DeclarationExp(e
.loc
, vthis2
);
8459 result
= Expression
.combine(de, result
);
8460 result
= result
.expressionSemantic(sc
);
8464 override void visit(DotTypeExp exp
)
8466 static if (LOGSEMANTIC
)
8468 printf("DotTypeExp::semantic('%s')\n", exp
.toChars());
8476 if (auto e
= unaSemantic(exp
, sc
))
8482 exp
.type
= exp
.sym
.getType().addMod(exp
.e1
.type
.mod
);
8486 override void visit(AddrExp exp
)
8488 static if (LOGSEMANTIC
)
8490 printf("AddrExp::semantic('%s')\n", exp
.toChars());
8498 if (Expression ex
= unaSemantic(exp
, sc
))
8504 if (sc
.flags
& SCOPE
.Cfile
)
8506 /* Special handling for &"string"/&(T[]){0, 1}
8507 * since C regards string/array literals as lvalues
8510 if(e
.isStringExp() || e
.isArrayLiteralExp())
8512 e
.type
= typeSemantic(e
.type
, Loc
.initial
, sc
);
8513 // if type is already a pointer exp is an illegal expression of the form `&(&"")`
8514 if (!e
.type
.isTypePointer())
8516 e
.type
= e
.type
.pointerTo();
8522 // `toLvalue` call further below is upon exp.e1, omitting & from the error message
8523 exp
.toLvalue(sc
, "take address of");
8529 int wasCond
= exp
.e1
.op
== EXP
.question
;
8531 if (exp
.e1
.op
== EXP
.dotTemplateInstance
)
8533 DotTemplateInstanceExp dti
= cast(DotTemplateInstanceExp
)exp
.e1
;
8534 TemplateInstance ti
= dti
.ti
;
8536 //assert(ti.needsTypeInference(sc));
8537 ti
.dsymbolSemantic(sc
);
8538 if (!ti
.inst || ti
.errors
) // if template failed to expand
8541 Dsymbol s
= ti
.toAlias();
8542 FuncDeclaration f
= s
.isFuncDeclaration();
8545 exp
.e1
= new DotVarExp(exp
.e1
.loc
, dti
.e1
, f
);
8546 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
8550 else if (exp
.e1
.op
== EXP
.scope_
)
8552 TemplateInstance ti
= (cast(ScopeExp
)exp
.e1
).sds
.isTemplateInstance();
8555 //assert(ti.needsTypeInference(sc));
8556 ti
.dsymbolSemantic(sc
);
8557 if (!ti
.inst || ti
.errors
) // if template failed to expand
8560 Dsymbol s
= ti
.toAlias();
8561 FuncDeclaration f
= s
.isFuncDeclaration();
8564 exp
.e1
= new VarExp(exp
.e1
.loc
, f
);
8565 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
8569 /* https://issues.dlang.org/show_bug.cgi?id=809
8571 * If the address of a lazy variable is taken,
8572 * the expression is rewritten so that the type
8573 * of it is the delegate type. This means that
8574 * the symbol is not going to represent a call
8575 * to the delegate anymore, but rather, the
8578 if (auto ve
= exp
.e1
.isVarExp())
8580 if (ve
.var
.storage_class
& STC
.lazy_
)
8582 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
8583 exp
.e1
= resolveProperties(sc
, exp
.e1
);
8584 if (auto callExp
= exp
.e1
.isCallExp())
8586 if (callExp
.e1
.type
.toBasetype().ty
== Tdelegate
)
8588 /* https://issues.dlang.org/show_bug.cgi?id=20551
8590 * Cannot take address of lazy parameter in @safe code
8591 * because it might end up being a pointer to undefined
8596 if (sc
.setUnsafe(false, exp
.loc
,
8597 "cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve
, sc
.func
))
8603 VarExp ve2
= callExp
.e1
.isVarExp();
8604 ve2
.delegateWasExtracted
= true;
8605 ve2
.var
.storage_class |
= STC
.scope_
;
8613 exp
.e1
= exp
.e1
.toLvalue(sc
, "take address of");
8614 if (exp
.e1
.op
== EXP
.error
)
8619 if (checkNonAssignmentArrayOp(exp
.e1
))
8624 error(exp
.loc
, "cannot take address of `%s`", exp
.e1
.toChars());
8627 if (!checkAddressable(exp
, sc
))
8631 if (auto f
= isFuncAddress(exp
, &hasOverloads
))
8633 if (!hasOverloads
&& f
.checkForwardRef(exp
.loc
))
8636 else if (!exp
.e1
.type
.deco
)
8638 // try to resolve the type
8639 exp
.e1
.type
= exp
.e1
.type
.typeSemantic(exp
.e1
.loc
, sc
);
8640 if (!exp
.e1
.type
.deco
) // still couldn't resolve it
8642 if (auto ve
= exp
.e1
.isVarExp())
8644 Declaration d
= ve
.var
;
8645 error(exp
.loc
, "forward reference to %s `%s`", d
.kind(), d
.toChars());
8648 error(exp
.loc
, "forward reference to type `%s` of expression `%s`", exp
.e1
.type
.toChars(), exp
.e1
.toChars());
8653 exp
.type
= exp
.e1
.type
.pointerTo();
8655 // See if this should really be a delegate
8656 if (exp
.e1
.op
== EXP
.dotVariable
)
8658 DotVarExp dve
= cast(DotVarExp
)exp
.e1
;
8659 FuncDeclaration f
= dve
.var
.isFuncDeclaration();
8662 f
= f
.toAliasFunc(); // FIXME, should see overloads
8663 // https://issues.dlang.org/show_bug.cgi?id=1983
8664 if (!dve
.hasOverloads
)
8669 e
= new DelegateExp(exp
.loc
, dve
.e1
, f
, dve
.hasOverloads
);
8670 else // It is a function pointer. Convert &v.f() --> (v, &V.f())
8671 e
= new CommaExp(exp
.loc
, dve
.e1
, new AddrExp(exp
.loc
, new VarExp(exp
.loc
, f
, dve
.hasOverloads
)));
8672 e
= e
.expressionSemantic(sc
);
8677 // Look for misaligned pointer in @safe mode
8678 if (checkUnsafeAccess(sc
, dve
, !exp
.type
.isMutable(), true))
8681 else if (exp
.e1
.op
== EXP
.variable
)
8683 VarExp ve
= cast(VarExp
)exp
.e1
;
8684 VarDeclaration v
= ve
.var
.isVarDeclaration();
8687 if (!checkAddressVar(sc
, exp
.e1
, v
))
8690 v
.checkPurity(ve
.loc
, sc
);
8692 FuncDeclaration f
= ve
.var
.isFuncDeclaration();
8695 /* Because nested functions cannot be overloaded,
8696 * mark here that we took its address because castTo()
8697 * may not be called with an exact match.
8699 * https://issues.dlang.org/show_bug.cgi?id=19285 :
8700 * We also need to make sure we aren't inside a typeof. Ideally the compiler
8701 * would do typeof(...) semantic analysis speculatively then collect information
8702 * about what it used rather than relying on what are effectively semantically-global
8703 * variables but it doesn't.
8705 if (!sc
.isFromSpeculativeSemanticContext() && (!ve
.hasOverloads ||
(f
.isNested() && !f
.needThis())))
8707 // TODO: Refactor to use a proper interface that can keep track of causes.
8711 if (f
.isNested() && !f
.needThis())
8713 if (f
.isFuncLiteralDeclaration())
8715 if (!f
.FuncDeclaration
.isNested())
8717 /* Supply a 'null' for a this pointer if no this is available
8719 Expression e
= new DelegateExp(exp
.loc
, new NullExp(exp
.loc
, Type
.tnull
), f
, ve
.hasOverloads
);
8720 e
= e
.expressionSemantic(sc
);
8725 Expression e
= new DelegateExp(exp
.loc
, exp
.e1
, f
, ve
.hasOverloads
);
8726 e
= e
.expressionSemantic(sc
);
8732 auto memberFunc
= hasThis(sc
);
8733 if (memberFunc
&& haveSameThis(memberFunc
, f
))
8735 /* Should probably supply 'this' after overload resolution,
8738 Expression ethis
= new ThisExp(exp
.loc
);
8739 Expression e
= new DelegateExp(exp
.loc
, ethis
, f
, ve
.hasOverloads
);
8740 e
= e
.expressionSemantic(sc
);
8744 if (sc
.func
&& !sc
.intypeof
&& !(sc
.flags
& SCOPE
.debug_
))
8746 sc
.setUnsafe(false, exp
.loc
,
8747 "`this` reference necessary to take address of member `%s` in `@safe` function `%s`",
8753 else if (exp
.e1
.op
== EXP
.index
)
8758 * check 'a' the same as for a regular variable
8760 if (VarDeclaration v
= expToVariable(exp
.e1
))
8762 v
.checkPurity(exp
.e1
.loc
, sc
);
8767 /* a ? b : c was transformed to *(a ? &b : &c), but we still
8768 * need to do safety checks
8770 assert(exp
.e1
.op
== EXP
.star
);
8771 PtrExp pe
= cast(PtrExp
)exp
.e1
;
8772 assert(pe
.e1
.op
== EXP
.question
);
8773 CondExp ce
= cast(CondExp
)pe
.e1
;
8774 assert(ce
.e1
.op
== EXP
.address
);
8775 assert(ce
.e2
.op
== EXP
.address
);
8777 // Re-run semantic on the address expressions only
8779 ce
.e1
= ce
.e1
.expressionSemantic(sc
);
8781 ce
.e2
= ce
.e2
.expressionSemantic(sc
);
8783 result
= exp
.optimize(WANTvalue
);
8786 override void visit(PtrExp exp
)
8788 static if (LOGSEMANTIC
)
8790 printf("PtrExp::semantic('%s')\n", exp
.toChars());
8798 Expression e
= exp
.op_overload(sc
);
8805 exp
.e1
= exp
.e1
.arrayFuncConv(sc
);
8807 Type tb
= exp
.e1
.type
.toBasetype();
8811 exp
.type
= (cast(TypePointer
)tb
).next
;
8816 if (isNonAssignmentArrayOp(exp
.e1
))
8818 error(exp
.loc
, "using `*` on an array is no longer supported; use `*(%s).ptr` instead", exp
.e1
.toChars());
8819 exp
.type
= (cast(TypeArray
)tb
).next
;
8820 exp
.e1
= exp
.e1
.castTo(sc
, exp
.type
.pointerTo());
8827 exp
.type
= Type
.tnoreturn
; // typeof(*null) is bottom type
8831 error(exp
.loc
, "can only `*` a pointer, not a `%s`", exp
.e1
.type
.toChars());
8835 if (sc
.flags
& SCOPE
.Cfile
&& exp
.type
&& exp
.type
.toBasetype().ty
== Tvoid
)
8837 // https://issues.dlang.org/show_bug.cgi?id=23752
8838 // `&*((void*)(0))` is allowed in C
8843 if (exp
.checkValue())
8849 override void visit(NegExp exp
)
8851 static if (LOGSEMANTIC
)
8853 printf("NegExp::semantic('%s')\n", exp
.toChars());
8861 Expression e
= exp
.op_overload(sc
);
8869 exp
.type
= exp
.e1
.type
;
8870 Type tb
= exp
.type
.toBasetype();
8871 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
8873 if (!isArrayOpValid(exp
.e1
))
8875 result
= arrayOpInvalidError(exp
);
8881 if (!target
.isVectorOpSupported(tb
, exp
.op
))
8883 result
= exp
.incompatibleTypes();
8886 if (exp
.e1
.checkNoBool())
8888 if (exp
.e1
.checkArithmetic(exp
.op
) ||
8889 exp
.e1
.checkSharedAccess(sc
))
8895 override void visit(UAddExp exp
)
8897 static if (LOGSEMANTIC
)
8899 printf("UAddExp::semantic('%s')\n", exp
.toChars());
8903 Expression e
= exp
.op_overload(sc
);
8911 if (!target
.isVectorOpSupported(exp
.e1
.type
.toBasetype(), exp
.op
))
8913 result
= exp
.incompatibleTypes();
8916 if (exp
.e1
.checkNoBool())
8918 if (exp
.e1
.checkArithmetic(exp
.op
))
8920 if (exp
.e1
.checkSharedAccess(sc
))
8926 override void visit(ComExp exp
)
8934 Expression e
= exp
.op_overload(sc
);
8942 exp
.type
= exp
.e1
.type
;
8943 Type tb
= exp
.type
.toBasetype();
8944 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
8946 if (!isArrayOpValid(exp
.e1
))
8948 result
= arrayOpInvalidError(exp
);
8954 if (!target
.isVectorOpSupported(tb
, exp
.op
))
8956 result
= exp
.incompatibleTypes();
8959 if (exp
.e1
.checkNoBool())
8961 if (exp
.e1
.checkIntegral() ||
8962 exp
.e1
.checkSharedAccess(sc
))
8968 override void visit(NotExp e
)
8976 e
.setNoderefOperand();
8978 // Note there is no operator overload
8979 if (Expression ex
= unaSemantic(e
, sc
))
8985 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
8986 if (e
.e1
.op
== EXP
.type
)
8987 e
.e1
= resolveAliasThis(sc
, e
.e1
);
8989 e
.e1
= resolveProperties(sc
, e
.e1
);
8990 e
.e1
= e
.e1
.toBoolean(sc
);
8991 if (e
.e1
.type
== Type
.terror
)
8997 if (!target
.isVectorOpSupported(e
.e1
.type
.toBasetype(), e
.op
))
8999 result
= e
.incompatibleTypes();
9001 // https://issues.dlang.org/show_bug.cgi?id=13910
9002 // Today NotExp can take an array as its operand.
9003 if (checkNonAssignmentArrayOp(e
.e1
))
9006 e
.type
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? Type
.tint32
: Type
.tbool
;
9010 override void visit(DeleteExp exp
)
9012 // @@@DEPRECATED_2.109@@@
9013 // 1. Deprecated since 2.079
9014 // 2. Error since 2.099
9015 // 3. Removal of keyword, "delete" can be used for other identities
9018 error(exp
.loc
, "the `delete` keyword is obsolete");
9019 errorSupplemental(exp
.loc
, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead");
9025 if (Expression ex
= unaSemantic(exp
, sc
))
9030 exp
.e1
= resolveProperties(sc
, exp
.e1
);
9031 exp
.e1
= exp
.e1
.modifiableLvalue(sc
);
9032 if (exp
.e1
.op
== EXP
.error
)
9037 exp
.type
= Type
.tvoid
;
9039 Type tb
= exp
.e1
.type
.toBasetype();
9041 /* Now that `delete` in user code is an error, we only get here when
9042 * `isRAII` has been set to true for the deletion of a `scope class`. */
9043 if (tb
.ty
!= Tclass
)
9045 error(exp
.loc
, "cannot delete type `%s`", exp
.e1
.type
.toChars());
9049 ClassDeclaration cd
= (cast(TypeClass
)tb
).sym
;
9050 if (cd
.isCOMinterface())
9052 /* Because COM classes are deleted by IUnknown.Release()
9054 error(exp
.loc
, "cannot `delete` instance of COM interface `%s`", cd
.toChars());
9061 err |
= !functionSemantic(cd
.dtor
);
9062 err |
= cd
.dtor
.checkPurity(exp
.loc
, sc
);
9063 err |
= cd
.dtor
.checkSafety(exp
.loc
, sc
);
9064 err |
= cd
.dtor
.checkNogc(exp
.loc
, sc
);
9072 override void visit(CastExp exp
)
9074 static if (LOGSEMANTIC
)
9076 printf("CastExp::semantic('%s')\n", exp
.toChars());
9078 //static int x; assert(++x < 10);
9085 if ((sc
&& sc
.flags
& SCOPE
.Cfile
) &&
9086 exp
.to
&& (exp
.to
.ty
== Tident || exp
.to
.ty
== Tsarray
) &&
9087 (exp
.e1
.op
== EXP
.address || exp
.e1
.op
== EXP
.star ||
9088 exp
.e1
.op
== EXP
.uadd || exp
.e1
.op
== EXP
.negate
))
9090 /* Ambiguous cases arise from CParser if type-name is just an identifier.
9091 * ( identifier ) cast-expression
9092 * ( identifier [expression]) cast-expression
9093 * If we determine that `identifier` is a variable, and cast-expression
9094 * is one of the unary operators (& * + -), then rewrite this cast
9095 * as a binary expression.
9101 exp
.to
.resolve(loc
, sc
, e
, t
, s
);
9104 if (auto ex
= exp
.e1
.isAddrExp()) // (ident) &exp -> (ident & exp)
9105 result
= new AndExp(loc
, e
, ex
.e1
);
9106 else if (auto ex
= exp
.e1
.isPtrExp()) // (ident) *exp -> (ident * exp)
9107 result
= new MulExp(loc
, e
, ex
.e1
);
9108 else if (auto ex
= exp
.e1
.isUAddExp()) // (ident) +exp -> (ident + exp)
9109 result
= new AddExp(loc
, e
, ex
.e1
);
9110 else if (auto ex
= exp
.e1
.isNegExp()) // (ident) -exp -> (ident - exp)
9111 result
= new MinExp(loc
, e
, ex
.e1
);
9114 result
= result
.expressionSemantic(sc
);
9121 exp
.to
= exp
.to
.typeSemantic(exp
.loc
, sc
);
9122 if (exp
.to
== Type
.terror
)
9125 if (!exp
.to
.hasPointers())
9126 exp
.setNoderefOperand();
9128 // When e1 is a template lambda, this cast may instantiate it with
9130 exp
.e1
= inferType(exp
.e1
, exp
.to
);
9133 if (auto e
= unaSemantic(exp
, sc
))
9139 if (exp
.to
&& !exp
.to
.isTypeSArray() && !exp
.to
.isTypeFunction())
9140 exp
.e1
= exp
.e1
.arrayFuncConv(sc
);
9142 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
9143 if (exp
.e1
.op
== EXP
.type
)
9144 exp
.e1
= resolveAliasThis(sc
, exp
.e1
);
9146 auto e1x
= resolveProperties(sc
, exp
.e1
);
9147 if (e1x
.op
== EXP
.error
)
9152 if (e1x
.checkType())
9158 error(exp
.loc
, "cannot cast `%s`", exp
.e1
.toChars());
9162 // https://issues.dlang.org/show_bug.cgi?id=19954
9163 if (exp
.e1
.type
.ty
== Ttuple
)
9167 if (TypeTuple tt
= exp
.to
.isTypeTuple())
9169 if (exp
.e1
.type
.implicitConvTo(tt
))
9171 result
= exp
.e1
.castTo(sc
, tt
);
9176 TupleExp te
= exp
.e1
.isTupleExp();
9177 if (te
.exps
.length
== 1)
9178 exp
.e1
= (*te
.exps
)[0];
9181 // only allow S(x) rewrite if cast specified S explicitly.
9182 // See https://issues.dlang.org/show_bug.cgi?id=18545
9183 const bool allowImplicitConstruction
= exp
.to
!is null;
9185 if (!exp
.to
) // Handle cast(const) and cast(immutable), etc.
9187 exp
.to
= exp
.e1
.type
.castMod(exp
.mod
);
9188 exp
.to
= exp
.to
.typeSemantic(exp
.loc
, sc
);
9190 if (exp
.to
== Type
.terror
)
9194 if (exp
.to
.ty
== Ttuple
)
9196 error(exp
.loc
, "cannot cast `%s` of type `%s` to type sequence `%s`", exp
.e1
.toChars(), exp
.e1
.type
.toChars(), exp
.to
.toChars());
9200 // cast(void) is used to mark e1 as unused, so it is safe
9201 if (exp
.to
.ty
== Tvoid
)
9208 if (!exp
.to
.equals(exp
.e1
.type
) && exp
.mod
== cast(ubyte)~0)
9210 if (Expression e
= exp
.op_overload(sc
))
9212 result
= e
.implicitCastTo(sc
, exp
.to
);
9217 Type t1b
= exp
.e1
.type
.toBasetype();
9218 Type tob
= exp
.to
.toBasetype();
9220 if (allowImplicitConstruction
&& tob
.ty
== Tstruct
&& !tob
.equals(t1b
))
9228 // Rewrite as to.call(e1)
9229 Expression e
= new TypeExp(exp
.loc
, exp
.to
);
9230 e
= new CallExp(exp
.loc
, e
, exp
.e1
);
9231 e
= e
.trySemantic(sc
);
9239 if (!t1b
.equals(tob
) && (t1b
.ty
== Tarray || t1b
.ty
== Tsarray
))
9241 if (checkNonAssignmentArrayOp(exp
.e1
))
9245 Expression ex
= exp
.e1
.castTo(sc
, exp
.to
);
9246 if (ex
.op
== EXP
.error
)
9252 // Check for unsafe casts
9253 if (!isSafeCast(ex
, t1b
, tob
))
9255 if (sc
.setUnsafe(false, exp
.loc
, "cast from `%s` to `%s` not allowed in safe code", exp
.e1
.type
, exp
.to
))
9261 // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built
9262 // to handle certain casts. Those casts which `object.__ArrayCast` does not support are filtered out.
9263 // See `e2ir.toElemCast` for other types of casts. If `object.__ArrayCast` is improved to support more
9264 // casts these conditions and potentially some logic in `e2ir.toElemCast` can be removed.
9265 if (tob
.ty
== Tarray
)
9267 // https://issues.dlang.org/show_bug.cgi?id=19840
9268 if (auto ad
= isAggregate(t1b
))
9272 Expression e
= resolveAliasThis(sc
, exp
.e1
);
9273 e
= new CastExp(exp
.loc
, e
, exp
.to
);
9274 result
= e
.expressionSemantic(sc
);
9279 if(t1b
.ty
== Tarray
&& exp
.e1
.op
!= EXP
.arrayLiteral
&& sc
.needsCodegen())
9281 auto tFrom
= t1b
.nextOf();
9282 auto tTo
= tob
.nextOf();
9284 // https://issues.dlang.org/show_bug.cgi?id=20130
9285 if (exp
.e1
.op
!= EXP
.string_ ||
!ex
.isStringExp
)
9287 const uint fromSize
= cast(uint)tFrom
.size();
9288 const uint toSize
= cast(uint)tTo
.size();
9289 if (fromSize
== SIZE_INVALID || toSize
== SIZE_INVALID
)
9292 // If array element sizes do not match, we must adjust the dimensions
9293 if (fromSize
!= toSize
)
9295 if (!verifyHookExist(exp
.loc
, *sc
, Id
.__ArrayCast
, "casting array of structs"))
9298 // A runtime check is needed in case arrays don't line up. That check should
9299 // be done in the implementation of `object.__ArrayCast`
9300 if (toSize
== 0 ||
(fromSize
% toSize
) != 0)
9302 // lower to `object.__ArrayCast!(TFrom, TTo)(from)`
9304 // fully qualify as `object.__ArrayCast`
9305 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
9306 auto dotid
= new DotIdExp(exp
.loc
, id
, Id
.object
);
9308 auto tiargs
= new Objects();
9311 auto dt = new DotTemplateInstanceExp(exp
.loc
, dotid
, Id
.__ArrayCast
, tiargs
);
9313 auto arguments
= new Expressions();
9314 arguments
.push(exp
.e1
);
9315 Expression ce
= new CallExp(exp
.loc
, dt, arguments
);
9317 result
= expressionSemantic(ce
, sc
);
9325 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
9327 /* C11 6.5.4-5: A cast does not yield an lvalue.
9328 * So ensure that castTo does not strip away the cast so that this
9329 * can be enforced in other semantic visitor methods.
9331 if (!ex
.isCastExp())
9333 ex
= new CastExp(exp
.loc
, ex
, exp
.to
);
9340 override void visit(VectorExp exp
)
9342 static if (LOGSEMANTIC
)
9344 printf("VectorExp::semantic('%s')\n", exp
.toChars());
9352 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
9353 exp
.type
= exp
.to
.typeSemantic(exp
.loc
, sc
);
9354 if (exp
.e1
.op
== EXP
.error || exp
.type
.ty
== Terror
)
9360 Type tb
= exp
.type
.toBasetype();
9361 assert(tb
.ty
== Tvector
);
9362 TypeVector tv
= cast(TypeVector
)tb
;
9363 Type te
= tv
.elementType();
9364 exp
.dim
= cast(int)(tv
.size(exp
.loc
) / te
.size(exp
.loc
));
9366 bool checkElem(Expression elem
)
9368 if (elem
.isConst() == 1)
9371 error(exp
.loc
, "constant expression expected, not `%s`", elem
.toChars());
9375 exp
.e1
= exp
.e1
.optimize(WANTvalue
);
9377 if (exp
.e1
.op
== EXP
.arrayLiteral
)
9379 foreach (i
; 0 .. exp
.dim
)
9381 // Do not stop on first error - check all AST nodes even if error found
9382 res |
= checkElem(exp
.e1
.isArrayLiteralExp()[i
]);
9385 else if (exp
.e1
.type
.ty
== Tvoid
)
9388 result
= res ? ErrorExp
.get() : exp
;
9391 override void visit(VectorArrayExp e
)
9393 static if (LOGSEMANTIC
)
9395 printf("VectorArrayExp::semantic('%s')\n", e
.toChars());
9400 e
.e1
= resolveProperties(sc
, e
.e1
);
9402 if (e
.e1
.op
== EXP
.error
)
9407 assert(e
.e1
.type
.ty
== Tvector
);
9408 e
.type
= e
.e1
.type
.isTypeVector().basetype
;
9413 override void visit(SliceExp exp
)
9415 static if (LOGSEMANTIC
)
9417 printf("SliceExp::semantic('%s')\n", exp
.toChars());
9425 // operator overloading should be handled in ArrayExp already.
9426 if (Expression ex
= unaSemantic(exp
, sc
))
9431 exp
.e1
= resolveProperties(sc
, exp
.e1
);
9432 if (exp
.e1
.op
== EXP
.type
&& exp
.e1
.type
.ty
!= Ttuple
)
9434 if (exp
.lwr || exp
.upr
)
9436 error(exp
.loc
, "cannot slice type `%s`", exp
.e1
.toChars());
9439 Expression e
= new TypeExp(exp
.loc
, exp
.e1
.type
.arrayOf());
9440 result
= e
.expressionSemantic(sc
);
9443 if (!exp
.lwr
&& !exp
.upr
)
9445 if (exp
.e1
.op
== EXP
.arrayLiteral
)
9447 // Convert [a,b,c][] to [a,b,c]
9448 Type t1b
= exp
.e1
.type
.toBasetype();
9449 Expression e
= exp
.e1
;
9450 if (t1b
.ty
== Tsarray
)
9453 e
.type
= t1b
.nextOf().arrayOf();
9458 if (exp
.e1
.op
== EXP
.slice
)
9460 // Convert e[][] to e[]
9461 SliceExp se
= cast(SliceExp
)exp
.e1
;
9462 if (!se
.lwr
&& !se
.upr
)
9468 if (isArrayOpOperand(exp
.e1
))
9470 // Convert (a[]+b[])[] to a[]+b[]
9475 if (exp
.e1
.op
== EXP
.error
)
9480 if (exp
.e1
.type
.ty
== Terror
)
9483 Type t1b
= exp
.e1
.type
.toBasetype();
9484 if (auto tp
= t1b
.isTypePointer())
9486 if (t1b
.isPtrToFunction())
9488 error(exp
.loc
, "cannot slice function pointer `%s`", exp
.e1
.toChars());
9491 if (!exp
.lwr ||
!exp
.upr
)
9493 error(exp
.loc
, "upper and lower bounds are needed to slice a pointer");
9494 if (auto ad
= isAggregate(tp
.next
.toBasetype()))
9496 auto s
= search_function(ad
, Id
.index
);
9497 if (!s
) s
= search_function(ad
, Id
.slice
);
9500 auto fd
= s
.isFuncDeclaration();
9501 if ((fd
&& !fd
.getParameterList().length
) || s
.isTemplateDeclaration())
9503 errorSupplemental(exp
.loc
,
9504 "pointer `%s` points to an aggregate that defines an `%s`, perhaps you meant `(*%s)[]`",
9516 if (sc
.setUnsafe(false, exp
.loc
, "pointer slicing not allowed in safe functions"))
9519 else if (t1b
.ty
== Tarray
)
9522 else if (t1b
.ty
== Tsarray
)
9525 else if (t1b
.ty
== Ttuple
)
9527 if (!exp
.lwr
&& !exp
.upr
)
9532 if (!exp
.lwr ||
!exp
.upr
)
9534 error(exp
.loc
, "need upper and lower bound to slice a sequence");
9538 else if (t1b
.ty
== Tvector
&& exp
.e1
.isLvalue())
9540 // Convert e1 to corresponding static array
9541 TypeVector tv1
= cast(TypeVector
)t1b
;
9543 t1b
= t1b
.castMod(tv1
.mod
);
9548 error(exp
.loc
, "`%s` cannot be sliced with `[]`", t1b
.ty
== Tvoid ? exp
.e1
.toChars() : t1b
.toChars());
9552 /* Run semantic on lwr and upr.
9555 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray || t1b
.ty
== Ttuple
)
9557 // Create scope for 'length' variable
9558 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, exp
);
9559 sym
.parent
= sc
.scopesym
;
9564 if (t1b
.ty
== Ttuple
)
9565 sc
= sc
.startCTFE();
9566 exp
.lwr
= exp
.lwr
.expressionSemantic(sc
);
9567 exp
.lwr
= resolveProperties(sc
, exp
.lwr
);
9568 if (t1b
.ty
== Ttuple
)
9570 exp
.lwr
= exp
.lwr
.implicitCastTo(sc
, Type
.tsize_t
);
9574 if (t1b
.ty
== Ttuple
)
9575 sc
= sc
.startCTFE();
9576 exp
.upr
= exp
.upr
.expressionSemantic(sc
);
9577 exp
.upr
= resolveProperties(sc
, exp
.upr
);
9578 if (t1b
.ty
== Ttuple
)
9580 exp
.upr
= exp
.upr
.implicitCastTo(sc
, Type
.tsize_t
);
9584 if (exp
.lwr
&& exp
.lwr
.type
== Type
.terror || exp
.upr
&& exp
.upr
.type
== Type
.terror
)
9587 if (t1b
.ty
== Ttuple
)
9589 exp
.lwr
= exp
.lwr
.ctfeInterpret();
9590 exp
.upr
= exp
.upr
.ctfeInterpret();
9591 uinteger_t i1
= exp
.lwr
.toUInteger();
9592 uinteger_t i2
= exp
.upr
.toUInteger();
9597 if (exp
.e1
.op
== EXP
.tuple
) // slicing an expression tuple
9599 te
= cast(TupleExp
)exp
.e1
;
9601 length
= te
.exps
.length
;
9603 else if (exp
.e1
.op
== EXP
.type
) // slicing a type tuple
9606 tup
= cast(TypeTuple
)t1b
;
9607 length
= Parameter
.dim(tup
.arguments
);
9612 if (i2
< i1 || length
< i2
)
9614 error(exp
.loc
, "string slice `[%llu .. %llu]` is out of bounds", i1
, i2
);
9618 size_t j1
= cast(size_t
)i1
;
9619 size_t j2
= cast(size_t
)i2
;
9621 if (exp
.e1
.op
== EXP
.tuple
)
9623 auto exps
= new Expressions(j2
- j1
);
9624 for (size_t i
= 0; i
< j2
- j1
; i
++)
9626 (*exps
)[i
] = (*te
.exps
)[j1
+ i
];
9628 e
= new TupleExp(exp
.loc
, te
.e0
, exps
);
9632 auto args
= new Parameters();
9633 args
.reserve(j2
- j1
);
9634 for (size_t i
= j1
; i
< j2
; i
++)
9636 Parameter arg
= Parameter
.getNth(tup
.arguments
, i
);
9639 e
= new TypeExp(exp
.e1
.loc
, new TypeTuple(args
));
9641 e
= e
.expressionSemantic(sc
);
9646 exp
.type
= t1b
.nextOf().arrayOf();
9647 // Allow typedef[] -> typedef[]
9648 if (exp
.type
.equals(t1b
))
9649 exp
.type
= exp
.e1
.type
;
9651 // We might know $ now
9652 setLengthVarIfKnown(exp
.lengthVar
, t1b
);
9654 if (exp
.lwr
&& exp
.upr
)
9656 exp
.lwr
= exp
.lwr
.optimize(WANTvalue
);
9657 exp
.upr
= exp
.upr
.optimize(WANTvalue
);
9659 IntRange lwrRange
= getIntRange(exp
.lwr
);
9660 IntRange uprRange
= getIntRange(exp
.upr
);
9662 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray
)
9664 Expression el
= new ArrayLengthExp(exp
.loc
, exp
.e1
);
9665 el
= el
.expressionSemantic(sc
);
9666 el
= el
.optimize(WANTvalue
);
9667 if (el
.op
== EXP
.int64
)
9669 // Array length is known at compile-time. Upper is in bounds if it fits length.
9670 dinteger_t length
= el
.toInteger();
9671 auto bounds
= IntRange(SignExtendedNumber(0), SignExtendedNumber(length
));
9672 exp
.upperIsInBounds
= bounds
.contains(uprRange
);
9674 else if (exp
.upr
.op
== EXP
.int64
&& exp
.upr
.toInteger() == 0)
9676 // Upper slice expression is '0'. Value is always in bounds.
9677 exp
.upperIsInBounds
= true;
9679 else if (exp
.upr
.op
== EXP
.variable
&& (cast(VarExp
)exp
.upr
).var
.ident
== Id
.dollar
)
9681 // Upper slice expression is '$'. Value is always in bounds.
9682 exp
.upperIsInBounds
= true;
9685 else if (t1b
.ty
== Tpointer
)
9687 exp
.upperIsInBounds
= true;
9692 exp
.lowerIsLessThanUpper
= (lwrRange
.imax
<= uprRange
.imin
);
9694 //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", exp.upperIsInBounds, exp.lowerIsLessThanUpper);
9700 override void visit(ArrayLengthExp e
)
9702 static if (LOGSEMANTIC
)
9704 printf("ArrayLengthExp::semantic('%s')\n", e
.toChars());
9712 if (Expression ex
= unaSemantic(e
, sc
))
9717 e
.e1
= resolveProperties(sc
, e
.e1
);
9719 e
.type
= Type
.tsize_t
;
9723 override void visit(ArrayExp exp
)
9725 static if (LOGSEMANTIC
)
9727 printf("ArrayExp::semantic('%s')\n", exp
.toChars());
9731 if (sc
.flags
& SCOPE
.Cfile
)
9733 /* See if need to rewrite the AST because of cast/call ambiguity
9735 if (auto e
= castCallAmbiguity(exp
, sc
))
9737 result
= expressionSemantic(e
, sc
);
9742 result
= exp
.carraySemantic(sc
); // C semantics
9746 Expression e
= exp
.op_overload(sc
);
9753 if (isAggregate(exp
.e1
.type
))
9754 error(exp
.loc
, "no `[]` operator overload for type `%s`", exp
.e1
.type
.toChars());
9755 else if (exp
.e1
.op
== EXP
.type
&& exp
.e1
.type
.ty
!= Ttuple
)
9756 error(exp
.loc
, "static array of `%s` with multiple lengths not allowed", exp
.e1
.type
.toChars());
9757 else if (isIndexableNonAggregate(exp
.e1
.type
))
9758 error(exp
.loc
, "only one index allowed to index `%s`", exp
.e1
.type
.toChars());
9760 error(exp
.loc
, "cannot use `[]` operator on expression of type `%s`", exp
.e1
.type
.toChars());
9762 result
= ErrorExp
.get();
9765 override void visit(DotExp exp
)
9767 static if (LOGSEMANTIC
)
9769 printf("DotExp::semantic('%s')\n", exp
.toChars());
9771 printf("\ttype = %s\n", exp
.type
.toChars());
9773 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
9774 exp
.e2
= exp
.e2
.expressionSemantic(sc
);
9776 if (exp
.e1
.op
== EXP
.type
)
9781 if (exp
.e2
.op
== EXP
.type
)
9786 if (auto te
= exp
.e2
.isTemplateExp())
9788 Expression e
= new DotTemplateExp(exp
.loc
, exp
.e1
, te
.td
);
9789 result
= e
.expressionSemantic(sc
);
9793 exp
.type
= exp
.e2
.type
;
9797 override void visit(CommaExp e
)
9799 //printf("Semantic.CommaExp() %s\n", e.toChars());
9806 // Allow `((a,b),(x,y))`
9807 if (e
.allowCommaExp
)
9809 CommaExp
.allow(e
.e1
);
9810 CommaExp
.allow(e
.e2
);
9813 if (Expression ex
= binSemanticProp(e
, sc
))
9818 e
.e1
= e
.e1
.addDtorHook(sc
);
9820 if (checkNonAssignmentArrayOp(e
.e1
))
9823 // Comma expressions trigger this conversion
9824 e
.e2
= e
.e2
.arrayFuncConv(sc
);
9829 if (sc
.flags
& SCOPE
.Cfile
)
9832 if (e
.type
is Type
.tvoid
)
9834 checkMustUse(e
.e1
, sc
);
9837 else if (!e
.allowCommaExp
&& !e
.isGenerated
)
9838 error(e
.loc
, "using the result of a comma expression is not allowed");
9841 override void visit(IntervalExp e
)
9843 static if (LOGSEMANTIC
)
9845 printf("IntervalExp::semantic('%s')\n", e
.toChars());
9853 Expression le
= e
.lwr
;
9854 le
= le
.expressionSemantic(sc
);
9855 le
= resolveProperties(sc
, le
);
9857 Expression ue
= e
.upr
;
9858 ue
= ue
.expressionSemantic(sc
);
9859 ue
= resolveProperties(sc
, ue
);
9861 if (le
.op
== EXP
.error
)
9866 if (ue
.op
== EXP
.error
)
9875 e
.type
= Type
.tvoid
;
9879 override void visit(DelegatePtrExp e
)
9881 static if (LOGSEMANTIC
)
9883 printf("DelegatePtrExp::semantic('%s')\n", e
.toChars());
9888 e
.e1
= resolveProperties(sc
, e
.e1
);
9890 if (e
.e1
.op
== EXP
.error
)
9895 e
.type
= Type
.tvoidptr
;
9900 override void visit(DelegateFuncptrExp e
)
9902 static if (LOGSEMANTIC
)
9904 printf("DelegateFuncptrExp::semantic('%s')\n", e
.toChars());
9909 e
.e1
= resolveProperties(sc
, e
.e1
);
9910 if (e
.e1
.op
== EXP
.error
)
9915 e
.type
= e
.e1
.type
.nextOf().pointerTo();
9920 override void visit(IndexExp exp
)
9922 static if (LOGSEMANTIC
)
9924 printf("IndexExp::semantic('%s')\n", exp
.toChars());
9932 // operator overloading should be handled in ArrayExp already.
9934 exp
.e1
= exp
.e1
.expressionSemantic(sc
).arrayFuncConv(sc
);
9935 assert(exp
.e1
.type
); // semantic() should already be run on it
9936 if (exp
.e1
.op
== EXP
.type
&& exp
.e1
.type
.ty
!= Ttuple
)
9938 exp
.e2
= exp
.e2
.expressionSemantic(sc
);
9939 exp
.e2
= resolveProperties(sc
, exp
.e2
);
9941 if (exp
.e2
.op
== EXP
.type
)
9942 nt
= new TypeAArray(exp
.e1
.type
, exp
.e2
.type
);
9944 nt
= new TypeSArray(exp
.e1
.type
, exp
.e2
);
9945 Expression e
= new TypeExp(exp
.loc
, nt
);
9946 result
= e
.expressionSemantic(sc
);
9949 if (exp
.e1
.op
== EXP
.error
)
9954 if (exp
.e1
.type
.ty
== Terror
)
9957 // Note that unlike C we do not implement the int[ptr]
9959 Type t1b
= exp
.e1
.type
.toBasetype();
9961 if (TypeVector tv1
= t1b
.isTypeVector())
9963 // Convert e1 to corresponding static array
9965 t1b
= t1b
.castMod(tv1
.mod
);
9966 exp
.e1
= exp
.e1
.castTo(sc
, t1b
);
9968 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray
)
9970 if (!checkAddressable(exp
, sc
))
9974 /* Run semantic on e2
9977 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray || t1b
.ty
== Ttuple
)
9979 // Create scope for 'length' variable
9980 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, exp
);
9981 sym
.parent
= sc
.scopesym
;
9984 if (t1b
.ty
== Ttuple
)
9985 sc
= sc
.startCTFE();
9986 exp
.e2
= exp
.e2
.expressionSemantic(sc
).arrayFuncConv(sc
);
9987 exp
.e2
= resolveProperties(sc
, exp
.e2
);
9988 if (t1b
.ty
== Ttuple
)
9990 if (exp
.e2
.op
== EXP
.tuple
)
9992 TupleExp te
= cast(TupleExp
)exp
.e2
;
9993 if (te
.exps
&& te
.exps
.length
== 1)
9994 exp
.e2
= Expression
.combine(te
.e0
, (*te
.exps
)[0]); // bug 4444 fix
9998 if (exp
.e2
.type
== Type
.terror
)
10001 if (checkNonAssignmentArrayOp(exp
.e1
))
10007 if (t1b
.isPtrToFunction())
10009 error(exp
.loc
, "cannot index function pointer `%s`", exp
.e1
.toChars());
10012 exp
.e2
= exp
.e2
.implicitCastTo(sc
, Type
.tsize_t
);
10013 if (exp
.e2
.type
== Type
.terror
)
10015 exp
.e2
= exp
.e2
.optimize(WANTvalue
);
10016 if (exp
.e2
.op
== EXP
.int64
&& exp
.e2
.toInteger() == 0)
10019 else if (sc
.setUnsafe(false, exp
.loc
, "`@safe` function `%s` cannot index pointer `%s`", sc
.func
, exp
.e1
))
10023 exp
.type
= (cast(TypeNext
)t1b
).next
;
10027 exp
.e2
= exp
.e2
.implicitCastTo(sc
, Type
.tsize_t
);
10028 if (exp
.e2
.type
== Type
.terror
)
10030 exp
.type
= (cast(TypeNext
)t1b
).next
;
10035 exp
.e2
= exp
.e2
.implicitCastTo(sc
, Type
.tsize_t
);
10036 if (exp
.e2
.type
== Type
.terror
)
10038 exp
.type
= t1b
.nextOf();
10043 TypeAArray taa
= cast(TypeAArray
)t1b
;
10044 /* We can skip the implicit conversion if they differ only by
10046 * https://issues.dlang.org/show_bug.cgi?id=2684
10047 * see also bug https://issues.dlang.org/show_bug.cgi?id=2954 b
10049 if (!arrayTypeCompatibleWithoutCasting(exp
.e2
.type
, taa
.index
))
10051 exp
.e2
= exp
.e2
.implicitCastTo(sc
, taa
.index
); // type checking
10052 if (exp
.e2
.type
== Type
.terror
)
10056 semanticTypeInfo(sc
, taa
);
10057 checkNewEscape(sc
, exp
.e2
, false);
10059 exp
.type
= taa
.next
;
10064 exp
.e2
= exp
.e2
.implicitCastTo(sc
, Type
.tsize_t
);
10065 if (exp
.e2
.type
== Type
.terror
)
10068 exp
.e2
= exp
.e2
.ctfeInterpret();
10069 uinteger_t index
= exp
.e2
.toUInteger();
10074 if (exp
.e1
.op
== EXP
.tuple
)
10076 te
= cast(TupleExp
)exp
.e1
;
10078 length
= te
.exps
.length
;
10080 else if (exp
.e1
.op
== EXP
.type
)
10083 tup
= cast(TypeTuple
)t1b
;
10084 length
= Parameter
.dim(tup
.arguments
);
10089 if (length
<= index
)
10091 error(exp
.loc
, "array index `[%llu]` is outside array bounds `[0 .. %llu]`", index
, cast(ulong)length
);
10095 if (exp
.e1
.op
== EXP
.tuple
)
10097 e
= (*te
.exps
)[cast(size_t
)index
];
10098 e
= Expression
.combine(te
.e0
, e
);
10101 e
= new TypeExp(exp
.e1
.loc
, Parameter
.getNth(tup
.arguments
, cast(size_t
)index
).type
);
10106 error(exp
.loc
, "`%s` must be an array or pointer type, not `%s`", exp
.e1
.toChars(), exp
.e1
.type
.toChars());
10110 // We might know $ now
10111 setLengthVarIfKnown(exp
.lengthVar
, t1b
);
10113 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray
)
10115 Expression el
= new ArrayLengthExp(exp
.loc
, exp
.e1
);
10116 el
= el
.expressionSemantic(sc
);
10117 el
= el
.optimize(WANTvalue
);
10118 if (el
.op
== EXP
.int64
)
10120 exp
.e2
= exp
.e2
.optimize(WANTvalue
);
10121 dinteger_t length
= el
.toInteger();
10124 auto bounds
= IntRange(SignExtendedNumber(0), SignExtendedNumber(length
- 1));
10125 // OR it in, because it might already be set for C array indexing
10126 exp
.indexIsInBounds |
= bounds
.contains(getIntRange(exp
.e2
));
10128 else if (sc
.flags
& SCOPE
.Cfile
&& t1b
.ty
== Tsarray
)
10130 if (auto ve
= exp
.e1
.isVarExp())
10132 /* Rewrite 0-length C array ve[exp.e2] as *(ve + exp.e2)
10134 auto vp
= ve
.castTo(sc
, t1b
.isTypeSArray().next
.pointerTo());
10135 auto e
= new AddExp(exp
.loc
, vp
, exp
.e2
);
10136 auto pe
= new PtrExp(exp
.loc
, e
);
10137 result
= pe
.expressionSemantic(sc
).optimize(WANTvalue
);
10147 override void visit(PostExp exp
)
10149 static if (LOGSEMANTIC
)
10151 printf("PostExp::semantic('%s')\n", exp
.toChars());
10159 if (sc
.flags
& SCOPE
.Cfile
)
10161 /* See if need to rewrite the AST because of cast/call ambiguity
10163 if (auto e
= castCallAmbiguity(exp
, sc
))
10165 result
= expressionSemantic(e
, sc
);
10170 if (Expression ex
= binSemantic(exp
, sc
))
10175 Expression e1x
= resolveProperties(sc
, exp
.e1
);
10176 if (e1x
.op
== EXP
.error
)
10183 Expression e
= exp
.op_overload(sc
);
10190 if (exp
.e1
.checkReadModifyWrite(exp
.op
))
10193 if (exp
.e1
.op
== EXP
.slice
)
10195 const(char)* s
= exp
.op
== EXP
.plusPlus ?
"increment" : "decrement";
10196 error(exp
.loc
, "cannot post-%s array slice `%s`, use pre-%s instead", s
, exp
.e1
.toChars(), s
);
10200 Type t1
= exp
.e1
.type
.toBasetype();
10201 if (t1
.ty
== Tclass || t1
.ty
== Tstruct || exp
.e1
.op
== EXP
.arrayLength
)
10203 /* Check for operator overloading,
10204 * but rewrite in terms of ++e instead of e++
10207 /* If e1 is not trivial, take a reference to it
10209 Expression
de = null;
10210 if (exp
.e1
.op
!= EXP
.variable
&& exp
.e1
.op
!= EXP
.arrayLength
)
10213 auto v
= copyToTemp(STC
.ref_
, "__postref", exp
.e1
);
10214 de = new DeclarationExp(exp
.loc
, v
);
10215 exp
.e1
= new VarExp(exp
.e1
.loc
, v
);
10219 * auto tmp = e1; ++e1; tmp
10221 auto tmp
= copyToTemp(0, "__pitmp", exp
.e1
);
10222 Expression ea
= new DeclarationExp(exp
.loc
, tmp
);
10224 Expression eb
= exp
.e1
.syntaxCopy();
10225 eb
= new PreExp(exp
.op
== EXP
.plusPlus ? EXP
.prePlusPlus
: EXP
.preMinusMinus
, exp
.loc
, eb
);
10227 Expression ec
= new VarExp(exp
.loc
, tmp
);
10229 // Combine de,ea,eb,ec
10231 ea
= new CommaExp(exp
.loc
, de, ea
);
10232 e
= new CommaExp(exp
.loc
, ea
, eb
);
10233 e
= new CommaExp(exp
.loc
, e
, ec
);
10234 e
= e
.expressionSemantic(sc
);
10239 exp
.e1
= exp
.e1
.modifiableLvalue(sc
);
10240 exp
.e1
= exp
.e1
.optimize(WANTvalue
, /*keepLvalue*/ true);
10243 if (exp
.e1
.checkScalar() ||
10244 exp
.e1
.checkSharedAccess(sc
))
10246 if (exp
.e1
.checkNoBool())
10249 if (exp
.e1
.type
.ty
== Tpointer
)
10250 e
= scaleFactor(exp
, sc
);
10252 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
);
10253 e
.type
= exp
.e1
.type
;
10257 override void visit(PreExp exp
)
10259 Expression e
= exp
.op_overload(sc
);
10260 // printf("PreExp::semantic('%s')\n", toChars());
10267 // Rewrite as e1+=1 or e1-=1
10268 if (exp
.op
== EXP
.prePlusPlus
)
10269 e
= new AddAssignExp(exp
.loc
, exp
.e1
, IntegerExp
.literal
!1);
10271 e
= new MinAssignExp(exp
.loc
, exp
.e1
, IntegerExp
.literal
!1);
10272 result
= e
.expressionSemantic(sc
);
10276 * Get the expression initializer for a specific struct
10279 * sd = the struct for which the expression initializer is needed
10280 * loc = the location of the initializer
10281 * sc = the scope where the expression is located
10282 * t = the type of the expression
10285 * The expression initializer or error expression if any errors occured
10287 private Expression
getInitExp(StructDeclaration sd
, Loc loc
, Scope
* sc
, Type t
)
10289 if (sd
.zeroInit
&& !sd
.isNested())
10291 // https://issues.dlang.org/show_bug.cgi?id=14606
10292 // Always use BlitExp for the special expression: (struct = 0)
10293 return IntegerExp
.literal
!0;
10298 auto sle
= new StructLiteralExp(loc
, sd
, null, t
);
10299 if (!sd
.fill(loc
, *sle
.elements
, true))
10300 return ErrorExp
.get();
10301 if (checkFrameAccess(loc
, sc
, sd
, sle
.elements
.length
))
10302 return ErrorExp
.get();
10308 return t
.defaultInit(loc
);
10311 override void visit(AssignExp exp
)
10313 static if (LOGSEMANTIC
)
10315 if (exp
.op
== EXP
.blit
) printf("BlitExp.toElem('%s')\n", exp
.toChars());
10316 if (exp
.op
== EXP
.assign
) printf("AssignExp.toElem('%s')\n", exp
.toChars());
10317 if (exp
.op
== EXP
.construct
) printf("ConstructExp.toElem('%s')\n", exp
.toChars());
10320 void setResult(Expression e
, int line
= __LINE__
)
10322 //printf("line %d\n", line);
10328 return setResult(exp
);
10331 Expression e1old
= exp
.e1
;
10333 if (auto e2comma
= exp
.e2
.isCommaExp())
10335 if (!e2comma
.isGenerated
&& !(sc
.flags
& SCOPE
.Cfile
))
10336 error(exp
.loc
, "using the result of a comma expression is not allowed");
10338 /* Rewrite to get rid of the comma from rvalue
10339 * e1=(e0,e2) => e0,(e1=e2)
10342 exp
.e2
= Expression
.extractLast(e2comma
, e0
);
10343 Expression e
= Expression
.combine(e0
, exp
);
10344 return setResult(e
.expressionSemantic(sc
));
10347 /* Look for operator overloading of a[arguments] = e2.
10348 * Do it before e1.expressionSemantic() otherwise the ArrayExp will have been
10349 * converted to unary operator overloading already.
10351 if (auto ae
= exp
.e1
.isArrayExp())
10355 ae
.e1
= ae
.e1
.expressionSemantic(sc
);
10356 ae
.e1
= resolveProperties(sc
, ae
.e1
);
10357 Expression ae1old
= ae
.e1
;
10359 const(bool) maybeSlice
=
10360 (ae
.arguments
.length
== 0 ||
10361 ae
.arguments
.length
== 1 && (*ae
.arguments
)[0].op
== EXP
.interval
);
10363 IntervalExp ie
= null;
10364 if (maybeSlice
&& ae
.arguments
.length
)
10366 assert((*ae
.arguments
)[0].op
== EXP
.interval
);
10367 ie
= cast(IntervalExp
)(*ae
.arguments
)[0];
10369 Type att
= null; // first cyclic `alias this` type
10372 if (ae
.e1
.op
== EXP
.error
)
10373 return setResult(ae
.e1
);
10375 Expression e0
= null;
10376 Expression ae1save
= ae
.e1
;
10377 ae
.lengthVar
= null;
10379 Type t1b
= ae
.e1
.type
.toBasetype();
10380 AggregateDeclaration ad
= isAggregate(t1b
);
10383 if (search_function(ad
, Id
.indexass
))
10386 res
= resolveOpDollar(sc
, ae
, &e0
);
10387 if (!res
) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
10389 if (res
.op
== EXP
.error
)
10390 return setResult(res
);
10392 res
= exp
.e2
.expressionSemantic(sc
);
10393 if (res
.op
== EXP
.error
)
10394 return setResult(res
);
10397 /* Rewrite (a[arguments] = e2) as:
10398 * a.opIndexAssign(e2, arguments)
10400 Expressions
* a
= ae
.arguments
.copy();
10401 a
.insert(0, exp
.e2
);
10402 res
= new DotIdExp(exp
.loc
, ae
.e1
, Id
.indexass
);
10403 res
= new CallExp(exp
.loc
, res
, a
);
10404 if (maybeSlice
) // a[] = e2 might be: a.opSliceAssign(e2)
10405 res
= res
.trySemantic(sc
);
10407 res
= res
.expressionSemantic(sc
);
10409 return setResult(Expression
.combine(e0
, res
));
10413 if (maybeSlice
&& search_function(ad
, Id
.sliceass
))
10416 res
= resolveOpDollar(sc
, ae
, ie
, &e0
);
10417 if (res
.op
== EXP
.error
)
10418 return setResult(res
);
10420 res
= exp
.e2
.expressionSemantic(sc
);
10421 if (res
.op
== EXP
.error
)
10422 return setResult(res
);
10426 /* Rewrite (a[i..j] = e2) as:
10427 * a.opSliceAssign(e2, i, j)
10429 auto a
= new Expressions();
10436 res
= new DotIdExp(exp
.loc
, ae
.e1
, Id
.sliceass
);
10437 res
= new CallExp(exp
.loc
, res
, a
);
10438 res
= res
.expressionSemantic(sc
);
10439 return setResult(Expression
.combine(e0
, res
));
10442 // No operator overloading member function found yet, but
10443 // there might be an alias this to try.
10444 if (ad
.aliasthis
&& !isRecursiveAliasThis(att
, ae
.e1
.type
))
10446 /* Rewrite (a[arguments] op e2) as:
10447 * a.aliasthis[arguments] op e2
10449 ae
.e1
= resolveAliasThis(sc
, ae1save
, true);
10455 ae
.e1
= ae1old
; // recovery
10456 ae
.lengthVar
= null;
10459 /* Run this.e1 semantic.
10462 Expression e1x
= exp
.e1
;
10464 /* With UFCS, e.f = value
10470 if (auto dti
= e1x
.isDotTemplateInstanceExp())
10472 Expression e
= dti
.dotTemplateSemanticProp(sc
, DotExpFlag
.gag
);
10475 return setResult(resolveUFCSProperties(sc
, e1x
, exp
.e2
));
10480 else if (sc
.flags
& SCOPE
.Cfile
&& e1x
.isDotIdExp())
10482 auto die
= e1x
.isDotIdExp();
10483 e1x
= fieldLookup(die
.e1
, sc
, die
.ident
, die
.arrow
);
10485 else if (auto die
= e1x
.isDotIdExp())
10487 Expression e
= die
.dotIdSemanticProp(sc
, 1);
10488 if (e
&& isDotOpDispatch(e
))
10490 /* https://issues.dlang.org/show_bug.cgi?id=19687
10492 * On this branch, e2 is semantically analyzed in resolvePropertiesX,
10493 * but that call is done with gagged errors. That is the only time when
10494 * semantic gets ran on e2, that is why the error never gets to be printed.
10495 * In order to make sure that UFCS is tried with correct parameters, e2
10496 * needs to have semantic ran on it.
10499 exp
.e2
= exp
.e2
.expressionSemantic(sc
);
10500 uint errors
= global
.startGagging();
10501 e
= resolvePropertiesX(sc
, e
, exp
.e2
);
10502 // Any error or if 'e' is not resolved, go to UFCS
10503 if (global
.endGagging(errors
) || e
is ode
)
10504 e
= null; /* fall down to UFCS */
10506 return setResult(e
);
10509 return setResult(resolveUFCSProperties(sc
, e1x
, exp
.e2
));
10514 if (auto se
= e1x
.isSliceExp())
10517 e1x
= e1x
.expressionSemantic(sc
);
10520 /* We have f = value.
10526 if (Expression e
= resolvePropertiesX(sc
, e1x
, exp
.e2
, exp
))
10527 return setResult(e
);
10529 if (e1x
.checkRightThis(sc
))
10534 assert(exp
.e1
.type
);
10536 Type t1
= exp
.e1
.type
.isTypeEnum() ? exp
.e1
.type
: exp
.e1
.type
.toBasetype();
10538 /* Run this.e2 semantic.
10539 * Different from other binary expressions, the analysis of e2
10540 * depends on the result of e1 in assignments.
10543 Expression e2x
= inferType(exp
.e2
, t1
.baseElemOf());
10544 e2x
= e2x
.expressionSemantic(sc
);
10545 if (!t1
.isTypeSArray())
10546 e2x
= e2x
.arrayFuncConv(sc
);
10547 e2x
= resolveProperties(sc
, e2x
);
10548 if (e2x
.op
== EXP
.type
)
10549 e2x
= resolveAliasThis(sc
, e2x
); //https://issues.dlang.org/show_bug.cgi?id=17684
10550 if (e2x
.op
== EXP
.error
)
10551 return setResult(e2x
);
10552 // We delay checking the value for structs/classes as these might have
10553 // an opAssign defined.
10554 if ((t1
.ty
!= Tstruct
&& t1
.ty
!= Tclass
&& e2x
.checkValue()) ||
10555 e2x
.checkSharedAccess(sc
))
10558 auto etmp
= checkNoreturnVarAccess(e2x
);
10560 return setResult(etmp
);
10565 /* Rewrite tuple assignment as a tuple of assignments.
10568 Expression e2x
= exp
.e2
;
10571 if (exp
.e1
.op
== EXP
.tuple
&& e2x
.op
== EXP
.tuple
)
10573 TupleExp tup1
= cast(TupleExp
)exp
.e1
;
10574 TupleExp tup2
= cast(TupleExp
)e2x
;
10575 size_t dim
= tup1
.exps
.length
;
10576 Expression e
= null;
10577 if (dim
!= tup2
.exps
.length
)
10579 error(exp
.loc
, "mismatched sequence lengths, %d and %d", cast(int)dim
, cast(int)tup2
.exps
.length
);
10584 e
= IntegerExp
.literal
!0;
10585 e
= new CastExp(exp
.loc
, e
, Type
.tvoid
); // avoid "has no effect" error
10586 e
= Expression
.combine(tup1
.e0
, tup2
.e0
, e
);
10590 auto exps
= new Expressions(dim
);
10591 for (size_t i
= 0; i
< dim
; i
++)
10593 Expression ex1
= (*tup1
.exps
)[i
];
10594 Expression ex2
= (*tup2
.exps
)[i
];
10595 (*exps
)[i
] = new AssignExp(exp
.loc
, ex1
, ex2
);
10597 e
= new TupleExp(exp
.loc
, Expression
.combine(tup1
.e0
, tup2
.e0
), exps
);
10599 return setResult(e
.expressionSemantic(sc
));
10602 /* Look for form: e1 = e2.aliasthis.
10604 if (exp
.e1
.op
== EXP
.tuple
)
10606 TupleDeclaration td
= isAliasThisTuple(e2x
);
10610 assert(exp
.e1
.type
.ty
== Ttuple
);
10611 TypeTuple tt
= cast(TypeTuple
)exp
.e1
.type
;
10614 Expression ev
= extractSideEffect(sc
, "__tup", e0
, e2x
);
10616 auto iexps
= new Expressions();
10618 for (size_t u
= 0; u
< iexps
.length
; u
++)
10621 Expression e
= (*iexps
)[u
];
10623 Parameter arg
= Parameter
.getNth(tt
.arguments
, u
);
10624 //printf("[%d] iexps.length = %d, ", u, iexps.length);
10625 //printf("e = (%s %s, %s), ", Token.toChars[e.op], e.toChars(), e.type.toChars());
10626 //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
10628 if (!arg ||
!e
.type
.implicitConvTo(arg
.type
))
10630 // expand initializer to tuple
10631 if (expandAliasThisTuples(iexps
, u
) != -1)
10633 if (iexps
.length
<= u
)
10640 e2x
= new TupleExp(e2x
.loc
, e0
, iexps
);
10641 e2x
= e2x
.expressionSemantic(sc
);
10642 if (e2x
.op
== EXP
.error
)
10647 // Do not need to overwrite this.e2
10653 /* Inside constructor, if this is the first assignment of object field,
10654 * rewrite this to initializing the field.
10656 if (exp
.op
== EXP
.assign
10657 && exp
.e1
.checkModifiable(sc
) == Modifiable
.initialization
)
10659 //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars());
10661 exp
= new ConstructExp(exp
.loc
, exp
.e1
, exp
.e2
);
10664 // https://issues.dlang.org/show_bug.cgi?id=13515
10665 // set Index::modifiable flag for complex AA element initialization
10666 if (auto ie1
= exp
.e1
.isIndexExp())
10668 Expression e1x
= ie1
.markSettingAAElem();
10669 if (e1x
.op
== EXP
.error
)
10676 else if (exp
.op
== EXP
.construct
&& exp
.e1
.op
== EXP
.variable
&&
10677 (cast(VarExp
)exp
.e1
).var
.storage_class
& (STC
.out_ | STC
.ref_
))
10679 exp
.memset
= MemorySet
.referenceInit
;
10682 if (exp
.op
== EXP
.assign
) // skip EXP.blit and EXP.construct, which are initializations
10684 exp
.e1
.checkSharedAccess(sc
);
10685 checkUnsafeAccess(sc
, exp
.e1
, false, true);
10688 checkUnsafeAccess(sc
, exp
.e2
, true, true); // Initializer must always be checked
10690 /* If it is an assignment from a 'foreign' type,
10691 * check for operator overloading.
10693 if (exp
.memset
== MemorySet
.referenceInit
)
10695 // If this is an initialization of a reference,
10698 else if (t1
.ty
== Tstruct
)
10702 auto sd
= (cast(TypeStruct
)t1
).sym
;
10704 if (exp
.op
== EXP
.construct
)
10706 Type t2
= e2x
.type
.toBasetype();
10707 if (t2
.ty
== Tstruct
&& sd
== (cast(TypeStruct
)t2
).sym
)
10710 if (sd
.sizeok
!= Sizeok
.done
)
10713 sd
.ctor
= sd
.searchCtor();
10715 // https://issues.dlang.org/show_bug.cgi?id=15661
10716 // Look for the form from last of comma chain.
10717 auto e2y
= lastComma(e2x
);
10719 CallExp ce
= (e2y
.op
== EXP
.call) ?
cast(CallExp
)e2y
: null;
10720 DotVarExp dve
= (ce
&& ce
.e1
.op
== EXP
.dotVariable
)
10721 ?
cast(DotVarExp
)ce
.e1
: null;
10722 if (sd
.ctor
&& ce
&& dve
&& dve
.var
.isCtorDeclaration() &&
10723 // https://issues.dlang.org/show_bug.cgi?id=19389
10724 dve
.e1
.op
!= EXP
.dotVariable
&&
10725 e2y
.type
.implicitConvTo(t1
))
10727 /* Look for form of constructor call which is:
10728 * __ctmp.ctor(arguments...)
10731 /* Before calling the constructor, initialize
10732 * variable with a bit copy of the default
10735 Expression einit
= getInitExp(sd
, exp
.loc
, sc
, t1
);
10736 if (einit
.op
== EXP
.error
)
10742 auto ae
= new BlitExp(exp
.loc
, exp
.e1
, einit
);
10743 ae
.type
= e1x
.type
;
10745 /* Replace __ctmp being constructed with e1.
10746 * We need to copy constructor call expression,
10747 * because it may be used in other place.
10749 auto dvx
= cast(DotVarExp
)dve
.copy();
10751 auto cx
= cast(CallExp
)ce
.copy();
10753 if (checkConstructorEscape(sc
, cx
, false))
10757 Expression
.extractLast(e2x
, e0
);
10759 auto e
= Expression
.combine(e0
, ae
, cx
);
10760 e
= e
.expressionSemantic(sc
);
10764 // https://issues.dlang.org/show_bug.cgi?id=21586
10765 // Rewrite CondExp or e1 will miss direct construction, e.g.
10766 // e1 = a ? S(1) : ...; -> AST: e1 = a ? (S(0)).this(1) : ...;
10767 // a temporary created and an extra destructor call.
10768 // AST will be rewritten to:
10769 // a ? e1 = 0, e1.this(1) : ...; -> blitting plus construction
10770 if (e2x
.op
== EXP
.question
)
10773 * a ? e1 = b : e1 = c;
10775 CondExp econd
= cast(CondExp
)e2x
;
10776 Expression ea1
= new ConstructExp(econd
.e1
.loc
, e1x
, econd
.e1
);
10777 Expression ea2
= new ConstructExp(econd
.e2
.loc
, e1x
, econd
.e2
);
10778 Expression e
= new CondExp(exp
.loc
, econd
.econd
, ea1
, ea2
);
10779 result
= e
.expressionSemantic(sc
);
10782 if (sd
.postblit || sd
.hasCopyCtor
)
10784 /* We have a copy constructor for this
10787 if (e2x
.isLvalue())
10789 if (sd
.hasCopyCtor
)
10792 * e1 = init, e1.copyCtor(e2);
10794 Expression einit
= new BlitExp(exp
.loc
, exp
.e1
, getInitExp(sd
, exp
.loc
, sc
, t1
));
10795 einit
.type
= e1x
.type
;
10798 e
= new DotIdExp(exp
.loc
, e1x
, Id
.ctor
);
10799 e
= new CallExp(exp
.loc
, e
, e2x
);
10800 e
= new CommaExp(exp
.loc
, einit
, e
);
10802 //printf("e: %s\n", e.toChars());
10804 result
= e
.expressionSemantic(sc
);
10809 if (!e2x
.type
.implicitConvTo(e1x
.type
))
10811 error(exp
.loc
, "conversion error from `%s` to `%s`",
10812 e2x
.type
.toChars(), e1x
.type
.toChars());
10817 * (e1 = e2).postblit();
10819 * Blit assignment e1 = e2 returns a reference to the original e1,
10820 * then call the postblit on it.
10822 Expression e
= e1x
.copy();
10823 e
.type
= e
.type
.mutableOf();
10824 if (e
.type
.isShared
&& !sd
.type
.isShared
)
10825 e
.type
= e
.type
.unSharedOf();
10826 e
= new BlitExp(exp
.loc
, e
, e2x
);
10827 e
= new DotVarExp(exp
.loc
, e
, sd
.postblit
, false);
10828 e
= new CallExp(exp
.loc
, e
);
10829 result
= e
.expressionSemantic(sc
);
10835 /* The struct value returned from the function is transferred
10836 * so should not call the destructor on it.
10838 e2x
= valueNoDtor(e2x
);
10842 // https://issues.dlang.org/show_bug.cgi?id=19251
10843 // if e2 cannot be converted to e1.type, maybe there is an alias this
10844 if (!e2x
.implicitConvTo(t1
))
10846 AggregateDeclaration ad2
= isAggregate(e2x
.type
);
10847 if (ad2
&& ad2
.aliasthis
&& !isRecursiveAliasThis(exp
.att2
, exp
.e2
.type
))
10849 /* Rewrite (e1 op e2) as:
10850 * (e1 op e2.aliasthis)
10852 exp
.e2
= new DotIdExp(exp
.e2
.loc
, exp
.e2
, ad2
.aliasthis
.ident
);
10853 result
= exp
.expressionSemantic(sc
);
10858 else if (!e2x
.implicitConvTo(t1
))
10861 if (sd
.sizeok
!= Sizeok
.done
)
10864 sd
.ctor
= sd
.searchCtor();
10868 /* Look for implicit constructor call
10870 * e1 = init, e1.ctor(e2)
10873 /* Fix Issue 5153 : https://issues.dlang.org/show_bug.cgi?id=5153
10874 * Using `new` to initialize a struct object is a common mistake, but
10875 * the error message from the compiler is not very helpful in that
10876 * case. If exp.e2 is a NewExp and the type of new is the same as
10877 * the type as exp.e1 (struct in this case), then we know for sure
10878 * that the user wants to instantiate a struct. This is done to avoid
10879 * issuing an error when the user actually wants to call a constructor
10880 * which receives a class object.
10882 * Foo f = new Foo2(0); is a valid expression if Foo has a constructor
10883 * which receives an instance of a Foo2 class
10885 if (exp
.e2
.op
== EXP
.new_
)
10887 auto newExp
= cast(NewExp
)(exp
.e2
);
10888 if (newExp
.newtype
&& newExp
.newtype
== t1
)
10890 error(exp
.loc
, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
10891 newExp
.toChars(), newExp
.type
.toChars(), t1
.toChars());
10892 errorSupplemental(exp
.loc
, "Perhaps remove the `new` keyword?");
10897 Expression einit
= new BlitExp(exp
.loc
, e1x
, getInitExp(sd
, exp
.loc
, sc
, t1
));
10898 einit
.type
= e1x
.type
;
10901 e
= new DotIdExp(exp
.loc
, e1x
, Id
.ctor
);
10902 e
= new CallExp(exp
.loc
, e
, e2x
);
10903 e
= new CommaExp(exp
.loc
, einit
, e
);
10904 e
= e
.expressionSemantic(sc
);
10908 if (search_function(sd
, Id
.call))
10910 /* Look for static opCall
10911 * https://issues.dlang.org/show_bug.cgi?id=2702
10913 * e1 = typeof(e1).opCall(arguments)
10915 e2x
= typeDotIdExp(e2x
.loc
, e1x
.type
, Id
.call);
10916 e2x
= new CallExp(exp
.loc
, e2x
, exp
.e2
);
10918 e2x
= e2x
.expressionSemantic(sc
);
10919 e2x
= resolveProperties(sc
, e2x
);
10920 if (e2x
.op
== EXP
.error
)
10925 if (e2x
.checkValue() || e2x
.checkSharedAccess(sc
))
10929 else // https://issues.dlang.org/show_bug.cgi?id=11355
10931 AggregateDeclaration ad2
= isAggregate(e2x
.type
);
10932 if (ad2
&& ad2
.aliasthis
&& !isRecursiveAliasThis(exp
.att2
, exp
.e2
.type
))
10934 /* Rewrite (e1 op e2) as:
10935 * (e1 op e2.aliasthis)
10937 exp
.e2
= new DotIdExp(exp
.e2
.loc
, exp
.e2
, ad2
.aliasthis
.ident
);
10938 result
= exp
.expressionSemantic(sc
);
10943 else if (exp
.op
== EXP
.assign
)
10945 if (e1x
.op
== EXP
.index
&& (cast(IndexExp
)e1x
).e1
.type
.toBasetype().ty
== Taarray
)
10951 * ref __aatmp = aa;
10952 * ref __aakey = key;
10953 * ref __aaval = e2;
10954 * (__aakey in __aatmp
10955 * ? __aatmp[__aakey].opAssign(__aaval)
10956 * : ConstructExp(__aatmp[__aakey], __aaval));
10958 // ensure we keep the expr modifiable
10959 Expression esetting
= (cast(IndexExp
)e1x
).markSettingAAElem();
10960 if (esetting
.op
== EXP
.error
)
10965 assert(esetting
.op
== EXP
.index
);
10966 IndexExp ie
= cast(IndexExp
) esetting
;
10967 Type t2
= e2x
.type
.toBasetype();
10969 Expression e0
= null;
10970 Expression ea
= extractSideEffect(sc
, "__aatmp", e0
, ie
.e1
);
10971 Expression ek
= extractSideEffect(sc
, "__aakey", e0
, ie
.e2
);
10972 Expression ev
= extractSideEffect(sc
, "__aaval", e0
, e2x
);
10974 AssignExp ae
= cast(AssignExp
)exp
.copy();
10975 ae
.e1
= new IndexExp(exp
.loc
, ea
, ek
);
10976 ae
.e1
= ae
.e1
.expressionSemantic(sc
);
10977 ae
.e1
= ae
.e1
.optimize(WANTvalue
);
10979 Expression e
= ae
.op_overload(sc
);
10982 Expression ey
= null;
10983 if (t2
.ty
== Tstruct
&& sd
== t2
.toDsymbol(sc
))
10987 else if (!ev
.implicitConvTo(ie
.type
) && sd
.ctor
)
10989 // Look for implicit constructor call
10990 // Rewrite as S().ctor(e2)
10991 ey
= new StructLiteralExp(exp
.loc
, sd
, null);
10992 ey
= new DotIdExp(exp
.loc
, ey
, Id
.ctor
);
10993 ey
= new CallExp(exp
.loc
, ey
, ev
);
10994 ey
= ey
.trySemantic(sc
);
10999 ex
= new IndexExp(exp
.loc
, ea
, ek
);
11000 ex
= ex
.expressionSemantic(sc
);
11001 ex
= ex
.modifiableLvalue(sc
); // allocate new slot
11002 ex
= ex
.optimize(WANTvalue
);
11004 ey
= new ConstructExp(exp
.loc
, ex
, ey
);
11005 ey
= ey
.expressionSemantic(sc
);
11006 if (ey
.op
== EXP
.error
)
11013 // https://issues.dlang.org/show_bug.cgi?id=14144
11014 // The whole expression should have the common type
11015 // of opAssign() return and assigned AA entry.
11016 // Even if there's no common type, expression should be typed as void.
11017 if (!typeMerge(sc
, EXP
.question
, ex
, ey
))
11019 ex
= new CastExp(ex
.loc
, ex
, Type
.tvoid
);
11020 ey
= new CastExp(ey
.loc
, ey
, Type
.tvoid
);
11022 e
= new CondExp(exp
.loc
, new InExp(exp
.loc
, ek
, ea
), ex
, ey
);
11024 e
= Expression
.combine(e0
, e
);
11025 e
= e
.expressionSemantic(sc
);
11032 Expression e
= exp
.op_overload(sc
);
11041 assert(exp
.op
== EXP
.blit
);
11043 if (e2x
.checkValue())
11049 else if (t1
.ty
== Tclass
)
11051 // Disallow assignment operator overloads for same type
11052 if (exp
.op
== EXP
.assign
&& !exp
.e2
.implicitConvTo(exp
.e1
.type
))
11054 Expression e
= exp
.op_overload(sc
);
11061 if (exp
.e2
.checkValue())
11064 else if (t1
.ty
== Tsarray
)
11066 // SliceExp cannot have static array type without context inference.
11067 assert(exp
.e1
.op
!= EXP
.slice
);
11068 Expression e1x
= exp
.e1
;
11069 Expression e2x
= exp
.e2
;
11071 /* C strings come through as static arrays. May need to adjust the size of the
11072 * string to match the size of e1.
11074 Type t2
= e2x
.type
.toBasetype();
11075 if (sc
.flags
& SCOPE
.Cfile
&& e2x
.isStringExp() && t2
.isTypeSArray())
11077 uinteger_t dim1
= t1
.isTypeSArray().dim
.toInteger();
11078 uinteger_t dim2
= t2
.isTypeSArray().dim
.toInteger();
11079 if (dim1
+ 1 == dim2 || dim2
< dim1
)
11081 auto tsa2
= t2
.isTypeSArray();
11082 auto newt
= tsa2
.next
.sarrayOf(dim1
).immutableOf();
11083 e2x
= castTo(e2x
, sc
, newt
);
11088 if (e2x
.implicitConvTo(e1x
.type
))
11090 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()))
11092 if (t1
.checkPostblit(e1x
.loc
, sc
))
11096 // e2 matches to t1 because of the implicit length match, so
11097 if (isUnaArrayOp(e2x
.op
) ||
isBinArrayOp(e2x
.op
))
11099 // convert e1 to e1[]
11100 // e.g. e1[] = a[] + b[];
11101 auto sle
= new SliceExp(e1x
.loc
, e1x
, null, null);
11102 sle
.arrayop
= true;
11103 e1x
= sle
.expressionSemantic(sc
);
11107 // convert e2 to t1 later
11108 // e.g. e1 = [1, 2, 3];
11113 if (e2x
.implicitConvTo(t1
.nextOf().arrayOf()) > MATCH
.nomatch
)
11115 uinteger_t dim1
= (cast(TypeSArray
)t1
).dim
.toInteger();
11116 uinteger_t dim2
= dim1
;
11117 if (auto ale
= e2x
.isArrayLiteralExp())
11119 dim2
= ale
.elements ? ale
.elements
.length
: 0;
11121 else if (auto se
= e2x
.isSliceExp())
11123 Type tx
= toStaticArrayType(se
);
11125 dim2
= (cast(TypeSArray
)tx
).dim
.toInteger();
11129 error(exp
.loc
, "mismatched array lengths, %d and %d", cast(int)dim1
, cast(int)dim2
);
11134 // May be block or element-wise assignment, so
11135 // convert e1 to e1[]
11136 if (exp
.op
!= EXP
.assign
)
11138 // If multidimensional static array, treat as one large array
11140 // Find the appropriate array type depending on the assignment, e.g.
11141 // int[3] = int => int[3]
11142 // int[3][2] = int => int[6]
11143 // int[3][2] = int[] => int[3][2]
11144 // int[3][2][4] + int => int[24]
11145 // int[3][2][4] + int[] => int[3][8]
11146 ulong dim
= t1
.isTypeSArray().dim
.toUInteger();
11147 auto type
= t1
.nextOf();
11149 for (TypeSArray tsa
; (tsa
= type
.isTypeSArray()) !is null; )
11151 import core
.checkedint
: mulu
;
11153 // Accumulate skipped dimensions
11154 bool overflow
= false;
11155 dim
= mulu(dim
, tsa
.dim
.toUInteger(), overflow
);
11156 if (overflow || dim
>= uint.max
)
11158 // dym exceeds maximum array size
11159 error(exp
.loc
, "static array `%s` size overflowed to %llu",
11160 e1x
.type
.toChars(), cast(ulong) dim
);
11164 // Move to the element type
11165 type
= tsa
.nextOf().toBasetype();
11167 // Rewrite ex1 as a static array if a matching type was found
11168 if (e2x
.implicitConvTo(type
) > MATCH
.nomatch
)
11170 e1x
.type
= type
.sarrayOf(dim
);
11175 auto sle
= new SliceExp(e1x
.loc
, e1x
, null, null);
11176 sle
.arrayop
= true;
11177 e1x
= sle
.expressionSemantic(sc
);
11179 if (e1x
.op
== EXP
.error
)
11180 return setResult(e1x
);
11181 if (e2x
.op
== EXP
.error
)
11182 return setResult(e2x
);
11186 t1
= e1x
.type
.toBasetype();
11188 /* Check the mutability of e1.
11190 if (auto ale
= exp
.e1
.isArrayLengthExp())
11192 // e1 is not an lvalue, but we let code generator handle it
11194 auto ale1x
= ale
.e1
.modifiableLvalueImpl(sc
, exp
.e1
);
11195 if (ale1x
.op
== EXP
.error
)
11196 return setResult(ale1x
);
11199 Type tn
= ale
.e1
.type
.toBasetype().nextOf();
11200 checkDefCtor(ale
.loc
, tn
);
11202 Identifier hook
= global
.params
.tracegc ? Id
._d_arraysetlengthTTrace
: Id
._d_arraysetlengthT
;
11203 if (!verifyHookExist(exp
.loc
, *sc
, Id
._d_arraysetlengthTImpl
, "resizing arrays"))
11206 exp
.e2
= exp
.e2
.expressionSemantic(sc
);
11207 auto lc
= lastComma(exp
.e2
);
11208 lc
= lc
.optimize(WANTvalue
);
11209 // use slice expression when arr.length = 0 to avoid runtime call
11210 if(lc
.op
== EXP
.int64
&& lc
.toInteger() == 0)
11212 Expression se
= new SliceExp(ale
.loc
, ale
.e1
, lc
, lc
);
11213 Expression as
= new AssignExp(ale
.loc
, ale
.e1
, se
);
11214 as
= as
.expressionSemantic(sc
);
11215 auto res
= Expression
.combine(as
, exp
.e2
);
11216 res
.type
= ale
.type
;
11217 return setResult(res
);
11220 if (!sc
.needsCodegen()) // if compile time creature only
11222 exp
.type
= Type
.tsize_t
;
11223 return setResult(exp
);
11226 // Lower to object._d_arraysetlengthTImpl!(typeof(e1))._d_arraysetlengthT{,Trace}(e1, e2)
11227 Expression id
= new IdentifierExp(ale
.loc
, Id
.empty
);
11228 id
= new DotIdExp(ale
.loc
, id
, Id
.object
);
11229 auto tiargs
= new Objects();
11230 tiargs
.push(ale
.e1
.type
);
11231 id
= new DotTemplateInstanceExp(ale
.loc
, id
, Id
._d_arraysetlengthTImpl
, tiargs
);
11232 id
= new DotIdExp(ale
.loc
, id
, hook
);
11233 id
= id
.expressionSemantic(sc
);
11235 auto arguments
= new Expressions();
11236 arguments
.reserve(5);
11237 if (global
.params
.tracegc
)
11239 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ? sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
11240 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
11241 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
11242 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
11244 arguments
.push(ale
.e1
);
11245 arguments
.push(exp
.e2
);
11247 Expression ce
= new CallExp(ale
.loc
, id
, arguments
).expressionSemantic(sc
);
11248 auto res
= new LoweredAssignExp(exp
, ce
);
11249 // if (global.params.verbose)
11250 // message("lowered %s =>\n %s", exp.toChars(), res.toChars());
11251 res
.type
= Type
.tsize_t
;
11252 return setResult(res
);
11254 else if (auto se
= exp
.e1
.isSliceExp())
11256 Type tn
= se
.type
.nextOf();
11257 const fun
= sc
.func
;
11258 if (exp
.op
== EXP
.assign
&& !tn
.isMutable() &&
11259 // allow modifiation in module ctor, see
11260 // https://issues.dlang.org/show_bug.cgi?id=9884
11261 (!fun ||
(fun
&& !fun
.isStaticCtorDeclaration())))
11263 error(exp
.loc
, "slice `%s` is not mutable", se
.toChars());
11267 if (exp
.op
== EXP
.assign
&& !tn
.baseElemOf().isAssignable())
11269 error(exp
.loc
, "slice `%s` is not mutable, struct `%s` has immutable members",
11270 exp
.e1
.toChars(), tn
.baseElemOf().toChars());
11271 result
= ErrorExp
.get();
11275 // For conditional operator, both branches need conversion.
11276 while (se
.e1
.op
== EXP
.slice
)
11277 se
= cast(SliceExp
)se
.e1
;
11278 if (se
.e1
.op
== EXP
.question
&& se
.e1
.type
.toBasetype().ty
== Tsarray
)
11280 se
.e1
= se
.e1
.modifiableLvalueImpl(sc
, exp
.e1
);
11281 if (se
.e1
.op
== EXP
.error
)
11282 return setResult(se
.e1
);
11287 if (t1
.ty
== Tsarray
&& exp
.op
== EXP
.assign
)
11289 Type tn
= exp
.e1
.type
.nextOf();
11290 if (tn
&& !tn
.baseElemOf().isAssignable())
11292 error(exp
.loc
, "array `%s` is not mutable, struct `%s` has immutable members",
11293 exp
.e1
.toChars(), tn
.baseElemOf().toChars());
11294 result
= ErrorExp
.get();
11299 Expression e1x
= exp
.e1
;
11301 // Try to do a decent error message with the expression
11302 // before it gets constant folded
11303 if (exp
.op
== EXP
.assign
)
11304 e1x
= e1x
.modifiableLvalueImpl(sc
, e1old
);
11306 e1x
= e1x
.optimize(WANTvalue
, /*keepLvalue*/ true);
11308 if (e1x
.op
== EXP
.error
)
11316 /* Tweak e2 based on the type of e1.
11318 Expression e2x
= exp
.e2
;
11319 Type t2
= e2x
.type
.toBasetype();
11321 // If it is a array, get the element type. Note that it may be
11322 // multi-dimensional.
11324 while (telem
.ty
== Tarray
)
11325 telem
= telem
.nextOf();
11327 if (exp
.e1
.op
== EXP
.slice
&& t1
.nextOf() &&
11328 (telem
.ty
!= Tvoid || e2x
.op
== EXP
.null_
) &&
11329 e2x
.implicitConvTo(t1
.nextOf()))
11331 // Check for block assignment. If it is of type void[], void[][], etc,
11332 // '= null' is the only allowable block assignment (Bug 7493)
11333 exp
.memset
= MemorySet
.blockAssign
; // make it easy for back end to tell what this is
11334 e2x
= e2x
.implicitCastTo(sc
, t1
.nextOf());
11335 if (exp
.op
!= EXP
.blit
&& e2x
.isLvalue() && t1
.nextOf
.checkPostblit(exp
.e1
.loc
, sc
))
11338 else if (exp
.e1
.op
== EXP
.slice
&&
11339 (t2
.ty
== Tarray || t2
.ty
== Tsarray
) &&
11340 t2
.nextOf().implicitConvTo(t1
.nextOf()))
11342 // Check element-wise assignment.
11344 /* If assigned elements number is known at compile time,
11345 * check the mismatch.
11347 SliceExp se1
= cast(SliceExp
)exp
.e1
;
11348 TypeSArray tsa1
= cast(TypeSArray
)toStaticArrayType(se1
);
11349 TypeSArray tsa2
= null;
11350 if (auto ale
= e2x
.isArrayLiteralExp())
11351 tsa2
= cast(TypeSArray
)t2
.nextOf().sarrayOf(ale
.elements
.length
);
11352 else if (auto se
= e2x
.isSliceExp())
11353 tsa2
= cast(TypeSArray
)toStaticArrayType(se
);
11355 tsa2
= t2
.isTypeSArray();
11359 uinteger_t dim1
= tsa1
.dim
.toInteger();
11360 uinteger_t dim2
= tsa2
.dim
.toInteger();
11363 error(exp
.loc
, "mismatched array lengths %d and %d for assignment `%s`", cast(int)dim1
, cast(int)dim2
, exp
.toChars());
11368 if (exp
.op
!= EXP
.blit
&&
11369 (e2x
.op
== EXP
.slice
&& (cast(UnaExp
)e2x
).e1
.isLvalue() ||
11370 e2x
.op
== EXP
.cast_
&& (cast(UnaExp
)e2x
).e1
.isLvalue() ||
11371 e2x
.op
!= EXP
.slice
&& e2x
.isLvalue()))
11373 if (t1
.nextOf().checkPostblit(exp
.e1
.loc
, sc
))
11377 Type t2n
= t2
.nextOf();
11378 Type t1n
= t1
.nextOf();
11380 if (t2n
.equivalent(t1n
) ||
11381 t1n
.isBaseOf(t2n
, &offset
) && offset
== 0)
11383 /* Allow copy of distinct qualifier elements.
11385 * char[] dst; const(char)[] src;
11388 * class C {} class D : C {}
11392 if (isArrayOpValid(e2x
))
11394 // Don't add CastExp to keep AST for array operations
11396 e2x
.type
= exp
.e1
.type
.constOf();
11399 e2x
= e2x
.castTo(sc
, exp
.e1
.type
.constOf());
11403 /* https://issues.dlang.org/show_bug.cgi?id=15778
11404 * A string literal has an array type of immutable
11405 * elements by default, and normally it cannot be convertible to
11406 * array type of mutable elements. But for element-wise assignment,
11407 * elements need to be const at best. So we should give a chance
11408 * to change code unit size for polysemous string literal.
11410 if (e2x
.op
== EXP
.string_
)
11411 e2x
= e2x
.implicitCastTo(sc
, exp
.e1
.type
.constOf());
11413 e2x
= e2x
.implicitCastTo(sc
, exp
.e1
.type
);
11415 if (t1n
.toBasetype
.ty
== Tvoid
&& t2n
.toBasetype
.ty
== Tvoid
)
11417 if (sc
.setUnsafe(false, exp
.loc
, "cannot copy `void[]` to `void[]` in `@safe` code"))
11423 if (exp
.op
== EXP
.blit
)
11424 e2x
= e2x
.castTo(sc
, exp
.e1
.type
);
11427 e2x
= e2x
.implicitCastTo(sc
, exp
.e1
.type
);
11429 // Fix Issue 13435: https://issues.dlang.org/show_bug.cgi?id=13435
11431 // If the implicit cast has failed and the assign expression is
11432 // the initialization of a struct member field
11433 if (e2x
.op
== EXP
.error
&& exp
.op
== EXP
.construct
&& t1
.ty
== Tstruct
)
11435 scope sd
= (cast(TypeStruct
)t1
).sym
;
11436 Dsymbol opAssign
= search_function(sd
, Id
.assign
);
11438 // and the struct defines an opAssign
11441 // offer more information about the cause of the problem
11442 errorSupplemental(exp
.loc
,
11443 "`%s` is the first assignment of `%s` therefore it represents its initialization",
11444 exp
.toChars(), exp
.e1
.toChars());
11445 errorSupplemental(exp
.loc
,
11446 "`opAssign` methods are not used for initialization, but for subsequent assignments");
11451 if (e2x
.op
== EXP
.error
)
11457 t2
= exp
.e2
.type
.toBasetype();
11459 /* Look for array operations
11461 if ((t2
.ty
== Tarray || t2
.ty
== Tsarray
) && isArrayOpValid(exp
.e2
))
11463 // Look for valid array operations
11464 if (exp
.memset
!= MemorySet
.blockAssign
&&
11465 exp
.e1
.op
== EXP
.slice
&&
11466 (isUnaArrayOp(exp
.e2
.op
) ||
isBinArrayOp(exp
.e2
.op
)))
11468 exp
.type
= exp
.e1
.type
;
11469 if (exp
.op
== EXP
.construct
) // https://issues.dlang.org/show_bug.cgi?id=10282
11470 // tweak mutability of e1 element
11471 exp
.e1
.type
= exp
.e1
.type
.nextOf().mutableOf().arrayOf();
11472 result
= arrayOp(exp
, sc
);
11476 // Drop invalid array operations in e2
11477 // d = a[] + b[], d = (a[] + b[])[0..2], etc
11478 if (checkNonAssignmentArrayOp(exp
.e2
, exp
.memset
!= MemorySet
.blockAssign
&& exp
.op
== EXP
.assign
))
11481 // Remains valid array assignments
11482 // d = d[], d = [1,2,3], etc
11485 /* Don't allow assignment to classes that were allocated on the stack with:
11486 * scope Class c = new Class();
11488 if (exp
.e1
.op
== EXP
.variable
&& exp
.op
== EXP
.assign
)
11490 VarExp ve
= cast(VarExp
)exp
.e1
;
11491 VarDeclaration vd
= ve
.var
.isVarDeclaration();
11492 if (vd
&& vd
.onstack
)
11494 assert(t1
.ty
== Tclass
);
11495 error(exp
.loc
, "cannot rebind scope variables");
11499 if (exp
.e1
.op
== EXP
.variable
&& (cast(VarExp
)exp
.e1
).var
.ident
== Id
.ctfe
)
11501 error(exp
.loc
, "cannot modify compiler-generated variable `__ctfe`");
11504 exp
.type
= exp
.e1
.type
;
11506 auto assignElem
= exp
.e2
;
11507 auto res
= exp
.op
== EXP
.assign ? exp
.reorderSettingAAElem(sc
) : exp
;
11508 /* https://issues.dlang.org/show_bug.cgi?id=22366
11510 * `reorderSettingAAElem` creates a tree of comma expressions, however,
11511 * `checkAssignExp` expects only AssignExps.
11513 if (res
== exp
) // no `AA[k] = v` rewrite was performed
11514 checkAssignEscape(sc
, res
, false, false);
11516 checkNewEscape(sc
, assignElem
, false); // assigning to AA puts it on heap
11518 if (auto ae
= res
.isConstructExp())
11520 Type t1b
= ae
.e1
.type
.toBasetype();
11521 if (t1b
.ty
!= Tsarray
&& t1b
.ty
!= Tarray
)
11522 return setResult(res
);
11524 // only non-trivial array constructions may need to be lowered (non-POD elements basically)
11525 Type t1e
= t1b
.nextOf();
11526 TypeStruct ts
= t1e
.baseElemOf().isTypeStruct();
11527 if (!ts ||
(!ts
.sym
.postblit
&& !ts
.sym
.hasCopyCtor
&& !ts
.sym
.dtor
))
11528 return setResult(res
);
11530 // don't lower ref-constructions etc.
11531 if (!(t1b
.ty
== Tsarray || ae
.e1
.isSliceExp
) ||
11532 (ae
.e1
.isVarExp
&& ae
.e1
.isVarExp
.var
.isVarDeclaration
.isReference
))
11533 return setResult(res
);
11535 // Construction from an equivalent other array?
11536 // Only lower with lvalue RHS elements; let the glue layer move rvalue elements.
11537 Type t2b
= ae
.e2
.type
.toBasetype();
11538 // skip over a (possibly implicit) cast of a static array RHS to a slice
11539 Expression rhs
= ae
.e2
;
11540 Type rhsType
= t2b
;
11541 if (t2b
.ty
== Tarray
)
11543 if (auto ce
= rhs
.isCastExp())
11545 auto ct
= ce
.e1
.type
.toBasetype();
11546 if (ct
.ty
== Tsarray
)
11554 if (!sc
.needsCodegen()) // interpreter can handle these
11555 return setResult(res
);
11557 const lowerToArrayCtor
=
11558 ( (rhsType
.ty
== Tarray
&& !rhs
.isArrayLiteralExp
) ||
11559 (rhsType
.ty
== Tsarray
&& rhs
.isLvalue
) ) &&
11560 t1e
.equivalent(t2b
.nextOf
);
11562 // Construction from a single element?
11563 // If the RHS is an rvalue, then we'll need to make a temporary for it (copied multiple times).
11564 const lowerToArraySetCtor
= !lowerToArrayCtor
&& t1e
.equivalent(t2b
);
11566 if (lowerToArrayCtor || lowerToArraySetCtor
)
11568 auto func
= lowerToArrayCtor ? Id
._d_arrayctor
: Id
._d_arraysetctor
;
11569 const other
= lowerToArrayCtor ?
"other array" : "value";
11570 if (!verifyHookExist(exp
.loc
, *sc
, func
, "construct array with " ~ other
, Id
.object
))
11573 // Lower to object._d_array{,set}ctor(e1, e2)
11574 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
11575 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
11576 id
= new DotIdExp(exp
.loc
, id
, func
);
11578 auto arguments
= new Expressions();
11579 arguments
.push(new CastExp(ae
.loc
, ae
.e1
, t1e
.arrayOf
).expressionSemantic(sc
));
11580 if (lowerToArrayCtor
)
11582 arguments
.push(new CastExp(ae
.loc
, rhs
, t2b
.nextOf
.arrayOf
).expressionSemantic(sc
));
11583 Expression ce
= new CallExp(exp
.loc
, id
, arguments
);
11584 res
= ce
.expressionSemantic(sc
);
11589 // promote an rvalue RHS element to a temporary, it's passed by ref to _d_arraysetctor
11590 if (!ae
.e2
.isLvalue
)
11592 auto vd
= copyToTemp(STC
.scope_
, "__setctor", ae
.e2
);
11593 e0
= new DeclarationExp(vd
.loc
, vd
).expressionSemantic(sc
);
11594 arguments
.push(new VarExp(vd
.loc
, vd
).expressionSemantic(sc
));
11597 arguments
.push(ae
.e2
);
11599 Expression ce
= new CallExp(exp
.loc
, id
, arguments
);
11600 res
= Expression
.combine(e0
, ce
).expressionSemantic(sc
);
11603 if (global
.params
.v
.verbose
)
11604 message("lowered %s =>\n %s", exp
.toChars(), res
.toChars());
11607 else if (auto ae
= res
.isAssignExp())
11608 res
= lowerArrayAssign(ae
);
11609 else if (auto ce
= res
.isCommaExp())
11611 if (auto ae1
= ce
.e1
.isAssignExp())
11612 ce
.e1
= lowerArrayAssign(ae1
, true);
11613 if (auto ae2
= ce
.e2
.isAssignExp())
11614 ce
.e2
= lowerArrayAssign(ae2
, true);
11617 return setResult(res
);
11620 /***************************************
11621 * Lower AssignExp to `_d_array{setassign,assign_l,assign_r}` if needed.
11624 * ae = the AssignExp to be lowered
11625 * fromCommaExp = indicates whether `ae` is part of a CommaExp or not,
11626 * so no unnecessary temporay variable is created.
11628 * a CommaExp contiaining call a to `_d_array{setassign,assign_l,assign_r}`
11629 * if needed or `ae` otherwise
11631 private Expression
lowerArrayAssign(AssignExp ae
, bool fromCommaExp
= false)
11633 Type t1b
= ae
.e1
.type
.toBasetype();
11634 if (t1b
.ty
!= Tsarray
&& t1b
.ty
!= Tarray
)
11637 const isArrayAssign
= (ae
.e1
.isSliceExp() || ae
.e1
.type
.ty
== Tsarray
) &&
11638 (ae
.e2
.type
.ty
== Tsarray || ae
.e2
.type
.ty
== Tarray
) &&
11639 (ae
.e1
.type
.nextOf() && ae
.e2
.type
.nextOf() && ae
.e1
.type
.nextOf
.mutableOf
.equals(ae
.e2
.type
.nextOf
.mutableOf()));
11641 const isArraySetAssign
= (ae
.e1
.isSliceExp() || ae
.e1
.type
.ty
== Tsarray
) &&
11642 (ae
.e1
.type
.nextOf() && ae
.e2
.type
.implicitConvTo(ae
.e1
.type
.nextOf()));
11644 if (!isArrayAssign
&& !isArraySetAssign
)
11647 const ts
= t1b
.nextOf().baseElemOf().isTypeStruct();
11648 if (!ts ||
(!ts
.sym
.postblit
&& !ts
.sym
.dtor
))
11652 Identifier func
= isArraySetAssign ? Id
._d_arraysetassign
:
11653 ae
.e2
.isLvalue() || ae
.e2
.isSliceExp() ? Id
._d_arrayassign_l
: Id
._d_arrayassign_r
;
11655 // Lower to `.object._d_array{setassign,assign_l,assign_r}(e1, e2)``
11656 Expression id
= new IdentifierExp(ae
.loc
, Id
.empty
);
11657 id
= new DotIdExp(ae
.loc
, id
, Id
.object
);
11658 id
= new DotIdExp(ae
.loc
, id
, func
);
11660 auto arguments
= new Expressions();
11661 arguments
.push(new CastExp(ae
.loc
, ae
.e1
, ae
.e1
.type
.nextOf
.arrayOf
)
11662 .expressionSemantic(sc
));
11664 Expression eValue2
, value2
= ae
.e2
;
11665 if (isArrayAssign
&& value2
.isLvalue())
11666 value2
= new CastExp(ae
.loc
, ae
.e2
, ae
.e2
.type
.nextOf
.arrayOf())
11667 .expressionSemantic(sc
);
11668 else if (!fromCommaExp
&&
11669 (isArrayAssign ||
(isArraySetAssign
&& !value2
.isLvalue())))
11671 // Rvalues from CommaExps were introduced in `visit(AssignExp)`
11672 // and are temporary variables themselves. Rvalues from trivial
11673 // SliceExps are simply passed by reference without any copying.
11675 // `__assigntmp` will be destroyed together with the array `ae.e1`.
11676 // When `ae.e2` is a variadic arg array, it is also `scope`, so
11677 // `__assigntmp` may also be scope.
11678 StorageClass
stc = STC
.nodtor
;
11680 stc |
= STC
.rvalue | STC
.scope_
;
11682 auto vd
= copyToTemp(stc, "__assigntmp", ae
.e2
);
11683 eValue2
= new DeclarationExp(vd
.loc
, vd
).expressionSemantic(sc
);
11684 value2
= new VarExp(vd
.loc
, vd
).expressionSemantic(sc
);
11686 arguments
.push(value2
);
11688 Expression ce
= new CallExp(ae
.loc
, id
, arguments
);
11689 res
= Expression
.combine(eValue2
, ce
).expressionSemantic(sc
);
11691 res
= Expression
.combine(res
, ae
.e1
).expressionSemantic(sc
);
11693 if (global
.params
.v
.verbose
)
11694 message("lowered %s =>\n %s", ae
.toChars(), res
.toChars());
11696 res
= new LoweredAssignExp(ae
, res
);
11697 res
.type
= ae
.type
;
11702 override void visit(PowAssignExp exp
)
11710 Expression e
= exp
.op_overload(sc
);
11717 if (exp
.e1
.checkReadModifyWrite(exp
.op
, exp
.e2
))
11720 assert(exp
.e1
.type
&& exp
.e2
.type
);
11721 if (exp
.e1
.op
== EXP
.slice || exp
.e1
.type
.ty
== Tarray || exp
.e1
.type
.ty
== Tsarray
)
11723 if (checkNonAssignmentArrayOp(exp
.e1
))
11727 if (exp
.e2
.implicitConvTo(exp
.e1
.type
.nextOf()))
11730 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
.nextOf());
11732 else if (Expression ex
= typeCombine(exp
, sc
))
11738 // Check element types are arithmetic
11739 Type tb1
= exp
.e1
.type
.nextOf().toBasetype();
11740 Type tb2
= exp
.e2
.type
.toBasetype();
11741 if (tb2
.ty
== Tarray || tb2
.ty
== Tsarray
)
11742 tb2
= tb2
.nextOf().toBasetype();
11743 if ((tb1
.isintegral() || tb1
.isfloating()) && (tb2
.isintegral() || tb2
.isfloating()))
11745 exp
.type
= exp
.e1
.type
;
11746 result
= arrayOp(exp
, sc
);
11752 exp
.e1
= exp
.e1
.modifiableLvalue(sc
);
11755 if ((exp
.e1
.type
.isintegral() || exp
.e1
.type
.isfloating()) && (exp
.e2
.type
.isintegral() || exp
.e2
.type
.isfloating()))
11757 Expression e0
= null;
11758 e
= exp
.reorderSettingAAElem(sc
);
11759 e
= Expression
.extractLast(e
, e0
);
11762 if (exp
.e1
.op
== EXP
.variable
)
11764 // Rewrite: e1 = e1 ^^ e2
11765 e
= new PowExp(exp
.loc
, exp
.e1
.syntaxCopy(), exp
.e2
);
11766 e
= new AssignExp(exp
.loc
, exp
.e1
, e
);
11770 // Rewrite: ref tmp = e1; tmp = tmp ^^ e2
11771 auto v
= copyToTemp(STC
.ref_
, "__powtmp", exp
.e1
);
11772 auto de = new DeclarationExp(exp
.e1
.loc
, v
);
11773 auto ve
= new VarExp(exp
.e1
.loc
, v
);
11774 e
= new PowExp(exp
.loc
, ve
, exp
.e2
);
11775 e
= new AssignExp(exp
.loc
, new VarExp(exp
.e1
.loc
, v
), e
);
11776 e
= new CommaExp(exp
.loc
, de, e
);
11778 e
= Expression
.combine(e0
, e
);
11779 e
= e
.expressionSemantic(sc
);
11783 result
= exp
.incompatibleTypes();
11786 override void visit(CatAssignExp exp
)
11794 //printf("CatAssignExp::semantic() %s\n", exp.toChars());
11795 Expression e
= exp
.op_overload(sc
);
11802 if (SliceExp se
= exp
.e1
.isSliceExp())
11804 if (se
.e1
.type
.toBasetype().ty
== Tsarray
)
11806 error(exp
.loc
, "cannot append to static array `%s`", se
.e1
.type
.toChars());
11811 exp
.e1
= exp
.e1
.modifiableLvalue(sc
);
11812 if (exp
.e1
.op
== EXP
.error
)
11817 if (exp
.e2
.op
== EXP
.error
)
11823 if (checkNonAssignmentArrayOp(exp
.e2
))
11826 Type tb1
= exp
.e1
.type
.toBasetype();
11827 Type tb1next
= tb1
.nextOf();
11828 Type tb2
= exp
.e2
.type
.toBasetype();
11831 * EXP.concatenateAssign: appending T[] to T[]
11832 * EXP.concatenateElemAssign: appending T to T[]
11833 * EXP.concatenateDcharAssign: appending dchar to T[]
11835 if ((tb1
.ty
== Tarray
) &&
11836 (tb2
.ty
== Tarray || tb2
.ty
== Tsarray
) &&
11837 (exp
.e2
.implicitConvTo(exp
.e1
.type
) ||
11838 (tb2
.nextOf().implicitConvTo(tb1next
) &&
11839 (tb2
.nextOf().size(Loc
.initial
) == tb1next
.size(Loc
.initial
)))))
11841 // EXP.concatenateAssign
11842 assert(exp
.op
== EXP
.concatenateAssign
);
11843 if (tb1next
.checkPostblit(exp
.e1
.loc
, sc
))
11846 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
);
11848 else if ((tb1
.ty
== Tarray
) && exp
.e2
.implicitConvTo(tb1next
))
11850 /* https://issues.dlang.org/show_bug.cgi?id=19782
11852 * If e2 is implicitly convertible to tb1next, the conversion
11853 * might be done through alias this, in which case, e2 needs to
11854 * be modified accordingly (e2 => e2.aliasthis).
11856 if (tb2
.ty
== Tstruct
&& (cast(TypeStruct
)tb2
).implicitConvToThroughAliasThis(tb1next
))
11858 if (tb2
.ty
== Tclass
&& (cast(TypeClass
)tb2
).implicitConvToThroughAliasThis(tb1next
))
11861 if (tb2
.checkPostblit(exp
.e2
.loc
, sc
))
11864 if (checkNewEscape(sc
, exp
.e2
, false))
11867 exp
= new CatElemAssignExp(exp
.loc
, exp
.type
, exp
.e1
, exp
.e2
.castTo(sc
, tb1next
));
11868 exp
.e2
= doCopyOrMove(sc
, exp
.e2
);
11870 else if (tb1
.ty
== Tarray
&&
11871 (tb1next
.ty
== Tchar || tb1next
.ty
== Twchar
) &&
11872 exp
.e2
.type
.ty
!= tb1next
.ty
&&
11873 exp
.e2
.implicitConvTo(Type
.tdchar
))
11875 // Append dchar to char[] or wchar[]
11876 exp
= new CatDcharAssignExp(exp
.loc
, exp
.type
, exp
.e1
, exp
.e2
.castTo(sc
, Type
.tdchar
));
11878 /* Do not allow appending wchar to char[] because if wchar happens
11879 * to be a surrogate pair, nothing good can result.
11884 // Try alias this on first operand
11885 static Expression
tryAliasThisForLhs(BinAssignExp exp
, Scope
* sc
)
11887 AggregateDeclaration ad1
= isAggregate(exp
.e1
.type
);
11888 if (!ad1 ||
!ad1
.aliasthis
)
11891 /* Rewrite (e1 op e2) as:
11892 * (e1.aliasthis op e2)
11894 if (isRecursiveAliasThis(exp
.att1
, exp
.e1
.type
))
11896 //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
11897 Expression e1
= new DotIdExp(exp
.loc
, exp
.e1
, ad1
.aliasthis
.ident
);
11898 BinExp be
= cast(BinExp
)exp
.copy();
11900 return be
.trySemantic(sc
);
11903 // Try alias this on second operand
11904 static Expression
tryAliasThisForRhs(BinAssignExp exp
, Scope
* sc
)
11906 AggregateDeclaration ad2
= isAggregate(exp
.e2
.type
);
11907 if (!ad2 ||
!ad2
.aliasthis
)
11909 /* Rewrite (e1 op e2) as:
11910 * (e1 op e2.aliasthis)
11912 if (isRecursiveAliasThis(exp
.att2
, exp
.e2
.type
))
11914 //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
11915 Expression e2
= new DotIdExp(exp
.loc
, exp
.e2
, ad2
.aliasthis
.ident
);
11916 BinExp be
= cast(BinExp
)exp
.copy();
11918 return be
.trySemantic(sc
);
11922 result
= tryAliasThisForLhs(exp
, sc
);
11926 result
= tryAliasThisForRhs(exp
, sc
);
11930 error(exp
.loc
, "cannot append type `%s` to type `%s`", tb2
.toChars(), tb1
.toChars());
11934 if (exp
.e2
.checkValue() || exp
.e2
.checkSharedAccess(sc
))
11937 exp
.type
= exp
.e1
.type
;
11938 auto assignElem
= exp
.e2
;
11939 auto res
= exp
.reorderSettingAAElem(sc
);
11940 if (res
!= exp
) // `AA[k] = v` rewrite was performed
11941 checkNewEscape(sc
, assignElem
, false);
11942 else if (exp
.op
== EXP
.concatenateElemAssign || exp
.op
== EXP
.concatenateDcharAssign
)
11943 checkAssignEscape(sc
, res
, false, false);
11947 if ((exp
.op
== EXP
.concatenateAssign || exp
.op
== EXP
.concatenateElemAssign
) && sc
.needsCodegen())
11949 // if aa ordering is triggered, `res` will be a CommaExp
11950 // and `.e2` will be the rewritten original expression.
11952 // `output` will point to the expression that the lowering will overwrite
11953 Expression
* output
;
11954 if (auto comma
= res
.isCommaExp())
11956 output
= &comma
.e2
;
11957 // manual cast because it could be either CatAssignExp or CatElemAssignExp
11958 exp
= cast(CatAssignExp
)comma
.e2
;
11963 exp
= cast(CatAssignExp
)result
;
11966 if (exp
.op
== EXP
.concatenateAssign
)
11968 Identifier hook
= global
.params
.tracegc ? Id
._d_arrayappendTTrace
: Id
._d_arrayappendT
;
11970 if (!verifyHookExist(exp
.loc
, *sc
, hook
, "appending array to arrays", Id
.object
))
11973 // Lower to object._d_arrayappendT{,Trace}({file, line, funcname}, e1, e2)
11974 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
11975 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
11976 id
= new DotIdExp(exp
.loc
, id
, hook
);
11978 auto arguments
= new Expressions();
11979 arguments
.reserve(5);
11980 if (global
.params
.tracegc
)
11982 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ? sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
11983 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
11984 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
11985 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
11988 arguments
.push(exp
.e1
);
11989 arguments
.push(exp
.e2
);
11990 Expression ce
= new CallExp(exp
.loc
, id
, arguments
);
11992 exp
.lowering
= ce
.expressionSemantic(sc
);
11995 else if (exp
.op
== EXP
.concatenateElemAssign
)
11997 /* Do not lower concats to the indices array returned by
11998 *`static foreach`, as this array is only used at compile-time.
12000 if (auto ve
= exp
.e1
.isVarExp
)
12002 import core
.stdc
.ctype
: isdigit
;
12003 // The name of the indices array that static foreach loops uses.
12004 // See dmd.cond.lowerNonArrayAggregate
12005 enum varName
= "__res";
12006 const(char)[] id
= ve
.var
.ident
.toString
;
12007 if (ve
.var
.storage_class
& STC
.temp
&& id
.length
> varName
.length
&&
12008 id
[0 .. varName
.length
] == varName
&& id
[varName
.length
].isdigit
)
12012 Identifier hook
= global
.params
.tracegc ? Id
._d_arrayappendcTXTrace
: Id
._d_arrayappendcTX
;
12013 if (!verifyHookExist(exp
.loc
, *sc
, hook
, "appending element to arrays", Id
.object
))
12016 // Lower to object._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2
12017 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
12018 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
12019 id
= new DotIdExp(exp
.loc
, id
, hook
);
12021 auto arguments
= new Expressions();
12022 arguments
.reserve(5);
12023 if (global
.params
.tracegc
)
12025 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ? sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
12026 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
12027 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
12028 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
12031 Expression eValue1
;
12032 Expression value1
= extractSideEffect(sc
, "__appendtmp", eValue1
, exp
.e1
);
12034 arguments
.push(value1
);
12035 arguments
.push(new IntegerExp(exp
.loc
, 1, Type
.tsize_t
));
12037 Expression ce
= new CallExp(exp
.loc
, id
, arguments
);
12039 Expression eValue2
;
12040 Expression value2
= exp
.e2
;
12041 if (!value2
.isVarExp() && !value2
.isConst())
12043 /* Before the template hook, this check was performed in e2ir.d
12044 * for expressions like `a ~= a[$-1]`. Here, $ will be modified
12045 * by calling `_d_arrayappendcTX`, so we need to save `a[$-1]` in
12046 * a temporary variable.
12048 value2
= extractSideEffect(sc
, "__appendtmp", eValue2
, value2
, true);
12050 // `__appendtmp*` will be destroyed together with the array `exp.e1`.
12051 auto vd
= eValue2
.isDeclarationExp().declaration
.isVarDeclaration();
12052 vd
.storage_class |
= STC
.nodtor
;
12053 // Be more explicit that this "declaration" is local to the expression
12054 vd
.storage_class |
= STC
.exptemp
;
12057 auto ale
= new ArrayLengthExp(exp
.loc
, value1
);
12058 auto elem
= new IndexExp(exp
.loc
, value1
, new MinExp(exp
.loc
, ale
, IntegerExp
.literal
!1));
12059 auto ae
= new ConstructExp(exp
.loc
, elem
, value2
);
12061 auto e0
= Expression
.combine(ce
, ae
).expressionSemantic(sc
);
12062 e0
= Expression
.combine(e0
, value1
);
12063 e0
= Expression
.combine(eValue1
, e0
);
12064 e0
= Expression
.combine(eValue2
, e0
);
12066 exp
.lowering
= e0
.expressionSemantic(sc
);
12072 override void visit(AddExp exp
)
12074 static if (LOGSEMANTIC
)
12076 printf("AddExp::semantic('%s')\n", exp
.toChars());
12084 if (Expression ex
= binSemanticProp(exp
, sc
))
12089 Expression e
= exp
.op_overload(sc
);
12096 /* ImportC: convert arrays to pointers, functions to pointers to functions
12098 exp
.e1
= exp
.e1
.arrayFuncConv(sc
);
12099 exp
.e2
= exp
.e2
.arrayFuncConv(sc
);
12101 Type tb1
= exp
.e1
.type
.toBasetype();
12102 Type tb2
= exp
.e2
.type
.toBasetype();
12105 if (tb1
.ty
== Tdelegate || tb1
.isPtrToFunction())
12107 err |
= exp
.e1
.checkArithmetic(exp
.op
) || exp
.e1
.checkSharedAccess(sc
);
12109 if (tb2
.ty
== Tdelegate || tb2
.isPtrToFunction())
12111 err |
= exp
.e2
.checkArithmetic(exp
.op
) || exp
.e2
.checkSharedAccess(sc
);
12116 if (tb1
.ty
== Tpointer
&& exp
.e2
.type
.isintegral() || tb2
.ty
== Tpointer
&& exp
.e1
.type
.isintegral())
12118 result
= scaleFactor(exp
, sc
);
12122 if (tb1
.ty
== Tpointer
&& tb2
.ty
== Tpointer
)
12124 result
= exp
.incompatibleTypes();
12128 if (Expression ex
= typeCombine(exp
, sc
))
12134 Type tb
= exp
.type
.toBasetype();
12135 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
12137 if (!isArrayOpValid(exp
))
12139 result
= arrayOpInvalidError(exp
);
12146 tb1
= exp
.e1
.type
.toBasetype();
12147 if (!target
.isVectorOpSupported(tb1
, exp
.op
, tb2
))
12149 result
= exp
.incompatibleTypes();
12152 if ((tb1
.isreal() && exp
.e2
.type
.isimaginary()) ||
(tb1
.isimaginary() && exp
.e2
.type
.isreal()))
12154 switch (exp
.type
.toBasetype().ty
)
12158 exp
.type
= Type
.tcomplex32
;
12163 exp
.type
= Type
.tcomplex64
;
12168 exp
.type
= Type
.tcomplex80
;
12178 override void visit(MinExp exp
)
12180 static if (LOGSEMANTIC
)
12182 printf("MinExp::semantic('%s')\n", exp
.toChars());
12190 if (Expression ex
= binSemanticProp(exp
, sc
))
12195 Expression e
= exp
.op_overload(sc
);
12202 /* ImportC: convert arrays to pointers, functions to pointers to functions
12204 exp
.e1
= exp
.e1
.arrayFuncConv(sc
);
12205 exp
.e2
= exp
.e2
.arrayFuncConv(sc
);
12207 Type t1
= exp
.e1
.type
.toBasetype();
12208 Type t2
= exp
.e2
.type
.toBasetype();
12211 if (t1
.ty
== Tdelegate || t1
.isPtrToFunction())
12213 err |
= exp
.e1
.checkArithmetic(exp
.op
) || exp
.e1
.checkSharedAccess(sc
);
12215 if (t2
.ty
== Tdelegate || t2
.isPtrToFunction())
12217 err |
= exp
.e2
.checkArithmetic(exp
.op
) || exp
.e2
.checkSharedAccess(sc
);
12222 if (t1
.ty
== Tpointer
)
12224 if (t2
.ty
== Tpointer
)
12226 // https://dlang.org/spec/expression.html#add_expressions
12227 // "If both operands are pointers, and the operator is -, the pointers are
12228 // subtracted and the result is divided by the size of the type pointed to
12229 // by the operands. It is an error if the pointers point to different types."
12230 Type p1
= t1
.nextOf();
12231 Type p2
= t2
.nextOf();
12233 if (!p1
.equivalent(p2
))
12235 // Deprecation to remain for at least a year, after which this should be
12236 // changed to an error
12237 // See https://github.com/dlang/dmd/pull/7332
12238 deprecation(exp
.loc
,
12239 "cannot subtract pointers to different types: `%s` and `%s`.",
12240 t1
.toChars(), t2
.toChars());
12243 // Need to divide the result by the stride
12244 // Replace (ptr - ptr) with (ptr - ptr) / stride
12247 // make sure pointer types are compatible
12248 if (Expression ex
= typeCombine(exp
, sc
))
12254 exp
.type
= Type
.tptrdiff_t
;
12255 stride
= t2
.nextOf().size();
12258 e
= new IntegerExp(exp
.loc
, 0, Type
.tptrdiff_t
);
12260 else if (stride
== cast(long)SIZE_INVALID
)
12261 e
= ErrorExp
.get();
12264 e
= new DivExp(exp
.loc
, exp
, new IntegerExp(Loc
.initial
, stride
, Type
.tptrdiff_t
));
12265 e
.type
= Type
.tptrdiff_t
;
12268 else if (t2
.isintegral())
12269 e
= scaleFactor(exp
, sc
);
12272 error(exp
.loc
, "can't subtract `%s` from pointer", t2
.toChars());
12273 e
= ErrorExp
.get();
12278 if (t2
.ty
== Tpointer
)
12280 exp
.type
= exp
.e2
.type
;
12281 error(exp
.loc
, "can't subtract pointer from `%s`", exp
.e1
.type
.toChars());
12285 if (Expression ex
= typeCombine(exp
, sc
))
12291 Type tb
= exp
.type
.toBasetype();
12292 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
12294 if (!isArrayOpValid(exp
))
12296 result
= arrayOpInvalidError(exp
);
12303 t1
= exp
.e1
.type
.toBasetype();
12304 t2
= exp
.e2
.type
.toBasetype();
12305 if (!target
.isVectorOpSupported(t1
, exp
.op
, t2
))
12307 result
= exp
.incompatibleTypes();
12310 if ((t1
.isreal() && t2
.isimaginary()) ||
(t1
.isimaginary() && t2
.isreal()))
12312 switch (exp
.type
.ty
)
12316 exp
.type
= Type
.tcomplex32
;
12321 exp
.type
= Type
.tcomplex64
;
12326 exp
.type
= Type
.tcomplex80
;
12338 * If the given expression is a `CatExp`, the function tries to lower it to
12339 * `_d_arraycatnTX`.
12342 * ee = the `CatExp` to lower
12344 * `_d_arraycatnTX(e1, e2, ..., en)` if `ee` is `e1 ~ e2 ~ ... en`
12347 private Expression
lowerToArrayCat(CatExp exp
)
12349 // String literals are concatenated by the compiler. No lowering is needed.
12350 if ((exp
.e1
.isStringExp() && (exp
.e2
.isIntegerExp() || exp
.e2
.isStringExp())) ||
12351 (exp
.e2
.isStringExp() && (exp
.e1
.isIntegerExp() || exp
.e1
.isStringExp())))
12354 bool useTraceGCHook
= global
.params
.tracegc
&& sc
.needsCodegen();
12356 Identifier hook
= useTraceGCHook ? Id
._d_arraycatnTXTrace
: Id
._d_arraycatnTX
;
12357 if (!verifyHookExist(exp
.loc
, *sc
, hook
, "concatenating arrays"))
12363 void handleCatArgument(Expressions
*arguments
, Expression e
, Type catType
, bool isRightArg
)
12365 auto tb
= e
.type
.toBasetype();
12367 if ((isRightArg
&& e
.parens
) ||
(!isRightArg
&& !tb
.equals(catType
)))
12373 if (auto ce
= e
.isCatExp())
12375 Expression lowering
= ce
.lowering
;
12377 /* Skip `file`, `line`, and `funcname` if the hook of the parent
12378 * `CatExp` is `_d_arraycatnTXTrace`.
12380 if (auto callExp
= isRuntimeHook(lowering
, hook
))
12382 if (hook
== Id
._d_arraycatnTX
)
12383 arguments
.pushSlice((*callExp
.arguments
)[]);
12385 arguments
.pushSlice((*callExp
.arguments
)[3 .. $]);
12392 auto arguments
= new Expressions();
12393 if (useTraceGCHook
)
12395 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ?
12396 sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
12397 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
12398 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
12399 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
12402 handleCatArgument(arguments
, exp
.e1
, exp
.type
.toBasetype(), false);
12403 handleCatArgument(arguments
, exp
.e2
, exp
.type
.toBasetype(), true);
12405 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
12406 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
12408 auto tiargs
= new Objects();
12409 tiargs
.push(exp
.type
);
12410 id
= new DotTemplateInstanceExp(exp
.loc
, id
, hook
, tiargs
);
12411 id
= new CallExp(exp
.loc
, id
, arguments
);
12412 return id
.expressionSemantic(sc
);
12415 void trySetCatExpLowering(Expression exp
)
12417 /* `_d_arraycatnTX` canot be used with `-betterC`, but `CatExp`s may be
12418 * used with `-betterC`, but only during CTFE.
12420 if (!global
.params
.useGC
)
12423 if (auto ce
= exp
.isCatExp())
12424 ce
.lowering
= lowerToArrayCat(ce
);
12427 override void visit(CatExp exp
)
12429 // https://dlang.org/spec/expression.html#cat_expressions
12430 //printf("CatExp.semantic() %s\n", toChars());
12437 if (Expression ex
= binSemanticProp(exp
, sc
))
12442 Expression e
= exp
.op_overload(sc
);
12449 Type tb1
= exp
.e1
.type
.toBasetype();
12450 Type tb2
= exp
.e2
.type
.toBasetype();
12452 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
12453 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
12457 Type tb1next
= tb1
.nextOf();
12458 Type tb2next
= tb2
.nextOf();
12460 // Check for: array ~ array
12461 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
)))
12463 /* https://issues.dlang.org/show_bug.cgi?id=9248
12464 * Here to avoid the case of:
12465 * void*[] a = [cast(void*)1];
12466 * void*[] b = [cast(void*)2];
12469 * a ~ [cast(void*)b];
12472 /* https://issues.dlang.org/show_bug.cgi?id=14682
12473 * Also to avoid the case of:
12477 * a ~ cast(int[])[];
12482 // Check for: array ~ element
12483 if ((tb1
.ty
== Tsarray || tb1
.ty
== Tarray
) && tb2
.ty
!= Tvoid
)
12485 if (exp
.e1
.op
== EXP
.arrayLiteral
)
12487 exp
.e2
= doCopyOrMove(sc
, exp
.e2
);
12488 // https://issues.dlang.org/show_bug.cgi?id=14686
12489 // Postblit call appears in AST, and this is
12490 // finally translated to an ArrayLiteralExp in below optimize().
12492 else if (exp
.e1
.op
== EXP
.string_
)
12494 // No postblit call exists on character (integer) value.
12498 if (tb2
.checkPostblit(exp
.e2
.loc
, sc
))
12500 // Postblit call will be done in runtime helper function
12503 if (exp
.e1
.op
== EXP
.arrayLiteral
&& exp
.e1
.implicitConvTo(tb2
.arrayOf()))
12505 exp
.e1
= exp
.e1
.implicitCastTo(sc
, tb2
.arrayOf());
12506 exp
.type
= tb2
.arrayOf();
12509 if (exp
.e2
.implicitConvTo(tb1next
) >= MATCH
.convert
)
12511 exp
.e2
= exp
.e2
.implicitCastTo(sc
, tb1next
);
12512 exp
.type
= tb1next
.arrayOf();
12514 if (checkNewEscape(sc
, exp
.e2
, false))
12516 result
= exp
.optimize(WANTvalue
);
12517 trySetCatExpLowering(result
);
12521 // Check for: element ~ array
12522 if ((tb2
.ty
== Tsarray || tb2
.ty
== Tarray
) && tb1
.ty
!= Tvoid
)
12524 if (exp
.e2
.op
== EXP
.arrayLiteral
)
12526 exp
.e1
= doCopyOrMove(sc
, exp
.e1
);
12528 else if (exp
.e2
.op
== EXP
.string_
)
12533 if (tb1
.checkPostblit(exp
.e1
.loc
, sc
))
12537 if (exp
.e2
.op
== EXP
.arrayLiteral
&& exp
.e2
.implicitConvTo(tb1
.arrayOf()))
12539 exp
.e2
= exp
.e2
.implicitCastTo(sc
, tb1
.arrayOf());
12540 exp
.type
= tb1
.arrayOf();
12543 if (exp
.e1
.implicitConvTo(tb2next
) >= MATCH
.convert
)
12545 exp
.e1
= exp
.e1
.implicitCastTo(sc
, tb2next
);
12546 exp
.type
= tb2next
.arrayOf();
12548 if (checkNewEscape(sc
, exp
.e1
, false))
12550 result
= exp
.optimize(WANTvalue
);
12551 trySetCatExpLowering(result
);
12557 if ((tb1
.ty
== Tsarray || tb1
.ty
== Tarray
) && (tb2
.ty
== Tsarray || tb2
.ty
== Tarray
) && (tb1next
.mod || tb2next
.mod
) && (tb1next
.mod
!= tb2next
.mod
))
12559 Type t1
= tb1next
.mutableOf().constOf().arrayOf();
12560 Type t2
= tb2next
.mutableOf().constOf().arrayOf();
12561 if (exp
.e1
.op
== EXP
.string_
&& !(cast(StringExp
)exp
.e1
).committed
)
12564 exp
.e1
= exp
.e1
.castTo(sc
, t1
);
12565 if (exp
.e2
.op
== EXP
.string_
&& !(cast(StringExp
)exp
.e2
).committed
)
12568 exp
.e2
= exp
.e2
.castTo(sc
, t2
);
12571 if (Expression ex
= typeCombine(exp
, sc
))
12574 trySetCatExpLowering(result
);
12577 exp
.type
= exp
.type
.toHeadMutable();
12579 Type tb
= exp
.type
.toBasetype();
12580 if (tb
.ty
== Tsarray
)
12581 exp
.type
= tb
.nextOf().arrayOf();
12582 if (exp
.type
.ty
== Tarray
&& tb1next
&& tb2next
&& tb1next
.mod
!= tb2next
.mod
)
12584 exp
.type
= exp
.type
.nextOf().toHeadMutable().arrayOf();
12586 if (Type tbn
= tb
.nextOf())
12588 if (tbn
.checkPostblit(exp
.loc
, sc
))
12591 Type t1
= exp
.e1
.type
.toBasetype();
12592 Type t2
= exp
.e2
.type
.toBasetype();
12593 if ((t1
.ty
== Tarray || t1
.ty
== Tsarray
) &&
12594 (t2
.ty
== Tarray || t2
.ty
== Tsarray
))
12596 // Normalize to ArrayLiteralExp or StringExp as far as possible
12597 e
= exp
.optimize(WANTvalue
);
12601 //printf("(%s) ~ (%s)\n", e1.toChars(), e2.toChars());
12602 result
= exp
.incompatibleTypes();
12607 trySetCatExpLowering(result
);
12610 override void visit(MulExp exp
)
12614 printf("MulExp::semantic() %s\n", exp
.toChars());
12622 if (Expression ex
= binSemanticProp(exp
, sc
))
12627 Expression e
= exp
.op_overload(sc
);
12634 if (Expression ex
= typeCombine(exp
, sc
))
12640 Type tb
= exp
.type
.toBasetype();
12641 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
12643 if (!isArrayOpValid(exp
))
12645 result
= arrayOpInvalidError(exp
);
12652 if (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
))
12655 if (exp
.type
.isfloating())
12657 Type t1
= exp
.e1
.type
;
12658 Type t2
= exp
.e2
.type
;
12664 else if (t2
.isreal())
12668 else if (t1
.isimaginary())
12670 if (t2
.isimaginary())
12672 switch (t1
.toBasetype().ty
)
12675 exp
.type
= Type
.tfloat32
;
12679 exp
.type
= Type
.tfloat64
;
12683 exp
.type
= Type
.tfloat80
;
12691 exp
.e1
.type
= exp
.type
;
12692 exp
.e2
.type
= exp
.type
;
12693 e
= new NegExp(exp
.loc
, exp
);
12694 e
= e
.expressionSemantic(sc
);
12699 exp
.type
= t2
; // t2 is complex
12701 else if (t2
.isimaginary())
12703 exp
.type
= t1
; // t1 is complex
12706 else if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
12708 result
= exp
.incompatibleTypes();
12714 override void visit(DivExp exp
)
12722 if (Expression ex
= binSemanticProp(exp
, sc
))
12727 Expression e
= exp
.op_overload(sc
);
12734 if (Expression ex
= typeCombine(exp
, sc
))
12740 Type tb
= exp
.type
.toBasetype();
12741 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
12743 if (!isArrayOpValid(exp
))
12745 result
= arrayOpInvalidError(exp
);
12752 if (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
))
12755 if (exp
.type
.isfloating())
12757 Type t1
= exp
.e1
.type
;
12758 Type t2
= exp
.e2
.type
;
12763 if (t2
.isimaginary())
12767 e
= new NegExp(exp
.loc
, exp
);
12768 e
= e
.expressionSemantic(sc
);
12773 else if (t2
.isreal())
12777 else if (t1
.isimaginary())
12779 if (t2
.isimaginary())
12781 switch (t1
.toBasetype().ty
)
12784 exp
.type
= Type
.tfloat32
;
12788 exp
.type
= Type
.tfloat64
;
12792 exp
.type
= Type
.tfloat80
;
12800 exp
.type
= t2
; // t2 is complex
12802 else if (t2
.isimaginary())
12804 exp
.type
= t1
; // t1 is complex
12807 else if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
12809 result
= exp
.incompatibleTypes();
12815 override void visit(ModExp exp
)
12823 if (Expression ex
= binSemanticProp(exp
, sc
))
12828 Expression e
= exp
.op_overload(sc
);
12835 if (Expression ex
= typeCombine(exp
, sc
))
12841 Type tb
= exp
.type
.toBasetype();
12842 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
12844 if (!isArrayOpValid(exp
))
12846 result
= arrayOpInvalidError(exp
);
12852 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
12854 result
= exp
.incompatibleTypes();
12858 if (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
))
12861 if (exp
.type
.isfloating())
12863 exp
.type
= exp
.e1
.type
;
12864 if (exp
.e2
.type
.iscomplex())
12866 error(exp
.loc
, "cannot perform modulo complex arithmetic");
12873 override void visit(PowExp exp
)
12881 //printf("PowExp::semantic() %s\n", toChars());
12882 if (Expression ex
= binSemanticProp(exp
, sc
))
12887 Expression e
= exp
.op_overload(sc
);
12894 if (Expression ex
= typeCombine(exp
, sc
))
12900 Type tb
= exp
.type
.toBasetype();
12901 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
12903 if (!isArrayOpValid(exp
))
12905 result
= arrayOpInvalidError(exp
);
12912 if (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
))
12915 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
12917 result
= exp
.incompatibleTypes();
12921 // First, attempt to fold the expression.
12922 e
= exp
.optimize(WANTvalue
);
12923 if (e
.op
!= EXP
.pow
)
12925 e
= e
.expressionSemantic(sc
);
12930 Module mmath
= Module
.loadStdMath();
12933 error(e
.loc
, "`%s` requires `std.math` for `^^` operators", e
.toChars());
12936 e
= new ScopeExp(exp
.loc
, mmath
);
12938 if (exp
.e2
.op
== EXP
.float64
&& exp
.e2
.toReal() == CTFloat
.half
)
12940 // Replace e1 ^^ 0.5 with .std.math.sqrt(e1)
12941 e
= new CallExp(exp
.loc
, new DotIdExp(exp
.loc
, e
, Id
._sqrt
), exp
.e1
);
12945 // Replace e1 ^^ e2 with .std.math.pow(e1, e2)
12946 e
= new CallExp(exp
.loc
, new DotIdExp(exp
.loc
, e
, Id
._pow
), exp
.e1
, exp
.e2
);
12948 e
= e
.expressionSemantic(sc
);
12953 override void visit(ShlExp exp
)
12955 //printf("ShlExp::semantic(), type = %p\n", type);
12962 if (Expression ex
= binSemanticProp(exp
, sc
))
12967 Expression e
= exp
.op_overload(sc
);
12974 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
12977 if (!target
.isVectorOpSupported(exp
.e1
.type
.toBasetype(), exp
.op
, exp
.e2
.type
.toBasetype()))
12979 result
= exp
.incompatibleTypes();
12982 exp
.e1
= integralPromotions(exp
.e1
, sc
);
12983 if (exp
.e2
.type
.toBasetype().ty
!= Tvector
)
12984 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tshiftcnt
);
12986 exp
.type
= exp
.e1
.type
;
12990 override void visit(ShrExp exp
)
12998 if (Expression ex
= binSemanticProp(exp
, sc
))
13003 Expression e
= exp
.op_overload(sc
);
13010 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
13013 if (!target
.isVectorOpSupported(exp
.e1
.type
.toBasetype(), exp
.op
, exp
.e2
.type
.toBasetype()))
13015 result
= exp
.incompatibleTypes();
13018 exp
.e1
= integralPromotions(exp
.e1
, sc
);
13019 if (exp
.e2
.type
.toBasetype().ty
!= Tvector
)
13020 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tshiftcnt
);
13022 exp
.type
= exp
.e1
.type
;
13026 override void visit(UshrExp exp
)
13034 if (Expression ex
= binSemanticProp(exp
, sc
))
13039 Expression e
= exp
.op_overload(sc
);
13046 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
13049 if (!target
.isVectorOpSupported(exp
.e1
.type
.toBasetype(), exp
.op
, exp
.e2
.type
.toBasetype()))
13051 result
= exp
.incompatibleTypes();
13054 exp
.e1
= integralPromotions(exp
.e1
, sc
);
13055 if (exp
.e2
.type
.toBasetype().ty
!= Tvector
)
13056 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tshiftcnt
);
13058 exp
.type
= exp
.e1
.type
;
13062 override void visit(AndExp exp
)
13070 if (Expression ex
= binSemanticProp(exp
, sc
))
13075 Expression e
= exp
.op_overload(sc
);
13082 if (exp
.e1
.type
.toBasetype().ty
== Tbool
&& exp
.e2
.type
.toBasetype().ty
== Tbool
)
13084 exp
.type
= exp
.e1
.type
;
13089 if (Expression ex
= typeCombine(exp
, sc
))
13095 Type tb
= exp
.type
.toBasetype();
13096 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
13098 if (!isArrayOpValid(exp
))
13100 result
= arrayOpInvalidError(exp
);
13106 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
13108 result
= exp
.incompatibleTypes();
13111 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
13117 override void visit(OrExp exp
)
13125 if (Expression ex
= binSemanticProp(exp
, sc
))
13130 Expression e
= exp
.op_overload(sc
);
13137 if (exp
.e1
.type
.toBasetype().ty
== Tbool
&& exp
.e2
.type
.toBasetype().ty
== Tbool
)
13139 exp
.type
= exp
.e1
.type
;
13144 if (Expression ex
= typeCombine(exp
, sc
))
13150 Type tb
= exp
.type
.toBasetype();
13151 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
13153 if (!isArrayOpValid(exp
))
13155 result
= arrayOpInvalidError(exp
);
13161 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
13163 result
= exp
.incompatibleTypes();
13166 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
13172 override void visit(XorExp exp
)
13180 if (Expression ex
= binSemanticProp(exp
, sc
))
13185 Expression e
= exp
.op_overload(sc
);
13192 if (exp
.e1
.type
.toBasetype().ty
== Tbool
&& exp
.e2
.type
.toBasetype().ty
== Tbool
)
13194 exp
.type
= exp
.e1
.type
;
13199 if (Expression ex
= typeCombine(exp
, sc
))
13205 Type tb
= exp
.type
.toBasetype();
13206 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
13208 if (!isArrayOpValid(exp
))
13210 result
= arrayOpInvalidError(exp
);
13216 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
13218 result
= exp
.incompatibleTypes();
13221 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
13227 override void visit(LogicalExp exp
)
13229 static if (LOGSEMANTIC
)
13231 printf("LogicalExp::semantic() %s\n", exp
.toChars());
13240 exp
.setNoderefOperands();
13242 Expression e1x
= exp
.e1
.expressionSemantic(sc
);
13244 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
13245 if (e1x
.op
== EXP
.type
)
13246 e1x
= resolveAliasThis(sc
, e1x
);
13248 e1x
= resolveProperties(sc
, e1x
);
13249 e1x
= e1x
.toBoolean(sc
);
13251 if (sc
.flags
& SCOPE
.condition
)
13253 /* If in static if, don't evaluate e2 if we don't have to.
13255 e1x
= e1x
.optimize(WANTvalue
);
13256 if (e1x
.toBool().hasValue(exp
.op
== EXP
.orOr
))
13258 if (sc
.flags
& SCOPE
.Cfile
)
13259 result
= new IntegerExp(exp
.op
== EXP
.orOr
);
13261 result
= IntegerExp
.createBool(exp
.op
== EXP
.orOr
);
13266 CtorFlow ctorflow
= sc
.ctorflow
.clone();
13267 Expression e2x
= exp
.e2
.expressionSemantic(sc
);
13268 sc
.merge(exp
.loc
, ctorflow
);
13269 ctorflow
.freeFieldinit();
13271 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
13272 if (e2x
.op
== EXP
.type
)
13273 e2x
= resolveAliasThis(sc
, e2x
);
13275 e2x
= resolveProperties(sc
, e2x
);
13277 auto f1
= checkNonAssignmentArrayOp(e1x
);
13278 auto f2
= checkNonAssignmentArrayOp(e2x
);
13282 // Unless the right operand is 'void', the expression is converted to 'bool'.
13283 if (e2x
.type
.ty
!= Tvoid
)
13284 e2x
= e2x
.toBoolean(sc
);
13286 if (e2x
.op
== EXP
.type || e2x
.op
== EXP
.scope_
)
13288 error(exp
.loc
, "`%s` is not an expression", exp
.e2
.toChars());
13291 if (e1x
.op
== EXP
.error || e1x
.type
.ty
== Tnoreturn
)
13296 if (e2x
.op
== EXP
.error
)
13302 // The result type is 'bool', unless the right operand has type 'void'.
13303 if (e2x
.type
.ty
== Tvoid
)
13304 exp
.type
= Type
.tvoid
;
13306 exp
.type
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? Type
.tint32
: Type
.tbool
;
13314 override void visit(CmpExp exp
)
13316 static if (LOGSEMANTIC
)
13318 printf("CmpExp::semantic('%s')\n", exp
.toChars());
13326 exp
.setNoderefOperands();
13328 if (Expression ex
= binSemanticProp(exp
, sc
))
13333 Type t1
= exp
.e1
.type
.toBasetype();
13334 Type t2
= exp
.e2
.type
.toBasetype();
13335 if (t1
.ty
== Tclass
&& exp
.e2
.op
== EXP
.null_ || t2
.ty
== Tclass
&& exp
.e1
.op
== EXP
.null_
)
13337 error(exp
.loc
, "do not use `null` when comparing class types");
13342 EXP cmpop
= exp
.op
;
13343 if (auto e
= exp
.op_overload(sc
, &cmpop
))
13345 if (!e
.type
.isscalar() && e
.type
.equals(exp
.e1
.type
))
13347 error(exp
.loc
, "recursive `opCmp` expansion");
13350 if (e
.op
== EXP
.call)
13353 if (t1
.ty
== Tclass
&& t2
.ty
== Tclass
)
13355 // Lower to object.__cmp(e1, e2)
13356 Expression cl
= new IdentifierExp(exp
.loc
, Id
.empty
);
13357 cl
= new DotIdExp(exp
.loc
, cl
, Id
.object
);
13358 cl
= new DotIdExp(exp
.loc
, cl
, Id
.__cmp
);
13359 cl
= cl
.expressionSemantic(sc
);
13361 auto arguments
= new Expressions();
13362 // Check if op_overload found a better match by calling e2.opCmp(e1)
13363 // If the operands were swapped, then the result must be reversed
13364 // e1.opCmp(e2) == -e2.opCmp(e1)
13365 // cmpop takes care of this
13366 if (exp
.op
== cmpop
)
13368 arguments
.push(exp
.e1
);
13369 arguments
.push(exp
.e2
);
13373 // Use better match found by op_overload
13374 arguments
.push(exp
.e2
);
13375 arguments
.push(exp
.e1
);
13378 cl
= new CallExp(exp
.loc
, cl
, arguments
);
13379 cl
= new CmpExp(cmpop
, exp
.loc
, cl
, new IntegerExp(0));
13380 result
= cl
.expressionSemantic(sc
);
13384 e
= new CmpExp(cmpop
, exp
.loc
, e
, IntegerExp
.literal
!0);
13385 e
= e
.expressionSemantic(sc
);
13392 if (Expression ex
= typeCombine(exp
, sc
))
13398 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
13399 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
13403 exp
.type
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? Type
.tint32
: Type
.tbool
;
13405 // Special handling for array comparisons
13406 Expression arrayLowering
= null;
13407 t1
= exp
.e1
.type
.toBasetype();
13408 t2
= exp
.e2
.type
.toBasetype();
13409 if ((t1
.ty
== Tarray || t1
.ty
== Tsarray || t1
.ty
== Tpointer
) && (t2
.ty
== Tarray || t2
.ty
== Tsarray || t2
.ty
== Tpointer
))
13411 Type t1next
= t1
.nextOf();
13412 Type t2next
= t2
.nextOf();
13413 if (t1next
.implicitConvTo(t2next
) < MATCH
.constant
&& t2next
.implicitConvTo(t1next
) < MATCH
.constant
&& (t1next
.ty
!= Tvoid
&& t2next
.ty
!= Tvoid
))
13415 error(exp
.loc
, "array comparison type mismatch, `%s` vs `%s`", t1next
.toChars(), t2next
.toChars());
13419 if ((t1
.ty
== Tarray || t1
.ty
== Tsarray
) &&
13420 (t2
.ty
== Tarray || t2
.ty
== Tsarray
))
13422 if (!verifyHookExist(exp
.loc
, *sc
, Id
.__cmp
, "comparing arrays"))
13425 // Lower to object.__cmp(e1, e2)
13426 Expression al
= new IdentifierExp(exp
.loc
, Id
.empty
);
13427 al
= new DotIdExp(exp
.loc
, al
, Id
.object
);
13428 al
= new DotIdExp(exp
.loc
, al
, Id
.__cmp
);
13429 al
= al
.expressionSemantic(sc
);
13431 auto arguments
= new Expressions(2);
13432 (*arguments
)[0] = exp
.e1
;
13433 (*arguments
)[1] = exp
.e2
;
13435 al
= new CallExp(exp
.loc
, al
, arguments
);
13436 al
= new CmpExp(exp
.op
, exp
.loc
, al
, IntegerExp
.literal
!0);
13438 arrayLowering
= al
;
13441 else if (t1
.ty
== Tstruct || t2
.ty
== Tstruct ||
(t1
.ty
== Tclass
&& t2
.ty
== Tclass
))
13443 if (t2
.ty
== Tstruct
)
13444 error(exp
.loc
, "need member function `opCmp()` for %s `%s` to compare", t2
.toDsymbol(sc
).kind(), t2
.toChars());
13446 error(exp
.loc
, "need member function `opCmp()` for %s `%s` to compare", t1
.toDsymbol(sc
).kind(), t1
.toChars());
13449 else if (t1
.iscomplex() || t2
.iscomplex())
13451 error(exp
.loc
, "compare not defined for complex operands");
13454 else if (t1
.ty
== Taarray || t2
.ty
== Taarray
)
13456 error(exp
.loc
, "`%s` is not defined for associative arrays", EXPtoString(exp
.op
).ptr
);
13459 else if (!target
.isVectorOpSupported(t1
, exp
.op
, t2
))
13461 result
= exp
.incompatibleTypes();
13466 bool r1
= exp
.e1
.checkValue() || exp
.e1
.checkSharedAccess(sc
);
13467 bool r2
= exp
.e2
.checkValue() || exp
.e2
.checkSharedAccess(sc
);
13472 //printf("CmpExp: %s, type = %s\n", e.toChars(), e.type.toChars());
13475 arrayLowering
= arrayLowering
.expressionSemantic(sc
);
13476 result
= arrayLowering
;
13480 if (auto tv
= t1
.isTypeVector())
13481 exp
.type
= tv
.toBooleanVector();
13487 override void visit(InExp exp
)
13495 if (Expression ex
= binSemanticProp(exp
, sc
))
13500 Expression e
= exp
.op_overload(sc
);
13507 Type t2b
= exp
.e2
.type
.toBasetype();
13512 TypeAArray ta
= cast(TypeAArray
)t2b
;
13514 // Special handling for array keys
13515 if (!arrayTypeCompatibleWithoutCasting(exp
.e1
.type
, ta
.index
))
13517 // Convert key to type of key
13518 exp
.e1
= exp
.e1
.implicitCastTo(sc
, ta
.index
);
13521 semanticTypeInfo(sc
, ta
.index
);
13523 // Return type is pointer to value
13524 exp
.type
= ta
.nextOf().pointerTo();
13531 case Tarray
, Tsarray
:
13532 result
= exp
.incompatibleTypes();
13533 errorSupplemental(exp
.loc
, "`in` is only allowed on associative arrays");
13534 const(char)* slice
= (t2b
.ty
== Tsarray
) ?
"[]" : "";
13535 errorSupplemental(exp
.loc
, "perhaps use `std.algorithm.find(%s, %s%s)` instead",
13536 exp
.e1
.toChars(), exp
.e2
.toChars(), slice
);
13540 result
= exp
.incompatibleTypes();
13546 override void visit(RemoveExp e
)
13548 if (Expression ex
= binSemantic(e
, sc
))
13556 override void visit(EqualExp exp
)
13558 //printf("EqualExp::semantic('%s')\n", exp.toChars());
13565 exp
.setNoderefOperands();
13567 if (auto e
= binSemanticProp(exp
, sc
))
13572 if (exp
.e1
.op
== EXP
.type || exp
.e2
.op
== EXP
.type
)
13574 /* https://issues.dlang.org/show_bug.cgi?id=12520
13575 * empty tuples are represented as types so special cases are added
13576 * so that they can be compared for equality with tuples of values.
13578 static auto extractTypeTupAndExpTup(Expression e
)
13580 static struct Result
{ bool ttEmpty
; bool te
; }
13581 auto tt
= e
.op
== EXP
.type ? e
.isTypeExp().type
.isTypeTuple() : null;
13582 return Result(tt
&& (!tt
.arguments ||
!tt
.arguments
.length
), e
.isTupleExp() !is null);
13584 auto tups1
= extractTypeTupAndExpTup(exp
.e1
);
13585 auto tups2
= extractTypeTupAndExpTup(exp
.e2
);
13586 // AliasSeq!() == AliasSeq!(<at least a value>)
13587 if (tups1
.ttEmpty
&& tups2
.te
)
13589 result
= IntegerExp
.createBool(exp
.op
!= EXP
.equal
);
13592 // AliasSeq!(<at least a value>) == AliasSeq!()
13593 else if (tups1
.te
&& tups2
.ttEmpty
)
13595 result
= IntegerExp
.createBool(exp
.op
!= EXP
.equal
);
13598 // AliasSeq!() == AliasSeq!()
13599 else if (tups1
.ttEmpty
&& tups2
.ttEmpty
)
13601 result
= IntegerExp
.createBool(exp
.op
== EXP
.equal
);
13604 // otherwise, two types are really not comparable
13605 result
= exp
.incompatibleTypes();
13610 auto t1
= exp
.e1
.type
;
13611 auto t2
= exp
.e2
.type
;
13612 if (t1
.ty
== Tenum
&& t2
.ty
== Tenum
&& !t1
.equivalent(t2
))
13613 error(exp
.loc
, "comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`",
13614 t1
.toChars(), t2
.toChars());
13617 /* Before checking for operator overloading, check to see if we're
13618 * comparing the addresses of two statics. If so, we can just see
13619 * if they are the same symbol.
13621 if (exp
.e1
.op
== EXP
.address
&& exp
.e2
.op
== EXP
.address
)
13623 AddrExp ae1
= cast(AddrExp
)exp
.e1
;
13624 AddrExp ae2
= cast(AddrExp
)exp
.e2
;
13625 if (ae1
.e1
.op
== EXP
.variable
&& ae2
.e1
.op
== EXP
.variable
)
13627 VarExp ve1
= cast(VarExp
)ae1
.e1
;
13628 VarExp ve2
= cast(VarExp
)ae2
.e1
;
13629 if (ve1
.var
== ve2
.var
)
13631 // They are the same, result is 'true' for ==, 'false' for !=
13632 result
= IntegerExp
.createBool(exp
.op
== EXP
.equal
);
13638 Type t1
= exp
.e1
.type
.toBasetype();
13639 Type t2
= exp
.e2
.type
.toBasetype();
13641 // Indicates whether the comparison of the 2 specified array types
13642 // requires an object.__equals() lowering.
13643 static bool needsDirectEq(Type t1
, Type t2
, Scope
* sc
)
13645 Type t1n
= t1
.nextOf().toBasetype();
13646 Type t2n
= t2
.nextOf().toBasetype();
13647 if ((t1n
.ty
.isSomeChar
&& t2n
.ty
.isSomeChar
) ||
13648 (t1n
.ty
== Tvoid || t2n
.ty
== Tvoid
))
13652 if (t1n
.constOf() != t2n
.constOf())
13656 while (t
.toBasetype().nextOf())
13657 t
= t
.nextOf().toBasetype();
13658 if (auto ts
= t
.isTypeStruct())
13660 // semanticTypeInfo() makes sure hasIdentityEquals has been computed
13661 if (global
.params
.useTypeInfo
&& Type
.dtypeinfo
)
13662 semanticTypeInfo(sc
, ts
);
13664 return ts
.sym
.hasIdentityEquals
; // has custom opEquals
13670 if (auto e
= exp
.op_overload(sc
))
13677 const isArrayComparison
= (t1
.ty
== Tarray || t1
.ty
== Tsarray
) &&
13678 (t2
.ty
== Tarray || t2
.ty
== Tsarray
);
13679 const needsArrayLowering
= isArrayComparison
&& needsDirectEq(t1
, t2
, sc
);
13681 if (!needsArrayLowering
)
13683 // https://issues.dlang.org/show_bug.cgi?id=23783
13684 if (exp
.e1
.checkSharedAccess(sc
) || exp
.e2
.checkSharedAccess(sc
))
13686 if (auto e
= typeCombine(exp
, sc
))
13693 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
13694 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
13698 exp
.type
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? Type
.tint32
: Type
.tbool
;
13700 if (!isArrayComparison
)
13702 if (exp
.e1
.type
!= exp
.e2
.type
&& exp
.e1
.type
.isfloating() && exp
.e2
.type
.isfloating())
13704 // Cast both to complex
13705 exp
.e1
= exp
.e1
.castTo(sc
, Type
.tcomplex80
);
13706 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tcomplex80
);
13710 // lower some array comparisons to object.__equals(e1, e2)
13711 if (needsArrayLowering ||
(t1
.ty
== Tarray
&& t2
.ty
== Tarray
))
13713 //printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars());
13715 // https://issues.dlang.org/show_bug.cgi?id=22390
13716 // Equality comparison between array of noreturns simply lowers to length equality comparison
13717 if (t1
.nextOf
.isTypeNoreturn() && t2
.nextOf
.isTypeNoreturn())
13719 Expression exp_l1
= new DotIdExp(exp
.e1
.loc
, exp
.e1
, Id
.length
);
13720 Expression exp_l2
= new DotIdExp(exp
.e2
.loc
, exp
.e2
, Id
.length
);
13721 auto e
= new EqualExp(EXP
.equal
, exp
.loc
, exp_l1
, exp_l2
);
13722 result
= e
.expressionSemantic(sc
);
13726 if (!verifyHookExist(exp
.loc
, *sc
, Id
.__equals
, "equal checks on arrays"))
13729 Expression __equals
= new IdentifierExp(exp
.loc
, Id
.empty
);
13730 Identifier id
= Identifier
.idPool("__equals");
13731 __equals
= new DotIdExp(exp
.loc
, __equals
, Id
.object
);
13732 __equals
= new DotIdExp(exp
.loc
, __equals
, id
);
13734 /* https://issues.dlang.org/show_bug.cgi?id=23674
13736 * Optimize before creating the call expression to the
13737 * druntime hook as the optimizer may output errors
13738 * that will get swallowed otherwise.
13740 exp
.e1
= exp
.e1
.optimize(WANTvalue
);
13741 exp
.e2
= exp
.e2
.optimize(WANTvalue
);
13743 auto arguments
= new Expressions(2);
13744 (*arguments
)[0] = exp
.e1
;
13745 (*arguments
)[1] = exp
.e2
;
13747 __equals
= new CallExp(exp
.loc
, __equals
, arguments
);
13748 if (exp
.op
== EXP
.notEqual
)
13750 __equals
= new NotExp(exp
.loc
, __equals
);
13752 __equals
= __equals
.trySemantic(sc
); // for better error message
13755 error(exp
.loc
, "incompatible types for array comparison: `%s` and `%s`",
13756 exp
.e1
.type
.toChars(), exp
.e2
.type
.toChars());
13757 __equals
= ErrorExp
.get();
13764 if (exp
.e1
.type
.toBasetype().ty
== Taarray
)
13765 semanticTypeInfo(sc
, exp
.e1
.type
.toBasetype());
13768 if (!target
.isVectorOpSupported(t1
, exp
.op
, t2
))
13770 result
= exp
.incompatibleTypes();
13774 if (auto tv
= t1
.isTypeVector())
13775 exp
.type
= tv
.toBooleanVector();
13780 override void visit(IdentityExp exp
)
13788 exp
.setNoderefOperands();
13790 if (auto e
= binSemanticProp(exp
, sc
))
13796 if (auto e
= typeCombine(exp
, sc
))
13802 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
13803 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
13807 if (exp
.e1
.op
== EXP
.type || exp
.e2
.op
== EXP
.type
)
13809 result
= exp
.incompatibleTypes();
13813 exp
.type
= Type
.tbool
;
13815 if (exp
.e1
.type
!= exp
.e2
.type
&& exp
.e1
.type
.isfloating() && exp
.e2
.type
.isfloating())
13817 // Cast both to complex
13818 exp
.e1
= exp
.e1
.castTo(sc
, Type
.tcomplex80
);
13819 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tcomplex80
);
13822 auto tb1
= exp
.e1
.type
.toBasetype();
13823 auto tb2
= exp
.e2
.type
.toBasetype();
13824 if (!target
.isVectorOpSupported(tb1
, exp
.op
, tb2
))
13826 result
= exp
.incompatibleTypes();
13830 if (exp
.e1
.op
== EXP
.call)
13831 exp
.e1
= (cast(CallExp
)exp
.e1
).addDtorHook(sc
);
13832 if (exp
.e2
.op
== EXP
.call)
13833 exp
.e2
= (cast(CallExp
)exp
.e2
).addDtorHook(sc
);
13835 if (exp
.e1
.type
.toBasetype().ty
== Tsarray ||
13836 exp
.e2
.type
.toBasetype().ty
== Tsarray
)
13837 deprecation(exp
.loc
, "identity comparison of static arrays "
13838 ~ "implicitly coerces them to slices, "
13839 ~ "which are compared by reference");
13844 override void visit(CondExp exp
)
13846 static if (LOGSEMANTIC
)
13848 printf("CondExp::semantic('%s')\n", exp
.toChars());
13856 if (auto die
= exp
.econd
.isDotIdExp())
13857 die
.noderef
= true;
13859 Expression ec
= exp
.econd
.expressionSemantic(sc
);
13860 ec
= resolveProperties(sc
, ec
);
13861 ec
= ec
.toBoolean(sc
);
13863 CtorFlow ctorflow_root
= sc
.ctorflow
.clone();
13864 Expression e1x
= exp
.e1
.expressionSemantic(sc
).arrayFuncConv(sc
);
13865 e1x
= resolveProperties(sc
, e1x
);
13867 CtorFlow ctorflow1
= sc
.ctorflow
;
13868 sc
.ctorflow
= ctorflow_root
;
13869 Expression e2x
= exp
.e2
.expressionSemantic(sc
).arrayFuncConv(sc
);
13870 e2x
= resolveProperties(sc
, e2x
);
13872 sc
.merge(exp
.loc
, ctorflow1
);
13873 ctorflow1
.freeFieldinit();
13875 if (ec
.op
== EXP
.error
)
13880 if (ec
.type
== Type
.terror
)
13884 if (e1x
.op
== EXP
.error
)
13889 if (e1x
.type
== Type
.terror
)
13893 if (e2x
.op
== EXP
.error
)
13898 if (e2x
.type
== Type
.terror
)
13902 auto f0
= checkNonAssignmentArrayOp(exp
.econd
);
13903 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
13904 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
13905 if (f0 || f1 || f2
)
13908 Type t1
= exp
.e1
.type
;
13909 Type t2
= exp
.e2
.type
;
13911 // https://issues.dlang.org/show_bug.cgi?id=23767
13912 // `cast(void*) 0` should be treated as `null` so the ternary expression
13913 // gets the pointer type of the other branch
13914 if (sc
.flags
& SCOPE
.Cfile
)
13916 static void rewriteCNull(ref Expression e
, ref Type t
)
13918 if (!t
.isTypePointer())
13920 if (auto ie
= e
.optimize(WANTvalue
).isIntegerExp())
13922 if (ie
.getInteger() == 0)
13924 e
= new NullExp(e
.loc
, Type
.tnull
);
13929 rewriteCNull(exp
.e1
, t1
);
13930 rewriteCNull(exp
.e2
, t2
);
13933 if (t1
.ty
== Tnoreturn
)
13936 exp
.e1
= specialNoreturnCast(exp
.e1
, exp
.type
);
13938 else if (t2
.ty
== Tnoreturn
)
13941 exp
.e2
= specialNoreturnCast(exp
.e2
, exp
.type
);
13943 // If either operand is void the result is void, we have to cast both
13944 // the expression to void so that we explicitly discard the expression
13946 // https://issues.dlang.org/show_bug.cgi?id=16598
13947 else if (t1
.ty
== Tvoid || t2
.ty
== Tvoid
)
13949 exp
.type
= Type
.tvoid
;
13950 exp
.e1
= exp
.e1
.castTo(sc
, exp
.type
);
13951 exp
.e2
= exp
.e2
.castTo(sc
, exp
.type
);
13957 if (Expression ex
= typeCombine(exp
, sc
))
13963 switch (exp
.e1
.type
.toBasetype().ty
)
13968 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
);
13973 switch (exp
.e2
.type
.toBasetype().ty
)
13978 exp
.e1
= exp
.e1
.castTo(sc
, exp
.e2
.type
);
13983 if (exp
.type
.toBasetype().ty
== Tarray
)
13985 exp
.e1
= exp
.e1
.castTo(sc
, exp
.type
);
13986 exp
.e2
= exp
.e2
.castTo(sc
, exp
.type
);
13989 exp
.type
= exp
.type
.merge2();
13992 printf("res: %s\n", exp
.type
.toChars());
13993 printf("e1 : %s\n", exp
.e1
.type
.toChars());
13994 printf("e2 : %s\n", exp
.e2
.type
.toChars());
13997 /* https://issues.dlang.org/show_bug.cgi?id=14696
13998 * If either e1 or e2 contain temporaries which need dtor,
13999 * make them conditional.
14001 * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2)
14003 * (auto __cond = cond) ? (... __tmp1) : (... __tmp2)
14004 * and replace edtors of __tmp1 and __tmp2 with:
14005 * __tmp1.edtor --> __cond && __tmp1.dtor()
14006 * __tmp2.edtor --> __cond || __tmp2.dtor()
14013 override void visit(GenericExp exp
)
14015 static if (LOGSEMANTIC
)
14017 printf("GenericExp::semantic('%s')\n", exp
.toChars());
14019 // C11 6.5.1.1 Generic Selection
14021 auto ec
= exp
.cntlExp
.expressionSemantic(sc
).arrayFuncConv(sc
);
14022 bool errors
= ec
.isErrorExp() !is null;
14025 auto types
= (*exp
.types
)[];
14026 foreach (i
, ref t
; types
)
14029 continue; // `default:` case
14030 t
= t
.typeSemantic(ec
.loc
, sc
);
14031 if (t
.isTypeError())
14037 /* C11 6.5.1-2 duplicate check
14039 /* C11 distinguishes int, long, and long long. But D doesn't, so depending on the
14040 * C target, a long may have the same type as `int` in the D type system.
14041 * So, skip checks when this may be the case. Later pick the first match
14044 (t
.ty
== Tint32 || t
.ty
== Tuns32
) && target
.c
.longsize
== 4 ||
14045 (t
.ty
== Tint64 || t
.ty
== Tuns64
) && target
.c
.longsize
== 8 ||
14046 (t
.ty
== Tfloat64 || t
.ty
== Timaginary64 || t
.ty
== Tcomplex64
) && target
.c
.long_doublesize
== 8
14050 foreach (t2
; types
[0 .. i
])
14052 if (t2
&& t2
.equals(t
))
14054 error(ec
.loc
, "generic association type `%s` can only appear once", t
.toChars());
14061 auto exps
= (*exp
.exps
)[];
14062 foreach (ref e
; exps
)
14064 e
= e
.expressionSemantic(sc
);
14065 if (e
.isErrorExp())
14072 enum size_t None
= ~0;
14073 size_t imatch
= None
;
14074 size_t idefault
= None
;
14075 foreach (const i
, t
; types
)
14079 /* if tc is compatible with t, it's a match
14080 * C11 6.2.7 defines a compatible type as being the same type, including qualifiers
14084 assert(imatch
== None
);
14086 break; // pick first match
14090 idefault
= i
; // multiple defaults are not allowed, and are caught by cparse
14093 if (imatch
== None
)
14095 if (imatch
== None
)
14097 error(exp
.loc
, "no compatible generic association type for controlling expression type `%s`", tc
.toChars());
14101 result
= exps
[imatch
];
14104 override void visit(FileInitExp e
)
14106 //printf("FileInitExp::semantic()\n");
14107 e
.type
= Type
.tstring
;
14108 result
= e
.resolveLoc(e
.loc
, sc
);
14111 override void visit(LineInitExp e
)
14113 e
.type
= Type
.tint32
;
14114 result
= e
.resolveLoc(e
.loc
, sc
);
14117 override void visit(ModuleInitExp e
)
14119 //printf("ModuleInitExp::semantic()\n");
14120 e
.type
= Type
.tstring
;
14121 result
= e
.resolveLoc(e
.loc
, sc
);
14124 override void visit(FuncInitExp e
)
14126 //printf("FuncInitExp::semantic()\n");
14127 e
.type
= Type
.tstring
;
14128 result
= e
.resolveLoc(e
.loc
, sc
);
14131 override void visit(PrettyFuncInitExp e
)
14133 //printf("PrettyFuncInitExp::semantic()\n");
14134 e
.type
= Type
.tstring
;
14135 result
= e
.resolveLoc(e
.loc
, sc
);
14139 /**********************************
14140 * Try to run semantic routines.
14141 * If they fail, return NULL.
14143 Expression
trySemantic(Expression exp
, Scope
* sc
)
14145 //printf("+trySemantic(%s)\n", exp.toChars());
14146 uint errors
= global
.startGagging();
14147 Expression e
= expressionSemantic(exp
, sc
);
14148 if (global
.endGagging(errors
))
14152 //printf("-trySemantic(%s)\n", exp.toChars());
14156 /**************************
14157 * Helper function for easy error propagation.
14158 * If error occurs, returns ErrorExp. Otherwise returns NULL.
14160 Expression
unaSemantic(UnaExp e
, Scope
* sc
)
14162 static if (LOGSEMANTIC
)
14164 printf("UnaExp::semantic('%s')\n", e
.toChars());
14166 Expression e1x
= e
.e1
.expressionSemantic(sc
);
14167 if (e1x
.op
== EXP
.error
)
14173 /**************************
14174 * Helper function for easy error propagation.
14175 * If error occurs, returns ErrorExp. Otherwise returns NULL.
14177 Expression
binSemantic(BinExp e
, Scope
* sc
)
14179 static if (LOGSEMANTIC
)
14181 printf("BinExp::semantic('%s')\n", e
.toChars());
14183 Expression e1x
= e
.e1
.expressionSemantic(sc
);
14184 Expression e2x
= e
.e2
.expressionSemantic(sc
);
14186 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
14187 if (e1x
.op
== EXP
.type
)
14188 e1x
= resolveAliasThis(sc
, e1x
);
14189 if (e2x
.op
== EXP
.type
)
14190 e2x
= resolveAliasThis(sc
, e2x
);
14192 if (e1x
.op
== EXP
.error
)
14194 if (e2x
.op
== EXP
.error
)
14201 Expression
binSemanticProp(BinExp e
, Scope
* sc
)
14203 if (Expression ex
= binSemantic(e
, sc
))
14205 Expression e1x
= resolveProperties(sc
, e
.e1
);
14206 Expression e2x
= resolveProperties(sc
, e
.e2
);
14207 if (e1x
.op
== EXP
.error
)
14209 if (e2x
.op
== EXP
.error
)
14216 // entrypoint for semantic ExpressionSemanticVisitor
14217 Expression
expressionSemantic(Expression e
, Scope
* sc
)
14219 scope v
= new ExpressionSemanticVisitor(sc
);
14224 private Expression
dotIdSemanticPropX(DotIdExp exp
, Scope
* sc
)
14226 //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars());
14227 if (Expression ex
= unaSemantic(exp
, sc
))
14230 if (!(sc
.flags
& SCOPE
.Cfile
) && exp
.ident
== Id
._mangleof
)
14234 // return mangleof as an Expression
14235 static Expression
dotMangleof(const ref Loc loc
, Scope
* sc
, Dsymbol
ds, bool hasOverloads
)
14240 if (auto f
= ds.isFuncDeclaration())
14242 if (f
.checkForwardRef(loc
))
14243 return ErrorExp
.get();
14245 if (f
.purityInprocess || f
.safetyInprocess || f
.nothrowInprocess || f
.nogcInprocess
)
14247 error(loc
, "%s `%s` cannot retrieve its `.mangleof` while inferring attributes", f
.kind
, f
.toPrettyChars
);
14248 return ErrorExp
.get();
14252 e
= StringExp
.create(loc
, mangleExact(f
));
14258 mangleToBuffer(ds, buf
);
14259 e
= new StringExp(loc
, buf
.extractSlice());
14262 return e
.expressionSemantic(sc
);
14268 case EXP
.scope_
: return dotMangleof(exp
.loc
, sc
, exp
.e1
.isScopeExp().sds
, false);
14269 case EXP
.overloadSet
: return dotMangleof(exp
.loc
, sc
, exp
.e1
.isOverExp().vars
, false);
14272 VarExp ve
= exp
.e1
.isVarExp();
14273 return dotMangleof(exp
.loc
, sc
, ve
.var
, ve
.hasOverloads
);
14275 case EXP
.dotVariable
:
14277 DotVarExp dve
= exp
.e1
.isDotVarExp();
14278 return dotMangleof(exp
.loc
, sc
, dve
.var
, dve
.hasOverloads
);
14280 case EXP
.template_
:
14282 TemplateExp te
= exp
.e1
.isTemplateExp();
14283 return dotMangleof(exp
.loc
, sc
, ds = te
.fd ? te
.fd
.isDsymbol() : te
.td
, false);
14291 if (exp
.e1
.isVarExp() && exp
.e1
.type
.toBasetype().isTypeSArray() && exp
.ident
== Id
.length
)
14293 // bypass checkPurity
14294 return exp
.e1
.type
.dotExp(sc
, exp
.e1
, exp
.ident
, cast(DotExpFlag
) (exp
.noderef
* DotExpFlag
.noDeref
));
14297 if (!exp
.e1
.isDotExp())
14299 exp
.e1
= resolvePropertiesX(sc
, exp
.e1
);
14302 if (auto te
= exp
.e1
.isTupleExp())
14304 if (exp
.ident
== Id
.offsetof
)
14306 /* 'distribute' the .offsetof to each of the tuple elements.
14308 auto exps
= new Expressions(te
.exps
.length
);
14309 foreach (i
, e
; (*te
.exps
)[])
14311 (*exps
)[i
] = new DotIdExp(e
.loc
, e
, Id
.offsetof
);
14313 // Don't evaluate te.e0 in runtime
14314 Expression e
= new TupleExp(exp
.loc
, null, exps
);
14315 e
= e
.expressionSemantic(sc
);
14318 if (exp
.ident
== Id
.length
)
14320 // Don't evaluate te.e0 in runtime
14321 return new IntegerExp(exp
.loc
, te
.exps
.length
, Type
.tsize_t
);
14325 // https://issues.dlang.org/show_bug.cgi?id=14416
14326 // Template has no built-in properties except for 'stringof'.
14327 if ((exp
.e1
.isDotTemplateExp() || exp
.e1
.isTemplateExp()) && exp
.ident
!= Id
.stringof
)
14329 error(exp
.loc
, "template `%s` does not have property `%s`", exp
.e1
.toChars(), exp
.ident
.toChars());
14330 return ErrorExp
.get();
14334 error(exp
.loc
, "expression `%s` does not have property `%s`", exp
.e1
.toChars(), exp
.ident
.toChars());
14335 return ErrorExp
.get();
14341 private bool checkDisabled(Dsymbol s
, ref Loc loc
, Scope
* sc
)
14343 if (auto d
= s
.isDeclaration())
14344 return d
.checkDisabled(loc
, sc
);
14349 /******************************
14350 * Resolve properties, i.e. `e1.ident`, without seeing UFCS.
14352 * exp = expression to resolve
14354 * gag = do not emit error messages, just return `null`
14356 * resolved expression, null if error
14358 Expression
dotIdSemanticProp(DotIdExp exp
, Scope
* sc
, bool gag
)
14360 //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars());
14362 //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
14364 const cfile
= (sc
.flags
& SCOPE
.Cfile
) != 0;
14366 /* Special case: rewrite this.id and super.id
14367 * to be classtype.id and baseclasstype.id
14368 * if we have no this pointer.
14370 if ((exp
.e1
.isThisExp() || exp
.e1
.isSuperExp()) && !hasThis(sc
))
14372 if (AggregateDeclaration ad
= sc
.getStructClassScope())
14374 if (exp
.e1
.isThisExp())
14376 exp
.e1
= new TypeExp(exp
.e1
.loc
, ad
.type
);
14380 if (auto cd
= ad
.isClassDeclaration())
14383 exp
.e1
= new TypeExp(exp
.e1
.loc
, cd
.baseClass
.type
);
14390 Expression e
= dotIdSemanticPropX(exp
, sc
);
14397 if (auto de = exp
.e1
.isDotExp())
14408 Type t1b
= exp
.e1
.type
.toBasetype();
14410 if (auto ie
= eright
.isScopeExp()) // also used for template alias's
14412 SearchOptFlags flags
= SearchOpt
.localsOnly
;
14413 /* Disable access to another module's private imports.
14414 * The check for 'is sds our current module' is because
14415 * the current module should have access to its own imports.
14417 if (ie
.sds
.isModule() && ie
.sds
!= sc
._module
)
14418 flags |
= SearchOpt
.ignorePrivateImports
;
14419 if (sc
.flags
& SCOPE
.ignoresymbolvisibility
)
14420 flags |
= SearchOpt
.ignoreVisibility
;
14421 Dsymbol s
= ie
.sds
.search(exp
.loc
, exp
.ident
, flags
);
14422 /* Check for visibility before resolving aliases because public
14423 * aliases to private symbols are public.
14425 if (s
&& !(sc
.flags
& SCOPE
.ignoresymbolvisibility
) && !symbolIsVisible(sc
._module
, s
))
14431 auto p
= s
.isPackage();
14432 if (p
&& checkAccess(sc
, p
))
14439 // if 's' is a tuple variable, the tuple is returned.
14442 s
.checkDeprecated(exp
.loc
, sc
);
14443 s
.checkDisabled(exp
.loc
, sc
);
14445 if (auto em
= s
.isEnumMember())
14447 return em
.getVarExp(exp
.loc
, sc
);
14449 if (auto v
= s
.isVarDeclaration())
14451 //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars());
14453 !v
.type
.deco
&& v
.inuse
)
14456 error(exp
.loc
, "circular reference to %s `%s`", v
.kind(), v
.toPrettyChars());
14458 error(exp
.loc
, "forward reference to %s `%s`", v
.kind(), v
.toPrettyChars());
14459 return ErrorExp
.get();
14461 if (v
.type
.isTypeError())
14462 return ErrorExp
.get();
14464 if ((v
.storage_class
& STC
.manifest
) && v
._init
&& !exp
.wantsym
)
14466 /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2().
14467 * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably
14468 * be reverted. `wantsym` is the hack to work around the problem.
14472 error(exp
.loc
, "circular initialization of %s `%s`", v
.kind(), v
.toPrettyChars());
14473 return ErrorExp
.get();
14475 auto e
= v
.expandInitializer(exp
.loc
);
14477 e
= e
.expressionSemantic(sc
);
14486 eleft
= new ThisExp(exp
.loc
);
14487 e
= new DotVarExp(exp
.loc
, eleft
, v
);
14488 e
= e
.expressionSemantic(sc
);
14492 e
= new VarExp(exp
.loc
, v
);
14495 e
= new CommaExp(exp
.loc
, eleft
, e
);
14500 return e
.expressionSemantic(sc
);
14503 if (auto f
= s
.isFuncDeclaration())
14505 //printf("it's a function\n");
14506 if (!functionSemantic(f
))
14507 return ErrorExp
.get();
14512 eleft
= new ThisExp(exp
.loc
);
14513 e
= new DotVarExp(exp
.loc
, eleft
, f
, true);
14514 e
= e
.expressionSemantic(sc
);
14518 e
= new VarExp(exp
.loc
, f
, true);
14521 e
= new CommaExp(exp
.loc
, eleft
, e
);
14527 if (auto td
= s
.isTemplateDeclaration())
14531 e
= new DotTemplateExp(exp
.loc
, eleft
, td
);
14533 e
= new TemplateExp(exp
.loc
, td
);
14534 e
= e
.expressionSemantic(sc
);
14537 if (OverDeclaration od
= s
.isOverDeclaration())
14539 Expression e
= new VarExp(exp
.loc
, od
, true);
14542 e
= new CommaExp(exp
.loc
, eleft
, e
);
14543 e
.type
= Type
.tvoid
; // ambiguous type?
14545 return e
.expressionSemantic(sc
);
14547 if (auto o
= s
.isOverloadSet())
14549 //printf("'%s' is an overload set\n", o.toChars());
14550 return new OverExp(exp
.loc
, o
);
14553 if (auto t
= s
.getType())
14555 return (new TypeExp(exp
.loc
, t
)).expressionSemantic(sc
);
14558 if (auto tup
= s
.isTupleDeclaration())
14562 Expression e
= new DotVarExp(exp
.loc
, eleft
, tup
);
14563 e
= e
.expressionSemantic(sc
);
14566 Expression e
= new TupleExp(exp
.loc
, tup
);
14567 e
= e
.expressionSemantic(sc
);
14571 if (auto sds
= s
.isScopeDsymbol())
14573 //printf("it's a ScopeDsymbol %s\n", ident.toChars());
14574 Expression e
= new ScopeExp(exp
.loc
, sds
);
14575 e
= e
.expressionSemantic(sc
);
14577 e
= new DotExp(exp
.loc
, eleft
, e
);
14581 if (auto imp
= s
.isImport())
14583 Expression se
= new ScopeExp(exp
.loc
, imp
.pkg
);
14584 return se
.expressionSemantic(sc
);
14587 if (auto attr
= s
.isAttribDeclaration())
14589 if (auto sm
= ie
.sds
.search(exp
.loc
, exp
.ident
, flags
))
14591 auto es
= new DsymbolExp(exp
.loc
, sm
);
14596 // BUG: handle other cases like in IdentifierExp::semantic()
14599 printf("s = %p '%s', kind = '%s'\n", s
, s
.toChars(), s
.kind());
14603 else if (exp
.ident
== Id
.stringof
)
14605 Expression e
= new StringExp(exp
.loc
, ie
.toString());
14606 e
= e
.expressionSemantic(sc
);
14609 if (ie
.sds
.isPackage() || ie
.sds
.isImport() || ie
.sds
.isModule())
14615 s
= ie
.sds
.search_correct(exp
.ident
);
14616 if (s
&& symbolIsVisible(sc
, s
))
14619 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());
14621 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());
14624 error(exp
.loc
, "undefined identifier `%s` in %s `%s`", exp
.ident
.toChars(), ie
.sds
.kind(), ie
.sds
.toPrettyChars());
14625 return ErrorExp
.get();
14627 else if (t1b
.ty
== Tpointer
&& exp
.e1
.type
.ty
!= Tenum
&&
14629 exp
.ident
== Id
.__sizeof ||
14630 exp
.ident
== Id
.__xalignof ||
14632 (exp
.ident
== Id
._mangleof ||
14633 exp
.ident
== Id
.offsetof ||
14634 exp
.ident
== Id
._init ||
14635 exp
.ident
== Id
.stringof
)
14638 Type t1bn
= t1b
.nextOf();
14641 if (AggregateDeclaration ad
= isAggregate(t1bn
))
14643 if (!ad
.members
) // https://issues.dlang.org/show_bug.cgi?id=11312
14653 if (gag
&& t1bn
.ty
== Tvoid
)
14655 Expression e
= new PtrExp(exp
.loc
, exp
.e1
);
14656 e
= e
.expressionSemantic(sc
);
14657 const newFlag
= cast(DotExpFlag
) (gag
* DotExpFlag
.gag | exp
.noderef
* DotExpFlag
.noDeref
);
14658 return e
.type
.dotExp(sc
, e
, exp
.ident
, newFlag
);
14660 else if (exp
.ident
== Id
.__xalignof
&&
14661 exp
.e1
.isVarExp() &&
14662 exp
.e1
.isVarExp().var
.isVarDeclaration() &&
14663 !exp
.e1
.isVarExp().var
.isVarDeclaration().alignment
.isUnknown())
14665 // For `x.alignof` get the alignment of the variable, not the alignment of its type
14666 const explicitAlignment
= exp
.e1
.isVarExp().var
.isVarDeclaration().alignment
;
14667 const naturalAlignment
= exp
.e1
.type
.alignsize();
14668 const actualAlignment
= explicitAlignment
.isDefault() ? naturalAlignment
: explicitAlignment
.get();
14669 Expression e
= new IntegerExp(exp
.loc
, actualAlignment
, Type
.tsize_t
);
14672 else if ((exp
.ident
== Id
.max || exp
.ident
== Id
.min
) &&
14673 exp
.e1
.isVarExp() &&
14674 exp
.e1
.isVarExp().var
.isBitFieldDeclaration())
14676 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
14677 auto bf
= exp
.e1
.isVarExp().var
.isBitFieldDeclaration();
14678 return new IntegerExp(exp
.loc
, bf
.getMinMax(exp
.ident
), bf
.type
);
14680 else if ((exp
.ident
== Id
.max || exp
.ident
== Id
.min
) &&
14681 exp
.e1
.isDotVarExp() &&
14682 exp
.e1
.isDotVarExp().var
.isBitFieldDeclaration())
14684 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
14685 auto bf
= exp
.e1
.isDotVarExp().var
.isBitFieldDeclaration();
14686 return new IntegerExp(exp
.loc
, bf
.getMinMax(exp
.ident
), bf
.type
);
14690 if (exp
.e1
.isTypeExp() || exp
.e1
.isTemplateExp())
14693 const flag
= cast(DotExpFlag
) (exp
.noderef
* DotExpFlag
.noDeref | gag
* DotExpFlag
.gag
);
14695 Expression e
= exp
.e1
.type
.dotExp(sc
, exp
.e1
, exp
.ident
, flag
);
14698 e
= e
.expressionSemantic(sc
);
14705 * Resolve `e1.ident!tiargs` without seeing UFCS.
14707 * exp = the `DotTemplateInstanceExp` to resolve
14708 * sc = the semantic scope
14709 * gag = stop "not a property" error and return `null`.
14711 * `null` if error or not found, or the resolved expression.
14713 Expression
dotTemplateSemanticProp(DotTemplateInstanceExp exp
, Scope
* sc
, bool gag
)
14715 static if (LOGSEMANTIC
)
14717 printf("DotTemplateInstanceExpY::semantic('%s')\n", exp
.toChars());
14720 static Expression
errorExp()
14722 return ErrorExp
.get();
14725 Expression e1
= exp
.e1
;
14727 if (exp
.ti
.tempdecl
&& exp
.ti
.tempdecl
.parent
&& exp
.ti
.tempdecl
.parent
.isTemplateMixin())
14729 // if 'ti.tempdecl' happens to be found in a mixin template don't lose that info
14730 // and do the symbol search in that context (Issue: 19476)
14731 auto tm
= cast(TemplateMixin
)exp
.ti
.tempdecl
.parent
;
14732 e1
= new DotExp(exp
.e1
.loc
, exp
.e1
, new ScopeExp(tm
.loc
, tm
));
14735 auto die
= new DotIdExp(exp
.loc
, e1
, exp
.ti
.name
);
14737 Expression e
= die
.dotIdSemanticPropX(sc
);
14740 exp
.e1
= die
.e1
; // take back
14741 Type t1b
= exp
.e1
.type
.toBasetype();
14742 if (t1b
.ty
== Tarray || t1b
.ty
== Tsarray || t1b
.ty
== Taarray || t1b
.ty
== Tnull ||
(t1b
.isTypeBasic() && t1b
.ty
!= Tvoid
))
14744 /* No built-in type has templatized properties, so do shortcut.
14745 * It is necessary in: 1024.max!"a < b"
14750 e
= die
.dotIdSemanticProp(sc
, gag
);
14754 isDotOpDispatch(e
))
14756 /* opDispatch!tiargs would be a function template that needs IFTI,
14757 * so it's not a template
14765 if (e
.op
== EXP
.error
)
14767 if (DotVarExp dve
= e
.isDotVarExp())
14769 if (FuncDeclaration fd
= dve
.var
.isFuncDeclaration())
14771 if (TemplateDeclaration td
= fd
.findTemplateDeclRoot())
14773 e
= new DotTemplateExp(dve
.loc
, dve
.e1
, td
);
14774 e
= e
.expressionSemantic(sc
);
14777 else if (OverDeclaration od
= dve
.var
.isOverDeclaration())
14779 exp
.e1
= dve
.e1
; // pull semantic() result
14781 if (!exp
.findTempDecl(sc
))
14783 if (exp
.ti
.needsTypeInference(sc
))
14785 exp
.ti
.dsymbolSemantic(sc
);
14786 if (!exp
.ti
.inst || exp
.ti
.errors
) // if template failed to expand
14789 if (Declaration v
= exp
.ti
.toAlias().isDeclaration())
14791 if (v
.type
&& !v
.type
.deco
)
14792 v
.type
= v
.type
.typeSemantic(v
.loc
, sc
);
14793 return new DotVarExp(exp
.loc
, exp
.e1
, v
)
14794 .expressionSemantic(sc
);
14796 return new DotExp(exp
.loc
, exp
.e1
, new ScopeExp(exp
.loc
, exp
.ti
))
14797 .expressionSemantic(sc
);
14800 else if (e
.op
== EXP
.variable
)
14802 VarExp ve
= cast(VarExp
)e
;
14803 if (FuncDeclaration fd
= ve
.var
.isFuncDeclaration())
14805 if (TemplateDeclaration td
= fd
.findTemplateDeclRoot())
14807 e
= new TemplateExp(ve
.loc
, td
)
14808 .expressionSemantic(sc
);
14811 else if (OverDeclaration od
= ve
.var
.isOverDeclaration())
14813 exp
.ti
.tempdecl
= od
;
14814 return new ScopeExp(exp
.loc
, exp
.ti
)
14815 .expressionSemantic(sc
);
14819 if (DotTemplateExp dte
= e
.isDotTemplateExp())
14821 exp
.e1
= dte
.e1
; // pull semantic() result
14823 exp
.ti
.tempdecl
= dte
.td
;
14824 if (!exp
.ti
.semanticTiargs(sc
))
14826 if (exp
.ti
.needsTypeInference(sc
))
14828 exp
.ti
.dsymbolSemantic(sc
);
14829 if (!exp
.ti
.inst || exp
.ti
.errors
) // if template failed to expand
14832 if (Declaration v
= exp
.ti
.toAlias().isDeclaration())
14834 return new DotVarExp(exp
.loc
, exp
.e1
, v
)
14835 .expressionSemantic(sc
);
14837 return new DotExp(exp
.loc
, exp
.e1
, new ScopeExp(exp
.loc
, exp
.ti
))
14838 .expressionSemantic(sc
);
14840 else if (e
.op
== EXP
.template_
)
14842 exp
.ti
.tempdecl
= (cast(TemplateExp
)e
).td
;
14843 return new ScopeExp(exp
.loc
, exp
.ti
)
14844 .expressionSemantic(sc
);
14846 else if (DotExp
de = e
.isDotExp())
14848 if (de.e2
.op
== EXP
.overloadSet
)
14850 if (!exp
.findTempDecl(sc
) ||
!exp
.ti
.semanticTiargs(sc
))
14854 if (exp
.ti
.needsTypeInference(sc
))
14856 exp
.ti
.dsymbolSemantic(sc
);
14857 if (!exp
.ti
.inst || exp
.ti
.errors
) // if template failed to expand
14860 if (Declaration v
= exp
.ti
.toAlias().isDeclaration())
14862 if (v
.type
&& !v
.type
.deco
)
14863 v
.type
= v
.type
.typeSemantic(v
.loc
, sc
);
14864 return new DotVarExp(exp
.loc
, exp
.e1
, v
)
14865 .expressionSemantic(sc
);
14867 return new DotExp(exp
.loc
, exp
.e1
, new ScopeExp(exp
.loc
, exp
.ti
))
14868 .expressionSemantic(sc
);
14871 else if (OverExp oe
= e
.isOverExp())
14873 exp
.ti
.tempdecl
= oe
.vars
;
14874 return new ScopeExp(exp
.loc
, exp
.ti
)
14875 .expressionSemantic(sc
);
14879 error(exp
.loc
, "`%s` isn't a template", e
.toChars());
14883 MATCH
matchType(FuncExp funcExp
, Type to
, Scope
* sc
, FuncExp
* presult
, ErrorSink eSink
)
14885 auto loc
= funcExp
.loc
;
14886 auto tok
= funcExp
.tok
;
14887 auto td
= funcExp
.td
;
14888 auto fd
= funcExp
.fd
;
14889 auto type
= funcExp
.type
;
14891 MATCH
cannotInfer()
14893 eSink
.error(loc
, "cannot infer parameter types from `%s`", to
.toChars());
14894 return MATCH
.nomatch
;
14897 //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars());
14901 TypeFunction tof
= null;
14902 if (to
.ty
== Tdelegate
)
14904 if (tok
== TOK
.function_
)
14906 eSink
.error(loc
, "cannot match function literal to delegate type `%s`", to
.toChars());
14907 return MATCH
.nomatch
;
14909 tof
= cast(TypeFunction
)to
.nextOf();
14911 else if (to
.ty
== Tpointer
&& (tof
= to
.nextOf().isTypeFunction()) !is null)
14913 if (tok
== TOK
.delegate_
)
14915 eSink
.error(loc
, "cannot match delegate literal to function pointer type `%s`", to
.toChars());
14916 return MATCH
.nomatch
;
14924 return cannotInfer();
14927 // Parameter types inference from 'tof'
14929 TypeFunction tf
= fd
.type
.isTypeFunction();
14930 //printf("\ttof = %s\n", tof.toChars());
14931 //printf("\ttf = %s\n", tf.toChars());
14932 const dim
= tf
.parameterList
.length
;
14934 if (tof
.parameterList
.length
!= dim || tof
.parameterList
.varargs
!= tf
.parameterList
.varargs
)
14935 return cannotInfer();
14937 auto tiargs
= new Objects();
14938 tiargs
.reserve(td
.parameters
.length
);
14940 foreach (tp
; *td
.parameters
)
14943 foreach (i
, p
; tf
.parameterList
)
14945 if (auto ti
= p
.type
.isTypeIdentifier())
14946 if (ti
&& ti
.ident
== tp
.ident
)
14952 Parameter pto
= tof
.parameterList
[u
];
14954 if (t
.ty
== Terror
)
14955 return cannotInfer();
14956 tf
.parameterList
[u
].storageClass
= tof
.parameterList
[u
].storageClass
;
14960 // Set target of return type inference
14961 if (!tf
.next
&& tof
.next
)
14964 auto ti
= new TemplateInstance(loc
, td
, tiargs
);
14965 Expression ex
= (new ScopeExp(loc
, ti
)).expressionSemantic(td
._scope
);
14967 // Reset inference target for the later re-semantic
14970 if (ex
.op
== EXP
.error
)
14971 return MATCH
.nomatch
;
14972 if (auto ef
= ex
.isFuncExp())
14973 return ef
.matchType(to
, sc
, presult
, eSink
);
14975 return cannotInfer();
14978 if (!tof ||
!tof
.next
)
14979 return MATCH
.nomatch
;
14981 assert(type
&& type
!= Type
.tvoid
);
14982 if (fd
.type
.ty
== Terror
)
14983 return MATCH
.nomatch
;
14984 auto tfx
= fd
.type
.isTypeFunction();
14985 bool convertMatch
= (type
.ty
!= to
.ty
);
14987 if (fd
.inferRetType
&& tfx
.next
.implicitConvTo(tof
.next
) == MATCH
.convert
)
14989 /* If return type is inferred and covariant return,
14990 * tweak return statements to required return type.
14993 * class C : Object, I{}
14995 * I delegate() dg = delegate() { return new class C(); }
14997 convertMatch
= true;
14999 auto tfy
= new TypeFunction(tfx
.parameterList
, tof
.next
,
15000 tfx
.linkage
, STC
.undefined_
);
15002 tfy
.trust
= tfx
.trust
;
15003 tfy
.isnothrow
= tfx
.isnothrow
;
15004 tfy
.isnogc
= tfx
.isnogc
;
15005 tfy
.purity
= tfx
.purity
;
15006 tfy
.isproperty
= tfx
.isproperty
;
15007 tfy
.isref
= tfx
.isref
;
15008 tfy
.isInOutParam
= tfx
.isInOutParam
;
15009 tfy
.isInOutQual
= tfx
.isInOutQual
;
15010 tfy
.deco
= tfy
.merge().deco
;
15015 if (tok
== TOK
.delegate_ ||
15016 tok
== TOK
.reserved
&& (type
.ty
== Tdelegate || type
.ty
== Tpointer
&& to
.ty
== Tdelegate
))
15018 // Allow conversion from implicit function pointer to delegate
15019 tx
= new TypeDelegate(tfx
);
15020 tx
.deco
= tx
.merge().deco
;
15024 assert(tok
== TOK
.function_ || tok
== TOK
.reserved
&& type
.ty
== Tpointer || fd
.errors
);
15025 tx
= tfx
.pointerTo();
15027 //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars());
15029 MATCH m
= tx
.implicitConvTo(to
);
15030 if (m
> MATCH
.nomatch
)
15032 // MATCH.exact: exact type match
15033 // MATCH.constant: covairiant type match (eg. attributes difference)
15034 // MATCH.convert: context conversion
15035 m
= convertMatch ? MATCH
.convert
: tx
.equals(to
) ? MATCH
.exact
: MATCH
.constant
;
15039 (*presult
) = cast(FuncExp
)funcExp
.copy();
15040 (*presult
).type
= to
;
15042 // https://issues.dlang.org/show_bug.cgi?id=12508
15043 // Tweak function body for covariant returns.
15044 (*presult
).fd
.modifyReturns(sc
, tof
.next
);
15047 else if (!cast(ErrorSinkNull
)eSink
)
15049 auto ts
= toAutoQualChars(tx
, to
);
15050 eSink
.error(loc
, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
15051 funcExp
.toChars(), ts
[0], ts
[1]);
15056 private bool checkSharedAccessBin(BinExp binExp
, Scope
* sc
)
15058 const r1
= binExp
.e1
.checkSharedAccess(sc
);
15059 const r2
= binExp
.e2
.checkSharedAccess(sc
);
15063 /***************************************
15064 * If expression is shared, check that we can access it.
15065 * Give error message if not.
15068 * e = expression to check
15070 * returnRef = Whether this expression is for a `return` statement
15071 * off a `ref` function, in which case a single level
15072 * of dereference is allowed (e.g. `shared(int)*`).
15076 bool checkSharedAccess(Expression e
, Scope
* sc
, bool returnRef
= false)
15078 if (global
.params
.noSharedAccess
!= FeatureState
.enabled ||
15081 sc
.flags
& SCOPE
.ctfe
)
15086 //printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef);
15088 bool check(Expression e
, bool allowRef
)
15090 bool sharedError(Expression e
)
15092 // https://dlang.org/phobos/core_atomic.html
15093 error(e
.loc
, "direct access to shared `%s` is not allowed, see `core.atomic`", e
.toChars());
15097 // Error by default
15098 bool visit(Expression e
)
15100 // https://issues.dlang.org/show_bug.cgi?id=23639
15101 // Should be able to cast(shared)
15102 if (!e
.isCastExp() && e
.type
.isShared())
15103 return sharedError(e
);
15107 bool visitNew(NewExp e
)
15110 check(e
.thisexp
, false);
15114 bool visitVar(VarExp e
)
15116 // https://issues.dlang.org/show_bug.cgi?id=20908
15117 // direct access to init symbols is ok as they
15118 // cannot be modified.
15119 if (e
.var
.isSymbolDeclaration())
15122 // https://issues.dlang.org/show_bug.cgi?id=22626
15123 // Synchronized functions don't need to use core.atomic
15124 // when accessing `this`.
15125 if (sc
.func
&& sc
.func
.isSynchronized())
15127 if (e
.var
.isThisDeclaration())
15130 return sharedError(e
);
15132 else if (!allowRef
&& e
.var
.type
.isShared())
15133 return sharedError(e
);
15138 bool visitAddr(AddrExp e
)
15140 return check(e
.e1
, true);
15143 bool visitPtr(PtrExp e
)
15145 if (!allowRef
&& e
.type
.isShared())
15146 return sharedError(e
);
15148 if (e
.e1
.type
.isShared())
15149 return sharedError(e
);
15151 return check(e
.e1
, false);
15154 bool visitDotVar(DotVarExp e
)
15156 //printf("dotvarexp = %s\n", e.toChars());
15157 if (e
.type
.isShared())
15159 if (e
.e1
.isThisExp())
15161 // https://issues.dlang.org/show_bug.cgi?id=22626
15162 if (sc
.func
&& sc
.func
.isSynchronized())
15165 // https://issues.dlang.org/show_bug.cgi?id=23790
15166 if (e
.e1
.type
.isTypeStruct())
15170 auto fd
= e
.var
.isFuncDeclaration();
15171 const sharedFunc
= fd
&& fd
.type
.isShared
;
15172 if (!allowRef
&& !sharedFunc
)
15173 return sharedError(e
);
15175 // Allow using `DotVarExp` within value types
15176 if (e
.e1
.type
.isTypeSArray() || e
.e1
.type
.isTypeStruct())
15177 return check(e
.e1
, allowRef
);
15179 // If we end up with a single `VarExp`, it might be a `ref` param
15180 // `shared ref T` param == `shared(T)*`.
15181 if (auto ve
= e
.e1
.isVarExp())
15183 return check(e
.e1
, allowRef
&& (ve
.var
.storage_class
& STC
.ref_
));
15186 return sharedError(e
);
15189 return check(e
.e1
, false);
15192 bool visitIndex(IndexExp e
)
15194 if (!allowRef
&& e
.type
.isShared())
15195 return sharedError(e
);
15197 if (e
.e1
.type
.isShared())
15198 return sharedError(e
);
15200 return check(e
.e1
, false);
15203 bool visitComma(CommaExp e
)
15205 // Cannot be `return ref` since we can't use the return,
15206 // but it's better to show that error than an unrelated `shared` one
15207 return check(e
.e2
, true);
15212 default: return visit(e
);
15214 // Those have no indirections / can be ignored
15217 case EXP
.complex80
:
15219 case EXP
.null_
: return false;
15221 case EXP
.variable
: return visitVar(e
.isVarExp());
15222 case EXP
.new_
: return visitNew(e
.isNewExp());
15223 case EXP
.address
: return visitAddr(e
.isAddrExp());
15224 case EXP
.star
: return visitPtr(e
.isPtrExp());
15225 case EXP
.dotVariable
: return visitDotVar(e
.isDotVarExp());
15226 case EXP
.index
: return visitIndex(e
.isIndexExp());
15230 return check(e
, returnRef
);
15233 /****************************************
15234 * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE_FULL_PATH__ to loc.
15236 Expression
resolveLoc(Expression exp
, const ref Loc loc
, Scope
* sc
)
15238 // Don't replace the special keywords, while we are inside a default
15239 // argument. They are replaced later when copied to the call site.
15240 if (sc
.inDefaultArg
)
15245 Expression
visit(Expression exp
)
15247 if (auto binExp
= exp
.isBinExp())
15249 binExp
.e1
= binExp
.e1
.resolveLoc(loc
, sc
);
15250 binExp
.e2
= binExp
.e2
.resolveLoc(loc
, sc
);
15253 if (auto unaExp
= exp
.isUnaExp())
15255 unaExp
.e1
= unaExp
.e1
.resolveLoc(loc
, sc
);
15261 Expression
visitCond(CondExp exp
)
15263 exp
.e1
= exp
.e1
.resolveLoc(loc
, sc
);
15264 exp
.e2
= exp
.e2
.resolveLoc(loc
, sc
);
15265 exp
.econd
= exp
.econd
.resolveLoc(loc
, sc
);
15269 Expression
visitCat(CatExp exp
)
15271 exp
.e1
= exp
.e1
.resolveLoc(loc
, sc
);
15272 exp
.e2
= exp
.e2
.resolveLoc(loc
, sc
);
15274 exp
.lowering
= exp
.lowering
.resolveLoc(loc
, sc
);
15278 Expression
visitStructLiteral(StructLiteralExp exp
)
15280 foreach (ref element
; *exp
.elements
)
15283 element
= element
.resolveLoc(loc
, sc
);
15289 Expression
visitNew(NewExp exp
)
15292 exp
.thisexp
= exp
.thisexp
.resolveLoc(loc
, sc
);
15294 exp
.argprefix
= exp
.argprefix
.resolveLoc(loc
, sc
);
15296 exp
.lowering
= exp
.lowering
.resolveLoc(loc
, sc
);
15298 foreach (ref element
; *exp
.arguments
)
15301 element
= element
.resolveLoc(loc
, sc
);
15307 Expression
visitCall(CallExp exp
)
15309 foreach (ref element
; *exp
.arguments
)
15312 element
= element
.resolveLoc(loc
, sc
);
15318 Expression
visitArray(ArrayExp exp
)
15320 exp
.e1
= exp
.e1
.resolveLoc(loc
, sc
);
15322 foreach (ref element
; *exp
.arguments
)
15325 element
= element
.resolveLoc(loc
, sc
);
15331 Expression
visitSlice(SliceExp exp
)
15333 exp
.e1
= exp
.e1
.resolveLoc(loc
, sc
);
15334 exp
.lwr
= exp
.lwr
.resolveLoc(loc
, sc
);
15335 exp
.upr
= exp
.upr
.resolveLoc(loc
, sc
);
15340 Expression
visitInterval(IntervalExp exp
)
15342 exp
.lwr
= exp
.lwr
.resolveLoc(loc
, sc
);
15343 exp
.upr
= exp
.upr
.resolveLoc(loc
, sc
);
15348 Expression
visitArrayLiteral(ArrayLiteralExp exp
)
15351 exp
.basis
= exp
.basis
.resolveLoc(loc
, sc
);
15353 foreach (ref element
; *exp
.elements
)
15356 element
= element
.resolveLoc(loc
, sc
);
15362 Expression
visitAssocArrayLiteral(AssocArrayLiteralExp exp
)
15364 foreach (ref element
; *exp
.keys
)
15367 element
= element
.resolveLoc(loc
, sc
);
15370 foreach (ref element
; *exp
.values
)
15373 element
= element
.resolveLoc(loc
, sc
);
15379 Expression
visitFileInit(FileInitExp exp
)
15381 //printf("FileInitExp::resolve() %s\n", exp.toChars());
15383 if (exp
.op
== EXP
.fileFullPath
)
15384 s
= FileName
.toAbsolute(loc
.isValid() ? loc
.filename
: sc
._module
.srcfile
.toChars());
15386 s
= loc
.isValid() ? loc
.filename
: sc
._module
.ident
.toChars();
15388 Expression e
= new StringExp(loc
, s
.toDString());
15389 return e
.expressionSemantic(sc
);
15392 Expression
visitLineInit(LineInitExp exp
)
15394 Expression e
= new IntegerExp(loc
, loc
.linnum
, Type
.tint32
);
15395 return e
.expressionSemantic(sc
);
15398 Expression
visitModuleInit(ModuleInitExp exp
)
15400 const auto s
= (sc
.callsc ? sc
.callsc
: sc
)._module
.toPrettyChars().toDString();
15401 Expression e
= new StringExp(loc
, s
);
15402 return e
.expressionSemantic(sc
);
15405 Expression
visitFuncInit(FuncInitExp exp
)
15408 if (sc
.callsc
&& sc
.callsc
.func
)
15409 s
= sc
.callsc
.func
.Dsymbol
.toPrettyChars();
15411 s
= sc
.func
.Dsymbol
.toPrettyChars();
15414 Expression e
= new StringExp(loc
, s
.toDString());
15415 return e
.expressionSemantic(sc
);
15418 Expression
visitPrettyFunc(PrettyFuncInitExp exp
)
15420 FuncDeclaration fd
= (sc
.callsc
&& sc
.callsc
.func
)
15427 const funcStr
= fd
.Dsymbol
.toPrettyChars();
15429 functionToBufferWithIdent(fd
.type
.isTypeFunction(), buf
, funcStr
, fd
.isStatic
);
15430 s
= buf
.extractChars();
15437 Expression e
= new StringExp(loc
, s
.toDString());
15438 e
= e
.expressionSemantic(sc
);
15439 e
.type
= Type
.tstring
;
15445 default: return visit(exp
);
15446 case EXP
.structLiteral
: return visitStructLiteral(exp
.isStructLiteralExp());
15447 case EXP
.new_
: return visitNew(exp
.isNewExp());
15448 case EXP
.concatenate
: return visitCat(exp
.isCatExp());
15449 case EXP
.call: return visitCall(exp
.isCallExp());
15450 case EXP
.question
: return visitCond(exp
.isCondExp());
15451 case EXP
.array
: return visitArray(exp
.isArrayExp());
15452 case EXP
.slice
: return visitSlice(exp
.isSliceExp());
15453 case EXP
.interval
: return visitInterval(exp
.isIntervalExp());
15454 case EXP
.arrayLiteral
: return visitArrayLiteral(exp
.isArrayLiteralExp());
15455 case EXP
.assocArrayLiteral
: return visitAssocArrayLiteral(exp
.isAssocArrayLiteralExp());
15457 case EXP
.fileFullPath
: return visitFileInit(exp
.isFileInitExp());
15458 case EXP
.line
: return visitLineInit(exp
.isLineInitExp
);
15459 case EXP
.moduleString
: return visitModuleInit(exp
.isModuleInitExp());
15460 case EXP
.functionString
: return visitFuncInit(exp
.isFuncInitExp());
15461 case EXP
.prettyFunction
: return visitPrettyFunc(exp
.isPrettyFuncInitExp());
15465 /************************************************
15466 * Destructors are attached to VarDeclarations.
15467 * Hence, if expression returns a temp that needs a destructor,
15468 * make sure and create a VarDeclaration for that temp.
15470 Expression
addDtorHook(Expression e
, Scope
* sc
)
15472 Expression
visit(Expression exp
)
15477 Expression
visitStructLiteral(StructLiteralExp exp
)
15480 /* If struct requires a destructor, rewrite as:
15481 * (S tmp = S()),tmp
15482 * so that the destructor can be hung on tmp.
15484 if (sd
.dtor
&& sc
.func
)
15486 /* Make an identifier for the temporary of the form:
15487 * __sl%s%d, where %s is the struct name
15489 char[10] buf
= void;
15490 const prefix
= "__sl";
15491 const ident
= sd
.ident
.toString
;
15492 const fullLen
= prefix
.length
+ ident
.length
;
15493 const len
= fullLen
< buf
.length ? fullLen
: buf
.length
;
15494 buf
[0 .. prefix
.length
] = prefix
;
15495 buf
[prefix
.length
.. len
] = ident
[0 .. len
- prefix
.length
];
15497 auto tmp
= copyToTemp(0, buf
[0 .. len
], exp
);
15498 Expression ae
= new DeclarationExp(exp
.loc
, tmp
);
15499 Expression e
= new CommaExp(exp
.loc
, ae
, new VarExp(exp
.loc
, tmp
));
15500 e
= e
.expressionSemantic(sc
);
15507 Expression
visitCall(CallExp exp
)
15510 auto type
= exp
.type
;
15511 /* Only need to add dtor hook if it's a type that needs destruction.
15512 * Use same logic as VarDeclaration::callScopeDtor()
15515 if (auto tf
= e1
.type
.isTypeFunction())
15521 Type tv
= type
.baseElemOf();
15522 if (auto ts
= tv
.isTypeStruct())
15524 StructDeclaration sd
= ts
.sym
;
15527 /* Type needs destruction, so declare a tmp
15528 * which the back end will recognize and call dtor on
15530 auto tmp
= copyToTemp(0, Id
.__tmpfordtor
.toString(), exp
);
15531 auto de = new DeclarationExp(exp
.loc
, tmp
);
15532 auto ve
= new VarExp(exp
.loc
, tmp
);
15533 Expression e
= new CommaExp(exp
.loc
, de, ve
);
15534 e
= e
.expressionSemantic(sc
);
15542 Expression
visitCast(CastExp exp
)
15544 if (exp
.to
.toBasetype().ty
== Tvoid
) // look past the cast(void)
15545 exp
.e1
= exp
.e1
.addDtorHook(sc
);
15549 Expression
visitComma(CommaExp exp
)
15551 exp
.e2
= exp
.e2
.addDtorHook(sc
);
15557 default: return visit(e
);
15559 case EXP
.structLiteral
: return visitStructLiteral(e
.isStructLiteralExp());
15560 case EXP
.call: return visitCall(e
.isCallExp());
15561 case EXP
.cast_
: return visitCast(e
.isCastExp());
15562 case EXP
.comma
: return visitComma(e
.isCommaExp());
15566 /*******************************
15567 * Try to convert an expression to be an lvalue.
15569 * Give error if we're not an lvalue.
15571 * _this = expression to convert
15573 * action = for error messages, what the lvalue is needed for (e.g. take address of for `&x`, modify for `x++`)
15574 * Returns: converted expression, or `ErrorExp` on error
15576 Expression
toLvalue(Expression _this
, Scope
* sc
, const(char)* action
)
15578 return toLvalueImpl(_this
, sc
, action
, _this
);
15581 // e = original un-lowered expression for error messages, in case of recursive calls
15582 private Expression
toLvalueImpl(Expression _this
, Scope
* sc
, const(char)* action
, Expression e
)
15585 action
= "create lvalue of";
15588 Expression
visit(Expression _this
)
15590 // BinaryAssignExp does not have an EXP associated
15591 // so it's treated on the default path.
15592 // Lvalue-ness will be handled in glue :layer.
15593 if (_this
.isBinAssignExp())
15595 if (!_this
.loc
.isValid())
15598 if (e
.op
== EXP
.type
)
15599 error(_this
.loc
, "cannot %s type `%s`", action
, e
.type
.toChars());
15600 else if (e
.op
== EXP
.template_
)
15601 error(_this
.loc
, "cannot %s template `%s`, perhaps instantiate it first", action
, e
.toChars());
15603 error(_this
.loc
, "cannot %s expression `%s` because it is not an lvalue", action
, e
.toChars());
15605 return ErrorExp
.get();
15608 Expression
visitInteger(IntegerExp _this
)
15610 if (!_this
.loc
.isValid())
15612 error(e
.loc
, "cannot %s constant `%s`", action
, e
.toChars());
15613 return ErrorExp
.get();
15616 Expression
visitThis(ThisExp _this
)
15618 if (_this
.type
.toBasetype().ty
== Tclass
)
15620 // Class `this` is an rvalue; struct `this` is an lvalue.
15621 return visit(_this
);
15627 Expression
visitString(StringExp _this
)
15629 //printf("StringExp::toLvalue(%s) type = %s\n", _this.toChars(), _this.type ? _this.type.toChars() : NULL);
15630 return (_this
.type
&& _this
.type
.toBasetype().ty
== Tsarray
) ? _this
: visit(_this
);
15633 Expression
visitStructLiteral(StructLiteralExp _this
)
15635 if (sc
.flags
& SCOPE
.Cfile
)
15636 return _this
; // C struct literals are lvalues
15638 return visit(_this
);
15641 Expression
visitTemplate(TemplateExp _this
)
15644 return visit(_this
);
15647 return symbolToExp(_this
.fd
, _this
.loc
, sc
, true);
15651 Expression
visitVar(VarExp _this
)
15653 auto var
= _this
.var
;
15654 if (var
.storage_class
& STC
.manifest
)
15656 error(_this
.loc
, "cannot %s manifest constant `%s`", action
, var
.toChars());
15657 return ErrorExp
.get();
15659 if (var
.storage_class
& STC
.lazy_
&& !_this
.delegateWasExtracted
)
15661 error(_this
.loc
, "cannot %s lazy variable `%s`", action
, var
.toChars());
15662 return ErrorExp
.get();
15664 if (var
.ident
== Id
.ctfe
)
15666 error(_this
.loc
, "cannot %s compiler-generated variable `__ctfe`", action
);
15667 return ErrorExp
.get();
15669 if (var
.ident
== Id
.dollar
) // https://issues.dlang.org/show_bug.cgi?id=13574
15671 error(_this
.loc
, "cannot %s operator `$`", action
);
15672 return ErrorExp
.get();
15677 Expression
visitDotVar(DotVarExp _this
)
15679 auto e1
= _this
.e1
;
15680 auto var
= _this
.var
;
15681 //printf("DotVarExp::toLvalue(%s)\n", toChars());
15682 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
15684 /* C11 6.5.2.3-3: A postfix expression followed by the '.' or '->' operator
15685 * is an lvalue if the first expression is an lvalue.
15687 if (!e1
.isLvalue())
15688 return visit(_this
);
15690 if (!_this
.isLvalue())
15691 return visit(_this
);
15692 if (e1
.op
== EXP
.this_
&& sc
.ctorflow
.fieldinit
.length
&& !(sc
.ctorflow
.callSuper
& CSX
.any_ctor
))
15694 if (VarDeclaration vd
= var
.isVarDeclaration())
15696 auto ad
= vd
.isMember2();
15697 if (ad
&& ad
.fields
.length
== sc
.ctorflow
.fieldinit
.length
)
15699 foreach (i
, f
; ad
.fields
)
15703 if (!(sc
.ctorflow
.fieldinit
[i
].csx
& CSX
.this_ctor
))
15705 /* If the address of vd is taken, assume it is thereby initialized
15706 * https://issues.dlang.org/show_bug.cgi?id=15869
15708 modifyFieldVar(_this
.loc
, sc
, vd
, e1
);
15719 Expression
visitCall(CallExp _this
)
15721 if (_this
.isLvalue())
15723 return visit(_this
);
15726 Expression
visitCast(CastExp _this
)
15728 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
15730 /* C11 6.5.4-5: A cast does not yield an lvalue.
15732 return visit(_this
);
15734 if (_this
.isLvalue())
15736 return visit(_this
);
15739 Expression
visitVectorArray(VectorArrayExp _this
)
15741 _this
.e1
= _this
.e1
.toLvalueImpl(sc
, action
, e
);
15745 Expression
visitSlice(SliceExp _this
)
15747 //printf("SliceExp::toLvalue(%s) _this.type = %s\n", _this.toChars(), _this.type ? _this.type.toChars() : NULL);
15748 return (_this
.type
&& _this
.type
.toBasetype().ty
== Tsarray
) ? _this
: visit(_this
);
15751 Expression
visitArray(ArrayExp _this
)
15753 if (_this
.type
&& _this
.type
.toBasetype().ty
== Tvoid
)
15754 error(_this
.loc
, "`void`s have no value");
15758 Expression
visitComma(CommaExp _this
)
15760 _this
.e2
= _this
.e2
.toLvalue(sc
, action
);
15764 Expression
visitDelegatePointer(DelegatePtrExp _this
)
15766 _this
.e1
= _this
.e1
.toLvalueImpl(sc
, action
, e
);
15770 Expression
visitDelegateFuncptr(DelegateFuncptrExp _this
)
15772 _this
.e1
= _this
.e1
.toLvalueImpl(sc
, action
, e
);
15776 Expression
visitIndex(IndexExp _this
)
15778 if (_this
.isLvalue())
15780 return visit(_this
);
15783 Expression
visitAssign(AssignExp _this
)
15785 if (_this
.e1
.op
== EXP
.slice || _this
.e1
.op
== EXP
.arrayLength
)
15787 return visit(_this
);
15790 /* In front-end level, AssignExp should make an lvalue of e1.
15791 * Taking the address of e1 will be handled in low level layer,
15792 * so this function does nothing.
15797 Expression
visitCond(CondExp _this
)
15799 // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
15800 CondExp e
= cast(CondExp
)(_this
.copy());
15801 e
.e1
= _this
.e1
.toLvalue(sc
, action
).addressOf();
15802 e
.e2
= _this
.e2
.toLvalue(sc
, action
).addressOf();
15803 e
.type
= _this
.type
.pointerTo();
15804 return new PtrExp(_this
.loc
, e
, _this
.type
);
15810 default: return visit(_this
);
15812 case EXP
.int64
: return visitInteger(_this
.isIntegerExp());
15813 case EXP
.error
: return _this
;
15814 case EXP
.identifier
: return _this
;
15815 case EXP
.dSymbol
: return _this
;
15816 case EXP
.this_
: return visitThis(_this
.isThisExp());
15817 case EXP
.super_
: return visitThis(_this
.isSuperExp());
15818 case EXP
.string_
: return visitString(_this
.isStringExp());
15819 case EXP
.structLiteral
: return visitStructLiteral(_this
.isStructLiteralExp());
15820 case EXP
.template_
: return visitTemplate(_this
.isTemplateExp());
15821 case EXP
.variable
: return visitVar(_this
.isVarExp());
15822 case EXP
.overloadSet
: return _this
;
15823 case EXP
.dotVariable
: return visitDotVar(_this
.isDotVarExp());
15824 case EXP
.call: return visitCall(_this
.isCallExp());
15825 case EXP
.star
: return _this
;
15826 case EXP
.cast_
: return visitCast(_this
.isCastExp());
15827 case EXP
.vectorArray
: return visitVectorArray(_this
.isVectorArrayExp());
15828 case EXP
.slice
: return visitSlice(_this
.isSliceExp());
15829 case EXP
.array
: return visitArray(_this
.isArrayExp());
15830 case EXP
.comma
: return visitComma(_this
.isCommaExp());
15831 case EXP
.delegatePointer
: return visitDelegatePointer(_this
.isDelegatePtrExp());
15832 case EXP
.delegateFunctionPointer
: return visitDelegateFuncptr(_this
.isDelegateFuncptrExp());
15833 case EXP
.index
: return visitIndex(_this
.isIndexExp());
15834 case EXP
.construct
: return visitAssign(_this
.isConstructExp());
15835 case EXP
.loweredAssignExp
: return visitAssign(_this
.isLoweredAssignExp());
15836 case EXP
.blit
: return visitAssign(_this
.isBlitExp());
15837 case EXP
.assign
: return visitAssign(_this
.isAssignExp());
15838 case EXP
.question
: return visitCond(_this
.isCondExp());
15842 /***************************************
15845 * flag: 1: do not issue error message for invalid modification
15846 2: the exp is a DotVarExp and a subfield of the leftmost
15847 variable is modified
15849 * Whether the type is modifiable
15851 Modifiable
checkModifiable(Expression exp
, Scope
* sc
, ModifyFlags flag
= ModifyFlags
.none
)
15856 auto varExp
= cast(VarExp
)exp
;
15858 //printf("VarExp::checkModifiable %s", varExp.toChars());
15859 assert(varExp
.type
);
15860 return varExp
.var
.checkModify(varExp
.loc
, sc
, null, flag
);
15862 case EXP
.dotVariable
:
15863 auto dotVarExp
= cast(DotVarExp
)exp
;
15865 //printf("DotVarExp::checkModifiable %s %s\n", dotVarExp.toChars(), dotVarExp.type.toChars());
15866 if (dotVarExp
.e1
.op
== EXP
.this_
)
15867 return dotVarExp
.var
.checkModify(dotVarExp
.loc
, sc
, dotVarExp
.e1
, flag
);
15869 /* https://issues.dlang.org/show_bug.cgi?id=12764
15870 * If inside a constructor and an expression of type `this.field.var`
15871 * is encountered, where `field` is a struct declaration with
15872 * default construction disabled, we must make sure that
15873 * assigning to `var` does not imply that `field` was initialized
15875 if (sc
.func
&& sc
.func
.isCtorDeclaration())
15877 // if inside a constructor scope and e1 of this DotVarExp
15878 // is another DotVarExp, then check if the leftmost expression is a `this` identifier
15879 if (auto dve
= dotVarExp
.e1
.isDotVarExp())
15881 // Iterate the chain of DotVarExp to find `this`
15882 // Keep track whether access to fields was limited to union members
15883 // s.t. one can initialize an entire struct inside nested unions
15884 // (but not its members)
15885 bool onlyUnion
= true;
15888 auto v
= dve
.var
.isVarDeclaration();
15891 // Accessing union member?
15892 auto t
= v
.type
.isTypeStruct();
15893 if (!t ||
!t
.sym
.isUnionDeclaration())
15896 // Another DotVarExp left?
15897 if (!dve
.e1 || dve
.e1
.op
!= EXP
.dotVariable
)
15900 dve
= cast(DotVarExp
) dve
.e1
;
15903 if (dve
.e1
.op
== EXP
.this_
)
15905 scope v
= dve
.var
.isVarDeclaration();
15906 /* if v is a struct member field with no initializer, no default construction
15907 * and v wasn't intialized before
15909 if (v
&& v
.isField() && !v
._init
&& !v
.ctorinit
)
15911 if (auto ts
= v
.type
.isTypeStruct())
15913 if (ts
.sym
.noDefaultCtor
)
15915 /* checkModify will consider that this is an initialization
15916 * of v while it is actually an assignment of a field of v
15918 scope modifyLevel
= v
.checkModify(dotVarExp
.loc
, sc
, dve
.e1
, !onlyUnion ?
(flag | ModifyFlags
.fieldAssign
) : flag
);
15919 if (modifyLevel
== Modifiable
.initialization
)
15921 // https://issues.dlang.org/show_bug.cgi?id=22118
15922 // v is a union type field that was assigned
15923 // a variable, therefore it counts as initialization
15925 return Modifiable
.initialization
;
15927 return Modifiable
.yes
;
15929 return modifyLevel
;
15937 //printf("\te1 = %s\n", e1.toChars());
15938 return dotVarExp
.e1
.checkModifiable(sc
, flag
);
15941 auto ptrExp
= cast(PtrExp
)exp
;
15942 if (auto se
= ptrExp
.e1
.isSymOffExp())
15944 return se
.var
.checkModify(ptrExp
.loc
, sc
, null, flag
);
15946 else if (auto ae
= ptrExp
.e1
.isAddrExp())
15948 return ae
.e1
.checkModifiable(sc
, flag
);
15950 return Modifiable
.yes
;
15953 auto sliceExp
= cast(SliceExp
)exp
;
15955 //printf("SliceExp::checkModifiable %s\n", sliceExp.toChars());
15956 auto e1
= sliceExp
.e1
;
15957 if (e1
.type
.ty
== Tsarray ||
(e1
.op
== EXP
.index
&& e1
.type
.ty
!= Tarray
) || e1
.op
== EXP
.slice
)
15959 return e1
.checkModifiable(sc
, flag
);
15961 return Modifiable
.yes
;
15964 return (cast(CommaExp
)exp
).e2
.checkModifiable(sc
, flag
);
15967 auto indexExp
= cast(IndexExp
)exp
;
15968 auto e1
= indexExp
.e1
;
15969 if (e1
.type
.ty
== Tsarray ||
15970 e1
.type
.ty
== Taarray ||
15971 (e1
.op
== EXP
.index
&& e1
.type
.ty
!= Tarray
) ||
15972 e1
.op
== EXP
.slice
)
15974 return e1
.checkModifiable(sc
, flag
);
15976 return Modifiable
.yes
;
15979 auto condExp
= cast(CondExp
)exp
;
15980 if (condExp
.e1
.checkModifiable(sc
, flag
) != Modifiable
.no
15981 && condExp
.e2
.checkModifiable(sc
, flag
) != Modifiable
.no
)
15982 return Modifiable
.yes
;
15983 return Modifiable
.no
;
15986 return exp
.type ? Modifiable
.yes
: Modifiable
.no
; // default modifiable
15991 * Similar to `toLvalue`, but also enforce it is mutable or raise an error.
15993 * _this = Expression to convert
15995 * Returns: `_this` converted to an lvalue, or an `ErrorExp`
15997 Expression
modifiableLvalue(Expression _this
, Scope
* sc
)
15999 return modifiableLvalueImpl(_this
, sc
, _this
);
16002 // e = original / un-lowered expression to print in error messages
16003 private Expression
modifiableLvalueImpl(Expression _this
, Scope
* sc
, Expression e
)
16006 Expression
visit(Expression exp
)
16008 //printf("Expression::modifiableLvalue() %s, type = %s\n", exp.toChars(), exp.type.toChars());
16009 // See if this expression is a modifiable lvalue (i.e. not const)
16010 if (exp
.isBinAssignExp())
16011 return exp
.toLvalue(sc
, "modify");
16013 auto type
= exp
.type
;
16014 if (checkModifiable(exp
, sc
) == Modifiable
.yes
)
16017 if (!type
.isMutable())
16019 if (auto dve
= exp
.isDotVarExp())
16021 if (isNeedThisScope(sc
, dve
.var
))
16022 for (Dsymbol s
= sc
.func
; s
; s
= s
.toParentLocal())
16024 FuncDeclaration ff
= s
.isFuncDeclaration();
16027 if (!ff
.type
.isMutable
)
16029 error(exp
.loc
, "cannot modify `%s` in `%s` function", exp
.toChars(), MODtoChars(type
.mod
));
16030 return ErrorExp
.get();
16034 error(exp
.loc
, "cannot modify `%s` expression `%s`", MODtoChars(type
.mod
), exp
.toChars());
16035 return ErrorExp
.get();
16037 else if (!type
.isAssignable())
16039 error(exp
.loc
, "cannot modify struct instance `%s` of type `%s` because it contains `const` or `immutable` members",
16040 exp
.toChars(), type
.toChars());
16041 return ErrorExp
.get();
16044 return exp
.toLvalueImpl(sc
, "modify", e
);
16047 Expression
visitString(StringExp exp
)
16049 error(exp
.loc
, "cannot modify string literal `%s`", exp
.toChars());
16050 return ErrorExp
.get();
16053 Expression
visitVar(VarExp exp
)
16055 //printf("VarExp::modifiableLvalue('%s')\n", exp.var.toChars());
16056 if (exp
.var
.storage_class
& STC
.manifest
)
16058 error(exp
.loc
, "cannot modify manifest constant `%s`", exp
.toChars());
16059 return ErrorExp
.get();
16061 // See if this expression is a modifiable lvalue (i.e. not const)
16065 Expression
visitPtr(PtrExp exp
)
16067 //printf("PtrExp::modifiableLvalue() %s, type %s\n", exp.toChars(), exp.type.toChars());
16070 if (auto se
= e1
.isSymOffExp())
16072 else if (auto ve
= e1
.isVarExp())
16074 if (var
&& var
.type
.isFunction_Delegate_PtrToFunction())
16076 if (var
.type
.isTypeFunction())
16077 error(exp
.loc
, "function `%s` is not an lvalue and cannot be modified", var
.toChars());
16079 error(exp
.loc
, "function pointed to by `%s` is not an lvalue and cannot be modified", var
.toChars());
16080 return ErrorExp
.get();
16085 Expression
visitSlice(SliceExp exp
)
16087 error(exp
.loc
, "slice expression `%s` is not a modifiable lvalue", exp
.toChars());
16091 Expression
visitComma(CommaExp exp
)
16093 exp
.e2
= exp
.e2
.modifiableLvalueImpl(sc
, e
);
16097 Expression
visitDelegatePtr(DelegatePtrExp exp
)
16099 if (sc
.setUnsafe(false, exp
.loc
, "cannot modify delegate pointer in `@safe` code `%s`", exp
))
16101 return ErrorExp
.get();
16106 Expression
visitDelegateFuncptr(DelegateFuncptrExp exp
)
16108 if (sc
.setUnsafe(false, exp
.loc
, "cannot modify delegate function pointer in `@safe` code `%s`", exp
))
16110 return ErrorExp
.get();
16115 Expression
visitIndex(IndexExp exp
)
16117 //printf("IndexExp::modifiableLvalue(%s)\n", exp.toChars());
16118 Expression ex
= exp
.markSettingAAElem();
16119 if (ex
.op
== EXP
.error
)
16125 Expression
visitCond(CondExp exp
)
16127 if (!exp
.e1
.isLvalue() && !exp
.e2
.isLvalue())
16129 error(exp
.loc
, "conditional expression `%s` is not a modifiable lvalue", exp
.toChars());
16130 return ErrorExp
.get();
16132 exp
.e1
= exp
.e1
.modifiableLvalue(sc
);
16133 exp
.e2
= exp
.e2
.modifiableLvalue(sc
);
16134 return exp
.toLvalue(sc
, "modify");
16139 default: return visit(_this
);
16140 case EXP
.string_
: return visitString(_this
.isStringExp());
16141 case EXP
.variable
: return visitVar(_this
.isVarExp());
16142 case EXP
.star
: return visitPtr(_this
.isPtrExp());
16143 case EXP
.slice
: return visitSlice(_this
.isSliceExp());
16144 case EXP
.comma
: return visitComma(_this
.isCommaExp());
16145 case EXP
.delegatePointer
: return visitDelegatePtr(_this
.isDelegatePtrExp());
16146 case EXP
.delegateFunctionPointer
: return visitDelegateFuncptr(_this
.isDelegateFuncptrExp());
16147 case EXP
.index
: return visitIndex(_this
.isIndexExp());
16148 case EXP
.question
: return visitCond(_this
.isCondExp());
16153 /****************************************************
16154 * Determine if `exp`, which gets its address taken, can do so safely.
16157 * exp = expression having its address taken
16158 * v = the variable getting its address taken
16160 * `true` if ok, `false` for error
16162 bool checkAddressVar(Scope
* sc
, Expression exp
, VarDeclaration v
)
16164 //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars());
16168 if (!v
.canTakeAddressOf())
16170 error(exp
.loc
, "cannot take address of `%s`", exp
.toChars());
16173 if (sc
.func
&& !sc
.intypeof
&& !v
.isDataseg())
16175 if (sc
.useDIP1000
!= FeatureState
.enabled
&&
16176 !(v
.storage_class
& STC
.temp
) &&
16177 sc
.setUnsafe(false, exp
.loc
, "cannot take address of local `%s` in `@safe` function `%s`", v
, sc
.func
))
16185 /**************************************
16186 * This check ensures that the object in `exp` can have its address taken, or
16187 * issue a diagnostic error.
16189 * e = expression to check
16192 * true if the expression is addressable
16194 bool checkAddressable(Expression e
, Scope
* sc
)
16201 case EXP
.dotVariable
:
16202 // https://issues.dlang.org/show_bug.cgi?id=22749
16203 // Error about taking address of any bit-field, regardless of
16204 // whether SCOPE.Cfile is set.
16205 if (auto bf
= ex
.isDotVarExp().var
.isBitFieldDeclaration())
16207 error(e
.loc
, "cannot take address of bit-field `%s`", bf
.toChars());
16210 goto case EXP
.cast_
;
16213 ex
= ex
.isBinExp().e1
;
16219 ex
= ex
.isUnaExp().e1
;
16223 if (sc
.flags
& SCOPE
.Cfile
)
16225 // C11 6.5.3.2: A variable that has its address taken cannot be
16226 // stored in a register.
16227 // C11 6.3.2.1: An array that has its address computed with `[]`
16228 // or cast to an lvalue pointer cannot be stored in a register.
16229 if (ex
.isVarExp().var
.storage_class
& STC
.register
)
16231 if (e
.isIndexExp())
16232 error(e
.loc
, "cannot index through register variable `%s`", ex
.toChars());
16234 error(e
.loc
, "cannot take address of register variable `%s`", ex
.toChars());
16249 /*******************************
16250 * Checks the attributes of a function.
16251 * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`)
16252 * and usage of `deprecated` and `@disabled`-ed symbols are checked.
16255 * exp = expression to check attributes for
16256 * sc = scope of the function
16257 * f = function to be checked
16258 * Returns: `true` if error occur.
16260 private bool checkFunctionAttributes(Expression exp
, Scope
* sc
, FuncDeclaration f
)
16262 bool error
= f
.checkDisabled(exp
.loc
, sc
);
16263 error |
= f
.checkDeprecated(exp
.loc
, sc
);
16264 error |
= f
.checkPurity(exp
.loc
, sc
);
16265 error |
= f
.checkSafety(exp
.loc
, sc
);
16266 error |
= f
.checkNogc(exp
.loc
, sc
);
16270 /*******************************
16271 * Helper function for `getRightThis()`.
16272 * Gets `this` of the next outer aggregate.
16274 * loc = location to use for error messages
16276 * s = the parent symbol of the existing `this`
16277 * ad = struct or class we need the correct `this` for
16278 * e1 = existing `this`
16279 * t = type of the existing `this`
16280 * var = the specific member of ad we're accessing
16281 * flag = if true, return `null` instead of throwing an error
16283 * Expression representing the `this` for the var
16285 Expression
getThisSkipNestedFuncs(const ref Loc loc
, Scope
* sc
, Dsymbol s
, AggregateDeclaration ad
, Expression e1
, Type t
, Dsymbol var
, bool flag
= false)
16288 while (s
&& s
.isFuncDeclaration())
16290 FuncDeclaration f
= s
.isFuncDeclaration();
16294 e1
= new VarExp(loc
, f
.vthis
);
16295 if (f
.hasDualContext())
16299 e1
= e1
.expressionSemantic(sc
);
16300 e1
= new PtrExp(loc
, e1
);
16301 uint i
= f
.followInstantiationContext(ad
);
16302 e1
= new IndexExp(loc
, e1
, new IntegerExp(i
));
16303 s
= f
.toParentP(ad
);
16311 error(e1
.loc
, "need `this` of type `%s` to access member `%s` from static function `%s`", ad
.toChars(), var
.toChars(), f
.toChars());
16312 e1
= ErrorExp
.get();
16317 if (n
> 1 || e1
.op
== EXP
.index
)
16318 e1
= e1
.expressionSemantic(sc
);
16319 if (s
&& e1
.type
.equivalent(Type
.tvoidptr
))
16321 if (auto sad
= s
.isAggregateDeclaration())
16323 Type ta
= sad
.handleType();
16324 if (ta
.ty
== Tstruct
)
16325 ta
= ta
.pointerTo();
16329 e1
.type
= e1
.type
.addMod(t
.mod
);
16333 /*******************************
16334 * Make a dual-context container for use as a `this` argument.
16336 * loc = location to use for error messages
16337 * sc = current scope
16338 * fd = target function that will take the `this` argument
16340 * Temporary closure variable.
16342 * The function `fd` is added to the nested references of the
16343 * newly created variable such that a closure is made for the variable when
16344 * the address of `fd` is taken.
16346 VarDeclaration
makeThis2Argument(const ref Loc loc
, Scope
* sc
, FuncDeclaration fd
)
16348 Type tthis2
= Type
.tvoidptr
.sarrayOf(2);
16349 VarDeclaration vthis2
= new VarDeclaration(loc
, tthis2
, Identifier
.generateId("__this"), null);
16350 vthis2
.storage_class |
= STC
.temp
;
16351 vthis2
.dsymbolSemantic(sc
);
16352 vthis2
.parent
= sc
.parent
;
16353 // make it a closure var
16355 sc
.func
.closureVars
.push(vthis2
);
16356 // add `fd` to the nested refs
16357 vthis2
.nestedrefs
.push(fd
);
16361 /*******************************
16362 * Make sure that the runtime hook `id` exists.
16364 * loc = location to use for error messages
16365 * sc = current scope
16366 * id = the hook identifier
16367 * description = what the hook does
16368 * module_ = what module the hook is located in
16370 * a `bool` indicating if the hook is present.
16372 bool verifyHookExist(const ref Loc loc
, ref Scope sc
, Identifier id
, string description
, Identifier module_
= Id
.object
)
16375 auto rootSymbol
= sc
.search(loc
, Id
.empty
, pscopesym
);
16376 if (auto moduleSymbol
= rootSymbol
.search(loc
, module_
))
16377 if (moduleSymbol
.search(loc
, id
))
16379 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
);
16383 /***************************************
16384 * Fit elements[] to the corresponding types of the `sd`'s fields.
16387 * sd = the struct declaration
16388 * loc = location to use for error messages
16390 * elements = explicit arguments used to construct object
16391 * stype = the constructed object type.
16393 * false if any errors occur,
16394 * otherwise true and elements[] are rewritten for the output.
16396 private bool fit(StructDeclaration sd
, const ref Loc loc
, Scope
* sc
, Expressions
* elements
, Type stype
)
16401 const nfields
= sd
.nonHiddenFields();
16403 for (size_t i
= 0; i
< elements
.length
; i
++)
16405 Expression e
= (*elements
)[i
];
16409 e
= resolveProperties(sc
, e
);
16412 if (i
< sd
.fields
.length
&& e
.op
== EXP
.null_
)
16414 // CTFE sometimes creates null as hidden pointer; we'll allow this.
16417 .error(loc
, "more initializers than fields (%llu) of `%s`", cast(ulong)nfields
, sd
.toChars());
16420 VarDeclaration v
= sd
.fields
[i
];
16421 if (v
.offset
< offset
)
16423 .error(loc
, "overlapping initialization for `%s`", v
.toChars());
16424 if (!sd
.isUnionDeclaration())
16426 enum errorMsg
= "`struct` initializers that contain anonymous unions" ~
16427 " must initialize only the first member of a `union`. All subsequent" ~
16428 " non-overlapping fields are default initialized";
16429 .errorSupplemental(loc
, errorMsg
);
16433 const vsize
= v
.type
.size();
16434 if (vsize
== SIZE_INVALID
)
16436 offset
= cast(uint)(v
.offset
+ vsize
);
16440 t
= t
.addMod(stype
.mod
);
16442 Type tb
= t
.toBasetype();
16444 const hasPointers
= tb
.hasPointers();
16447 if ((!stype
.alignment
.isDefault() && stype
.alignment
.get() < target
.ptrsize ||
16448 (v
.offset
& (target
.ptrsize
- 1))) &&
16449 (sc
.setUnsafe(false, loc
,
16450 "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd
, v
)))
16456 /* Look for case of initializing a static array with a too-short
16457 * string literal, such as:
16458 * char[5] foo = "abc";
16459 * Allow this by doing an explicit cast, which will lengthen the string
16462 if (e
.op
== EXP
.string_
&& tb
.ty
== Tsarray
)
16464 StringExp se
= cast(StringExp
)e
;
16465 Type typeb
= se
.type
.toBasetype();
16466 TY tynto
= tb
.nextOf().ty
;
16467 if (!se
.committed
&&
16468 (typeb
.ty
== Tarray || typeb
.ty
== Tsarray
) && tynto
.isSomeChar
&&
16469 se
.numberOfCodeUnits(tynto
) < (cast(TypeSArray
)tb
).dim
.toInteger())
16471 e
= se
.castTo(sc
, t
);
16476 while (!e
.implicitConvTo(t
) && tb
.ty
== Tsarray
)
16478 /* Static array initialization, as in:
16482 tb
= t
.toBasetype();
16484 if (!e
.implicitConvTo(t
))
16485 t
= origType
; // restore type for better diagnostic
16487 e
= e
.implicitCastTo(sc
, t
);
16489 if (e
.op
== EXP
.error
)
16492 (*elements
)[i
] = doCopyOrMove(sc
, e
);
16499 * Returns `em` as a VariableExp
16501 * em = the EnumMember to wrap
16502 * loc = location of use of em
16503 * sc = scope of use of em
16505 * VarExp referenceing `em` or ErrorExp if `em` if disabled/deprecated
16507 Expression
getVarExp(EnumMember em
, const ref Loc loc
, Scope
* sc
)
16509 dsymbolSemantic(em
, sc
);
16511 return ErrorExp
.get();
16512 em
.checkDisabled(loc
, sc
);
16514 if (em
.depdecl
&& !em
.depdecl
._scope
)
16516 em
.depdecl
._scope
= sc
;
16517 em
.depdecl
._scope
.setNoFree();
16519 em
.checkDeprecated(loc
, sc
);
16522 return ErrorExp
.get();
16523 Expression e
= new VarExp(loc
, em
);
16524 e
= e
.expressionSemantic(sc
);
16525 if (!(sc
.flags
& SCOPE
.Cfile
) && em
.isCsymbol())
16527 /* C11 types them as int. But if in D file,
16528 * type qualified names as the enum
16530 e
.type
= em
.parent
.isEnumDeclaration().type
;
16537 /*****************************
16538 * Try to treat `exp` as a boolean,
16540 * exp = the expression
16541 * sc = scope to evalute `exp` in
16543 * Modified expression on success, ErrorExp on error
16545 Expression
toBoolean(Expression exp
, Scope
* sc
)
16550 error(exp
.loc
, "`delete` does not give a boolean result");
16551 return ErrorExp
.get();
16554 auto ce
= exp
.isCommaExp();
16555 auto ex2
= ce
.e2
.toBoolean(sc
);
16556 if (ex2
.op
== EXP
.error
)
16559 ce
.type
= ce
.e2
.type
;
16563 case EXP
.construct
:
16565 case EXP
.loweredAssignExp
:
16566 if (sc
.flags
& SCOPE
.Cfile
)
16570 // are usually mistakes.
16571 error(exp
.loc
, "assignment cannot be used as a condition, perhaps `==` was meant?");
16572 return ErrorExp
.get();
16577 auto le
= exp
.isLogicalExp();
16578 auto ex2
= le
.e2
.toBoolean(sc
);
16579 if (ex2
.op
== EXP
.error
)
16585 auto ce
= exp
.isCondExp();
16586 auto ex1
= ce
.e1
.toBoolean(sc
);
16587 auto ex2
= ce
.e2
.toBoolean(sc
);
16588 if (ex1
.op
== EXP
.error
)
16590 if (ex2
.op
== EXP
.error
)
16598 // Default is 'yes' - do nothing
16599 Expression e
= arrayFuncConv(exp
, sc
);
16601 Type tb
= t
.toBasetype();
16606 // Structs can be converted to bool using opCast(bool)()
16607 if (auto ts
= tb
.isTypeStruct())
16609 AggregateDeclaration ad
= ts
.sym
;
16610 /* Don't really need to check for opCast first, but by doing so we
16611 * get better error messages if it isn't there.
16613 if (Dsymbol fd
= search_function(ad
, Id
._cast
))
16615 e
= new CastExp(exp
.loc
, e
, Type
.tbool
);
16616 e
= e
.expressionSemantic(sc
);
16620 // Forward to aliasthis.
16621 if (ad
.aliasthis
&& !isRecursiveAliasThis(att
, tb
))
16623 e
= resolveAliasThis(sc
, e
);
16625 tb
= e
.type
.toBasetype();
16632 if (!t
.isBoolean())
16634 if (tb
!= Type
.terror
)
16635 error(exp
.loc
, "expression `%s` of type `%s` does not have a boolean value",
16636 exp
.toChars(), t
.toChars());
16637 return ErrorExp
.get();
16643 /********************************************
16644 * Semantically analyze and then evaluate a static condition at compile time.
16645 * This is special because short circuit operators &&, || and ?: at the top
16646 * level are not semantically analyzed if the result of the expression is not
16649 * sc = instantiating scope
16650 * original = original expression, for error messages
16651 * e = resulting expression
16652 * errors = set to `true` if errors occurred
16653 * negatives = array to store negative clauses
16655 * true if evaluates to true
16657 bool evalStaticCondition(Scope
* sc
, Expression original
, Expression e
, out bool errors
, Expressions
* negatives
= null)
16660 negatives
.setDim(0);
16662 bool impl(Expression e
)
16666 NotExp ne
= cast(NotExp
)e
;
16667 return !impl(ne
.e1
);
16670 if (e
.op
== EXP
.andAnd || e
.op
== EXP
.orOr
)
16672 LogicalExp aae
= cast(LogicalExp
)e
;
16673 bool result
= impl(aae
.e1
);
16676 if (e
.op
== EXP
.andAnd
)
16686 result
= impl(aae
.e2
);
16687 return !errors
&& result
;
16690 if (e
.op
== EXP
.question
)
16692 CondExp ce
= cast(CondExp
)e
;
16693 bool result
= impl(ce
.econd
);
16696 Expression leg
= result ? ce
.e1
: ce
.e2
;
16697 result
= impl(leg
);
16698 return !errors
&& result
;
16701 Expression before
= e
;
16702 const uint nerrors
= global
.errors
;
16704 sc
= sc
.startCTFE();
16705 sc
.flags |
= SCOPE
.condition
;
16707 e
= e
.expressionSemantic(sc
);
16708 e
= resolveProperties(sc
, e
);
16709 e
= e
.toBoolean(sc
);
16712 e
= e
.optimize(WANTvalue
);
16714 if (nerrors
!= global
.errors ||
16716 e
.type
.toBasetype() == Type
.terror
)
16722 e
= e
.ctfeInterpret();
16724 const opt
= e
.toBool();
16727 if (!e
.type
.isTypeError())
16728 error(e
.loc
, "expression `%s` is not constant", e
.toChars());
16733 if (negatives
&& !opt
.get())
16734 negatives
.push(before
);