2 * Semantic analysis of expressions.
4 * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions)
6 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expressionsem.d, _expressionsem.d)
10 * Documentation: https://dlang.org/phobos/dmd_expressionsem.html
11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/expressionsem.d
14 module dmd
.expressionsem
;
16 import core
.stdc
.stdio
;
22 import dmd
.arraytypes
;
24 import dmd
.astcodegen
;
31 import dmd
.declaration
;
34 import dmd
.delegatize
;
37 import dmd
.dinterpret
;
41 import dmd
.dsymbolsem
;
45 import dmd
.expression
;
46 import dmd
.file_manager
;
51 import dmd
.identifier
;
66 import dmd
.root
.array
;
67 import dmd
.root
.ctfloat
;
68 import dmd
.root
.filename
;
69 import dmd
.common
.outbuffer
;
70 import dmd
.root
.rootobject
;
71 import dmd
.root
.string
;
75 import dmd
.sideeffect
;
85 enum LOGSEMANTIC
= false;
87 /********************************************************
88 * Perform semantic analysis and CTFE on expressions to produce
91 * buf = append generated string to buffer
93 * exps = array of Expressions
97 bool expressionsToString(ref OutBuffer buf
, Scope
* sc
, Expressions
* exps
)
106 auto sc2
= sc
.startCTFE();
108 sc2
.minst
= null; // prevents emission of any instantiated templates to object file
109 auto e2
= ex
.expressionSemantic(sc2
);
110 auto e3
= resolveProperties(sc2
, e2
);
113 // allowed to contain types as well as expressions
114 auto e4
= ctfeInterpretForPragmaMsg(e3
);
115 if (!e4 || e4
.op
== EXP
.error
)
119 if (auto te
= e4
.isTupleExp())
121 if (expressionsToString(buf
, sc
, te
.exps
))
125 // char literals exp `.toStringExp` return `null` but we cant override it
126 // because in most contexts we don't want the conversion to succeed.
127 IntegerExp ie
= e4
.isIntegerExp();
128 const ty
= (ie
&& ie
.type
) ? ie
.type
.ty
: Terror
;
131 auto tsa
= new TypeSArray(ie
.type
, IntegerExp
.literal
!1);
132 e4
= new ArrayLiteralExp(ex
.loc
, tsa
, ie
);
135 if (StringExp se
= e4
.toStringExp())
136 buf
.writestring(se
.toUTF8(sc
).peekString());
138 buf
.writestring(e4
.toString());
144 /***********************************************************
145 * Resolve `exp` as a compile-time known string.
148 * exp = Expression which expected as a string
149 * s = What the string is expected for, will be used in error diagnostic.
151 * String literal, or `null` if error happens.
153 StringExp
semanticString(Scope
*sc
, Expression exp
, const char* s
)
156 exp
= exp
.expressionSemantic(sc
);
157 exp
= resolveProperties(sc
, exp
);
160 if (exp
.op
== EXP
.error
)
164 if (exp
.type
.isString())
166 e
= e
.ctfeInterpret();
167 if (e
.op
== EXP
.error
)
171 auto se
= e
.toStringExp();
174 exp
.error("`string` expected for %s, not `(%s)` of type `%s`",
175 s
, exp
.toChars(), exp
.type
.toChars());
181 private Expression
extractOpDollarSideEffect(Scope
* sc
, UnaExp ue
)
184 Expression e1
= Expression
.extractLast(ue
.e1
, e0
);
185 // https://issues.dlang.org/show_bug.cgi?id=12585
186 // Extract the side effect part if ue.e1 is comma.
188 if ((sc
.flags
& SCOPE
.ctfe
) ?
hasSideEffect(e1
) : !isTrivialExp(e1
)) // match logic in extractSideEffect()
190 /* Even if opDollar is needed, 'e1' should be evaluate only once. So
192 * e1.opIndex( ... use of $ ... )
193 * e1.opSlice( ... use of $ ... )
195 * (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...)
196 * (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
198 e1
= extractSideEffect(sc
, "__dop", e0
, e1
, false);
199 assert(e1
.isVarExp());
200 e1
.isVarExp().var
.storage_class |
= STC
.exptemp
; // lifetime limited to expression
206 /**************************************
207 * Runs semantic on ae.arguments. Declares temporary variables
210 Expression
resolveOpDollar(Scope
* sc
, ArrayExp ae
, Expression
* pe0
)
212 assert(!ae
.lengthVar
);
214 AggregateDeclaration ad
= isAggregate(ae
.e1
.type
);
215 Dsymbol slice
= search_function(ad
, Id
.slice
);
216 //printf("slice = %s %s\n", slice.kind(), slice.toChars());
217 foreach (i
, e
; *ae
.arguments
)
220 *pe0
= extractOpDollarSideEffect(sc
, ae
);
222 if (e
.op
== EXP
.interval
&& !(slice
&& slice
.isTemplateDeclaration()))
225 if (ae
.arguments
.length
== 1)
227 ae
.error("multi-dimensional slicing requires template `opSlice`");
228 return ErrorExp
.get();
230 //printf("[%d] e = %s\n", i, e.toChars());
232 // Create scope for '$' variable for this dimension
233 auto sym
= new ArrayScopeSymbol(sc
, ae
);
234 sym
.parent
= sc
.scopesym
;
236 ae
.lengthVar
= null; // Create it only if required
237 ae
.currentDimension
= i
; // Dimension for $, if required
239 e
= e
.expressionSemantic(sc
);
240 e
= resolveProperties(sc
, e
);
242 if (ae
.lengthVar
&& sc
.func
)
244 // If $ was used, declare it now
245 Expression
de = new DeclarationExp(ae
.loc
, ae
.lengthVar
);
246 de = de.expressionSemantic(sc
);
247 *pe0
= Expression
.combine(*pe0
, de);
251 if (auto ie
= e
.isIntervalExp())
253 auto tiargs
= new Objects();
254 Expression edim
= new IntegerExp(ae
.loc
, i
, Type
.tsize_t
);
255 edim
= edim
.expressionSemantic(sc
);
258 auto fargs
= new Expressions(2);
259 (*fargs
)[0] = ie
.lwr
;
260 (*fargs
)[1] = ie
.upr
;
262 uint xerrors
= global
.startGagging();
264 FuncDeclaration fslice
= resolveFuncCall(ae
.loc
, sc
, slice
, tiargs
, ae
.e1
.type
, ArgumentList(fargs
), FuncResolveFlag
.quiet
);
266 global
.endGagging(xerrors
);
270 e
= new DotTemplateInstanceExp(ae
.loc
, ae
.e1
, slice
.ident
, tiargs
);
271 e
= new CallExp(ae
.loc
, e
, fargs
);
272 e
= e
.expressionSemantic(sc
);
277 ae
.error("`%s` has no value", e
.toChars());
280 if (e
.op
== EXP
.error
)
283 (*ae
.arguments
)[i
] = e
;
288 /**************************************
289 * Runs semantic on se.lwr and se.upr. Declares a temporary variable
292 * ae, or ErrorExp if errors occurred
294 Expression
resolveOpDollar(Scope
* sc
, ArrayExp ae
, IntervalExp ie
, Expression
* pe0
)
296 //assert(!ae.lengthVar);
300 VarDeclaration lengthVar
= ae
.lengthVar
;
303 // create scope for '$'
304 auto sym
= new ArrayScopeSymbol(sc
, ae
);
305 sym
.parent
= sc
.scopesym
;
308 Expression
sem(Expression e
)
310 e
= e
.expressionSemantic(sc
);
311 e
= resolveProperties(sc
, e
);
314 ae
.error("`%s` has no value", e
.toChars());
320 ie
.lwr
= sem(ie
.lwr
);
321 ie
.upr
= sem(ie
.upr
);
323 if (ie
.lwr
.isErrorExp() || ie
.upr
.isErrorExp())
326 if (lengthVar
!= ae
.lengthVar
&& sc
.func
)
328 // If $ was used, declare it now
329 Expression
de = new DeclarationExp(ae
.loc
, ae
.lengthVar
);
330 de = de.expressionSemantic(sc
);
331 *pe0
= Expression
.combine(*pe0
, de);
336 return errors ? ErrorExp
.get() : ae
;
339 /******************************
340 * Perform semantic() on an array of Expressions.
342 extern(D
) bool arrayExpressionSemantic(
343 Expression
[] exps
, Scope
* sc
, bool preserveErrors
= false)
346 foreach (ref e
; exps
)
348 if (e
is null) continue;
349 auto e2
= e
.expressionSemantic(sc
);
350 if (e2
.op
== EXP
.error
)
352 if (preserveErrors || e2
.op
!= EXP
.error
)
359 Checks if `exp` contains a direct access to a `noreturn`
360 variable. If that is the case, an `assert(0)` expression
361 is generated and returned. This function should be called
362 only after semantic analysis has been performed on `exp`.
365 exp = expression that is checked
368 An `assert(0)` expression if `exp` contains a `noreturn`
369 variable access, `exp` otherwise.
372 Expression
checkNoreturnVarAccess(Expression exp
)
376 Expression result
= exp
;
377 if (exp
.type
.isTypeNoreturn() && !exp
.isAssertExp() &&
378 !exp
.isThrowExp() && !exp
.isCallExp())
380 auto msg
= new StringExp(exp
.loc
, "Accessed expression of type `noreturn`");
381 msg
.type
= Type
.tstring
;
382 result
= new AssertExp(exp
.loc
, IntegerExp
.literal
!0, msg
);
383 result
.type
= exp
.type
;
389 /******************************
390 * Find symbol in accordance with the UFCS name look up rule
392 private Expression
searchUFCS(Scope
* sc
, UnaExp ue
, Identifier ident
)
394 //printf("searchUFCS(ident = %s)\n", ident.toChars());
397 // TODO: merge with Scope.search.searchScopes()
398 Dsymbol
searchScopes(int flags
)
401 for (Scope
* scx
= sc
; scx
; scx
= scx
.enclosing
)
405 if (scx
.scopesym
.isModule())
406 flags |
= SearchUnqualifiedModule
; // tell Module.search() that SearchLocalsOnly is to be obeyed
407 s
= scx
.scopesym
.search(loc
, ident
, flags
);
410 // overload set contains only module scope symbols.
411 if (s
.isOverloadSet())
413 // selective/renamed imports also be picked up
414 if (AliasDeclaration ad
= s
.isAliasDeclaration())
419 // See only module scope symbols for UFCS target.
420 Dsymbol p
= s
.toParent2();
421 if (p
&& p
.isModule())
426 // Stop when we hit a module, but keep going if that is not just under the global scope
427 if (scx
.scopesym
.isModule() && !(scx
.enclosing
&& !scx
.enclosing
.enclosing
))
436 if (sc
.flags
& SCOPE
.ignoresymbolvisibility
)
437 flags |
= IgnoreSymbolVisibility
;
439 // First look in local scopes
440 s
= searchScopes(flags | SearchLocalsOnly
);
443 // Second look in imported modules
444 s
= searchScopes(flags | SearchImportsOnly
);
448 return ue
.e1
.type
.getProperty(sc
, loc
, ident
, 0, ue
.e1
);
450 FuncDeclaration f
= s
.isFuncDeclaration();
453 TemplateDeclaration td
= getFuncTemplateDecl(f
);
462 if (auto dti
= ue
.isDotTemplateInstanceExp())
464 // https://issues.dlang.org/show_bug.cgi?id=23968
465 // Typically, deprecated alias declarations are caught
466 // when `TemplateInstance.findTempDecl` is called,
467 // however, in this case the tempdecl field is updated
468 // therefore `findTempDecl` will return immediately
469 // and not get the chance to issue the deprecation.
470 if (s
.isAliasDeclaration())
471 s
.checkDeprecated(ue
.loc
, sc
);
473 auto ti
= new TemplateInstance(loc
, s
.ident
, dti
.ti
.tiargs
);
474 if (!ti
.updateTempDecl(sc
, s
))
475 return ErrorExp
.get();
476 return new ScopeExp(loc
, ti
);
480 //printf("-searchUFCS() %s\n", s.toChars());
481 return new DsymbolExp(loc
, s
);
485 /******************************
486 * Pull out callable entity with UFCS.
488 private Expression
resolveUFCS(Scope
* sc
, CallExp ce
)
494 if (auto die
= ce
.e1
.isDotIdExp())
496 Identifier ident
= die
.ident
;
498 Expression ex
= die
.dotIdSemanticPropX(sc
);
506 Type t
= eleft
.type
.toBasetype();
507 if (t
.ty
== Tarray || t
.ty
== Tsarray || t
.ty
== Tnull ||
(t
.isTypeBasic() && t
.ty
!= Tvoid
))
509 /* Built-in types and arrays have no callable properties, so do shortcut.
510 * It is necessary in: e.init()
513 else if (t
.ty
== Taarray
)
515 if (ident
== Id
.remove
)
518 * aa.remove(arg) into delete aa[arg]
520 if (!ce
.arguments || ce
.arguments
.length
!= 1)
522 ce
.error("expected key as argument to `aa.remove()`");
523 return ErrorExp
.get();
525 if (!eleft
.type
.isMutable())
527 ce
.error("cannot remove key from `%s` associative array `%s`", MODtoChars(t
.mod
), eleft
.toChars());
528 return ErrorExp
.get();
530 Expression key
= (*ce
.arguments
)[0];
531 key
= key
.expressionSemantic(sc
);
532 key
= resolveProperties(sc
, key
);
534 TypeAArray taa
= t
.isTypeAArray();
535 key
= key
.implicitCastTo(sc
, taa
.index
);
537 if (key
.checkValue() || key
.checkSharedAccess(sc
))
538 return ErrorExp
.get();
540 semanticTypeInfo(sc
, taa
.index
);
542 return new RemoveExp(loc
, eleft
, key
);
547 if (Expression ey
= die
.dotIdSemanticProp(sc
, 1))
549 if (ey
.op
== EXP
.error
)
552 if (isDotOpDispatch(ey
))
554 // even opDispatch and UFCS must have valid arguments,
555 // so now that we've seen indication of a problem,
556 // check them for issues.
557 Expressions
* originalArguments
= Expression
.arraySyntaxCopy(ce
.arguments
);
559 uint errors
= global
.startGagging();
560 e
= ce
.expressionSemantic(sc
);
561 if (!global
.endGagging(errors
))
564 if (arrayExpressionSemantic(originalArguments
.peekSlice(), sc
))
565 return ErrorExp
.get();
567 /* fall down to UFCS */
574 /* https://issues.dlang.org/show_bug.cgi?id=13953
576 * If a struct has an alias this to an associative array
577 * and remove is used on a struct instance, we have to
578 * check first if there is a remove function that can be called
579 * on the struct. If not we must check the alias this.
593 const errors
= global
.startGagging();
594 e
= searchUFCS(sc
, die
, ident
);
595 // if there were any errors and the identifier was remove
596 if (global
.endGagging(errors
))
598 if (ident
== Id
.remove
)
601 Expression alias_e
= resolveAliasThis(sc
, die
.e1
, 1);
602 if (alias_e
&& alias_e
!= die
.e1
)
605 CallExp ce2
= ce
.syntaxCopy();
607 e
= ce2
.isCallExp().trySemantic(sc
);
612 // if alias this did not work out, print the initial errors
613 searchUFCS(sc
, die
, ident
);
616 else if (auto dti
= ce
.e1
.isDotTemplateInstanceExp())
618 if (Expression ey
= dti
.dotTemplateSemanticProp(sc
, DotExpFlag
.gag
))
624 e
= searchUFCS(sc
, dti
, dti
.ti
.name
);
632 ce
.arguments
= new Expressions();
633 ce
.arguments
.shift(eleft
);
635 ce
.names
= new Identifiers();
636 ce
.names
.shift(null);
637 ce
.isUfcsRewrite
= true;
641 /******************************
642 * Pull out property with UFCS.
644 private Expression
resolveUFCSProperties(Scope
* sc
, Expression e1
, Expression e2
= null)
650 if (auto die
= e1
.isDotIdExp())
653 e
= searchUFCS(sc
, die
, die
.ident
);
655 else if (auto dti
= e1
.isDotTemplateInstanceExp())
658 e
= searchUFCS(sc
, dti
, dti
.ti
.name
);
669 // run semantic without gagging
670 e2
= e2
.expressionSemantic(sc
);
674 Expression ex
= e
.copy();
675 auto a1
= new Expressions(1);
677 ex
= new CallExp(loc
, ex
, a1
);
678 auto e1PassSemantic
= ex
.trySemantic(sc
);
682 auto a2
= new Expressions(2);
685 e
= new CallExp(loc
, e
, a2
);
686 e
= e
.trySemantic(sc
);
687 if (!e1PassSemantic
&& !e
)
689 /* https://issues.dlang.org/show_bug.cgi?id=20448
691 * If both versions have failed to pass semantic,
692 * f(e1) = e2 gets priority in error printing
693 * because f might be a templated function that
694 * failed to instantiate and we have to print
695 * the instantiation errors.
697 return e1
.expressionSemantic(sc
);
701 ex
= new AssignExp(loc
, ex
, e2
);
702 return ex
.expressionSemantic(sc
);
706 // strict setter prints errors if fails
707 e
= e
.expressionSemantic(sc
);
715 auto arguments
= new Expressions(1);
716 (*arguments
)[0] = eleft
;
717 e
= new CallExp(loc
, e
, arguments
);
719 // https://issues.dlang.org/show_bug.cgi?id=24017
720 if (sc
.flags
& SCOPE
.debug_
)
721 e
.isCallExp().inDebugStatement
= true;
723 e
= e
.expressionSemantic(sc
);
728 /******************************
729 * If e1 is a property function (template), resolve it.
731 Expression
resolvePropertiesOnly(Scope
* sc
, Expression e1
)
733 //printf("e1 = %s %s\n", Token.toChars(e1.op), e1.toChars());
735 Expression
handleOverloadSet(OverloadSet os
)
740 auto fd
= s
.isFuncDeclaration();
741 auto td
= s
.isTemplateDeclaration();
744 if (fd
.type
.isTypeFunction().isproperty
)
745 return resolveProperties(sc
, e1
);
747 else if (td
&& td
.onemember
&& (fd
= td
.onemember
.isFuncDeclaration()) !is null)
749 if (fd
.type
.isTypeFunction().isproperty ||
750 (fd
.storage_class2
& STC
.property
) ||
751 (td
._scope
.stc & STC
.property
))
752 return resolveProperties(sc
, e1
);
758 Expression
handleTemplateDecl(TemplateDeclaration td
)
763 if (auto fd
= td
.onemember
.isFuncDeclaration())
765 if (fd
.type
.isTypeFunction().isproperty ||
766 (fd
.storage_class2
& STC
.property
) ||
767 (td
._scope
.stc & STC
.property
))
768 return resolveProperties(sc
, e1
);
774 Expression
handleFuncDecl(FuncDeclaration fd
)
777 if (fd
.type
.isTypeFunction().isproperty
)
778 return resolveProperties(sc
, e1
);
782 if (auto de = e1
.isDotExp())
784 if (auto os
= de.e2
.isOverExp())
785 return handleOverloadSet(os
.vars
);
787 else if (auto oe
= e1
.isOverExp())
788 return handleOverloadSet(oe
.vars
);
789 else if (auto dti
= e1
.isDotTemplateInstanceExp())
792 if (auto td
= dti
.ti
.tempdecl
.isTemplateDeclaration())
793 return handleTemplateDecl(td
);
795 else if (auto dte
= e1
.isDotTemplateExp())
796 return handleTemplateDecl(dte
.td
);
797 else if (auto se
= e1
.isScopeExp())
800 TemplateInstance ti
= s
.isTemplateInstance();
801 if (ti
&& !ti
.semanticRun
&& ti
.tempdecl
)
802 if (auto td
= ti
.tempdecl
.isTemplateDeclaration())
803 return handleTemplateDecl(td
);
805 else if (auto et
= e1
.isTemplateExp())
806 return handleTemplateDecl(et
.td
);
807 else if (e1
.isDotVarExp() && e1
.type
.isTypeFunction())
809 DotVarExp dve
= e1
.isDotVarExp();
810 return handleFuncDecl(dve
.var
.isFuncDeclaration());
812 else if (e1
.isVarExp() && e1
.type
&& e1
.type
.isTypeFunction() && (sc
.intypeof ||
!e1
.isVarExp().var
.needThis()))
813 return handleFuncDecl(e1
.isVarExp().var
.isFuncDeclaration());
817 /****************************************
818 * Turn symbol `s` into the expression it represents.
821 * s = symbol to resolve
822 * loc = location of use of `s`
824 * hasOverloads = applies if `s` represents a function.
825 * true means it's overloaded and will be resolved later,
826 * false means it's the exact function symbol.
828 * `s` turned into an expression, `ErrorExp` if an error occurred
830 Expression
symbolToExp(Dsymbol s
, const ref Loc loc
, Scope
*sc
, bool hasOverloads
)
832 static if (LOGSEMANTIC
)
834 printf("DsymbolExp::resolve(%s %s)\n", s
.kind(), s
.toChars());
840 //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars());
841 //printf("s = '%s', s.kind = '%s'\n", s.toChars(), s.kind());
843 Declaration d
= s
.isDeclaration();
844 if (d
&& (d
.storage_class
& STC
.templateparameter
))
850 // functions are checked after overloading
851 // templates are checked after matching constraints
852 if (!s
.isFuncDeclaration() && !s
.isTemplateDeclaration())
854 s
.checkDeprecated(loc
, sc
);
856 d
.checkDisabled(loc
, sc
);
859 // https://issues.dlang.org/show_bug.cgi?id=12023
860 // if 's' is a tuple variable, the tuple is returned.
863 //printf("s = '%s', s.kind = '%s', s.needThis() = %p\n", s.toChars(), s.kind(), s.needThis());
864 if (s
!= olds
&& !s
.isFuncDeclaration() && !s
.isTemplateDeclaration())
866 s
.checkDeprecated(loc
, sc
);
868 d
.checkDisabled(loc
, sc
);
871 if (auto sd
= s
.isDeclaration())
875 if (sc
.setUnsafePreview(global
.params
.systemVariables
, false, loc
,
876 "cannot access `@system` variable `%s` in @safe code", sd
))
878 return ErrorExp
.get();
884 if (auto em
= s
.isEnumMember())
886 return em
.getVarExp(loc
, sc
);
888 if (auto v
= s
.isVarDeclaration())
890 //printf("Identifier '%s' is a variable, type '%s'\n", s.toChars(), v.type.toChars());
891 if (sc
.intypeof
== 1 && !v
.inuse
)
892 v
.dsymbolSemantic(sc
);
893 if (!v
.type ||
// during variable type inference
894 !v
.type
.deco
&& v
.inuse
) // during variable type semantic
896 if (v
.inuse
) // variable type depends on the variable itself
897 error(loc
, "circular reference to %s `%s`", v
.kind(), v
.toPrettyChars());
898 else // variable type cannot be determined
899 error(loc
, "forward reference to %s `%s`", v
.kind(), v
.toPrettyChars());
900 return ErrorExp
.get();
902 if (v
.type
.ty
== Terror
)
903 return ErrorExp
.get();
905 if ((v
.storage_class
& STC
.manifest
) && v
._init
)
909 error(loc
, "circular initialization of %s `%s`", v
.kind(), v
.toPrettyChars());
910 return ErrorExp
.get();
912 e
= v
.expandInitializer(loc
);
914 e
= e
.expressionSemantic(sc
);
919 // We need to run semantics to correctly set 'STC.field' if it is a member variable
920 // that could be forward referenced. This is needed for 'v.needThis()' to work
922 v
.dsymbolSemantic(sc
);
924 // Change the ancestor lambdas to delegate before hasThis(sc) call.
925 if (v
.checkNestedReference(sc
, loc
))
926 return ErrorExp
.get();
928 if (v
.needThis() && hasThis(sc
))
929 e
= new DotVarExp(loc
, new ThisExp(loc
), v
);
931 e
= new VarExp(loc
, v
);
932 e
= e
.expressionSemantic(sc
);
935 if (auto fld = s
.isFuncLiteralDeclaration())
937 //printf("'%s' is a function literal\n", fld.toChars());
938 e
= new FuncExp(loc
, fld);
939 return e
.expressionSemantic(sc
);
941 if (auto f
= s
.isFuncDeclaration())
944 if (!f
.functionSemantic())
945 return ErrorExp
.get();
947 if (!hasOverloads
&& f
.checkForwardRef(loc
))
948 return ErrorExp
.get();
950 auto fd
= s
.isFuncDeclaration();
952 return new VarExp(loc
, fd
, hasOverloads
);
954 if (OverDeclaration od
= s
.isOverDeclaration())
956 e
= new VarExp(loc
, od
, true);
960 if (OverloadSet o
= s
.isOverloadSet())
962 //printf("'%s' is an overload set\n", o.toChars());
963 return new OverExp(loc
, o
);
966 if (Import imp
= s
.isImport())
970 .error(loc
, "forward reference of import `%s`", imp
.toChars());
971 return ErrorExp
.get();
973 auto ie
= new ScopeExp(loc
, imp
.pkg
);
974 return ie
.expressionSemantic(sc
);
976 if (Package pkg
= s
.isPackage())
978 auto ie
= new ScopeExp(loc
, pkg
);
979 return ie
.expressionSemantic(sc
);
981 if (Module mod
= s
.isModule())
983 auto ie
= new ScopeExp(loc
, mod
);
984 return ie
.expressionSemantic(sc
);
986 if (Nspace ns
= s
.isNspace())
988 auto ie
= new ScopeExp(loc
, ns
);
989 return ie
.expressionSemantic(sc
);
992 if (Type t
= s
.getType())
994 return (new TypeExp(loc
, t
)).expressionSemantic(sc
);
997 if (TupleDeclaration tup
= s
.isTupleDeclaration())
999 if (tup
.needThis() && hasThis(sc
))
1000 e
= new DotVarExp(loc
, new ThisExp(loc
), tup
);
1002 e
= new TupleExp(loc
, tup
);
1003 e
= e
.expressionSemantic(sc
);
1007 if (TemplateInstance ti
= s
.isTemplateInstance())
1009 ti
.dsymbolSemantic(sc
);
1010 if (!ti
.inst || ti
.errors
)
1011 return ErrorExp
.get();
1013 if (!s
.isTemplateInstance())
1015 e
= new ScopeExp(loc
, ti
);
1016 e
= e
.expressionSemantic(sc
);
1019 if (TemplateDeclaration td
= s
.isTemplateDeclaration())
1021 Dsymbol p
= td
.toParentLocal();
1022 FuncDeclaration fdthis
= hasThis(sc
);
1023 AggregateDeclaration ad
= p ? p
.isAggregateDeclaration() : null;
1024 if (fdthis
&& ad
&& fdthis
.isMemberLocal() == ad
&& (td
._scope
.stc & STC
.static_
) == 0)
1026 e
= new DotTemplateExp(loc
, new ThisExp(loc
), td
);
1029 e
= new TemplateExp(loc
, td
);
1030 e
= e
.expressionSemantic(sc
);
1034 .error(loc
, "%s `%s` is not a variable", s
.kind(), s
.toChars());
1035 return ErrorExp
.get();
1038 /*************************************************************
1039 * Given var, get the
1040 * right `this` pointer if var is in an outer class, but our
1041 * existing `this` pointer is in an inner class.
1043 * loc = location to use for error messages
1045 * ad = struct or class we need the correct `this` for
1046 * e1 = existing `this`
1047 * var = the specific member of ad we're accessing
1048 * flag = if true, return `null` instead of throwing an error
1050 * Expression representing the `this` for the var
1052 private Expression
getRightThis(const ref Loc loc
, Scope
* sc
, AggregateDeclaration ad
, Expression e1
, Dsymbol var
, int flag
= 0)
1054 //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars());
1056 Type t
= e1
.type
.toBasetype();
1057 //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars());
1059 if (e1
.op
== EXP
.objcClassReference
)
1061 // We already have an Objective-C class reference, just use that as 'this'.
1064 else if (ad
&& ad
.isClassDeclaration
&& ad
.isClassDeclaration
.classKind
== ClassKind
.objc
&&
1065 var
.isFuncDeclaration
&& var
.isFuncDeclaration
.isStatic
&&
1066 var
.isFuncDeclaration
.objc
.selector
)
1068 return new ObjcClassReferenceExp(e1
.loc
, ad
.isClassDeclaration());
1071 /* Access of a member which is a template parameter in dual-scope scenario
1072 * class A { inc(alias m)() { ++m; } } // `m` needs `this` of `B`
1073 * class B {int m; inc() { new A().inc!m(); } }
1075 if (e1
.op
== EXP
.this_
)
1077 FuncDeclaration f
= hasThis(sc
);
1078 if (f
&& f
.hasDualContext())
1080 if (f
.followInstantiationContext(ad
))
1082 e1
= new VarExp(loc
, f
.vthis
);
1083 e1
= new PtrExp(loc
, e1
);
1084 e1
= new IndexExp(loc
, e1
, IntegerExp
.literal
!1);
1085 e1
= getThisSkipNestedFuncs(loc
, sc
, f
.toParent2(), ad
, e1
, t
, var
);
1086 if (e1
.op
== EXP
.error
)
1093 /* If e1 is not the 'this' pointer for ad
1096 !(t
.isTypePointer() && t
.nextOf().isTypeStruct() && t
.nextOf().isTypeStruct().sym
== ad
) &&
1097 !(t
.isTypeStruct() && t
.isTypeStruct().sym
== ad
))
1099 ClassDeclaration cd
= ad
.isClassDeclaration();
1100 ClassDeclaration tcd
= t
.isClassHandle();
1102 /* e1 is the right this if ad is a base class of e1
1104 if (!cd ||
!tcd ||
!(tcd
== cd || cd
.isBaseOf(tcd
, null)))
1106 /* Only classes can be inner classes with an 'outer'
1107 * member pointing to the enclosing class instance
1109 if (tcd
&& tcd
.isNested())
1111 /* e1 is the 'this' pointer for an inner class: tcd.
1112 * Rewrite it as the 'this' pointer for the outer class.
1114 auto vthis
= tcd
.followInstantiationContext(ad
) ? tcd
.vthis2
: tcd
.vthis
;
1115 e1
= new DotVarExp(loc
, e1
, vthis
);
1116 e1
.type
= vthis
.type
;
1117 e1
.type
= e1
.type
.addMod(t
.mod
);
1118 // Do not call ensureStaticLinkTo()
1119 //e1 = e1.semantic(sc);
1121 // Skip up over nested functions, and get the enclosing
1123 e1
= getThisSkipNestedFuncs(loc
, sc
, tcd
.toParentP(ad
), ad
, e1
, t
, var
);
1124 if (e1
.op
== EXP
.error
)
1129 /* Can't find a path from e1 to ad
1133 e1
.error("`this` for `%s` needs to be type `%s` not type `%s`", var
.toChars(), ad
.toChars(), t
.toChars());
1134 return ErrorExp
.get();
1141 * Check whether `outerFunc` and `calledFunc` have the same `this`.
1142 * If `calledFunc` is the member of a base class of the class that contains
1143 * `outerFunc` we consider that they have the same this.
1145 * This function is used to test whether `this` needs to be prepended to
1146 * a function call or function symbol. For example:
1162 * When `fun` is called, `outerfunc` = `sun` and `calledFunc = `fun`.
1163 * `sun` is a member of `A` and `fun` is also a member of `A`, therefore
1164 * `this` can be prepended to `fun`. When `gun` is called (it will result
1165 * in an error, but that is not relevant here), which is a member of `X`,
1166 * no `this` is needed because the outer function does not have the same
1170 * `true` if outerFunc and calledFunc may use the same `this` pointer.
1171 * `false` otherwise.
1173 private bool haveSameThis(FuncDeclaration outerFunc
, FuncDeclaration calledFunc
)
1175 // https://issues.dlang.org/show_bug.cgi?id=24013
1176 // traits(getOverloads) inserts an alias to select the overload.
1177 // When searching for the right this we need to use the aliased
1178 // overload/function, not the alias.
1179 outerFunc
= outerFunc
.toAliasFunc();
1180 calledFunc
= calledFunc
.toAliasFunc();
1182 auto thisAd
= outerFunc
.isMemberLocal();
1186 auto requiredAd
= calledFunc
.isMemberLocal();
1190 if (thisAd
== requiredAd
)
1193 // outerfunc is the member of a base class that contains calledFunc,
1194 // then we consider that they have the same this.
1195 auto cd
= requiredAd
.isClassDeclaration();
1199 if (cd
.isBaseOf2(thisAd
.isClassDeclaration()))
1202 // if outerfunc is the member of a nested aggregate, then let
1203 // getRightThis take care of this.
1204 if (thisAd
.isNested())
1210 /***************************************
1211 * Pull out any properties.
1213 private Expression
resolvePropertiesX(Scope
* sc
, Expression e1
, Expression e2
= null, BinExp saveAtts
= null)
1215 //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null);
1222 if (auto de = e1
.isDotExp())
1224 if (auto oe
= de.e2
.isOverExp())
1232 else if (e1
.isOverExp())
1236 os
= e1
.isOverExp().vars
;
1239 FuncDeclaration fd
= null;
1242 e2
= e2
.expressionSemantic(sc
);
1243 if (e2
.op
== EXP
.error
)
1244 return ErrorExp
.get();
1245 e2
= resolveProperties(sc
, e2
);
1247 Expressions
* a
= new Expressions();
1250 for (size_t i
= 0; i
< os
.a
.length
; i
++)
1252 if (FuncDeclaration f
= resolveFuncCall(loc
, sc
, os
.a
[i
], tiargs
, tthis
, ArgumentList(a
), FuncResolveFlag
.quiet
))
1255 return ErrorExp
.get();
1257 assert(fd
.type
.ty
== Tfunction
);
1262 Expression e
= new CallExp(loc
, e1
, e2
);
1263 return e
.expressionSemantic(sc
);
1267 for (size_t i
= 0; i
< os
.a
.length
; i
++)
1269 if (FuncDeclaration f
= resolveFuncCall(loc
, sc
, os
.a
[i
], tiargs
, tthis
, ArgumentList(), FuncResolveFlag
.quiet
))
1272 return ErrorExp
.get();
1274 assert(fd
.type
.ty
== Tfunction
);
1275 auto tf
= fd
.type
.isTypeFunction();
1276 if (!tf
.isref
&& e2
)
1278 error(loc
, "%s is not an lvalue", e1
.toChars());
1279 return ErrorExp
.get();
1285 Expression e
= new CallExp(loc
, e1
);
1288 e
= new AssignExp(loc
, e
, e2
);
1291 (cast(BinExp
)e
).att1
= saveAtts
.att1
;
1292 (cast(BinExp
)e
).att2
= saveAtts
.att2
;
1295 return e
.expressionSemantic(sc
);
1301 else if (auto dti
= e1
.isDotTemplateInstanceExp())
1303 if (!dti
.findTempDecl(sc
))
1305 if (!dti
.ti
.semanticTiargs(sc
))
1307 tiargs
= dti
.ti
.tiargs
;
1308 tthis
= dti
.e1
.type
;
1309 if ((os
= dti
.ti
.tempdecl
.isOverloadSet()) !is null)
1311 if ((s
= dti
.ti
.tempdecl
) !is null)
1314 else if (auto dte
= e1
.isDotTemplateExp())
1318 tthis
= dte
.e1
.type
;
1321 else if (auto se
= e1
.isScopeExp())
1324 TemplateInstance ti
= s
.isTemplateInstance();
1325 if (ti
&& !ti
.semanticRun
&& ti
.tempdecl
)
1327 //assert(ti.needsTypeInference(sc));
1328 if (!ti
.semanticTiargs(sc
))
1332 if ((os
= ti
.tempdecl
.isOverloadSet()) !is null)
1334 if ((s
= ti
.tempdecl
) !is null)
1338 else if (auto te
= e1
.isTemplateExp())
1345 else if (e1
.isDotVarExp() && e1
.type
&& (e1
.type
.toBasetype().isTypeFunction() || e1
.isDotVarExp().var
.isOverDeclaration()))
1347 DotVarExp dve
= e1
.isDotVarExp();
1350 tthis
= dve
.e1
.type
;
1353 else if (sc
&& sc
.flags
& SCOPE
.Cfile
&& e1
.isVarExp() && !e2
)
1355 // ImportC: do not implicitly call function if no ( ) are present
1357 else if (e1
.isVarExp() && e1
.type
&& (e1
.type
.toBasetype().isTypeFunction() || e1
.isVarExp().var
.isOverDeclaration()))
1359 s
= e1
.isVarExp().var
;
1366 e2
= e2
.expressionSemantic(sc
);
1367 if (e2
.op
== EXP
.error
)
1368 return ErrorExp
.get();
1369 e2
= resolveProperties(sc
, e2
);
1371 Expressions
* a
= new Expressions();
1374 FuncDeclaration fd
= resolveFuncCall(loc
, sc
, s
, tiargs
, tthis
, ArgumentList(a
), FuncResolveFlag
.quiet
);
1378 return ErrorExp
.get();
1379 assert(fd
.type
.ty
== Tfunction
);
1380 Expression e
= new CallExp(loc
, e1
, e2
);
1381 return e
.expressionSemantic(sc
);
1385 FuncDeclaration fd
= resolveFuncCall(loc
, sc
, s
, tiargs
, tthis
, ArgumentList(), FuncResolveFlag
.quiet
);
1389 return ErrorExp
.get();
1390 TypeFunction tf
= fd
.type
.isTypeFunction();
1391 if (!e2 || tf
.isref
)
1393 Expression e
= new CallExp(loc
, e1
);
1396 e
= new AssignExp(loc
, e
, e2
);
1399 (cast(BinExp
)e
).att1
= saveAtts
.att1
;
1400 (cast(BinExp
)e
).att2
= saveAtts
.att2
;
1403 return e
.expressionSemantic(sc
);
1407 if (FuncDeclaration fd
= s
.isFuncDeclaration())
1409 // Keep better diagnostic message for invalid property usage of functions
1410 assert(fd
.type
.ty
== Tfunction
);
1411 Expression e
= new CallExp(loc
, e1
, e2
);
1412 return e
.expressionSemantic(sc
);
1417 if (auto ve
= e1
.isVarExp())
1419 if (auto v
= ve
.var
.isVarDeclaration())
1421 if (ve
.checkPurity(sc
, v
))
1422 return ErrorExp
.get();
1428 if (e1
.type
&& !e1
.isTypeExp()) // function type is not a property
1430 /* Look for e1 being a lazy parameter; rewrite as delegate call
1431 * only if the symbol wasn't already treated as a delegate
1433 auto ve
= e1
.isVarExp();
1434 if (ve
&& ve
.var
.storage_class
& STC
.lazy_
&& !ve
.delegateWasExtracted
)
1436 Expression e
= new CallExp(loc
, e1
);
1437 return e
.expressionSemantic(sc
);
1439 else if (e1
.isDotVarExp())
1441 // Check for reading overlapped pointer field in @safe code.
1442 if (checkUnsafeAccess(sc
, e1
, true, true))
1443 return ErrorExp
.get();
1445 else if (auto ce
= e1
.isCallExp())
1447 // Check for reading overlapped pointer field in @safe code.
1448 if (checkUnsafeAccess(sc
, ce
.e1
, true, true))
1449 return ErrorExp
.get();
1455 error(loc
, "cannot resolve type for %s", e1
.toChars());
1456 e1
= ErrorExp
.get();
1461 error(loc
, "not a property %s", e1
.toChars());
1462 return ErrorExp
.get();
1465 extern (C
++) Expression
resolveProperties(Scope
* sc
, Expression e
)
1467 //printf("resolveProperties(%s)\n", e.toChars());
1468 e
= resolvePropertiesX(sc
, e
);
1469 if (e
.checkRightThis(sc
))
1470 return ErrorExp
.get();
1474 /****************************************
1475 * The common type is determined by applying ?: to each pair.
1477 * exps[] properties resolved, implicitly cast to common type, rewritten in place
1479 * The common type, or `null` if an error has occured
1481 private Type
arrayExpressionToCommonType(Scope
* sc
, ref Expressions exps
)
1483 /* Still have a problem with:
1484 * ubyte[][] = [ cast(ubyte[])"hello", [1]];
1485 * which works if the array literal is initialized top down with the ubyte[][]
1486 * type, but fails with this function doing bottom up typing.
1489 //printf("arrayExpressionToCommonType()\n");
1490 scope IntegerExp integerexp
= IntegerExp
.literal
!0;
1491 scope CondExp condexp
= new CondExp(Loc
.initial
, integerexp
, null, null);
1494 Expression e0
= null;
1497 for (size_t i
= 0; i
< exps
.length
; i
++)
1499 Expression e
= exps
[i
];
1503 e
= resolveProperties(sc
, e
);
1506 e
.error("`%s` has no value", e
.toChars());
1510 if (e
.op
== EXP
.type
)
1512 foundType
= true; // do not break immediately, there might be more errors
1513 e
.checkValue(); // report an error "type T has no value"
1517 if (e
.type
.ty
== Tvoid
)
1519 // void expressions do not concur to the determination of the common
1523 if (checkNonAssignmentArrayOp(e
))
1529 e
= doCopyOrMove(sc
, e
);
1531 if (!foundType
&& t0
&& !t0
.equals(e
.type
))
1533 /* This applies ?: to merge the types. It's backwards;
1534 * ?: should call this function to merge types.
1536 condexp
.type
= null;
1539 condexp
.loc
= e
.loc
;
1540 Expression ex
= condexp
.expressionSemantic(sc
);
1541 if (ex
.op
== EXP
.error
)
1545 // Convert to common type
1546 exps
[i
] = condexp
.e1
.castTo(sc
, condexp
.type
);
1547 e
= condexp
.e2
.castTo(sc
, condexp
.type
);
1552 if (e
.op
!= EXP
.error
)
1556 // [] is typed as void[]
1560 // It's an error, don't do the cast
1561 if (t0
.ty
== Terror
)
1564 for (size_t i
= 0; i
< exps
.length
; i
++)
1566 Expression e
= exps
[i
];
1570 e
= e
.implicitCastTo(sc
, t0
);
1571 if (e
.op
== EXP
.error
)
1573 /* https://issues.dlang.org/show_bug.cgi?id=13024
1574 * a workaround for the bug in typeMerge -
1575 * it should paint e1 and e2 by deduced common type,
1576 * but doesn't in this particular case.
1585 private Expression
opAssignToOp(const ref Loc loc
, EXP op
, Expression e1
, Expression e2
)
1591 e
= new AddExp(loc
, e1
, e2
);
1595 e
= new MinExp(loc
, e1
, e2
);
1599 e
= new MulExp(loc
, e1
, e2
);
1603 e
= new DivExp(loc
, e1
, e2
);
1607 e
= new ModExp(loc
, e1
, e2
);
1611 e
= new AndExp(loc
, e1
, e2
);
1615 e
= new OrExp(loc
, e1
, e2
);
1619 e
= new XorExp(loc
, e1
, e2
);
1622 case EXP
.leftShiftAssign
:
1623 e
= new ShlExp(loc
, e1
, e2
);
1626 case EXP
.rightShiftAssign
:
1627 e
= new ShrExp(loc
, e1
, e2
);
1630 case EXP
.unsignedRightShiftAssign
:
1631 e
= new UshrExp(loc
, e1
, e2
);
1640 /*********************
1642 * array.length op= e2
1644 private Expression
rewriteOpAssign(BinExp exp
)
1646 ArrayLengthExp ale
= exp
.e1
.isArrayLengthExp();
1647 if (ale
.e1
.isVarExp())
1649 // array.length = array.length op e2
1650 Expression e
= opAssignToOp(exp
.loc
, exp
.op
, ale
, exp
.e2
);
1651 e
= new AssignExp(exp
.loc
, ale
.syntaxCopy(), e
);
1656 // (ref tmp = array;), tmp.length = tmp.length op e2
1657 auto tmp
= copyToTemp(STC
.ref_
, "__arraylength", ale
.e1
);
1658 Expression e1
= new ArrayLengthExp(ale
.loc
, new VarExp(ale
.loc
, tmp
));
1659 Expression elvalue
= e1
.syntaxCopy();
1660 Expression e
= opAssignToOp(exp
.loc
, exp
.op
, e1
, exp
.e2
);
1661 e
= new AssignExp(exp
.loc
, elvalue
, e
);
1662 e
= new CommaExp(exp
.loc
, new DeclarationExp(ale
.loc
, tmp
), e
);
1667 /****************************************
1668 * Preprocess arguments to function.
1670 * Tuples in argumentList get expanded, properties resolved, rewritten in place
1674 * argumentList = arguments to function
1675 * reportErrors = whether or not to report errors here. Some callers are not
1676 * checking actual function params, so they'll do their own error reporting
1678 * `true` when a semantic error occurred
1680 private bool preFunctionParameters(Scope
* sc
, ArgumentList argumentList
, const bool reportErrors
= true)
1682 Expressions
* exps
= argumentList
.arguments
;
1686 expandTuples(exps
, argumentList
.names
);
1688 for (size_t i
= 0; i
< exps
.length
; i
++)
1690 Expression arg
= (*exps
)[i
];
1691 arg
= resolveProperties(sc
, arg
);
1692 arg
= arg
.arrayFuncConv(sc
);
1693 if (arg
.op
== EXP
.type
)
1695 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
1696 arg
= resolveAliasThis(sc
, arg
);
1698 if (arg
.op
== EXP
.type
)
1702 arg
.error("cannot pass type `%s` as a function argument", arg
.toChars());
1703 arg
= ErrorExp
.get();
1708 else if (arg
.type
.toBasetype().ty
== Tfunction
)
1712 arg
.error("cannot pass function `%s` as a function argument", arg
.toChars());
1713 arg
= ErrorExp
.get();
1717 else if (checkNonAssignmentArrayOp(arg
))
1719 arg
= ErrorExp
.get();
1728 /********************************************
1729 * Issue an error if default construction is disabled for type t.
1730 * Default construction is required for arrays and 'out' parameters.
1732 * true an error was issued
1734 private bool checkDefCtor(Loc loc
, Type t
)
1736 if (auto ts
= t
.baseElemOf().isTypeStruct())
1738 StructDeclaration sd
= ts
.sym
;
1739 if (sd
.noDefaultCtor
)
1741 sd
.error(loc
, "default construction is disabled");
1748 /****************************************
1749 * Now that we know the exact type of the function we're calling,
1750 * the arguments[] need to be adjusted:
1751 * 1. implicitly convert argument to the corresponding parameter type
1752 * 2. add default arguments for any missing arguments
1753 * 3. do default promotions on arguments corresponding to ...
1754 * 4. add hidden _arguments[] argument
1755 * 5. call copy constructor for struct value arguments
1757 * loc = location of function call
1759 * tf = type of the function
1760 * ethis = `this` argument, `null` if none or not known
1761 * tthis = type of `this` argument, `null` if no `this` argument
1762 * argumentsList = array of actual arguments to function call
1763 * fd = the function being called, `null` if called indirectly
1764 * prettype = set to return type of function
1765 * peprefix = set to expression to execute before `arguments[]` are evaluated, `null` if none
1767 * true errors happened
1769 private bool functionParameters(const ref Loc loc
, Scope
* sc
,
1770 TypeFunction tf
, Expression ethis
, Type tthis
, ArgumentList argumentList
, FuncDeclaration fd
,
1771 Type
* prettype
, Expression
* peprefix
)
1773 Expressions
* arguments
= argumentList
.arguments
;
1774 //printf("functionParameters() %s\n", fd ? fd.toChars() : "");
1776 assert(fd || tf
.next
);
1777 const size_t nparams
= tf
.parameterList
.length
;
1778 const olderrors
= global
.errors
;
1780 Expression eprefix
= null;
1783 if (argumentList
.names
)
1785 const(char)* msg
= null;
1786 auto resolvedArgs
= tf
.resolveNamedArgs(argumentList
, &msg
);
1789 // while errors are usually already caught by `tf.callMatch`,
1790 // this can happen when calling `typeof(freefunc)`
1792 error(loc
, "%s", msg
);
1795 // note: the argument list should be mutated with named arguments / default arguments,
1796 // so we can't simply change the pointer like `arguments = resolvedArgs;`
1797 arguments
.setDim(0);
1798 arguments
.pushSlice((*resolvedArgs
)[]);
1800 size_t nargs
= arguments ? arguments
.length
: 0;
1802 if (nargs
> nparams
&& tf
.parameterList
.varargs
== VarArg
.none
)
1804 error(loc
, "expected %llu arguments, not %llu for non-variadic function type `%s`", cast(ulong)nparams
, cast(ulong)nargs
, tf
.toChars());
1808 // If inferring return type, and semantic3() needs to be run if not already run
1809 if (!tf
.next
&& fd
.inferRetType
)
1811 fd
.functionSemantic();
1813 else if (fd
&& fd
.parent
)
1815 TemplateInstance ti
= fd
.parent
.isTemplateInstance();
1816 if (ti
&& ti
.tempdecl
)
1818 fd
.functionSemantic3();
1822 /* If calling a pragma(inline, true) function,
1823 * set flag to later scan for inlines.
1825 if (fd
&& fd
.inlining
== PINLINE
.always
)
1828 sc
._module
.hasAlwaysInlines
= true;
1830 sc
.func
.hasAlwaysInlines
= true;
1833 const isCtorCall
= fd
&& fd
.needThis() && fd
.isCtorDeclaration();
1835 const size_t n
= (nargs
> nparams
) ? nargs
: nparams
; // n = max(nargs, nparams)
1837 /* If the function return type has wildcards in it, we'll need to figure out the actual type
1838 * based on the actual argument types.
1839 * Start with the `this` argument, later on merge into wildmatch the mod bits of the rest
1842 MOD wildmatch
= (tthis
&& !isCtorCall
) ? tthis
.Type
.deduceWild(tf
, false) : 0;
1845 foreach (const i
; 0 .. n
)
1847 Expression arg
= (i
< nargs
) ?
(*arguments
)[i
] : null;
1853 error(loc
, "expected %llu function arguments, not %llu", cast(ulong)nparams
, cast(ulong)nargs
);
1857 Parameter p
= tf
.parameterList
[i
];
1863 if (tf
.parameterList
.varargs
== VarArg
.typesafe
&& i
+ 1 == nparams
)
1869 arg
= arg
.expressionSemantic(sc
);
1870 arg
= inlineCopy(arg
, sc
);
1871 // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
1872 arg
= arg
.resolveLoc(loc
, sc
);
1875 arguments
.push(arg
);
1879 (*arguments
)[i
] = arg
;
1883 if (isDefaultInitOp(arg
.op
))
1885 arg
= arg
.resolveLoc(loc
, sc
);
1886 (*arguments
)[i
] = arg
;
1891 if (tf
.parameterList
.varargs
== VarArg
.typesafe
&& i
+ 1 == nparams
) // https://dlang.org/spec/function.html#variadic
1893 //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars());
1896 if ((m
= arg
.implicitConvTo(p
.type
)) > MATCH
.nomatch
)
1898 if (p
.type
.nextOf() && arg
.implicitConvTo(p
.type
.nextOf()) >= m
)
1900 else if (nargs
!= nparams
)
1906 Type tb
= p
.type
.toBasetype();
1912 /* Create a static array variable v of type arg.type:
1913 * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
1915 * The array literal in the initializer of the hidden variable
1917 * https://issues.dlang.org/show_bug.cgi?id=2356
1919 Type tbn
= (cast(TypeArray
)tb
).next
; // array element type
1920 Type tret
= p
.isLazyArray();
1922 auto elements
= new Expressions(nargs
- i
);
1923 foreach (u
; 0 .. elements
.length
)
1925 Expression a
= (*arguments
)[i
+ u
];
1926 if (tret
&& a
.implicitConvTo(tret
))
1928 // p is a lazy array of delegates, tret is return type of the delegates
1929 a
= a
.implicitCastTo(sc
, tret
)
1930 .optimize(WANTvalue
)
1931 .toDelegate(tret
, sc
);
1934 a
= a
.implicitCastTo(sc
, tbn
);
1935 a
= a
.addDtorHook(sc
);
1938 // https://issues.dlang.org/show_bug.cgi?id=14395
1939 // Convert to a static array literal, or its slice.
1940 arg
= new ArrayLiteralExp(loc
, tbn
.sarrayOf(nargs
- i
), elements
);
1941 if (tb
.ty
== Tarray
)
1943 arg
= new SliceExp(loc
, arg
, null, null);
1951 * new Tclass(arg0, arg1, ..., argn)
1953 auto args
= new Expressions(nargs
- i
);
1954 foreach (u
; i
.. nargs
)
1955 (*args
)[u
- i
] = (*arguments
)[u
];
1956 arg
= new NewExp(loc
, null, p
.type
, args
);
1962 error(loc
, "not enough arguments");
1967 arg
= arg
.expressionSemantic(sc
);
1968 //printf("\targ = '%s'\n", arg.toChars());
1969 arguments
.setDim(i
+ 1);
1970 (*arguments
)[i
] = arg
;
1976 if (!(p
.isLazy() && p
.type
.ty
== Tvoid
))
1978 if (ubyte wm
= arg
.type
.deduceWild(p
.type
, p
.isReference()))
1980 wildmatch
= wildmatch ?
MODmerge(wildmatch
, wm
) : wm
;
1981 //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p.type.toChars(), arg.type.toChars(), wm, wildmatch);
1988 if ((wildmatch
== MODFlags
.mutable || wildmatch
== MODFlags
.immutable_
) &&
1989 tf
.next
&& tf
.next
.hasWild() &&
1990 (tf
.isref ||
!tf
.next
.implicitConvTo(tf
.next
.immutableOf())))
1992 bool errorInout(MOD wildmatch
)
1994 const(char)* s
= wildmatch
== MODFlags
.mutable ?
"mutable" : MODtoChars(wildmatch
);
1995 error(loc
, "modify `inout` to `%s` is not allowed inside `inout` function", s
);
2001 /* If the called function may return the reference to
2002 * outer inout data, it should be rejected.
2004 * void foo(ref inout(int) x) {
2005 * ref inout(int) bar(inout(int)) { return x; }
2007 * ref inout(int) bar() inout { return x; }
2008 * ref inout(int) baz(alias a)() inout { return x; }
2010 * bar(int.init) = 1; // bad!
2011 * S().bar() = 1; // bad!
2016 * s.baz!a() = 1; // bad!
2020 bool checkEnclosingWild(Dsymbol s
)
2022 bool checkWild(Dsymbol s
)
2026 if (auto ad
= s
.isAggregateDeclaration())
2029 return checkEnclosingWild(s
);
2031 else if (auto ff
= s
.isFuncDeclaration())
2033 if (ff
.type
.isTypeFunction().iswild
)
2034 return errorInout(wildmatch
);
2036 if (ff
.isNested() || ff
.isThis())
2037 return checkEnclosingWild(s
);
2042 Dsymbol ctx0
= s
.toParent2();
2043 Dsymbol ctx1
= s
.toParentLocal();
2044 if (checkWild(ctx0
))
2047 return checkWild(ctx1
);
2050 if ((fd
.isThis() || fd
.isNested()) && checkEnclosingWild(fd
))
2053 else if (tf
.isWild())
2054 return errorInout(wildmatch
);
2057 Expression firstArg
= null;
2058 final switch (returnParamDest(tf
, tthis
))
2060 case ReturnParamDest
.returnVal
:
2062 case ReturnParamDest
.firstArg
:
2063 firstArg
= nargs
> 0 ?
(*arguments
)[0] : null;
2065 case ReturnParamDest
.this_
:
2070 assert(nargs
>= nparams
);
2071 foreach (const i
, arg
; (*arguments
)[0 .. nargs
])
2076 Parameter p
= tf
.parameterList
[i
];
2077 Type targ
= arg
.type
; // keep original type for isCopyable() because alias this
2078 // resolution may hide an uncopyable type
2080 if (!(p
.isLazy() && p
.type
.ty
== Tvoid
))
2082 Type tprm
= p
.type
.hasWild()
2083 ? p
.type
.substWildTo(wildmatch
)
2086 const hasCopyCtor
= arg
.type
.isTypeStruct() && arg
.type
.isTypeStruct().sym
.hasCopyCtor
;
2087 const typesMatch
= arg
.type
.mutableOf().unSharedOf().equals(tprm
.mutableOf().unSharedOf());
2088 if (!((hasCopyCtor
&& typesMatch
) || tprm
.equals(arg
.type
)))
2090 //printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars());
2091 arg
= arg
.implicitCastTo(sc
, tprm
);
2092 arg
= arg
.optimize(WANTvalue
, p
.isReference());
2096 // Support passing rvalue to `in` parameters
2097 if ((p
.storageClass
& (STC
.in_ | STC
.ref_
)) == (STC
.in_ | STC
.ref_
))
2099 if (!arg
.isLvalue())
2101 auto v
= copyToTemp(STC
.exptemp
, "__rvalue", arg
);
2102 Expression ev
= new DeclarationExp(arg
.loc
, v
);
2103 ev
= new CommaExp(arg
.loc
, ev
, new VarExp(arg
.loc
, v
));
2104 arg
= ev
.expressionSemantic(sc
);
2106 arg
= arg
.toLvalue(sc
, arg
);
2108 // Look for mutable misaligned pointer, etc., in @safe mode
2109 err |
= checkUnsafeAccess(sc
, arg
, false, true);
2111 else if (p
.storageClass
& STC
.ref_
)
2113 if (global
.params
.rvalueRefParam
== FeatureState
.enabled
&&
2116 { /* allow rvalues to be passed to ref parameters by copying
2117 * them to a temp, then pass the temp as the argument
2119 auto v
= copyToTemp(0, "__rvalue", arg
);
2120 Expression ev
= new DeclarationExp(arg
.loc
, v
);
2121 ev
= new CommaExp(arg
.loc
, ev
, new VarExp(arg
.loc
, v
));
2122 arg
= ev
.expressionSemantic(sc
);
2124 arg
= arg
.toLvalue(sc
, arg
);
2126 // Look for mutable misaligned pointer, etc., in @safe mode
2127 err |
= checkUnsafeAccess(sc
, arg
, false, true);
2129 else if (p
.storageClass
& STC
.out_
)
2132 if (!t
.isMutable() ||
!t
.isAssignable()) // check blit assignable
2134 arg
.error("cannot modify struct `%s` with immutable members", arg
.toChars());
2139 // Look for misaligned pointer, etc., in @safe mode
2140 err |
= checkUnsafeAccess(sc
, arg
, false, true);
2141 err |
= checkDefCtor(arg
.loc
, t
); // t must be default constructible
2143 arg
= arg
.toLvalue(sc
, arg
);
2145 else if (p
.isLazy())
2147 // Convert lazy argument to a delegate
2148 auto t
= (p
.type
.ty
== Tvoid
) ? p
.type
: arg
.type
;
2149 arg
= toDelegate(arg
, t
, sc
);
2151 //printf("arg: %s\n", arg.toChars());
2152 //printf("type: %s\n", arg.type.toChars());
2153 //printf("param: %s\n", p.toChars());
2155 const pStc
= tf
.parameterStorageClass(tthis
, p
);
2157 if (firstArg
&& (pStc
& STC
.return_
))
2159 /* Argument value can be assigned to firstArg.
2160 * Check arg to see if it matters.
2162 err |
= checkParamArgumentReturn(sc
, firstArg
, arg
, p
, false);
2164 // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along
2165 // as lazy parameters to the next function, but that isn't escaping.
2166 // The arguments of `_d_arraycatnTX` are already handled in
2167 // expressionsem.d, via `checkNewEscape`. Without `-dip1000`, the
2168 // check does not return an error, so the lowering of `a ~ b` to
2169 // `_d_arraycatnTX(a, b)` still occurs.
2170 else if (!(pStc
& STC
.lazy_
) && (!fd || fd
.ident
!= Id
._d_arraycatnTX
))
2172 /* Argument value can escape from the called function.
2173 * Check arg to see if it matters.
2175 VarDeclaration vPar
= fd ?
(fd
.parameters ?
(*fd
.parameters
)[i
] : null) : null;
2176 err |
= checkParamArgumentEscape(sc
, fd
, p
.ident
, vPar
, cast(STC
) pStc
, arg
, false, false);
2179 // Turning heap allocations into stack allocations is dangerous without dip1000, since `scope` inference
2180 // may be unreliable when scope violations only manifest as deprecation warnings.
2181 // However, existing `@nogc` code may rely on it, so still do it when the parameter is explicitly marked `scope`
2182 const explicitScope
= p
.isLazy() ||
2183 ((p
.storageClass
& STC
.scope_
) && !(p
.storageClass
& STC
.scopeinferred
));
2184 if ((pStc
& (STC
.scope_ | STC
.lazy_
)) &&
2185 ((global
.params
.useDIP1000
== FeatureState
.enabled
) || explicitScope
) &&
2186 !(pStc
& STC
.return_
))
2188 /* Argument value cannot escape from the called function.
2191 if (auto ce
= a
.isCastExp())
2194 ArrayLiteralExp ale
;
2195 if (p
.type
.toBasetype().ty
== Tarray
&&
2196 (ale
= a
.isArrayLiteralExp()) !is null && ale
.elements
&& ale
.elements
.length
> 0)
2198 // allocate the array literal as temporary static array on the stack
2199 ale
.type
= ale
.type
.nextOf().sarrayOf(ale
.elements
.length
);
2200 auto tmp
= copyToTemp(0, "__arrayliteral_on_stack", ale
);
2201 tmp
.storage_class |
= STC
.exptemp
;
2202 auto declareTmp
= new DeclarationExp(ale
.loc
, tmp
);
2203 auto castToSlice
= new CastExp(ale
.loc
, new VarExp(ale
.loc
, tmp
),
2204 p
.type
.substWildTo(MODFlags
.mutable
));
2205 arg
= CommaExp
.combine(declareTmp
, castToSlice
);
2206 arg
= arg
.expressionSemantic(sc
);
2208 else if (auto fe
= a
.isFuncExp())
2210 /* Function literals can only appear once, so if this
2211 * appearance was scoped, there cannot be any others.
2213 fe
.fd
.tookAddressOf
= 0;
2215 else if (auto de = a
.isDelegateExp())
2217 /* For passing a delegate to a scoped parameter,
2218 * this doesn't count as taking the address of it.
2219 * We only worry about 'escaping' references to the function.
2221 if (auto ve
= de.e1
.isVarExp())
2223 if (auto f
= ve
.var
.isFuncDeclaration())
2225 if (f
.tookAddressOf
)
2227 //printf("--tookAddressOf = %d\n", f.tookAddressOf);
2232 if (!p
.isReference())
2233 err |
= arg
.checkSharedAccess(sc
);
2235 arg
= arg
.optimize(WANTvalue
, p
.isReference());
2239 // These will be the trailing ... arguments
2240 // If not D linkage, do promotions
2241 if (tf
.linkage
!= LINK
.d
)
2243 // Promote bytes, words, etc., to ints
2244 arg
= integralPromotions(arg
, sc
);
2246 // Promote floats to doubles
2247 switch (arg
.type
.ty
)
2250 arg
= arg
.castTo(sc
, Type
.tfloat64
);
2254 arg
= arg
.castTo(sc
, Type
.timaginary64
);
2260 if (tf
.parameterList
.varargs
== VarArg
.variadic ||
2261 tf
.parameterList
.varargs
== VarArg
.KRvariadic
)
2263 const(char)* p
= tf
.linkage
== LINK
.c ?
"extern(C)" : "extern(C++)";
2264 if (arg
.type
.ty
== Tarray
)
2266 arg
.error("cannot pass dynamic arrays to `%s` vararg functions", p
);
2269 if (arg
.type
.ty
== Tsarray
)
2271 arg
.error("cannot pass static arrays to `%s` vararg functions", p
);
2277 // Do not allow types that need destructors or copy constructors.
2278 if (arg
.type
.needsDestruction())
2280 arg
.error("cannot pass types that need destruction as variadic arguments");
2283 if (arg
.type
.needsCopyOrPostblit())
2285 arg
.error("cannot pass types with postblits or copy constructors as variadic arguments");
2289 // Convert static arrays to dynamic arrays
2290 // BUG: I don't think this is right for D2
2291 Type tb
= arg
.type
.toBasetype();
2292 if (auto ts
= tb
.isTypeSArray())
2294 Type ta
= ts
.next
.arrayOf();
2295 if (ts
.size(arg
.loc
) == 0)
2296 arg
= new NullExp(arg
.loc
, ta
);
2298 arg
= arg
.castTo(sc
, ta
);
2300 if (tb
.ty
== Tstruct
)
2302 //arg = callCpCtor(sc, arg);
2304 // Give error for overloaded function addresses
2305 if (auto se
= arg
.isSymOffExp())
2307 if (se
.hasOverloads
&& !se
.var
.isFuncDeclaration().isUnique())
2309 arg
.error("function `%s` is overloaded", arg
.toChars());
2313 err |
= arg
.checkValue();
2314 err |
= arg
.checkSharedAccess(sc
);
2315 arg
= arg
.optimize(WANTvalue
);
2317 (*arguments
)[i
] = arg
;
2320 /* If calling C scanf(), printf(), or any variants, check the format string against the arguments
2322 const isVa_list
= tf
.parameterList
.varargs
== VarArg
.none
;
2323 if (fd
&& fd
.printf
)
2325 if (auto se
= (*arguments
)[nparams
- 1 - isVa_list
].isStringExp())
2327 checkPrintfFormat(se
.loc
, se
.peekString(), (*arguments
)[nparams
.. nargs
], isVa_list
);
2330 else if (fd
&& fd
.scanf
)
2332 if (auto se
= (*arguments
)[nparams
- 1 - isVa_list
].isStringExp())
2334 checkScanfFormat(se
.loc
, se
.peekString(), (*arguments
)[nparams
.. nargs
], isVa_list
);
2339 // TODO: not checking the "v" functions yet (for those, check format string only, not args)
2342 /* Remaining problems:
2343 * 1. value structs (or static arrays of them) that need to be copy constructed
2344 * 2. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
2345 * function gets called.
2346 * 3. value structs need to be destructed after the function call for platforms where the caller destroys the arguments.
2347 * Those are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
2348 * up properly. Pushing arguments on the stack then cannot fail.
2351 /* Does Problem (3) apply?
2353 const bool callerDestroysArgs
= !target
.isCalleeDestroyingArgs(tf
);
2355 /* Compute indices of last throwing argument and first arg needing destruction.
2356 * Used to not set up destructors unless an arg needs destruction on a throw
2357 * in a later argument.
2359 ptrdiff_t lastthrow
= -1; // last argument that may throw
2360 ptrdiff_t firstdtor
= -1; // first argument that needs destruction
2361 ptrdiff_t lastdtor
= -1; // last argument that needs destruction
2362 for (ptrdiff_t i
= 0; i
!= nargs
; i
++)
2364 Expression arg
= (*arguments
)[i
];
2365 if (canThrow(arg
, sc
.func
, false))
2367 if (arg
.type
.needsDestruction())
2369 Parameter p
= (i
>= nparams ?
null : tf
.parameterList
[i
]);
2370 if (!(p
&& (p
.isLazy() || p
.isReference())))
2372 if (firstdtor
== -1)
2379 /* Do we need 'eprefix' for problems 2 or 3?
2381 const bool needsPrefix
= callerDestroysArgs
2382 ? firstdtor
>= 0 // true if any argument needs destruction
2383 : firstdtor
>= 0 && lastthrow
>= 0 &&
2384 (lastthrow
- firstdtor
) > 0; // last throw after first destruction
2385 const ptrdiff_t lastPrefix
= callerDestroysArgs
2386 ? lastdtor
// up to last argument requiring destruction
2387 : lastthrow
; // up to last potentially throwing argument
2389 /* Problem 3: initialize 'eprefix' by declaring the gate
2391 VarDeclaration gate
;
2392 if (needsPrefix
&& !callerDestroysArgs
)
2394 // eprefix => bool __gate [= false]
2395 Identifier idtmp
= Identifier
.generateId("__gate");
2396 gate
= new VarDeclaration(loc
, Type
.tbool
, idtmp
, null);
2397 gate
.storage_class |
= STC
.temp | STC
.ctfe | STC
.volatile_
;
2398 gate
.dsymbolSemantic(sc
);
2400 auto ae
= new DeclarationExp(loc
, gate
);
2401 eprefix
= ae
.expressionSemantic(sc
);
2404 for (ptrdiff_t i
= 0; i
!= nargs
; i
++)
2406 Expression arg
= (*arguments
)[i
];
2407 //printf("arg[%d]: %s\n", cast(int)i, arg.toChars());
2409 Parameter parameter
= (i
>= nparams ?
null : tf
.parameterList
[i
]);
2410 const bool isRef
= parameter
&& parameter
.isReference();
2411 const bool isLazy
= parameter
&& parameter
.isLazy();
2413 /* Skip lazy parameters
2418 /* Do we have 'eprefix' and aren't past 'lastPrefix' yet?
2419 * Then declare a temporary variable for this arg and append that declaration
2420 * to 'eprefix', which will implicitly take care of potential problem 1) for
2422 * 'eprefix' will therefore finally contain all args up to and including 'lastPrefix',
2423 * excluding all lazy parameters.
2425 if (needsPrefix
&& (lastPrefix
- i
) >= 0)
2427 const bool needsDtor
= !isRef
&& arg
.type
.needsDestruction() &&
2428 // Problem 3: last throwing arg doesn't require dtor patching
2429 (callerDestroysArgs || i
!= lastPrefix
);
2431 /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
2433 auto tmp
= copyToTemp(
2434 (parameter ? parameter
.storageClass
: tf
.parameterList
.stc) & (STC
.scope_
),
2435 needsDtor ?
"__pfx" : "__pfy",
2436 !isRef ? arg
: arg
.addressOf());
2437 tmp
.dsymbolSemantic(sc
);
2439 if (callerDestroysArgs
)
2441 /* Problem 4: Normal temporary, destructed after the call
2444 tmp
.isArgDtorVar
= true; // mark it so that the backend passes it by ref to the function being called
2448 /* Problem 2: Modify the destructor so it only runs if gate==false,
2449 * i.e., only if there was a throw while constructing the args
2455 assert(i
== lastPrefix
);
2461 // edtor => (__gate || edtor)
2463 Expression e
= tmp
.edtor
;
2464 e
= new LogicalExp(e
.loc
, EXP
.orOr
, new VarExp(e
.loc
, gate
), e
);
2465 tmp
.edtor
= e
.expressionSemantic(sc
);
2466 //printf("edtor: %s\n", tmp.edtor.toChars());
2470 // eprefix => (eprefix, auto __pfx/y = arg)
2471 auto ae
= new DeclarationExp(loc
, tmp
);
2472 eprefix
= Expression
.combine(eprefix
, ae
.expressionSemantic(sc
));
2475 arg
= new VarExp(loc
, tmp
);
2476 arg
= arg
.expressionSemantic(sc
);
2479 arg
= new PtrExp(loc
, arg
);
2480 arg
= arg
.expressionSemantic(sc
);
2483 /* Problem 2: Last throwing arg?
2484 * Then finalize eprefix => (eprefix, gate = true), i.e., disable the
2485 * dtors right after constructing the last throwing arg.
2486 * From now on, the callee will take care of destructing the args because
2487 * the args are implicitly moved into function parameters.
2489 if (!callerDestroysArgs
&& i
== lastPrefix
)
2491 auto e
= new AssignExp(gate
.loc
, new VarExp(gate
.loc
, gate
), IntegerExp
.createBool(true));
2492 eprefix
= Expression
.combine(eprefix
, e
.expressionSemantic(sc
));
2495 else // not part of 'eprefix'
2497 /* Handle problem 1) by calling the copy constructor for value structs
2498 * (or static arrays of them) if appropriate.
2500 Type tv
= arg
.type
.baseElemOf();
2501 if (!isRef
&& tv
.ty
== Tstruct
)
2502 arg
= doCopyOrMove(sc
, arg
, parameter ? parameter
.type
: null);
2505 (*arguments
)[i
] = arg
;
2508 //if (eprefix) printf("eprefix: %s\n", eprefix.toChars());
2510 /* Test compliance with DIP1021 Argument Ownership and Function Calls
2512 if (global
.params
.useDIP1021
&& (tf
.trust
== TRUST
.safe || tf
.trust
== TRUST
.default_
) ||
2514 err |
= checkMutableArguments(sc
, fd
, tf
, ethis
, arguments
, false);
2516 // If D linkage and variadic, add _arguments[] as first argument
2517 if (tf
.isDstyleVariadic())
2519 assert(arguments
.length
>= nparams
);
2521 auto args
= new Parameters(arguments
.length
- nparams
);
2522 for (size_t i
= 0; i
< arguments
.length
- nparams
; i
++)
2524 auto arg
= new Parameter(STC
.in_
, (*arguments
)[nparams
+ i
].type
, null, null, null);
2527 auto tup
= new TypeTuple(args
);
2528 Expression e
= (new TypeidExp(loc
, tup
)).expressionSemantic(sc
);
2529 arguments
.insert(0, e
);
2532 /* Determine function return type: tret
2534 Type tret
= tf
.next
;
2537 //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd.toChars(), fd.type.toChars(),
2538 // wildmatch, tf.isWild(), fd.isReturnIsolated());
2541 assert(sc
.intypeof || global
.errors
);
2542 tthis
= fd
.isThis().type
.addMod(fd
.type
.mod
);
2544 if (tf
.isWild() && !fd
.isReturnIsolated())
2547 tret
= tret
.substWildTo(wildmatch
);
2549 if (!tret
.implicitConvTo(tthis
) && !(MODimplicitConv(tret
.mod
, tthis
.mod
) && tret
.isBaseOf(tthis
, &offset
) && offset
== 0))
2551 const(char)* s1
= tret
.isNaked() ?
" mutable" : tret
.modToChars();
2552 const(char)* s2
= tthis
.isNaked() ?
" mutable" : tthis
.modToChars();
2553 .error(loc
, "`inout` constructor `%s` creates%s object, not%s", fd
.toPrettyChars(), s1
, s2
);
2559 else if (wildmatch
&& tret
)
2561 /* Adjust function return type based on wildmatch
2563 //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret.toChars());
2564 tret
= tret
.substWildTo(wildmatch
);
2568 *peprefix
= eprefix
;
2569 return (err || olderrors
!= global
.errors
);
2573 * Determines whether a symbol represents a module or package
2574 * (Used as a helper for is(type == module) and is(type == package))
2577 * sym = the symbol to be checked
2580 * the symbol which `sym` represents (or `null` if it doesn't represent a `Package`)
2582 Package
resolveIsPackage(Dsymbol sym
)
2585 if (Import imp
= sym
.isImport())
2587 if (imp
.pkg
is null)
2589 .error(sym
.loc
, "internal compiler error: unable to process forward-referenced import `%s`",
2595 else if (auto mod
= sym
.isModule())
2596 pkg
= mod
.isPackageFile ? mod
.pkg
: sym
.isPackage();
2598 pkg
= sym
.isPackage();
2600 pkg
.resolvePKGunknown();
2605 private extern (C
++) final class ExpressionSemanticVisitor
: Visitor
2607 alias visit
= Visitor
.visit
;
2612 this(Scope
* sc
) scope
2617 private void setError()
2619 result
= ErrorExp
.get();
2622 /**************************
2623 * Semantically analyze Expression.
2624 * Determine types, fold constants, etc.
2626 override void visit(Expression e
)
2628 static if (LOGSEMANTIC
)
2630 printf("Expression::semantic() %s\n", e
.toChars());
2633 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
2635 e
.type
= Type
.tvoid
;
2639 override void visit(IntegerExp e
)
2642 if (e
.type
.ty
== Terror
)
2645 assert(e
.type
.deco
);
2646 e
.setInteger(e
.getInteger());
2650 override void visit(RealExp e
)
2653 e
.type
= Type
.tfloat64
;
2654 else if (e
.type
.isimaginary
&& sc
.flags
& SCOPE
.Cfile
)
2656 /* Convert to core.stdc.config.complex
2658 Type t
= getComplexLibraryType(e
.loc
, sc
, e
.type
.ty
);
2665 case Timaginary32
: tf
= Type
.tfloat32
; break;
2666 case Timaginary64
: tf
= Type
.tfloat64
; break;
2667 case Timaginary80
: tf
= Type
.tfloat80
; break;
2672 /* Construct ts{re : 0.0, im : e}
2674 TypeStruct ts
= t
.isTypeStruct
;
2675 Expressions
* elements
= new Expressions(2);
2676 (*elements
)[0] = new RealExp(e
.loc
, CTFloat
.zero
, tf
);
2677 (*elements
)[1] = new RealExp(e
.loc
, e
.toImaginary(), tf
);
2678 Expression sle
= new StructLiteralExp(e
.loc
, ts
.sym
, elements
);
2679 result
= sle
.expressionSemantic(sc
);
2683 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
2687 override void visit(ComplexExp e
)
2690 e
.type
= Type
.tcomplex80
;
2692 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
2696 override void visit(IdentifierExp exp
)
2698 static if (LOGSEMANTIC
)
2700 printf("IdentifierExp::semantic('%s')\n", exp
.ident
.toChars());
2702 if (exp
.type
) // This is used as the dummy expression
2709 Dsymbol s
= sc
.search(exp
.loc
, exp
.ident
, &scopesym
);
2717 /* See if the symbol was a member of an enclosing 'with'
2719 WithScopeSymbol withsym
= scopesym
.isWithScopeSymbol();
2720 if (withsym
&& withsym
.withstate
.wthis
&& symbolIsVisible(sc
, s
))
2722 /* Disallow shadowing
2724 // First find the scope of the with
2726 while (scwith
.scopesym
!= scopesym
)
2728 scwith
= scwith
.enclosing
;
2731 // Look at enclosing scopes for symbols with the same name,
2732 // in the same function
2733 for (Scope
* scx
= scwith
; scx
&& scx
.func
== scwith
.func
; scx
= scx
.enclosing
)
2736 if (scx
.scopesym
&& scx
.scopesym
.symtab
&& (s2
= scx
.scopesym
.symtab
.lookup(s
.ident
)) !is null && s
!= s2
)
2738 exp
.error("with symbol `%s` is shadowing local symbol `%s`", s
.toPrettyChars(), s2
.toPrettyChars());
2744 // Same as wthis.ident
2745 // TODO: DotIdExp.semantic will find 'ident' from 'wthis' again.
2746 // The redudancy should be removed.
2747 e
= new VarExp(exp
.loc
, withsym
.withstate
.wthis
);
2748 e
= new DotIdExp(exp
.loc
, e
, exp
.ident
);
2749 e
= e
.expressionSemantic(sc
);
2755 if (withsym
.withstate
.exp
.type
.ty
!= Tvoid
)
2757 // 'with (exp)' is a type expression
2758 // or 's' is not visible there (for error message)
2759 e
= new TypeExp(exp
.loc
, withsym
.withstate
.exp
.type
);
2763 // 'with (exp)' is a Package/Module
2764 e
= withsym
.withstate
.exp
;
2766 e
= new DotIdExp(exp
.loc
, e
, exp
.ident
);
2767 result
= e
.expressionSemantic(sc
);
2771 /* If f is really a function template,
2772 * then replace f with the function template declaration.
2774 FuncDeclaration f
= s
.isFuncDeclaration();
2777 TemplateDeclaration td
= getFuncTemplateDecl(f
);
2780 if (td
.overroot
) // if not start of overloaded list of TemplateDeclaration's
2781 td
= td
.overroot
; // then get the start
2782 e
= new TemplateExp(exp
.loc
, td
, f
);
2783 e
= e
.expressionSemantic(sc
);
2789 if (global
.params
.fixAliasThis
)
2791 ExpressionDsymbol expDsym
= scopesym
.isExpressionDsymbol();
2794 //printf("expDsym = %s\n", expDsym.exp.toChars());
2795 result
= expDsym
.exp
.expressionSemantic(sc
);
2799 // Haven't done overload resolution yet, so pass 1
2800 e
= symbolToExp(s
, exp
.loc
, sc
, true);
2806 if (!global
.params
.fixAliasThis
&& hasThis(sc
))
2808 for (AggregateDeclaration ad
= sc
.getStructClassScope(); ad
;)
2813 e
= new ThisExp(exp
.loc
);
2814 e
= new DotIdExp(exp
.loc
, e
, ad
.aliasthis
.ident
);
2815 e
= new DotIdExp(exp
.loc
, e
, exp
.ident
);
2816 e
= e
.trySemantic(sc
);
2824 auto cd
= ad
.isClassDeclaration();
2825 if (cd
&& cd
.baseClass
&& cd
.baseClass
!= ClassDeclaration
.object
)
2834 if (exp
.ident
== Id
.ctfe
)
2836 if (sc
.flags
& SCOPE
.ctfe
)
2838 exp
.error("variable `__ctfe` cannot be read at compile time");
2842 // Create the magic __ctfe bool variable
2843 auto vd
= new VarDeclaration(exp
.loc
, Type
.tbool
, Id
.ctfe
, null);
2844 vd
.storage_class |
= STC
.temp
;
2845 vd
.semanticRun
= PASS
.semanticdone
;
2846 Expression e
= new VarExp(exp
.loc
, vd
);
2847 e
= e
.expressionSemantic(sc
);
2852 // If we've reached this point and are inside a with() scope then we may
2853 // try one last attempt by checking whether the 'wthis' object supports
2854 // dynamic dispatching via opDispatch.
2855 // This is done by rewriting this expression as wthis.ident.
2856 // The innermost with() scope of the hierarchy to satisfy the condition
2858 // https://issues.dlang.org/show_bug.cgi?id=6400
2859 for (Scope
* sc2
= sc
; sc2
; sc2
= sc2
.enclosing
)
2864 if (auto ss
= sc2
.scopesym
.isWithScopeSymbol())
2866 if (ss
.withstate
.wthis
)
2869 e
= new VarExp(exp
.loc
, ss
.withstate
.wthis
);
2870 e
= new DotIdExp(exp
.loc
, e
, exp
.ident
);
2871 e
= e
.trySemantic(sc
);
2878 // Try Type.opDispatch (so the static version)
2879 else if (ss
.withstate
.exp
&& ss
.withstate
.exp
.op
== EXP
.type
)
2881 if (Type t
= ss
.withstate
.exp
.isTypeExp().type
)
2884 e
= new TypeExp(exp
.loc
, t
);
2885 e
= new DotIdExp(exp
.loc
, e
, exp
.ident
);
2886 e
= e
.trySemantic(sc
);
2897 /* Look for what user might have meant
2899 if (const n
= importHint(exp
.ident
.toString()))
2900 exp
.error("`%s` is not defined, perhaps `import %.*s;` is needed?", exp
.ident
.toChars(), cast(int)n
.length
, n
.ptr
);
2901 else if (auto s2
= sc
.search_correct(exp
.ident
))
2902 exp
.error("undefined identifier `%s`, did you mean %s `%s`?", exp
.ident
.toChars(), s2
.kind(), s2
.toChars());
2903 else if (const p
= Scope
.search_correct_C(exp
.ident
))
2904 exp
.error("undefined identifier `%s`, did you mean `%s`?", exp
.ident
.toChars(), p
);
2905 else if (exp
.ident
== Id
.dollar
)
2906 exp
.error("undefined identifier `$`");
2908 exp
.error("undefined identifier `%s`", exp
.ident
.toChars());
2910 result
= ErrorExp
.get();
2913 override void visit(DsymbolExp e
)
2915 result
= symbolToExp(e
.s
, e
.loc
, sc
, e
.hasOverloads
);
2918 override void visit(ThisExp e
)
2920 static if (LOGSEMANTIC
)
2922 printf("ThisExp::semantic()\n");
2930 FuncDeclaration fd
= hasThis(sc
); // fd is the uplevel function with the 'this' variable
2931 AggregateDeclaration ad
;
2933 /* Special case for typeof(this) and typeof(super) since both
2934 * should work even if they are not inside a non-static member function
2936 if (!fd
&& sc
.intypeof
== 1)
2938 // Find enclosing struct or class
2939 for (Dsymbol s
= sc
.getStructClassScope(); 1; s
= s
.parent
)
2943 e
.error("`%s` is not in a class or struct scope", e
.toChars());
2946 ClassDeclaration cd
= s
.isClassDeclaration();
2953 StructDeclaration sd
= s
.isStructDeclaration();
2964 e
.error("`this` is only defined in non-static member functions, not `%s`", sc
.parent
.toChars());
2970 assert(e
.var
.parent
);
2971 ad
= fd
.isMemberLocal();
2973 ad
= fd
.isMember2();
2975 e
.type
= ad
.type
.addMod(e
.var
.type
.mod
);
2977 if (e
.var
.checkNestedReference(sc
, e
.loc
))
2983 override void visit(SuperExp e
)
2985 static if (LOGSEMANTIC
)
2987 printf("SuperExp::semantic('%s')\n", e
.toChars());
2995 FuncDeclaration fd
= hasThis(sc
);
2996 ClassDeclaration cd
;
2999 /* Special case for typeof(this) and typeof(super) since both
3000 * should work even if they are not inside a non-static member function
3002 if (!fd
&& sc
.intypeof
== 1)
3004 // Find enclosing class
3005 for (s
= sc
.getStructClassScope(); 1; s
= s
.parent
)
3009 e
.error("`%s` is not in a class scope", e
.toChars());
3012 cd
= s
.isClassDeclaration();
3018 e
.error("class `%s` has no `super`", s
.toChars());
3031 assert(e
.var
&& e
.var
.parent
);
3033 s
= fd
.toParentDecl();
3034 if (s
.isTemplateDeclaration()) // allow inside template constraint
3037 cd
= s
.isClassDeclaration();
3038 //printf("parent is %s %s\n", fd.toParent().kind(), fd.toParent().toChars());
3043 e
.error("no base class for `%s`", cd
.toChars());
3044 e
.type
= cd
.type
.addMod(e
.var
.type
.mod
);
3048 e
.type
= cd
.baseClass
.type
;
3049 e
.type
= e
.type
.castMod(e
.var
.type
.mod
);
3052 if (e
.var
.checkNestedReference(sc
, e
.loc
))
3059 e
.error("`super` is only allowed in non-static class member functions");
3060 result
= ErrorExp
.get();
3063 override void visit(NullExp e
)
3065 static if (LOGSEMANTIC
)
3067 printf("NullExp::semantic('%s')\n", e
.toChars());
3069 // NULL is the same as (void *)0
3075 e
.type
= Type
.tnull
;
3079 override void visit(StringExp e
)
3081 static if (LOGSEMANTIC
)
3083 printf("StringExp::semantic() %s\n", e
.toChars());
3099 for (u
= 0; u
< e
.len
;)
3101 if (const p
= utf_decodeChar(e
.peekString(), u
, c
))
3103 e
.error("%.*s", cast(int)p
.length
, p
.ptr
);
3113 e
.setData(buffer
.extractData(), newlen
, 4);
3114 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
3115 e
.type
= Type
.tuns32
.sarrayOf(e
.len
+ 1);
3117 e
.type
= Type
.tdchar
.immutableOf().arrayOf();
3122 for (u
= 0; u
< e
.len
;)
3124 if (const p
= utf_decodeChar(e
.peekString(), u
, c
))
3126 e
.error("%.*s", cast(int)p
.length
, p
.ptr
);
3131 buffer
.writeUTF16(c
);
3137 buffer
.writeUTF16(0);
3138 e
.setData(buffer
.extractData(), newlen
, 2);
3139 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
3140 e
.type
= Type
.tuns16
.sarrayOf(e
.len
+ 1);
3142 e
.type
= Type
.twchar
.immutableOf().arrayOf();
3151 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
3152 e
.type
= Type
.tchar
.sarrayOf(e
.len
+ 1);
3154 e
.type
= Type
.tchar
.immutableOf().arrayOf();
3157 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
3158 //type = type.immutableOf();
3159 //printf("type = %s\n", type.toChars());
3164 override void visit(TupleExp exp
)
3166 static if (LOGSEMANTIC
)
3168 printf("+TupleExp::semantic(%s)\n", exp
.toChars());
3177 exp
.e0
= exp
.e0
.expressionSemantic(sc
);
3179 // Run semantic() on each argument
3181 for (size_t i
= 0; i
< exp
.exps
.length
; i
++)
3183 Expression e
= (*exp
.exps
)[i
];
3184 e
= e
.expressionSemantic(sc
);
3187 exp
.error("`%s` has no value", e
.toChars());
3190 else if (e
.op
== EXP
.error
)
3198 expandTuples(exp
.exps
);
3200 exp
.type
= new TypeTuple(exp
.exps
);
3201 exp
.type
= exp
.type
.typeSemantic(exp
.loc
, sc
);
3202 //printf("-TupleExp::semantic(%s)\n", toChars());
3206 override void visit(ArrayLiteralExp e
)
3208 static if (LOGSEMANTIC
)
3210 printf("ArrayLiteralExp::semantic('%s')\n", e
.toChars());
3218 /* Perhaps an empty array literal [ ] should be rewritten as null?
3222 e
.basis
= e
.basis
.expressionSemantic(sc
);
3223 if (arrayExpressionSemantic(e
.elements
.peekSlice(), sc
) ||
(e
.basis
&& e
.basis
.op
== EXP
.error
))
3226 expandTuples(e
.elements
);
3229 e
.elements
.push(e
.basis
);
3230 Type t0
= arrayExpressionToCommonType(sc
, *e
.elements
);
3232 e
.basis
= e
.elements
.pop();
3236 e
.type
= t0
.arrayOf();
3237 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
3239 /* Disallow array literals of type void being used.
3241 if (e
.elements
.length
> 0 && t0
.ty
== Tvoid
)
3243 e
.error("`%s` of type `%s` has no value", e
.toChars(), e
.type
.toChars());
3247 if (global
.params
.useTypeInfo
&& Type
.dtypeinfo
)
3248 semanticTypeInfo(sc
, e
.type
);
3253 override void visit(AssocArrayLiteralExp e
)
3255 static if (LOGSEMANTIC
)
3257 printf("AssocArrayLiteralExp::semantic('%s')\n", e
.toChars());
3265 // Run semantic() on each element
3266 bool err_keys
= arrayExpressionSemantic(e
.keys
.peekSlice(), sc
);
3267 bool err_vals
= arrayExpressionSemantic(e
.values
.peekSlice(), sc
);
3268 if (err_keys || err_vals
)
3271 expandTuples(e
.keys
);
3272 expandTuples(e
.values
);
3273 if (e
.keys
.length
!= e
.values
.length
)
3275 e
.error("number of keys is %llu, must match number of values %llu",
3276 cast(ulong) e
.keys
.length
, cast(ulong) e
.values
.length
);
3280 Type tkey
= arrayExpressionToCommonType(sc
, *e
.keys
);
3281 Type tvalue
= arrayExpressionToCommonType(sc
, *e
.values
);
3282 if (tkey
is null || tvalue
is null)
3285 e
.type
= new TypeAArray(tvalue
, tkey
);
3286 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
3288 semanticTypeInfo(sc
, e
.type
);
3290 if (checkAssocArrayLiteralEscape(sc
, e
, false))
3296 override void visit(StructLiteralExp e
)
3298 static if (LOGSEMANTIC
)
3300 printf("StructLiteralExp::semantic('%s')\n", e
.toChars());
3309 if (e
.sd
.sizeok
!= Sizeok
.done
)
3312 // run semantic() on each element
3313 if (arrayExpressionSemantic(e
.elements
.peekSlice(), sc
))
3316 expandTuples(e
.elements
);
3318 /* Fit elements[] to the corresponding type of field[].
3320 if (!e
.sd
.fit(e
.loc
, sc
, e
.elements
, e
.stype
))
3323 /* Fill out remainder of elements[] with default initializers for fields[]
3325 if (!e
.sd
.fill(e
.loc
, *e
.elements
, false))
3327 /* An error in the initializer needs to be recorded as an error
3328 * in the enclosing function or template, since the initializer
3329 * will be part of the stuct declaration.
3331 global
.increaseErrorCount();
3335 if (checkFrameAccess(e
.loc
, sc
, e
.sd
, e
.elements
.length
))
3338 e
.type
= e
.stype ? e
.stype
: e
.sd
.type
;
3342 override void visit(CompoundLiteralExp cle
)
3344 static if (LOGSEMANTIC
)
3346 printf("CompoundLiteralExp::semantic('%s')\n", cle
.toChars());
3348 Type t
= cle
.type
.typeSemantic(cle
.loc
, sc
);
3349 auto init
= initializerSemantic(cle
.initializer
, sc
, t
, INITnointerpret
);
3350 auto e
= initializerToExpression(init
, t
, (sc
.flags
& SCOPE
.Cfile
) != 0);
3353 error(cle
.loc
, "cannot convert initializer `%s` to expression", init
.toChars());
3360 override void visit(TypeExp exp
)
3362 if (exp
.type
.ty
== Terror
)
3365 //printf("TypeExp::semantic(%s)\n", exp.type.toChars());
3370 dmd
.typesem
.resolve(exp
.type
, exp
.loc
, sc
, e
, t
, s
, true);
3373 // `(Type)` is actually `(var)` so if `(var)` is a member requiring `this`
3374 // then rewrite as `(this.var)` in case it would be followed by a DotVar
3375 // to fix https://issues.dlang.org/show_bug.cgi?id=9490
3376 VarExp ve
= e
.isVarExp();
3377 if (ve
&& ve
.var
&& exp
.parens
&& !ve
.var
.isStatic() && !(sc
.stc & STC
.static_
) &&
3378 sc
.func
&& sc
.func
.needThis
&& ve
.var
.isMember2())
3380 // printf("apply fix for bugzilla issue 9490: add `this.` to `%s`...\n", e.toChars());
3381 e
= new DotVarExp(exp
.loc
, new ThisExp(exp
.loc
), ve
.var
, false);
3383 //printf("e = %s %s\n", Token.toChars(e.op), e.toChars());
3384 e
= e
.expressionSemantic(sc
);
3388 //printf("t = %d %s\n", t.ty, t.toChars());
3389 exp
.type
= t
.typeSemantic(exp
.loc
, sc
);
3394 //printf("s = %s %s\n", s.kind(), s.toChars());
3395 e
= symbolToExp(s
, exp
.loc
, sc
, true);
3400 exp
.type
.checkComplexTransition(exp
.loc
, sc
);
3405 override void visit(ScopeExp exp
)
3407 static if (LOGSEMANTIC
)
3409 printf("+ScopeExp::semantic(%p '%s')\n", exp
, exp
.toChars());
3417 ScopeDsymbol sds2
= exp
.sds
;
3418 TemplateInstance ti
= sds2
.isTemplateInstance();
3421 WithScopeSymbol withsym
;
3422 if (!ti
.findTempDecl(sc
, &withsym
) ||
!ti
.semanticTiargs(sc
))
3424 if (withsym
&& withsym
.withstate
.wthis
)
3426 Expression e
= new VarExp(exp
.loc
, withsym
.withstate
.wthis
);
3427 e
= new DotTemplateInstanceExp(exp
.loc
, e
, ti
);
3428 result
= e
.expressionSemantic(sc
);
3431 if (ti
.needsTypeInference(sc
))
3433 if (TemplateDeclaration td
= ti
.tempdecl
.isTemplateDeclaration())
3435 Dsymbol p
= td
.toParentLocal();
3436 FuncDeclaration fdthis
= hasThis(sc
);
3437 AggregateDeclaration ad
= p ? p
.isAggregateDeclaration() : null;
3438 if (fdthis
&& ad
&& fdthis
.isMemberLocal() == ad
&& (td
._scope
.stc & STC
.static_
) == 0)
3440 Expression e
= new DotTemplateInstanceExp(exp
.loc
, new ThisExp(exp
.loc
), ti
);
3441 result
= e
.expressionSemantic(sc
);
3445 else if (OverloadSet os
= ti
.tempdecl
.isOverloadSet())
3447 FuncDeclaration fdthis
= hasThis(sc
);
3448 AggregateDeclaration ad
= os
.parent
.isAggregateDeclaration();
3449 if (fdthis
&& ad
&& fdthis
.isMemberLocal() == ad
)
3451 Expression e
= new DotTemplateInstanceExp(exp
.loc
, new ThisExp(exp
.loc
), ti
);
3452 result
= e
.expressionSemantic(sc
);
3456 // ti is an instance which requires IFTI.
3458 exp
.type
= Type
.tvoid
;
3462 ti
.dsymbolSemantic(sc
);
3463 if (!ti
.inst || ti
.errors
)
3466 Dsymbol s
= ti
.toAlias();
3470 exp
.type
= Type
.tvoid
;
3474 sds2
= s
.isScopeDsymbol();
3477 ti
= sds2
.isTemplateInstance();
3478 //printf("+ sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
3482 if (auto v
= s
.isVarDeclaration())
3486 exp
.error("forward reference of %s `%s`", v
.kind(), v
.toChars());
3489 if ((v
.storage_class
& STC
.manifest
) && v
._init
)
3491 /* When an instance that will be converted to a constant exists,
3492 * the instance representation "foo!tiargs" is treated like a
3493 * variable name, and its recursive appearance check (note that
3494 * it's equivalent with a recursive instantiation of foo) is done
3495 * separately from the circular initialization check for the
3496 * eponymous enum variable declaration.
3499 * enum bool foo = foo; // recursive definition check (v.inuse)
3502 * enum bool bar = bar!T; // recursive instantiation check (ti.inuse)
3507 exp
.error("recursive expansion of %s `%s`", ti
.kind(), ti
.toPrettyChars());
3510 v
.checkDeprecated(exp
.loc
, sc
);
3511 auto e
= v
.expandInitializer(exp
.loc
);
3513 e
= e
.expressionSemantic(sc
);
3520 //printf("s = %s, '%s'\n", s.kind(), s.toChars());
3521 auto e
= symbolToExp(s
, exp
.loc
, sc
, true);
3522 //printf("-1ScopeExp::semantic()\n");
3527 //printf("sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
3528 //printf("\tparent = '%s'\n", sds2.parent.toChars());
3529 sds2
.dsymbolSemantic(sc
);
3531 // (Aggregate|Enum)Declaration
3532 if (auto t
= sds2
.getType())
3534 result
= (new TypeExp(exp
.loc
, t
)).expressionSemantic(sc
);
3538 if (auto td
= sds2
.isTemplateDeclaration())
3540 result
= (new TemplateExp(exp
.loc
, td
)).expressionSemantic(sc
);
3545 exp
.type
= Type
.tvoid
;
3546 //printf("-2ScopeExp::semantic() %s\n", toChars());
3551 * Sets the `lowering` field of a `NewExp` to a call to `_d_newitemT` unless
3552 * compiling with `-betterC` or within `__traits(compiles)`.
3555 * ne = the `NewExp` to lower
3557 private void tryLowerToNewItem(NewExp ne
)
3559 if (!global
.params
.useGC ||
!sc
.needsCodegen())
3562 auto hook
= global
.params
.tracegc ? Id
._d_newitemTTrace
: Id
._d_newitemT
;
3563 if (!verifyHookExist(ne
.loc
, *sc
, hook
, "new struct"))
3566 /* Lower the memory allocation and initialization of `new T()` to
3567 * `_d_newitemT!T()`.
3569 Expression id
= new IdentifierExp(ne
.loc
, Id
.empty
);
3570 id
= new DotIdExp(ne
.loc
, id
, Id
.object
);
3571 auto tiargs
= new Objects();
3573 * Remove `inout`, `const`, `immutable` and `shared` to reduce the
3574 * number of generated `_d_newitemT` instances.
3576 auto t
= ne
.type
.nextOf
.unqualify(MODFlags
.wild | MODFlags
.const_ |
3577 MODFlags
.immutable_ | MODFlags
.shared_
);
3579 id
= new DotTemplateInstanceExp(ne
.loc
, id
, hook
, tiargs
);
3581 auto arguments
= new Expressions();
3582 if (global
.params
.tracegc
)
3584 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ?
3585 sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
3586 arguments
.push(new StringExp(ne
.loc
, ne
.loc
.filename
.toDString()));
3587 arguments
.push(new IntegerExp(ne
.loc
, ne
.loc
.linnum
, Type
.tint32
));
3588 arguments
.push(new StringExp(ne
.loc
, funcname
.toDString()));
3590 id
= new CallExp(ne
.loc
, id
, arguments
);
3592 ne
.lowering
= id
.expressionSemantic(sc
);
3595 override void visit(NewExp exp
)
3597 static if (LOGSEMANTIC
)
3599 printf("NewExp::semantic() %s\n", exp
.toChars());
3601 printf("\tthisexp = %s\n", exp
.thisexp
.toChars());
3602 printf("\tnewtype: %s\n", exp
.newtype
.toChars());
3604 if (exp
.type
) // if semantic() already run
3610 //for error messages if the argument in [] is not convertible to size_t
3611 const originalNewtype
= exp
.newtype
;
3613 // https://issues.dlang.org/show_bug.cgi?id=11581
3614 // With the syntax `new T[edim]` or `thisexp.new T[edim]`,
3615 // T should be analyzed first and edim should go into arguments iff it's
3617 Expression edim
= null;
3618 if (!exp
.arguments
&& exp
.newtype
.isTypeSArray())
3620 auto ts
= exp
.newtype
.isTypeSArray();
3621 // check `new Value[Key]`
3622 ts
.dim
= ts
.dim
.expressionSemantic(sc
);
3623 if (ts
.dim
.op
== EXP
.type
)
3625 exp
.newtype
= new TypeAArray(ts
.next
, ts
.dim
.isTypeExp().type
);
3630 exp
.newtype
= ts
.next
;
3634 ClassDeclaration cdthis
= null;
3637 exp
.thisexp
= exp
.thisexp
.expressionSemantic(sc
);
3638 if (exp
.thisexp
.op
== EXP
.error
)
3641 cdthis
= exp
.thisexp
.type
.isClassHandle();
3644 exp
.error("`this` for nested class must be a class type, not `%s`", exp
.thisexp
.type
.toChars());
3648 sc
= sc
.push(cdthis
);
3649 exp
.type
= exp
.newtype
.typeSemantic(exp
.loc
, sc
);
3654 exp
.type
= exp
.newtype
.typeSemantic(exp
.loc
, sc
);
3656 if (exp
.type
.ty
== Terror
)
3661 if (exp
.type
.toBasetype().ty
== Ttuple
)
3664 exp
.type
= new TypeSArray(exp
.type
, edim
);
3665 exp
.type
= exp
.type
.typeSemantic(exp
.loc
, sc
);
3666 if (exp
.type
.ty
== Terror
)
3671 // --> new T[](edim)
3672 exp
.arguments
= new Expressions();
3673 exp
.arguments
.push(edim
);
3674 exp
.type
= exp
.type
.arrayOf();
3678 exp
.newtype
= exp
.type
; // in case type gets cast to something else
3679 Type tb
= exp
.type
.toBasetype();
3680 //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco);
3681 if (arrayExpressionSemantic(exp
.arguments
.peekSlice(), sc
))
3685 if (preFunctionParameters(sc
, exp
.argumentList
))
3690 if (exp
.thisexp
&& tb
.ty
!= Tclass
)
3692 exp
.error("`.new` is only for allocating nested classes, not `%s`", tb
.toChars());
3696 const size_t nargs
= exp
.arguments ? exp
.arguments
.length
: 0;
3697 Expression newprefix
= null;
3699 if (auto tc
= tb
.isTypeClass())
3705 if (cd
.sizeok
!= Sizeok
.done
)
3708 cd
.ctor
= cd
.searchCtor();
3709 if (cd
.noDefaultCtor
&& !nargs
&& !cd
.defaultCtor
)
3711 exp
.error("default construction is disabled for type `%s`", cd
.type
.toChars());
3715 if (cd
.isInterfaceDeclaration())
3717 exp
.error("cannot create instance of interface `%s`", cd
.toChars());
3721 if (cd
.isAbstract())
3723 exp
.error("cannot create instance of abstract class `%s`", cd
.toChars());
3724 for (size_t i
= 0; i
< cd
.vtbl
.length
; i
++)
3726 FuncDeclaration fd
= cd
.vtbl
[i
].isFuncDeclaration();
3727 if (fd
&& fd
.isAbstract())
3729 errorSupplemental(exp
.loc
, "function `%s` is not implemented",
3730 fd
.toFullSignature());
3735 // checkDeprecated() is already done in newtype.typeSemantic().
3739 /* We need a 'this' pointer for the nested class.
3740 * Ensure we have the right one.
3742 Dsymbol s
= cd
.toParentLocal();
3744 //printf("cd isNested, parent = %s '%s'\n", s.kind(), s.toPrettyChars());
3745 if (auto cdn
= s
.isClassDeclaration())
3749 void noReferenceToOuterClass()
3752 exp
.error("cannot construct anonymous nested class because no implicit `this` reference to outer class is available");
3754 exp
.error("cannot construct nested class `%s` because no implicit `this` reference to outer class `%s` is available",
3755 cd
.toChars(), cdn
.toChars());
3760 return noReferenceToOuterClass();
3762 // Supply an implicit 'this' and try again
3763 exp
.thisexp
= new ThisExp(exp
.loc
);
3764 for (Dsymbol sp
= sc
.parent
; 1; sp
= sp
.toParentLocal())
3767 return noReferenceToOuterClass();
3768 ClassDeclaration cdp
= sp
.isClassDeclaration();
3771 if (cdp
== cdn || cdn
.isBaseOf(cdp
, null))
3773 // Add a '.outer' and try again
3774 exp
.thisexp
= new DotIdExp(exp
.loc
, exp
.thisexp
, Id
.outer
);
3777 exp
.thisexp
= exp
.thisexp
.expressionSemantic(sc
);
3778 if (exp
.thisexp
.op
== EXP
.error
)
3780 cdthis
= exp
.thisexp
.type
.isClassHandle();
3782 if (cdthis
!= cdn
&& !cdn
.isBaseOf(cdthis
, null))
3784 //printf("cdthis = %s\n", cdthis.toChars());
3785 exp
.error("`this` for nested class must be of type `%s`, not `%s`",
3786 cdn
.toChars(), exp
.thisexp
.type
.toChars());
3789 if (!MODimplicitConv(exp
.thisexp
.type
.mod
, exp
.newtype
.mod
))
3791 exp
.error("nested type `%s` should have the same or weaker constancy as enclosing type `%s`",
3792 exp
.newtype
.toChars(), exp
.thisexp
.type
.toChars());
3796 else if (exp
.thisexp
)
3798 exp
.error("`.new` is only for allocating nested classes");
3801 else if (auto fdn
= s
.isFuncDeclaration())
3803 // make sure the parent context fdn of cd is reachable from sc
3804 if (!ensureStaticLinkTo(sc
.parent
, fdn
))
3806 exp
.error("outer function context of `%s` is needed to `new` nested class `%s`",
3807 fdn
.toPrettyChars(), cd
.toPrettyChars());
3814 else if (exp
.thisexp
)
3816 exp
.error("`.new` is only for allocating nested classes");
3822 if (AggregateDeclaration ad2
= cd
.isMember2())
3824 Expression te
= new ThisExp(exp
.loc
).expressionSemantic(sc
);
3825 if (te
.op
!= EXP
.error
)
3826 te
= getRightThis(exp
.loc
, sc
, ad2
, te
, cd
);
3827 if (te
.op
== EXP
.error
)
3829 exp
.error("need `this` of type `%s` needed to `new` nested class `%s`", ad2
.toChars(), cd
.toChars());
3835 if (cd
.disableNew
&& !exp
.onstack
)
3837 exp
.error("cannot allocate `class %s` with `new` because it is annotated with `@disable new()`",
3838 originalNewtype
.toChars());
3844 FuncDeclaration f
= resolveFuncCall(exp
.loc
, sc
, cd
.ctor
, null, tb
, exp
.argumentList
, FuncResolveFlag
.standard
);
3848 checkFunctionAttributes(exp
, sc
, f
);
3849 checkAccess(cd
, exp
.loc
, sc
, f
);
3851 TypeFunction tf
= f
.type
.isTypeFunction();
3853 exp
.arguments
= new Expressions();
3854 if (functionParameters(exp
.loc
, sc
, tf
, null, exp
.type
, exp
.argumentList
, f
, &exp
.type
, &exp
.argprefix
))
3857 exp
.member
= f
.isCtorDeclaration();
3864 exp
.error("no constructor for `%s`", cd
.toChars());
3868 // https://issues.dlang.org/show_bug.cgi?id=19941
3869 // Run semantic on all field initializers to resolve any forward
3870 // references. This is the same as done for structs in sd.fill().
3871 for (ClassDeclaration c
= cd
; c
; c
= c
.baseClass
)
3873 foreach (v
; c
.fields
)
3875 if (v
.inuse || v
._scope
is null || v
._init
is null ||
3876 v
._init
.isVoidInitializer())
3879 v
._init
= v
._init
.initializerSemantic(v
._scope
, v
.type
, INITinterpret
);
3885 // When using `@nogc` exception handling, lower `throw new E(args)` to
3886 // `throw (__tmp = _d_newThrowable!E(), __tmp.__ctor(args), __tmp)`.
3887 if (global
.params
.ehnogc
&& exp
.thrownew
&&
3888 !cd
.isCOMclass() && !cd
.isCPPclass())
3892 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
3893 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
3895 auto tiargs
= new Objects();
3896 tiargs
.push(exp
.newtype
);
3897 id
= new DotTemplateInstanceExp(exp
.loc
, id
, Id
._d_newThrowable
, tiargs
);
3898 id
= new CallExp(exp
.loc
, id
).expressionSemantic(sc
);
3901 Expression tmp
= extractSideEffect(sc
, "__tmpThrowable", idVal
, id
, true);
3902 // auto castTmp = new CastExp(exp.loc, tmp, exp.type);
3904 auto ctor
= new DotIdExp(exp
.loc
, tmp
, Id
.ctor
).expressionSemantic(sc
);
3905 auto ctorCall
= new CallExp(exp
.loc
, ctor
, exp
.arguments
);
3907 id
= Expression
.combine(idVal
, exp
.argprefix
).expressionSemantic(sc
);
3908 id
= Expression
.combine(id
, ctorCall
).expressionSemantic(sc
);
3909 // id = Expression.combine(id, castTmp).expressionSemantic(sc);
3911 result
= id
.expressionSemantic(sc
);
3914 else if (sc
.needsCodegen() && // interpreter doesn't need this lowered
3915 !exp
.onstack
&& !exp
.type
.isscope()) // these won't use the GC
3917 /* replace `new T(arguments)` with `core.lifetime._d_newclassT!T(arguments)`
3918 * or `_d_newclassTTrace`
3920 auto hook
= global
.params
.tracegc ? Id
._d_newclassTTrace
: Id
._d_newclassT
;
3921 if (!verifyHookExist(exp
.loc
, *sc
, hook
, "new class"))
3924 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
3925 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
3927 auto tiargs
= new Objects();
3928 auto t
= exp
.newtype
.unqualify(MODFlags
.wild
); // remove `inout`
3930 id
= new DotTemplateInstanceExp(exp
.loc
, id
, hook
, tiargs
);
3931 auto arguments
= new Expressions();
3932 if (global
.params
.tracegc
)
3934 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ?
3935 sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
3936 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
3937 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
3938 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
3940 id
= new CallExp(exp
.loc
, id
, arguments
);
3942 exp
.lowering
= id
.expressionSemantic(sc
);
3945 else if (auto ts
= tb
.isTypeStruct())
3949 if (sd
.sizeok
!= Sizeok
.done
)
3952 sd
.ctor
= sd
.searchCtor();
3953 if (sd
.noDefaultCtor
&& !nargs
)
3955 exp
.error("default construction is disabled for type `%s`", sd
.type
.toChars());
3958 // checkDeprecated() is already done in newtype.typeSemantic().
3962 exp
.error("cannot allocate `struct %s` with `new` because it is annotated with `@disable new()`",
3963 originalNewtype
.toChars());
3967 // https://issues.dlang.org/show_bug.cgi?id=22639
3968 // If the new expression has arguments, we either should call a
3969 // regular constructor of a copy constructor if the first argument
3970 // is the same type as the struct
3971 if (nargs
&& (sd
.hasRegularCtor() ||
(sd
.ctor
&& (*exp
.arguments
)[0].type
.mutableOf() == sd
.type
.mutableOf())))
3973 FuncDeclaration f
= resolveFuncCall(exp
.loc
, sc
, sd
.ctor
, null, tb
, exp
.argumentList
, FuncResolveFlag
.standard
);
3977 checkFunctionAttributes(exp
, sc
, f
);
3978 checkAccess(sd
, exp
.loc
, sc
, f
);
3980 TypeFunction tf
= f
.type
.isTypeFunction();
3982 exp
.arguments
= new Expressions();
3983 if (functionParameters(exp
.loc
, sc
, tf
, null, exp
.type
, exp
.argumentList
, f
, &exp
.type
, &exp
.argprefix
))
3986 exp
.member
= f
.isCtorDeclaration();
3989 if (checkFrameAccess(exp
.loc
, sc
, sd
, sd
.fields
.length
))
3996 exp
.arguments
= resolveStructLiteralNamedArgs(sd
, exp
.type
, sc
, exp
.loc
,
3997 exp
.names ?
(*exp
.names
)[] : null,
3998 (size_t i
, Type t
) => (*exp
.arguments
)[i
],
3999 i
=> (*exp
.arguments
)[i
].loc
4004 else if (!exp
.arguments
)
4006 exp
.arguments
= new Expressions();
4009 if (!sd
.fit(exp
.loc
, sc
, exp
.arguments
, tb
))
4012 if (!sd
.fill(exp
.loc
, *exp
.arguments
, false))
4015 if (checkFrameAccess(exp
.loc
, sc
, sd
, exp
.arguments ? exp
.arguments
.length
: 0))
4018 /* Since a `new` allocation may escape, check each of the arguments for escaping
4020 foreach (arg
; *exp
.arguments
)
4022 if (arg
&& checkNewEscape(sc
, arg
, false))
4027 exp
.type
= exp
.type
.pointerTo();
4028 tryLowerToNewItem(exp
);
4030 else if (tb
.ty
== Tarray
)
4034 // https://issues.dlang.org/show_bug.cgi?id=20422
4035 // Without this check the compiler would give a misleading error
4036 exp
.error("missing length argument for array");
4040 Type tn
= tb
.nextOf().baseElemOf();
4041 Dsymbol s
= tn
.toDsymbol(sc
);
4042 AggregateDeclaration ad
= s ? s
.isAggregateDeclaration() : null;
4043 if (ad
&& ad
.noDefaultCtor
)
4045 exp
.error("default construction is disabled for type `%s`", tb
.nextOf().toChars());
4048 for (size_t i
= 0; i
< nargs
; i
++)
4050 if (tb
.ty
!= Tarray
)
4052 exp
.error("too many arguments for array");
4056 Expression arg
= (*exp
.arguments
)[i
];
4057 if (exp
.names
&& (*exp
.names
)[i
])
4059 exp
.error("no named argument `%s` allowed for array dimension", (*exp
.names
)[i
].toChars());
4063 arg
= resolveProperties(sc
, arg
);
4064 arg
= arg
.implicitCastTo(sc
, Type
.tsize_t
);
4065 if (arg
.op
== EXP
.error
)
4067 arg
= arg
.optimize(WANTvalue
);
4068 if (arg
.op
== EXP
.int64
&& (target
.isLP64 ?
4069 cast(sinteger_t
)arg
.toInteger() : cast(int)arg
.toInteger()) < 0)
4071 exp
.error("negative array dimension `%s`", (*exp
.arguments
)[i
].toChars());
4074 (*exp
.arguments
)[i
] = arg
;
4075 tb
= tb
.isTypeDArray().next
.toBasetype();
4078 else if (tb
.isscalar())
4083 else if (nargs
== 1)
4085 if (exp
.names
&& (*exp
.names
)[0])
4087 exp
.error("no named argument `%s` allowed for scalar", (*exp
.names
)[0].toChars());
4090 Expression e
= (*exp
.arguments
)[0];
4091 e
= e
.implicitCastTo(sc
, tb
);
4092 (*exp
.arguments
)[0] = e
;
4096 exp
.error("more than one argument for construction of `%s`", exp
.type
.toChars());
4100 exp
.type
= exp
.type
.pointerTo();
4101 tryLowerToNewItem(exp
);
4103 else if (tb
.ty
== Taarray
)
4105 // e.g. `new Alias(args)`
4108 exp
.error("`new` cannot take arguments for an associative array");
4114 exp
.error("cannot create a `%s` with `new`", exp
.type
.toChars());
4118 //printf("NewExp: '%s'\n", toChars());
4119 //printf("NewExp:type '%s'\n", type.toChars());
4120 semanticTypeInfo(sc
, exp
.type
);
4124 result
= Expression
.combine(newprefix
, exp
);
4130 override void visit(NewAnonClassExp e
)
4132 static if (LOGSEMANTIC
)
4134 printf("NewAnonClassExp::semantic() %s\n", e
.toChars());
4135 //printf("thisexp = %p\n", thisexp);
4136 //printf("type: %s\n", type.toChars());
4139 Expression d
= new DeclarationExp(e
.loc
, e
.cd
);
4140 sc
= sc
.push(); // just create new scope
4141 sc
.flags
&= ~SCOPE
.ctfe
; // temporary stop CTFE
4142 d
= d
.expressionSemantic(sc
);
4145 if (!e
.cd
.errors
&& sc
.intypeof
&& !sc
.parent
.inNonRoot())
4147 ScopeDsymbol sds
= sc
.tinst ?
cast(ScopeDsymbol
)sc
.tinst
: sc
._module
;
4149 sds
.members
= new Dsymbols();
4150 sds
.members
.push(e
.cd
);
4153 Expression n
= new NewExp(e
.loc
, e
.thisexp
, e
.cd
.type
, e
.arguments
);
4155 Expression c
= new CommaExp(e
.loc
, d
, n
);
4156 result
= c
.expressionSemantic(sc
);
4159 override void visit(SymOffExp e
)
4161 static if (LOGSEMANTIC
)
4163 printf("SymOffExp::semantic('%s')\n", e
.toChars());
4165 //var.dsymbolSemantic(sc);
4167 e
.type
= e
.var
.type
.pointerTo();
4169 if (auto v
= e
.var
.isVarDeclaration())
4171 if (v
.checkNestedReference(sc
, e
.loc
))
4174 else if (auto f
= e
.var
.isFuncDeclaration())
4176 if (f
.checkNestedReference(sc
, e
.loc
))
4183 override void visit(VarExp e
)
4185 static if (LOGSEMANTIC
)
4187 printf("VarExp::semantic(%s)\n", e
.toChars());
4190 auto vd
= e
.var
.isVarDeclaration();
4191 auto fd
= e
.var
.isFuncDeclaration();
4195 //printf("L%d fd = %s\n", __LINE__, f.toChars());
4196 if (!fd
.functionSemantic())
4201 e
.type
= e
.var
.type
;
4202 if (e
.type
&& !e
.type
.deco
)
4204 auto decl
= e
.var
.isDeclaration();
4207 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
4212 /* Fix for 1161 doesn't work because it causes visibility
4213 * problems when instantiating imported templates passing private
4214 * variables as alias template parameters.
4216 //checkAccess(loc, sc, NULL, var);
4220 if (vd
.checkNestedReference(sc
, e
.loc
))
4223 // https://issues.dlang.org/show_bug.cgi?id=12025
4224 // If the variable is not actually used in runtime code,
4225 // the purity violation error is redundant.
4226 //checkPurity(sc, vd);
4230 // TODO: If fd isn't yet resolved its overload, the checkNestedReference
4231 // call would cause incorrect validation.
4232 // Maybe here should be moved in CallExp, or AddrExp for functions.
4233 if (fd
.checkNestedReference(sc
, e
.loc
))
4236 else if (auto od
= e
.var
.isOverDeclaration())
4238 e
.type
= Type
.tvoid
; // ambiguous type?
4244 override void visit(FuncExp exp
)
4246 static if (LOGSEMANTIC
)
4248 printf("FuncExp::semantic(%s)\n", exp
.toChars());
4250 printf(" treq = %s\n", exp
.fd
.treq
.toChars());
4262 sc
= sc
.push(); // just create new scope
4263 sc
.flags
&= ~SCOPE
.ctfe
; // temporary stop CTFE
4264 sc
.visibility
= Visibility(Visibility
.Kind
.public_
); // https://issues.dlang.org/show_bug.cgi?id=12506
4266 /* fd.treq might be incomplete type,
4267 * so should not semantic it.
4268 * void foo(T)(T delegate(int) dg){}
4269 * foo(a=>a); // in IFTI, treq == T delegate(int)
4272 // fd.treq = fd.treq.dsymbolSemantic(loc, sc);
4276 // Set target of return type inference
4277 if (exp
.fd
.treq
&& !exp
.fd
.type
.nextOf())
4279 TypeFunction tfv
= null;
4280 if (exp
.fd
.treq
.ty
== Tdelegate || exp
.fd
.treq
.isPtrToFunction())
4281 tfv
= cast(TypeFunction
)exp
.fd
.treq
.nextOf();
4284 TypeFunction tfl
= cast(TypeFunction
)exp
.fd
.type
;
4285 tfl
.next
= tfv
.nextOf();
4289 //printf("td = %p, treq = %p\n", td, fd.treq);
4292 assert(exp
.td
.parameters
&& exp
.td
.parameters
.length
);
4293 exp
.td
.dsymbolSemantic(sc
);
4294 exp
.type
= Type
.tvoid
; // temporary type
4296 if (exp
.fd
.treq
) // defer type determination
4299 if (exp
.matchType(exp
.fd
.treq
, sc
, &fe
) > MATCH
.nomatch
)
4307 olderrors
= global
.errors
;
4308 exp
.fd
.dsymbolSemantic(sc
);
4309 if (olderrors
== global
.errors
)
4311 exp
.fd
.semantic2(sc
);
4312 if (olderrors
== global
.errors
)
4313 exp
.fd
.semantic3(sc
);
4315 if (olderrors
!= global
.errors
)
4317 if (exp
.fd
.type
&& exp
.fd
.type
.ty
== Tfunction
&& !exp
.fd
.type
.nextOf())
4318 (cast(TypeFunction
)exp
.fd
.type
).next
= Type
.terror
;
4323 // Type is a "delegate to" or "pointer to" the function literal
4324 if ((exp
.fd
.isNested() && exp
.fd
.tok
== TOK
.delegate_
) ||
(exp
.tok
== TOK
.reserved
&& exp
.fd
.treq
&& exp
.fd
.treq
.ty
== Tdelegate
))
4326 // https://issues.dlang.org/show_bug.cgi?id=22686
4327 // if the delegate return type is an error
4328 // abort semantic of the FuncExp and propagate
4330 if (exp
.fd
.type
.isTypeError())
4335 exp
.type
= new TypeDelegate(exp
.fd
.type
.isTypeFunction());
4336 exp
.type
= exp
.type
.typeSemantic(exp
.loc
, sc
);
4338 exp
.fd
.tok
= TOK
.delegate_
;
4342 exp
.type
= new TypePointer(exp
.fd
.type
);
4343 exp
.type
= exp
.type
.typeSemantic(exp
.loc
, sc
);
4344 //type = fd.type.pointerTo();
4346 /* A lambda expression deduced to function pointer might become
4347 * to a delegate literal implicitly.
4349 * auto foo(void function() fp) { return 1; }
4350 * assert(foo({}) == 1);
4352 * So, should keep fd.tok == TOK.reserve if fd.treq == NULL.
4354 if (exp
.fd
.treq
&& exp
.fd
.treq
.ty
== Tpointer
)
4356 // change to non-nested
4357 exp
.fd
.tok
= TOK
.function_
;
4358 exp
.fd
.vthis
= null;
4361 exp
.fd
.tookAddressOf
++;
4369 * Perform semantic analysis on function literals
4371 * Test the following construct:
4373 * (x, y, z) { return x + y + z; }(42, 84, 1992);
4376 Expression
callExpSemantic(FuncExp exp
, Scope
* sc
, Expressions
* arguments
)
4378 if ((!exp
.type || exp
.type
== Type
.tvoid
) && exp
.td
&& arguments
&& arguments
.length
)
4380 for (size_t k
= 0; k
< arguments
.length
; k
++)
4382 Expression checkarg
= (*arguments
)[k
];
4383 if (checkarg
.op
== EXP
.error
)
4389 assert(exp
.td
.parameters
&& exp
.td
.parameters
.length
);
4390 exp
.td
.dsymbolSemantic(sc
);
4392 TypeFunction tfl
= cast(TypeFunction
)exp
.fd
.type
;
4393 size_t dim
= tfl
.parameterList
.length
;
4394 if (arguments
.length
< dim
)
4396 // Default arguments are always typed, so they don't need inference.
4397 Parameter p
= tfl
.parameterList
[arguments
.length
];
4399 dim
= arguments
.length
;
4402 if ((tfl
.parameterList
.varargs
== VarArg
.none
&& arguments
.length
> dim
) ||
4403 arguments
.length
< dim
)
4406 foreach (idx
, ref arg
; *arguments
)
4407 buf
.printf("%s%s", (idx ?
", ".ptr
: "".ptr
), arg
.type
.toChars());
4408 exp
.error("function literal `%s%s` is not callable using argument types `(%s)`",
4409 exp
.fd
.toChars(), parametersTypeToChars(tfl
.parameterList
),
4411 exp
.errorSupplemental("too %s arguments, expected %d, got %d",
4412 arguments
.length
< dim ?
"few".ptr
: "many".ptr
,
4413 cast(int)dim
, cast(int)arguments
.length
);
4414 return ErrorExp
.get();
4417 auto tiargs
= new Objects();
4418 tiargs
.reserve(exp
.td
.parameters
.length
);
4420 for (size_t i
= 0; i
< exp
.td
.parameters
.length
; i
++)
4422 TemplateParameter tp
= (*exp
.td
.parameters
)[i
];
4423 assert(dim
<= tfl
.parameterList
.length
);
4424 foreach (u
, p
; tfl
.parameterList
)
4429 if (p
.type
.ty
== Tident
&& (cast(TypeIdentifier
)p
.type
).ident
== tp
.ident
)
4431 Expression e
= (*arguments
)[u
];
4432 tiargs
.push(e
.type
);
4438 auto ti
= new TemplateInstance(exp
.loc
, exp
.td
, tiargs
);
4439 return (new ScopeExp(exp
.loc
, ti
)).expressionSemantic(sc
);
4441 return exp
.expressionSemantic(sc
);
4444 override void visit(CallExp exp
)
4446 static if (LOGSEMANTIC
)
4448 printf("CallExp::semantic() %s\n", exp
.toChars());
4453 return; // semantic() already run
4456 Objects
* tiargs
= null; // initial list of template arguments
4457 Expression ethis
= null;
4459 Expression e1org
= exp
.e1
;
4461 if (auto ce
= exp
.e1
.isCommaExp())
4463 /* Rewrite (a,b)(args) as (a,(b(args)))
4467 result
= ce
.expressionSemantic(sc
);
4470 if (DelegateExp
de = exp
.e1
.isDelegateExp())
4472 exp
.e1
= new DotVarExp(de.loc
, de.e1
, de.func
, de.hasOverloads
);
4476 if (FuncExp fe
= exp
.e1
.isFuncExp())
4478 if (arrayExpressionSemantic(exp
.arguments
.peekSlice(), sc
) ||
4479 preFunctionParameters(sc
, exp
.argumentList
))
4482 // Run e1 semantic even if arguments have any errors
4483 exp
.e1
= callExpSemantic(fe
, sc
, exp
.arguments
);
4484 if (exp
.e1
.op
== EXP
.error
)
4490 if (sc
.flags
& SCOPE
.Cfile
)
4492 /* See if need to rewrite the AST because of cast/call ambiguity
4494 if (auto e
= castCallAmbiguity(exp
, sc
))
4496 result
= expressionSemantic(e
, sc
);
4501 if (Expression ex
= resolveUFCS(sc
, exp
))
4508 * foo!(tiargs)(funcargs)
4510 if (ScopeExp se
= exp
.e1
.isScopeExp())
4512 TemplateInstance ti
= se
.sds
.isTemplateInstance();
4515 /* Attempt to instantiate ti. If that works, go with it.
4516 * If not, go with partial explicit specialization.
4518 WithScopeSymbol withsym
;
4519 if (!ti
.findTempDecl(sc
, &withsym
) ||
!ti
.semanticTiargs(sc
))
4521 if (withsym
&& withsym
.withstate
.wthis
)
4523 exp
.e1
= new VarExp(exp
.e1
.loc
, withsym
.withstate
.wthis
);
4524 exp
.e1
= new DotTemplateInstanceExp(exp
.e1
.loc
, exp
.e1
, ti
);
4527 if (ti
.needsTypeInference(sc
, 1))
4529 /* Go with partial explicit specialization
4532 assert(ti
.tempdecl
);
4533 if (TemplateDeclaration td
= ti
.tempdecl
.isTemplateDeclaration())
4534 exp
.e1
= new TemplateExp(exp
.loc
, td
);
4535 else if (OverDeclaration od
= ti
.tempdecl
.isOverDeclaration())
4536 exp
.e1
= new VarExp(exp
.loc
, od
);
4538 exp
.e1
= new OverExp(exp
.loc
, ti
.tempdecl
.isOverloadSet());
4542 Expression e1x
= exp
.e1
.expressionSemantic(sc
);
4543 if (e1x
.op
== EXP
.error
)
4554 * expr.foo!(tiargs)(funcargs)
4557 if (DotTemplateInstanceExp se
= exp
.e1
.isDotTemplateInstanceExp())
4559 TemplateInstance ti
= se
.ti
;
4561 /* Attempt to instantiate ti. If that works, go with it.
4562 * If not, go with partial explicit specialization.
4564 if (!se
.findTempDecl(sc
) ||
!ti
.semanticTiargs(sc
))
4566 if (ti
.needsTypeInference(sc
, 1))
4568 /* Go with partial explicit specialization
4571 assert(ti
.tempdecl
);
4572 if (TemplateDeclaration td
= ti
.tempdecl
.isTemplateDeclaration())
4573 exp
.e1
= new DotTemplateExp(exp
.loc
, se
.e1
, td
);
4574 else if (OverDeclaration od
= ti
.tempdecl
.isOverDeclaration())
4576 exp
.e1
= new DotVarExp(exp
.loc
, se
.e1
, od
, true);
4579 exp
.e1
= new DotExp(exp
.loc
, se
.e1
, new OverExp(exp
.loc
, ti
.tempdecl
.isOverloadSet()));
4583 Expression e1x
= exp
.e1
.expressionSemantic(sc
);
4584 if (e1x
.op
== EXP
.error
)
4596 //printf("Lagain: %s\n", toChars());
4598 if (exp
.e1
.op
== EXP
.this_ || exp
.e1
.op
== EXP
.super_
)
4600 // semantic() run later for these
4604 if (DotIdExp die
= exp
.e1
.isDotIdExp())
4606 exp
.e1
= die
.expressionSemantic(sc
);
4607 /* Look for e1 having been rewritten to expr.opDispatch!(string)
4608 * We handle such earlier, so go back.
4609 * Note that in the rewrite, we carefully did not run semantic() on e1
4611 if (exp
.e1
.op
== EXP
.dotTemplateInstance
)
4619 if (++nest
> global
.recursionLimit
)
4621 exp
.error("recursive evaluation of `%s`", exp
.toChars());
4625 Expression ex
= unaSemantic(exp
, sc
);
4634 /* Look for e1 being a lazy parameter
4636 if (VarExp ve
= exp
.e1
.isVarExp())
4638 if (ve
.var
.storage_class
& STC
.lazy_
)
4640 // lazy parameters can be called without violating purity and safety
4641 Type tw
= ve
.var
.type
;
4642 Type tc
= ve
.var
.type
.substWildTo(MODFlags
.const_
);
4643 auto tf
= new TypeFunction(ParameterList(), tc
, LINK
.d
, STC
.safe | STC
.pure_
);
4644 (tf
= cast(TypeFunction
)tf
.typeSemantic(exp
.loc
, sc
)).next
= tw
; // hack for bug7757
4645 auto t
= new TypeDelegate(tf
);
4646 ve
.type
= t
.typeSemantic(exp
.loc
, sc
);
4648 VarDeclaration v
= ve
.var
.isVarDeclaration();
4649 if (v
&& ve
.checkPurity(sc
, v
))
4653 if (exp
.e1
.op
== EXP
.symbolOffset
&& (cast(SymOffExp
)exp
.e1
).hasOverloads
)
4655 SymOffExp se
= cast(SymOffExp
)exp
.e1
;
4656 exp
.e1
= new VarExp(se
.loc
, se
.var
, true);
4657 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
4659 else if (DotExp
de = exp
.e1
.isDotExp())
4661 if (de.e2
.op
== EXP
.overloadSet
)
4668 else if (exp
.e1
.op
== EXP
.star
&& exp
.e1
.type
.ty
== Tfunction
)
4670 // Rewrite (*fp)(arguments) to fp(arguments)
4671 exp
.e1
= (cast(PtrExp
)exp
.e1
).e1
;
4673 else if (exp
.e1
.op
== EXP
.type
&& (sc
&& sc
.flags
& SCOPE
.Cfile
))
4675 const numArgs
= exp
.arguments ? exp
.arguments
.length
: 0;
4677 /* Ambiguous cases arise from CParser where there is not enough
4678 * information to determine if we have a function call or declaration.
4679 * type-name ( identifier ) ;
4680 * identifier ( identifier ) ;
4681 * If exp.e1 is a type-name, then this is a declaration. C11 does not
4682 * have type construction syntax, so don't convert this to a cast().
4686 Expression arg
= (*exp
.arguments
)[0];
4687 if (auto ie
= (*exp
.arguments
)[0].isIdentifierExp())
4689 TypeExp te
= cast(TypeExp
)exp
.e1
;
4690 auto initializer
= new VoidInitializer(ie
.loc
);
4691 Dsymbol s
= new VarDeclaration(ie
.loc
, te
.type
, ie
.ident
, initializer
);
4692 auto decls
= new Dsymbols(1);
4694 s
= new LinkDeclaration(s
.loc
, LINK
.c
, decls
);
4695 result
= new DeclarationExp(exp
.loc
, s
);
4696 result
= result
.expressionSemantic(sc
);
4700 arg
.error("identifier or `(` expected");
4701 result
= ErrorExp
.get();
4705 exp
.error("identifier or `(` expected before `)`");
4706 result
= ErrorExp
.get();
4711 Type t1
= exp
.e1
.type ? exp
.e1
.type
.toBasetype() : null;
4713 if (exp
.e1
.op
== EXP
.error
)
4718 if (arrayExpressionSemantic(exp
.arguments
.peekSlice(), sc
) ||
4719 preFunctionParameters(sc
, exp
.argumentList
))
4722 // Check for call operator overload
4725 if (t1
.ty
== Tstruct
)
4727 auto sd
= (cast(TypeStruct
)t1
).sym
;
4728 sd
.size(exp
.loc
); // Resolve forward references to construct object
4729 if (sd
.sizeok
!= Sizeok
.done
)
4732 sd
.ctor
= sd
.searchCtor();
4733 /* If `sd.ctor` is a generated copy constructor, this means that it
4734 is the single constructor that this struct has. In order to not
4735 disable default construction, the ctor is nullified. The side effect
4736 of this is that the generated copy constructor cannot be called
4737 explicitly, but that is ok, because when calling a constructor the
4738 default constructor should have priority over the generated copy
4743 auto ctor
= sd
.ctor
.isCtorDeclaration();
4744 if (ctor
&& ctor
.isCpCtor
&& ctor
.isGenerated())
4748 // First look for constructor
4749 if (exp
.e1
.op
== EXP
.type
&& sd
.ctor
)
4751 if (!sd
.noDefaultCtor
&& !(exp
.arguments
&& exp
.arguments
.length
))
4754 /* https://issues.dlang.org/show_bug.cgi?id=20695
4755 If all constructors are copy constructors, then
4756 try default construction.
4758 if (!sd
.hasRegularCtor
&&
4759 // https://issues.dlang.org/show_bug.cgi?id=22639
4760 // we might still have a copy constructor that could be called
4761 (*exp
.arguments
)[0].type
.mutableOf
!= sd
.type
.mutableOf())
4764 auto sle
= new StructLiteralExp(exp
.loc
, sd
, null, exp
.e1
.type
);
4765 if (!sd
.fill(exp
.loc
, *sle
.elements
, true))
4767 if (checkFrameAccess(exp
.loc
, sc
, sd
, sle
.elements
.length
))
4770 // https://issues.dlang.org/show_bug.cgi?id=14556
4771 // Set concrete type to avoid further redundant semantic().
4772 sle
.type
= exp
.e1
.type
;
4774 /* Constructor takes a mutable object, so don't use
4775 * the immutable initializer symbol.
4777 sle
.useStaticInit
= false;
4780 if (auto cf
= sd
.ctor
.isCtorDeclaration())
4782 e
= new DotVarExp(exp
.loc
, e
, cf
, true);
4784 else if (auto td
= sd
.ctor
.isTemplateDeclaration())
4786 e
= new DotIdExp(exp
.loc
, e
, td
.ident
);
4788 else if (auto os
= sd
.ctor
.isOverloadSet())
4790 e
= new DotExp(exp
.loc
, e
, new OverExp(exp
.loc
, os
));
4794 e
= new CallExp(exp
.loc
, e
, exp
.arguments
);
4795 e
= e
.expressionSemantic(sc
);
4799 // No constructor, look for overload of opCall
4800 if (search_function(sd
, Id
.call))
4802 // overload of opCall, therefore it's a call
4803 if (exp
.e1
.op
!= EXP
.type
)
4805 if (sd
.aliasthis
&& !isRecursiveAliasThis(att
, exp
.e1
.type
))
4807 exp
.e1
= resolveAliasThis(sc
, exp
.e1
);
4810 exp
.error("%s `%s` does not overload ()", sd
.kind(), sd
.toChars());
4814 /* It's a struct literal
4817 Expressions
* resolvedArgs
= exp
.arguments
;
4820 resolvedArgs
= resolveStructLiteralNamedArgs(sd
, exp
.e1
.type
, sc
, exp
.loc
,
4822 (size_t i
, Type t
) => (*exp
.arguments
)[i
],
4823 i
=> (*exp
.arguments
)[i
].loc
4827 result
= ErrorExp
.get();
4832 Expression e
= new StructLiteralExp(exp
.loc
, sd
, resolvedArgs
, exp
.e1
.type
);
4833 e
= e
.expressionSemantic(sc
);
4837 else if (t1
.ty
== Tclass
)
4840 // Rewrite as e1.call(arguments)
4841 Expression e
= new DotIdExp(exp
.loc
, exp
.e1
, Id
.call);
4842 e
= new CallExp(exp
.loc
, e
, exp
.arguments
, exp
.names
);
4843 e
= e
.expressionSemantic(sc
);
4847 else if (exp
.e1
.op
== EXP
.type
&& t1
.isscalar())
4851 // Make sure to use the enum type itself rather than its
4853 // https://issues.dlang.org/show_bug.cgi?id=16346
4854 if (exp
.e1
.type
.ty
== Tenum
)
4859 if (!exp
.arguments || exp
.arguments
.length
== 0)
4861 e
= t1
.defaultInitLiteral(exp
.loc
);
4863 else if (exp
.arguments
.length
== 1)
4865 e
= (*exp
.arguments
)[0];
4866 e
= e
.implicitCastTo(sc
, t1
);
4867 e
= new CastExp(exp
.loc
, e
, t1
);
4871 exp
.error("more than one argument for construction of `%s`", t1
.toChars());
4874 e
= e
.expressionSemantic(sc
);
4880 FuncDeclaration
resolveOverloadSet(Loc loc
, Scope
* sc
,
4881 OverloadSet os
, Objects
* tiargs
, Type tthis
, ArgumentList argumentList
)
4883 FuncDeclaration f
= null;
4886 if (tiargs
&& s
.isFuncDeclaration())
4888 if (auto f2
= resolveFuncCall(loc
, sc
, s
, tiargs
, tthis
, argumentList
, FuncResolveFlag
.quiet
))
4894 /* Match in more than one overload set,
4895 * even if one is a 'better' match than the other.
4897 if (f
.isCsymbol() && f2
.isCsymbol())
4899 /* C has global name space, so just pick one, such as f.
4900 * If f and f2 are not compatible, that's how C rolls.
4904 ScopeDsymbol
.multiplyDefined(loc
, f
, f2
); // issue error
4912 .error(loc
, "no overload matches for `%s`", exp
.toChars());
4913 errorSupplemental(loc
, "Candidates are:");
4916 overloadApply(s
, (ds){
4917 if (auto fd
= ds.isFuncDeclaration())
4918 .errorSupplemental(ds.loc
, "%s%s", fd
.toChars(),
4919 fd
.type
.toTypeFunction().parameterList
.parametersTypeToChars());
4921 .errorSupplemental(ds.loc
, "%s", ds.toChars());
4931 bool isSuper
= false;
4932 if (exp
.e1
.op
== EXP
.dotVariable
&& t1
.ty
== Tfunction || exp
.e1
.op
== EXP
.dotTemplateDeclaration
)
4934 UnaExp ue
= cast(UnaExp
)exp
.e1
;
4936 Expression ue1old
= ue
.e1
; // need for 'right this' check
4940 if (exp
.e1
.op
== EXP
.dotVariable
)
4942 dve
= cast(DotVarExp
)exp
.e1
;
4950 dte
= cast(DotTemplateExp
)exp
.e1
;
4954 // Do overload resolution
4955 exp
.f
= resolveFuncCall(exp
.loc
, sc
, s
, tiargs
, ue
.e1
.type
, exp
.argumentList
, FuncResolveFlag
.standard
);
4956 if (!exp
.f || exp
.f
.errors || exp
.f
.type
.ty
== Terror
)
4959 if (exp
.f
.interfaceVirtual
)
4961 /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent
4963 auto b
= exp
.f
.interfaceVirtual
;
4965 ue
.e1
= ue
.e1
.castTo(sc
, ad2
.type
.addMod(ue
.e1
.type
.mod
));
4966 ue
.e1
= ue
.e1
.expressionSemantic(sc
);
4967 auto vi
= exp
.f
.findVtblIndex(&ad2
.vtbl
, cast(int)ad2
.vtbl
.length
);
4969 exp
.f
= ad2
.vtbl
[vi
].isFuncDeclaration();
4972 if (exp
.f
.needThis())
4974 AggregateDeclaration ad
= exp
.f
.isMemberLocal();
4975 ue
.e1
= getRightThis(exp
.loc
, sc
, ad
, ue
.e1
, exp
.f
);
4976 if (ue
.e1
.op
== EXP
.error
)
4983 if (!(exp
.f
.type
.ty
== Tfunction
&& (cast(TypeFunction
)exp
.f
.type
).isScopeQual
))
4985 if (checkParamArgumentEscape(sc
, exp
.f
, Id
.This
, exp
.f
.vthis
, STC
.undefined_
, ethis
, false, false))
4990 /* Cannot call public functions from inside invariant
4991 * (because then the invariant would have infinite recursion)
4993 if (sc
.func
&& sc
.func
.isInvariantDeclaration() && ue
.e1
.op
== EXP
.this_
&& exp
.f
.addPostInvariant())
4995 exp
.error("cannot call `public`/`export` function `%s` from invariant", exp
.f
.toChars());
4999 if (!exp
.ignoreAttributes
)
5000 checkFunctionAttributes(exp
, sc
, exp
.f
);
5002 // Cut-down version of checkAccess() that doesn't use the "most visible" version of exp.f.
5003 // We've already selected an overload here.
5004 const parent
= exp
.f
.toParent();
5005 if (parent
&& parent
.isTemplateInstance())
5007 // already a deprecation
5009 else if (!checkSymbolAccess(sc
, exp
.f
))
5011 exp
.error("%s `%s` of type `%s` is not accessible from module `%s`",
5012 exp
.f
.kind(), exp
.f
.toPrettyChars(), exp
.f
.type
.toChars(), sc
._module
.toChars
);
5016 if (!exp
.f
.needThis())
5018 exp
.e1
= Expression
.combine(ue
.e1
, new VarExp(exp
.loc
, exp
.f
, false));
5022 if (ue1old
.checkRightThis(sc
))
5024 if (exp
.e1
.op
== EXP
.dotVariable
)
5027 exp
.e1
.type
= exp
.f
.type
;
5031 exp
.e1
= new DotVarExp(exp
.loc
, dte
.e1
, exp
.f
, false);
5032 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
5033 if (exp
.e1
.op
== EXP
.error
)
5035 ue
= cast(UnaExp
)exp
.e1
;
5039 printf("ue.e1 = %s\n", ue
.e1
.toChars());
5040 printf("f = %s\n", exp
.f
.toChars());
5041 printf("t1 = %s\n", t1
.toChars());
5042 printf("e1 = %s\n", exp
.e1
.toChars());
5043 printf("e1.type = %s\n", exp
.e1
.type
.toChars());
5046 // See if we need to adjust the 'this' pointer
5047 AggregateDeclaration ad
= exp
.f
.isThis();
5048 ClassDeclaration cd
= ue
.e1
.type
.isClassHandle();
5049 if (ad
&& cd
&& ad
.isClassDeclaration())
5051 if (ue
.e1
.op
== EXP
.dotType
)
5053 ue
.e1
= (cast(DotTypeExp
)ue
.e1
).e1
;
5054 exp
.directcall
= true;
5056 else if (ue
.e1
.op
== EXP
.super_
)
5057 exp
.directcall
= true;
5058 else if ((cd
.storage_class
& STC
.final_
) != 0) // https://issues.dlang.org/show_bug.cgi?id=14211
5059 exp
.directcall
= true;
5063 ue
.e1
= ue
.e1
.castTo(sc
, ad
.type
.addMod(ue
.e1
.type
.mod
));
5064 ue
.e1
= ue
.e1
.expressionSemantic(sc
);
5068 // If we've got a pointer to a function then deference it
5069 // https://issues.dlang.org/show_bug.cgi?id=16483
5070 if (exp
.e1
.type
.isPtrToFunction())
5072 Expression e
= new PtrExp(exp
.loc
, exp
.e1
);
5073 e
.type
= exp
.e1
.type
.nextOf();
5078 else if (exp
.e1
.op
== EXP
.super_ || exp
.e1
.op
== EXP
.this_
)
5080 auto ad
= sc
.func ? sc
.func
.isThis() : null;
5081 auto cd
= ad ? ad
.isClassDeclaration() : null;
5083 isSuper
= exp
.e1
.op
== EXP
.super_
;
5086 // Base class constructor call
5087 if (!cd ||
!cd
.baseClass ||
!sc
.func
.isCtorDeclaration())
5089 exp
.error("super class constructor call must be in a constructor");
5092 if (!cd
.baseClass
.ctor
)
5094 exp
.error("no super class constructor for `%s`", cd
.baseClass
.toChars());
5100 // `this` call expression must be inside a
5102 if (!ad ||
!sc
.func
.isCtorDeclaration())
5104 exp
.error("constructor call must be in a constructor");
5108 // https://issues.dlang.org/show_bug.cgi?id=18719
5109 // If `exp` is a call expression to another constructor
5110 // then it means that all struct/class fields will be
5111 // initialized after this call.
5112 foreach (ref field
; sc
.ctorflow
.fieldinit
)
5114 field
.csx |
= CSX
.this_ctor
;
5118 if (!sc
.intypeof
&& !(sc
.ctorflow
.callSuper
& CSX
.halt
))
5120 if (sc
.inLoop || sc
.ctorflow
.callSuper
& CSX
.label
)
5121 exp
.error("constructor calls not allowed in loops or after labels");
5122 if (sc
.ctorflow
.callSuper
& (CSX
.super_ctor | CSX
.this_ctor
))
5123 exp
.error("multiple constructor calls");
5124 if ((sc
.ctorflow
.callSuper
& CSX
.return_
) && !(sc
.ctorflow
.callSuper
& CSX
.any_ctor
))
5125 exp
.error("an earlier `return` statement skips constructor");
5126 sc
.ctorflow
.callSuper |
= CSX
.any_ctor |
(isSuper ? CSX
.super_ctor
: CSX
.this_ctor
);
5129 tthis
= ad
.type
.addMod(sc
.func
.type
.mod
);
5130 auto ctor
= isSuper ? cd
.baseClass
.ctor
: ad
.ctor
;
5131 if (auto os
= ctor
.isOverloadSet())
5132 exp
.f
= resolveOverloadSet(exp
.loc
, sc
, os
, null, tthis
, exp
.argumentList
);
5134 exp
.f
= resolveFuncCall(exp
.loc
, sc
, ctor
, null, tthis
, exp
.argumentList
, FuncResolveFlag
.standard
);
5136 if (!exp
.f || exp
.f
.errors
)
5139 checkFunctionAttributes(exp
, sc
, exp
.f
);
5140 checkAccess(exp
.loc
, sc
, null, exp
.f
);
5142 exp
.e1
= new DotVarExp(exp
.e1
.loc
, exp
.e1
, exp
.f
, false);
5143 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
5144 // https://issues.dlang.org/show_bug.cgi?id=21095
5145 if (exp
.e1
.op
== EXP
.error
)
5149 // BUG: this should really be done by checking the static
5151 if (exp
.f
== sc
.func
)
5153 exp
.error("cyclic constructor call");
5157 else if (auto oe
= exp
.e1
.isOverExp())
5159 exp
.f
= resolveOverloadSet(exp
.loc
, sc
, oe
.vars
, tiargs
, tthis
, exp
.argumentList
);
5163 exp
.e1
= new DotVarExp(exp
.loc
, ethis
, exp
.f
, false);
5165 exp
.e1
= new VarExp(exp
.loc
, exp
.f
, false);
5170 exp
.error("function expected before `()`, not `%s`", exp
.e1
.toChars());
5173 else if (t1
.ty
== Terror
)
5177 else if (t1
.ty
!= Tfunction
)
5183 if (auto fe
= exp
.e1
.isFuncExp())
5185 // function literal that direct called is always inferred.
5188 tf
= cast(TypeFunction
)exp
.f
.type
;
5189 p
= "function literal";
5191 else if (t1
.ty
== Tdelegate
)
5193 TypeDelegate td
= cast(TypeDelegate
)t1
;
5194 assert(td
.next
.ty
== Tfunction
);
5195 tf
= cast(TypeFunction
)td
.next
;
5198 else if (auto tfx
= t1
.isPtrToFunction())
5201 p
= "function pointer";
5203 else if (exp
.e1
.op
== EXP
.dotVariable
&& (cast(DotVarExp
)exp
.e1
).var
.isOverDeclaration())
5205 DotVarExp dve
= cast(DotVarExp
)exp
.e1
;
5206 exp
.f
= resolveFuncCall(exp
.loc
, sc
, dve
.var
, tiargs
, dve
.e1
.type
, exp
.argumentList
, FuncResolveFlag
.overloadOnly
);
5209 if (exp
.f
.needThis())
5212 dve
.type
= exp
.f
.type
;
5213 dve
.hasOverloads
= false;
5216 exp
.e1
= new VarExp(dve
.loc
, exp
.f
, false);
5217 Expression e
= new CommaExp(exp
.loc
, dve
.e1
, exp
);
5218 result
= e
.expressionSemantic(sc
);
5221 else if (exp
.e1
.op
== EXP
.variable
&& (cast(VarExp
)exp
.e1
).var
.isOverDeclaration())
5223 s
= (cast(VarExp
)exp
.e1
).var
;
5226 else if (exp
.e1
.op
== EXP
.template_
)
5228 s
= (cast(TemplateExp
)exp
.e1
).td
;
5230 exp
.f
= resolveFuncCall(exp
.loc
, sc
, s
, tiargs
, null, exp
.argumentList
,
5231 exp
.isUfcsRewrite ? FuncResolveFlag
.ufcs
: FuncResolveFlag
.standard
);
5232 if (!exp
.f || exp
.f
.errors
)
5234 if (exp
.f
.needThis())
5238 // Supply an implicit 'this', as in
5240 exp
.e1
= new DotVarExp(exp
.loc
, (new ThisExp(exp
.loc
)).expressionSemantic(sc
), exp
.f
, false);
5243 else if (isNeedThisScope(sc
, exp
.f
))
5245 exp
.error("need `this` for `%s` of type `%s`", exp
.f
.toChars(), exp
.f
.type
.toChars());
5249 exp
.e1
= new VarExp(exp
.e1
.loc
, exp
.f
, false);
5254 exp
.error("function expected before `()`, not `%s` of type `%s`", exp
.e1
.toChars(), exp
.e1
.type
.toChars());
5258 const(char)* failMessage
;
5259 if (!tf
.callMatch(null, exp
.argumentList
, 0, &failMessage
, sc
))
5263 argExpTypesToCBuffer(&buf
, exp
.arguments
);
5266 tthis
.modToBuffer(&buf
);
5268 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
5269 .error(exp
.loc
, "%s `%s%s` is not callable using argument types `%s`",
5270 p
, exp
.e1
.toChars(), parametersTypeToChars(tf
.parameterList
), buf
.peekChars());
5272 errorSupplemental(exp
.loc
, "%s", failMessage
);
5275 // Purity and safety check should run after testing arguments matching
5278 exp
.checkPurity(sc
, exp
.f
);
5279 exp
.checkSafety(sc
, exp
.f
);
5280 exp
.checkNogc(sc
, exp
.f
);
5281 if (exp
.f
.checkNestedReference(sc
, exp
.loc
))
5284 else if (sc
.func
&& sc
.intypeof
!= 1 && !(sc
.flags
& (SCOPE
.ctfe | SCOPE
.debug_
)))
5287 if (!tf
.purity
&& sc
.func
.setImpure(exp
.loc
, "`pure` %s `%s` cannot call impure `%s`", exp
.e1
))
5289 exp
.error("`pure` %s `%s` cannot call impure %s `%s`",
5290 sc
.func
.kind(), sc
.func
.toPrettyChars(), p
, exp
.e1
.toChars());
5293 if (!tf
.isnogc
&& sc
.func
.setGC(exp
.loc
, "`@nogc` %s `%s` cannot call non-@nogc `%s`", exp
.e1
))
5295 exp
.error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
5296 sc
.func
.kind(), sc
.func
.toPrettyChars(), p
, exp
.e1
.toChars());
5299 if (tf
.trust
<= TRUST
.system
&& sc
.setUnsafe(true, exp
.loc
,
5300 "`@safe` function `%s` cannot call `@system` `%s`", sc
.func
, exp
.e1
))
5302 exp
.error("`@safe` %s `%s` cannot call `@system` %s `%s`",
5303 sc
.func
.kind(), sc
.func
.toPrettyChars(), p
, exp
.e1
.toChars());
5310 if (t1
.ty
== Tpointer
)
5312 Expression e
= new PtrExp(exp
.loc
, exp
.e1
);
5318 else if (VarExp ve
= exp
.e1
.isVarExp())
5320 // Do overload resolution
5321 exp
.f
= ve
.var
.isFuncDeclaration();
5326 exp
.f
= resolveFuncCall(exp
.loc
, sc
, exp
.f
, tiargs
, null, exp
.argumentList
, FuncResolveFlag
.overloadOnly
);
5329 exp
.f
= exp
.f
.toAliasFunc();
5330 TypeFunction tf
= cast(TypeFunction
)exp
.f
.type
;
5331 const(char)* failMessage
;
5332 if (!tf
.callMatch(null, exp
.argumentList
, 0, &failMessage
, sc
))
5336 argExpTypesToCBuffer(&buf
, exp
.arguments
);
5339 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
5340 if (exp
.isUfcsRewrite
)
5342 const arg
= (*exp
.argumentList
.arguments
)[0];
5343 .error(exp
.loc
, "no property `%s` for `%s` of type `%s`", exp
.f
.ident
.toChars(), arg
.toChars(), arg
.type
.toChars());
5344 .errorSupplemental(exp
.loc
, "the following error occured while looking for a UFCS match");
5347 .error(exp
.loc
, "%s `%s%s` is not callable using argument types `%s`",
5348 exp
.f
.kind(), exp
.f
.toPrettyChars(), parametersTypeToChars(tf
.parameterList
), buf
.peekChars());
5350 errorSupplemental(exp
.loc
, "%s", failMessage
);
5354 if (!exp
.f || exp
.f
.errors
)
5357 if (exp
.f
.needThis())
5359 // Change the ancestor lambdas to delegate before hasThis(sc) call.
5360 if (exp
.f
.checkNestedReference(sc
, exp
.loc
))
5363 auto memberFunc
= hasThis(sc
);
5364 if (memberFunc
&& haveSameThis(memberFunc
, exp
.f
))
5366 // Supply an implicit 'this', as in
5368 exp
.e1
= new DotVarExp(exp
.loc
, (new ThisExp(exp
.loc
)).expressionSemantic(sc
), ve
.var
);
5369 // Note: we cannot use f directly, because further overload resolution
5370 // through the supplied 'this' may cause different result.
5373 else if (isNeedThisScope(sc
, exp
.f
))
5375 // At this point it is possible that `exp.f` had an ambiguity error that was
5376 // silenced because the previous call to `resolveFuncCall` was done using
5377 // `FuncResolveFlag.overloadOnly`. To make sure that a proper error message
5378 // is printed, redo the call with `FuncResolveFlag.standard`.
5380 // https://issues.dlang.org/show_bug.cgi?id=22157
5382 exp
.f
= resolveFuncCall(exp
.loc
, sc
, exp
.f
, tiargs
, null, exp
.argumentList
, FuncResolveFlag
.standard
);
5384 if (!exp
.f || exp
.f
.errors
)
5387 // If no error is printed, it means that `f` is the single matching overload
5388 // and it needs `this`.
5389 exp
.error("need `this` for `%s` of type `%s`", exp
.f
.toChars(), exp
.f
.type
.toChars());
5394 checkFunctionAttributes(exp
, sc
, exp
.f
);
5395 checkAccess(exp
.loc
, sc
, null, exp
.f
);
5396 if (exp
.f
.checkNestedReference(sc
, exp
.loc
))
5402 if (ve
.hasOverloads
)
5404 exp
.e1
= new VarExp(ve
.loc
, exp
.f
, false);
5405 exp
.e1
.type
= exp
.f
.type
;
5409 assert(t1
.ty
== Tfunction
);
5411 Expression argprefix
;
5413 exp
.arguments
= new Expressions();
5414 if (functionParameters(exp
.loc
, sc
, cast(TypeFunction
)t1
, ethis
, tthis
, exp
.argumentList
, exp
.f
, &exp
.type
, &argprefix
))
5419 exp
.e1
= e1org
; // https://issues.dlang.org/show_bug.cgi?id=10922
5420 // avoid recursive expression printing
5421 exp
.error("forward reference to inferred return type of function call `%s`", exp
.toChars());
5425 if (exp
.f
&& exp
.f
.tintro
)
5429 TypeFunction tf
= cast(TypeFunction
)exp
.f
.tintro
;
5430 if (tf
.next
.isBaseOf(t
, &offset
) && offset
)
5433 result
= Expression
.combine(argprefix
, exp
.castTo(sc
, t
));
5438 // Handle the case of a direct lambda call
5439 if (exp
.f
&& exp
.f
.isFuncLiteralDeclaration() && sc
.func
&& !sc
.intypeof
)
5441 exp
.f
.tookAddressOf
= 0;
5444 result
= Expression
.combine(argprefix
, exp
);
5448 auto ad
= sc
.func ? sc
.func
.isThis() : null;
5449 auto cd
= ad ? ad
.isClassDeclaration() : null;
5450 if (cd
&& cd
.classKind
== ClassKind
.cpp
&& exp
.f
&& !exp
.f
.fbody
)
5452 // if super is defined in C++, it sets the vtable pointer to the base class
5453 // so we have to restore it, but still return 'this' from super() call:
5454 // (auto __vptrTmp = this.__vptr, auto __superTmp = super()), (this.__vptr = __vptrTmp, __superTmp)
5457 auto vptr
= new DotIdExp(loc
, new ThisExp(loc
), Id
.__vptr
);
5458 auto vptrTmpDecl
= copyToTemp(0, "__vptrTmp", vptr
);
5459 auto declareVptrTmp
= new DeclarationExp(loc
, vptrTmpDecl
);
5461 auto superTmpDecl
= copyToTemp(0, "__superTmp", result
);
5462 auto declareSuperTmp
= new DeclarationExp(loc
, superTmpDecl
);
5464 auto declareTmps
= new CommaExp(loc
, declareVptrTmp
, declareSuperTmp
);
5466 auto restoreVptr
= new AssignExp(loc
, vptr
.syntaxCopy(), new VarExp(loc
, vptrTmpDecl
));
5468 Expression e
= new CommaExp(loc
, declareTmps
, new CommaExp(loc
, restoreVptr
, new VarExp(loc
, superTmpDecl
)));
5469 result
= e
.expressionSemantic(sc
);
5473 // declare dual-context container
5474 if (exp
.f
&& exp
.f
.hasDualContext() && !sc
.intypeof
&& sc
.func
)
5476 // check access to second `this`
5477 if (AggregateDeclaration ad2
= exp
.f
.isMember2())
5479 Expression te
= new ThisExp(exp
.loc
).expressionSemantic(sc
);
5480 if (te
.op
!= EXP
.error
)
5481 te
= getRightThis(exp
.loc
, sc
, ad2
, te
, exp
.f
);
5482 if (te
.op
== EXP
.error
)
5484 exp
.error("need `this` of type `%s` to call function `%s`", ad2
.toChars(), exp
.f
.toChars());
5488 exp
.vthis2
= makeThis2Argument(exp
.loc
, sc
, exp
.f
);
5489 Expression
de = new DeclarationExp(exp
.loc
, exp
.vthis2
);
5490 result
= Expression
.combine(de, result
);
5491 result
= result
.expressionSemantic(sc
);
5495 override void visit(DeclarationExp e
)
5502 static if (LOGSEMANTIC
)
5504 printf("DeclarationExp::semantic() %s\n", e
.toChars());
5507 uint olderrors
= global
.errors
;
5509 /* This is here to support extern(linkage) declaration,
5510 * where the extern(linkage) winds up being an AttribDeclaration
5513 Dsymbol s
= e
.declaration
;
5517 AttribDeclaration ad
= s
.isAttribDeclaration();
5520 if (ad
.decl
&& ad
.decl
.length
== 1)
5529 //printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc);
5530 // Insert into both local scope and function scope.
5531 // Must be unique in both.
5534 VarDeclaration v
= s
.isVarDeclaration();
5537 if (sc
.flags
& SCOPE
.Cfile
)
5539 /* Do semantic() on the type before inserting v into the symbol table
5541 if (!v
.originalType
)
5542 v
.originalType
= v
.type
.syntaxCopy();
5543 Scope
* sc2
= sc
.push();
5544 sc2
.stc |
= v
.storage_class
& STC
.FUNCATTR
;
5545 sc2
.linkage
= LINK
.c
; // account for the extern(C) in front of the declaration
5547 v
.type
= v
.type
.typeSemantic(v
.loc
, sc2
);
5553 /* Do semantic() on initializer first so this will be illegal:
5556 e
.declaration
.dsymbolSemantic(sc
);
5557 s
.parent
= sc
.parent
;
5563 auto conflict
= sc
.search(Loc
.initial
, s
.ident
, null);
5564 e
.error("declaration `%s` is already defined", s
.toPrettyChars());
5565 errorSupplemental(conflict
.loc
, "`%s` `%s` is defined here",
5566 conflict
.kind(), conflict
.toChars());
5570 if (v
&& (sc
.flags
& SCOPE
.Cfile
))
5572 /* Do semantic() on initializer last so this will be legal:
5575 e
.declaration
.dsymbolSemantic(sc
);
5576 s
.parent
= sc
.parent
;
5581 // https://issues.dlang.org/show_bug.cgi?id=11720
5582 if ((s
.isFuncDeclaration() ||
5583 s
.isAggregateDeclaration() ||
5584 s
.isEnumDeclaration() ||
5585 s
.isTemplateDeclaration() ||
5587 ) && !sc
.func
.localsymtab
.insert(s
))
5589 // Get the previous symbol
5590 Dsymbol originalSymbol
= sc
.func
.localsymtab
.lookup(s
.ident
);
5592 // Perturb the name mangling so that the symbols can co-exist
5593 // instead of colliding
5594 s
.localNum
= cast(ushort)(originalSymbol
.localNum
+ 1);
5595 // 65535 should be enough for anyone
5598 e
.error("more than 65535 symbols with name `%s` generated", s
.ident
.toChars());
5602 // Replace originalSymbol with s, which updates the localCount
5603 sc
.func
.localsymtab
.update(s
);
5605 // The mangling change only works for D mangling
5608 if (!(sc
.flags
& SCOPE
.Cfile
))
5610 /* https://issues.dlang.org/show_bug.cgi?id=21272
5611 * If we are in a foreach body we need to extract the
5612 * function containing the foreach
5614 FuncDeclaration fes_enclosing_func
;
5615 if (sc
.func
&& sc
.func
.fes
)
5616 fes_enclosing_func
= sc
.enclosing
.enclosing
.func
;
5618 // Disallow shadowing
5619 for (Scope
* scx
= sc
.enclosing
; scx
&& (scx
.func
== sc
.func ||
(fes_enclosing_func
&& scx
.func
== fes_enclosing_func
)); scx
= scx
.enclosing
)
5622 if (scx
.scopesym
&& scx
.scopesym
.symtab
&& (s2
= scx
.scopesym
.symtab
.lookup(s
.ident
)) !is null && s
!= s2
)
5624 // allow STC.local symbols to be shadowed
5625 // TODO: not really an optimal design
5626 auto decl
= s2
.isDeclaration();
5627 if (!decl ||
!(decl
.storage_class
& STC
.local
))
5631 e
.deprecation("%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.", s
.kind(), s
.ident
.toChars(), s2
.kind(), s2
.toPrettyChars());
5635 e
.error("%s `%s` is shadowing %s `%s`", s
.kind(), s
.ident
.toChars(), s2
.kind(), s2
.toPrettyChars());
5644 if (!s
.isVarDeclaration())
5647 if (sc2
.stc & (STC
.pure_ | STC
.nothrow_ | STC
.nogc
))
5649 sc2
.stc &= ~(STC
.pure_ | STC
.nothrow_ | STC
.nogc
);
5650 e
.declaration
.dsymbolSemantic(sc2
);
5653 s
.parent
= sc
.parent
;
5655 if (global
.errors
== olderrors
)
5657 e
.declaration
.semantic2(sc
);
5658 if (global
.errors
== olderrors
)
5660 e
.declaration
.semantic3(sc
);
5663 // todo: error in declaration should be propagated.
5665 e
.type
= Type
.tvoid
;
5669 override void visit(TypeidExp exp
)
5671 static if (LOGSEMANTIC
)
5673 printf("TypeidExp::semantic() %s\n", exp
.toChars());
5675 Type ta
= isType(exp
.obj
);
5676 Expression ea
= isExpression(exp
.obj
);
5677 Dsymbol sa
= isDsymbol(exp
.obj
);
5678 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
5682 dmd
.typesem
.resolve(ta
, exp
.loc
, sc
, ea
, ta
, sa
, true);
5687 if (auto sym
= getDsymbol(ea
))
5688 ea
= symbolToExp(sym
, exp
.loc
, sc
, false);
5690 ea
= ea
.expressionSemantic(sc
);
5691 ea
= resolveProperties(sc
, ea
);
5693 if (ea
.op
== EXP
.type
)
5699 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
5700 exp
.error("no type for `typeid(%s)`", ea ? ea
.toChars() : (sa ? sa
.toChars() : ""));
5704 ta
.checkComplexTransition(exp
.loc
, sc
);
5707 auto tb
= ta
.toBasetype();
5708 if (ea
&& tb
.ty
== Tclass
)
5710 if (tb
.toDsymbol(sc
).isClassDeclaration().classKind
== ClassKind
.cpp
)
5712 error(exp
.loc
, "runtime type information is not supported for `extern(C++)` classes");
5715 else if (!Type
.typeinfoclass
)
5717 error(exp
.loc
, "`object.TypeInfo_Class` could not be found, but is implicitly used");
5722 /* Get the dynamic type, which is .classinfo
5724 ea
= ea
.expressionSemantic(sc
);
5725 e
= new TypeidExp(ea
.loc
, ea
);
5726 e
.type
= Type
.typeinfoclass
.type
;
5729 else if (ta
.ty
== Terror
)
5735 // Handle this in the glue layer
5736 e
= new TypeidExp(exp
.loc
, ta
);
5738 bool genObjCode
= true;
5740 // https://issues.dlang.org/show_bug.cgi?id=23650
5741 // We generate object code for typeinfo, required
5742 // by typeid, only if in non-speculative context
5743 if (sc
.flags
& SCOPE
.compile
)
5748 e
.type
= getTypeInfoType(exp
.loc
, ta
, sc
, genObjCode
);
5749 semanticTypeInfo(sc
, ta
);
5753 e
= new CommaExp(exp
.loc
, ea
, e
); // execute ea
5754 e
= e
.expressionSemantic(sc
);
5760 override void visit(TraitsExp e
)
5762 result
= semanticTraits(e
, sc
);
5765 override void visit(HaltExp e
)
5767 static if (LOGSEMANTIC
)
5769 printf("HaltExp::semantic()\n");
5771 e
.type
= Type
.tnoreturn
;
5775 override void visit(IsExp e
)
5777 /* is(targ id tok tspec)
5778 * is(targ id : tok2)
5779 * is(targ id == tok2)
5788 result
= IntegerExp
.createBool(true);
5793 Tuple tup
= isTuple(tded
);
5795 s
= new TupleDeclaration(e
.loc
, e
.id
, &tup
.objects
);
5797 s
= new AliasDeclaration(e
.loc
, e
.id
, tded
);
5798 s
.dsymbolSemantic(sc
);
5800 /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there.
5801 * More investigation is needed.
5803 if (!tup
&& !sc
.insert(s
))
5805 auto conflict
= sc
.search(Loc
.initial
, s
.ident
, null);
5806 e
.error("declaration `%s` is already defined", s
.toPrettyChars());
5807 errorSupplemental(conflict
.loc
, "`%s` `%s` is defined here",
5808 conflict
.kind(), conflict
.toChars());
5811 unSpeculative(sc
, s
);
5813 result
= IntegerExp
.createBool(true);
5817 result
= IntegerExp
.createBool(false);
5821 static if (LOGSEMANTIC
)
5823 printf("IsExp::semantic(%s)\n", e
.toChars());
5825 if (e
.id
&& !(sc
.flags
& SCOPE
.condition
))
5827 e
.error("can only declare type aliases within `static if` conditionals or `static assert`s");
5831 if (e
.tok2
== TOK
.package_ || e
.tok2
== TOK
.module_
) // These is() expressions are special because they can work on modules, not just types.
5833 const oldErrors
= global
.startGagging();
5834 Dsymbol sym
= e
.targ
.toDsymbol(sc
);
5835 global
.endGagging(oldErrors
);
5839 Package p
= resolveIsPackage(sym
);
5842 if (e
.tok2
== TOK
.package_
&& p
.isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module.
5844 else if(e
.tok2
== TOK
.module_
&& !(p
.isModule() || p
.isPackageMod()))
5851 Scope
* sc2
= sc
.copy(); // keep sc.flags
5854 sc2
.flags |
= SCOPE
.fullinst
;
5855 Type t
= e
.targ
.trySemantic(e
.loc
, sc2
);
5857 if (!t
) // errors, so condition is false
5862 if (e
.tok2
!= TOK
.reserved
)
5867 if (e
.targ
.ty
!= Tstruct
)
5869 if ((cast(TypeStruct
)e
.targ
).sym
.isUnionDeclaration())
5875 if (e
.targ
.ty
!= Tstruct
)
5877 if (!(cast(TypeStruct
)e
.targ
).sym
.isUnionDeclaration())
5883 if (e
.targ
.ty
!= Tclass
)
5885 if ((cast(TypeClass
)e
.targ
).sym
.isInterfaceDeclaration())
5890 case TOK
.interface_
:
5891 if (e
.targ
.ty
!= Tclass
)
5893 if (!(cast(TypeClass
)e
.targ
).sym
.isInterfaceDeclaration())
5899 if (!e
.targ
.isConst())
5904 case TOK
.immutable_
:
5905 if (!e
.targ
.isImmutable())
5911 if (!e
.targ
.isShared())
5917 if (!e
.targ
.isWild())
5923 // If class or interface, get the base class and interfaces
5924 if (e
.targ
.ty
!= Tclass
)
5928 ClassDeclaration cd
= (cast(TypeClass
)e
.targ
).sym
;
5929 auto args
= new Parameters();
5930 args
.reserve(cd
.baseclasses
.length
);
5931 if (cd
.semanticRun
< PASS
.semanticdone
)
5932 cd
.dsymbolSemantic(null);
5933 for (size_t i
= 0; i
< cd
.baseclasses
.length
; i
++)
5935 BaseClass
* b
= (*cd
.baseclasses
)[i
];
5936 args
.push(new Parameter(STC
.in_
, b
.type
, null, null, null));
5938 tded
= new TypeTuple(args
);
5943 if (e
.targ
.ty
!= Tenum
)
5946 tded
= (cast(TypeEnum
)e
.targ
).sym
.getMemtype(e
.loc
);
5950 if (tded
.ty
== Terror
)
5955 if (e
.targ
.ty
!= Tdelegate
)
5957 tded
= (cast(TypeDelegate
)e
.targ
).next
; // the underlying function type
5961 case TOK
.parameters
:
5963 if (e
.targ
.ty
!= Tfunction
)
5967 /* Generate tuple from function parameter types.
5969 assert(tded
.ty
== Tfunction
);
5970 auto tdedf
= tded
.isTypeFunction();
5971 auto args
= new Parameters();
5972 foreach (i
, arg
; tdedf
.parameterList
)
5974 assert(arg
&& arg
.type
);
5975 /* If one of the default arguments was an error,
5976 don't return an invalid tuple
5978 if (e
.tok2
== TOK
.parameters
&& arg
.defaultArg
&& arg
.defaultArg
.op
== EXP
.error
)
5980 args
.push(new Parameter(arg
.storageClass
, arg
.type
, (e
.tok2
== TOK
.parameters
) ? arg
.ident
: null, (e
.tok2
== TOK
.parameters
) ? arg
.defaultArg
: null, arg
.userAttribDecl
));
5982 tded
= new TypeTuple(args
);
5986 /* Get the 'return type' for the function,
5987 * delegate, or pointer to function.
5989 if (auto tf
= e
.targ
.isFunction_Delegate_PtrToFunction())
5995 case TOK
.argumentTypes
:
5996 /* Generate a type tuple of the equivalent types used to determine if a
5997 * function argument of this type can be passed in registers.
5998 * The results of this are highly platform dependent, and intended
5999 * primarly for use in implementing va_arg().
6001 tded
= target
.toArgTypes(e
.targ
);
6004 // not valid for a parameter
6008 if (e
.targ
.ty
!= Tvector
)
6010 tded
= (cast(TypeVector
)e
.targ
).basetype
;
6017 // https://issues.dlang.org/show_bug.cgi?id=18753
6022 else if (e
.tspec
&& !e
.id
&& !(e
.parameters
&& e
.parameters
.length
))
6024 /* Evaluate to true if targ matches tspec
6028 e
.tspec
= e
.tspec
.typeSemantic(e
.loc
, sc
);
6029 //printf("targ = %s, %s\n", e.targ.toChars(), e.targ.deco);
6030 //printf("tspec = %s, %s\n", e.tspec.toChars(), e.tspec.deco);
6032 if (e
.tok
== TOK
.colon
)
6034 // current scope is itself deprecated, or deprecations are not errors
6035 const bool deprecationAllowed
= sc
.isDeprecated
6036 || global
.params
.useDeprecated
!= DiagnosticReporting
.error
;
6037 const bool preventAliasThis
= e
.targ
.hasDeprecatedAliasThis
&& !deprecationAllowed
;
6039 if (preventAliasThis
&& e
.targ
.ty
== Tstruct
)
6041 if ((cast(TypeStruct
) e
.targ
).implicitConvToWithoutAliasThis(e
.tspec
))
6046 else if (preventAliasThis
&& e
.targ
.ty
== Tclass
)
6048 if ((cast(TypeClass
) e
.targ
).implicitConvToWithoutAliasThis(e
.tspec
))
6053 else if (e
.targ
.implicitConvTo(e
.tspec
))
6060 if (e
.targ
.equals(e
.tspec
))
6068 /* Evaluate to true if targ matches tspec.
6069 * If true, declare id as an alias for the specialized type.
6070 * is(targ == tspec, tpl)
6071 * is(targ : tspec, tpl)
6072 * is(targ id == tspec)
6073 * is(targ id : tspec)
6074 * is(targ id == tspec, tpl)
6075 * is(targ id : tspec, tpl)
6077 Identifier tid
= e
.id ? e
.id
: Identifier
.generateId("__isexp_id");
6078 e
.parameters
.insert(0, new TemplateTypeParameter(e
.loc
, tid
, null, null));
6080 Objects dedtypes
= Objects(e
.parameters
.length
);
6083 MATCH m
= deduceType(e
.targ
, sc
, e
.tspec
, e
.parameters
, &dedtypes
, null, 0, e
.tok
== TOK
.equal
);
6085 if (m
== MATCH
.nomatch ||
(m
!= MATCH
.exact
&& e
.tok
== TOK
.equal
))
6091 tded
= cast(Type
)dedtypes
[0];
6094 Objects tiargs
= Objects(1);
6097 /* Declare trailing parameters
6099 for (size_t i
= 1; i
< e
.parameters
.length
; i
++)
6101 TemplateParameter tp
= (*e
.parameters
)[i
];
6102 Declaration s
= null;
6104 m
= tp
.matchArg(e
.loc
, sc
, &tiargs
, i
, e
.parameters
, &dedtypes
, &s
);
6105 if (m
== MATCH
.nomatch
)
6107 s
.dsymbolSemantic(sc
);
6110 auto conflict
= sc
.search(Loc
.initial
, s
.ident
, null);
6111 e
.error("declaration `%s` is already defined", s
.toPrettyChars());
6112 errorSupplemental(conflict
.loc
, "`%s` `%s` is defined here",
6113 conflict
.kind(), conflict
.toChars());
6116 unSpeculative(sc
, s
);
6123 /* Declare id as an alias for type targ. Evaluate to true
6131 override void visit(BinAssignExp exp
)
6139 Expression e
= exp
.op_overload(sc
);
6146 if (exp
.e1
.op
== EXP
.arrayLength
)
6148 // arr.length op= e2;
6149 e
= rewriteOpAssign(exp
);
6150 e
= e
.expressionSemantic(sc
);
6154 if (exp
.e1
.op
== EXP
.slice || exp
.e1
.type
.ty
== Tarray || exp
.e1
.type
.ty
== Tsarray
)
6156 if (checkNonAssignmentArrayOp(exp
.e1
))
6159 if (exp
.e1
.op
== EXP
.slice
)
6160 (cast(SliceExp
)exp
.e1
).arrayop
= true;
6163 if (exp
.e2
.implicitConvTo(exp
.e1
.type
.nextOf()))
6166 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
.nextOf());
6168 else if (Expression ex
= typeCombine(exp
, sc
))
6173 exp
.type
= exp
.e1
.type
;
6174 result
= arrayOp(exp
, sc
);
6178 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
6179 exp
.e1
= exp
.e1
.modifiableLvalue(sc
, exp
.e1
);
6180 exp
.e1
= exp
.e1
.optimize(WANTvalue
, /*keepLvalue*/ true);
6181 exp
.type
= exp
.e1
.type
;
6183 if (auto ad
= isAggregate(exp
.e1
.type
))
6185 if (const s
= search_function(ad
, Id
.opOpAssign
))
6187 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());
6191 if (exp
.e1
.checkScalar() ||
6192 exp
.e1
.checkReadModifyWrite(exp
.op
, exp
.e2
) ||
6193 exp
.e1
.checkSharedAccess(sc
))
6196 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
);
6197 int bitwise
= (exp
.op
== EXP
.andAssign || exp
.op
== EXP
.orAssign || exp
.op
== EXP
.xorAssign
);
6198 int shift
= (exp
.op
== EXP
.leftShiftAssign || exp
.op
== EXP
.rightShiftAssign || exp
.op
== EXP
.unsignedRightShiftAssign
);
6200 if (bitwise
&& exp
.type
.toBasetype().ty
== Tbool
)
6201 exp
.e2
= exp
.e2
.implicitCastTo(sc
, exp
.type
);
6202 else if (exp
.checkNoBool())
6205 if ((exp
.op
== EXP
.addAssign || exp
.op
== EXP
.minAssign
) && exp
.e1
.type
.toBasetype().ty
== Tpointer
&& exp
.e2
.type
.toBasetype().isintegral())
6207 result
= scaleFactor(exp
, sc
);
6211 if (Expression ex
= typeCombine(exp
, sc
))
6217 if (arith
&& (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
)))
6219 if ((bitwise || shift
) && (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
)))
6224 if (exp
.e2
.type
.toBasetype().ty
!= Tvector
)
6225 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tshiftcnt
);
6228 if (!target
.isVectorOpSupported(exp
.type
.toBasetype(), exp
.op
, exp
.e2
.type
.toBasetype()))
6230 result
= exp
.incompatibleTypes();
6234 if (exp
.e1
.op
== EXP
.error || exp
.e2
.op
== EXP
.error
)
6237 e
= exp
.checkOpAssignTypes(sc
);
6238 if (e
.op
== EXP
.error
)
6244 assert(e
.op
== EXP
.assign || e
== exp
);
6245 result
= (cast(BinExp
)e
).reorderSettingAAElem(sc
);
6248 private Expression
compileIt(MixinExp exp
)
6251 if (expressionsToString(buf
, sc
, exp
.exps
))
6254 uint errors
= global
.errors
;
6255 const len
= buf
.length
;
6256 const str = buf
.extractChars()[0 .. len
];
6257 const bool doUnittests
= global
.params
.useUnitTests || global
.params
.ddoc
.doOutput || global
.params
.dihdr
.doOutput
;
6258 auto loc
= adjustLocForMixin(str, exp
.loc
, global
.params
.mixinOut
);
6259 scope p
= new Parser
!ASTCodegen(loc
, sc
._module
, str, false, global
.errorSink
, &global
.compileEnv
, doUnittests
);
6260 p
.transitionIn
= global
.params
.vin
;
6262 //printf("p.loc.linnum = %d\n", p.loc.linnum);
6264 Expression e
= p
.parseExpression();
6265 if (global
.errors
!= errors
)
6268 if (p
.token
.value
!= TOK
.endOfFile
)
6270 exp
.error("incomplete mixin expression `%s`", str.ptr
);
6276 override void visit(MixinExp exp
)
6278 /* https://dlang.org/spec/expression.html#mixin_expressions
6281 static if (LOGSEMANTIC
)
6283 printf("MixinExp::semantic('%s')\n", exp
.toChars());
6286 auto e
= compileIt(exp
);
6289 result
= e
.expressionSemantic(sc
);
6292 override void visit(ImportExp e
)
6294 static if (LOGSEMANTIC
)
6296 printf("ImportExp::semantic('%s')\n", e
.toChars());
6299 auto se
= semanticString(sc
, e
.e1
, "file name argument");
6304 auto namez
= se
.toStringz();
6305 if (!global
.filePath
)
6307 e
.error("need `-J` switch to import text file `%s`", namez
.ptr
);
6311 /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
6312 * ('Path Traversal') attacks.
6313 * https://cwe.mitre.org/data/definitions/22.html
6316 if (FileName
.absolute(namez
))
6318 e
.error("absolute path is not allowed in import expression: `%s`", se
.toChars());
6322 auto idxReserved
= FileName
.findReservedChar(namez
);
6323 if (idxReserved
!= size_t
.max
)
6325 e
.error("`%s` is not a valid filename on this platform", se
.toChars());
6326 e
.errorSupplemental("Character `'%c'` is reserved and cannot be used", namez
[idxReserved
]);
6330 if (FileName
.refersToParentDir(namez
))
6332 e
.error("path refers to parent (`..`) directory: `%s`", se
.toChars());
6336 auto resolvedNamez
= FileName
.searchPath(global
.filePath
, namez
, false);
6339 e
.error("file `%s` cannot be found or not in a path specified with `-J`", se
.toChars());
6340 e
.errorSupplemental("Path(s) searched (as provided by `-J`):");
6341 foreach (idx
, path
; *global
.filePath
)
6343 const attr
= FileName
.exists(path
);
6344 const(char)* err
= attr
== 2 ?
"" :
6345 (attr
== 1 ?
" (not a directory)" : " (path not found)");
6346 e
.errorSupplemental("[%llu]: `%s`%s", cast(ulong)idx
, path
, err
);
6351 sc
._module
.contentImportedFiles
.push(resolvedNamez
.ptr
);
6352 if (global
.params
.verbose
)
6354 const slice
= se
.peekString();
6355 message("file %.*s\t(%s)", cast(int)slice
.length
, slice
.ptr
, resolvedNamez
.ptr
);
6357 if (global
.params
.moduleDeps
.buffer
!is null)
6359 OutBuffer
* ob
= global
.params
.moduleDeps
.buffer
;
6360 Module imod
= sc
._module
;
6362 if (!global
.params
.moduleDeps
.name
)
6363 ob
.writestring("depsFile ");
6364 ob
.writestring(imod
.toPrettyChars());
6365 ob
.writestring(" (");
6366 escapePath(ob
, imod
.srcfile
.toChars());
6367 ob
.writestring(") : ");
6368 if (global
.params
.moduleDeps
.name
)
6369 ob
.writestring("string : ");
6370 ob
.write(se
.peekString());
6371 ob
.writestring(" (");
6372 escapePath(ob
, resolvedNamez
.ptr
);
6373 ob
.writestring(")");
6376 if (global
.params
.makeDeps
.doOutput
)
6378 global
.params
.makeDeps
.files
.push(resolvedNamez
.ptr
);
6382 auto fileName
= FileName(resolvedNamez
);
6383 if (auto fmResult
= global
.fileManager
.lookup(fileName
))
6385 se
= new StringExp(e
.loc
, fmResult
);
6389 e
.error("cannot read file `%s`", resolvedNamez
.ptr
);
6393 result
= se
.expressionSemantic(sc
);
6396 override void visit(AssertExp exp
)
6398 // https://dlang.org/spec/expression.html#assert_expressions
6399 static if (LOGSEMANTIC
)
6401 printf("AssertExp::semantic('%s')\n", exp
.toChars());
6404 const generateMsg
= !exp
.msg
&&
6405 sc
.needsCodegen() && // let ctfe interpreter handle the error message
6406 global
.params
.checkAction
== CHECKACTION
.context
&&
6407 global
.params
.useAssert
== CHECKENABLE
.on
;
6408 Expression temporariesPrefix
;
6411 // no message - use assert expression as msg
6413 if (!verifyHookExist(exp
.loc
, *sc
, Id
._d_assert_fail
, "generating assert messages"))
6418 auto a = e1, b = e2;
6419 assert(a == b, _d_assert_fail!"=="(a, b));
6424 Stores the result of an operand expression into a temporary
6425 if necessary, e.g. if it is an impure fuction call containing side
6426 effects as in https://issues.dlang.org/show_bug.cgi?id=20114
6429 op = an expression which may require a temporary (added to
6430 `temporariesPrefix`: `auto tmp = op`) and will be replaced
6431 by `tmp` if necessary
6433 Returns: (possibly replaced) `op`
6435 Expression
maybePromoteToTmp(ref Expression op
)
6437 // https://issues.dlang.org/show_bug.cgi?id=20989
6438 // Flag that _d_assert_fail will never dereference `array.ptr` to avoid safety
6439 // errors for `assert(!array.ptr)` => `_d_assert_fail!"!"(array.ptr)`
6441 auto die
= op
.isDotIdExp();
6442 if (die
&& die
.ident
== Id
.ptr
)
6446 op
= op
.expressionSemantic(sc
);
6447 op
= resolveProperties(sc
, op
);
6449 // Detect assert's using static operator overloads (e.g. `"var" in environment`)
6450 if (auto te
= op
.isTypeExp())
6452 // Replace the TypeExp with it's textual representation
6453 // Including "..." in the error message isn't quite right but
6454 // proper solutions require more drastic changes, e.g. directly
6455 // using miniFormat and combine instead of calling _d_assert_fail
6456 auto name
= new StringExp(te
.loc
, te
.toString());
6457 return name
.expressionSemantic(sc
);
6460 // Create a temporary for expressions with side effects
6461 // Defensively assume that function calls may have side effects even
6462 // though it's not detected by hasSideEffect (e.g. `debug puts("Hello")` )
6463 // Rewriting CallExp's also avoids some issues with the inliner/debug generation
6464 if (op
.hasSideEffect(true))
6466 // Don't create an invalid temporary for void-expressions
6467 // Further semantic will issue an appropriate error
6468 if (op
.type
.ty
== Tvoid
)
6471 // https://issues.dlang.org/show_bug.cgi?id=21590
6472 // Don't create unnecessary temporaries and detect `assert(a = b)`
6473 if (op
.isAssignExp() || op
.isBinAssignExp())
6475 auto left
= (cast(BinExp
) op
).e1
;
6477 // Find leftmost expression to handle other rewrites,
6478 // e.g. --(++a) => a += 1 -= 1
6479 while (left
.isAssignExp() || left
.isBinAssignExp())
6480 left
= (cast(BinExp
) left
).e1
;
6482 // Only use the assignee if it's a variable and skip
6483 // other lvalues (e.g. ref's returned by functions)
6484 if (left
.isVarExp())
6487 // Sanity check that `op` can be converted to boolean
6488 // But don't raise errors for assignments enclosed in another expression
6493 // Tuples with side-effects already receive a temporary during semantic
6494 if (op
.type
.isTypeTuple())
6496 auto te
= op
.isTupleExp();
6499 // Create a new tuple without the associated temporary
6500 auto res
= new TupleExp(op
.loc
, te
.exps
);
6501 return res
.expressionSemantic(sc
);
6504 const stc = op
.isLvalue() ? STC
.ref_
: 0;
6505 auto tmp
= copyToTemp(stc, "__assertOp", op
);
6506 tmp
.dsymbolSemantic(sc
);
6508 auto decl
= new DeclarationExp(op
.loc
, tmp
);
6509 temporariesPrefix
= Expression
.combine(temporariesPrefix
, decl
);
6511 op
= new VarExp(op
.loc
, tmp
);
6512 op
= op
.expressionSemantic(sc
);
6517 // if the assert condition is a mixin expression, try to compile it
6518 if (auto ce
= exp
.e1
.isMixinExp())
6520 if (auto e1
= compileIt(ce
))
6526 Loc loc
= exp
.e1
.loc
;
6528 const op
= exp
.e1
.op
;
6529 bool isEqualsCallExpression
;
6530 if (const callExp
= exp
.e1
.isCallExp())
6532 // https://issues.dlang.org/show_bug.cgi?id=20331
6533 // callExp.f may be null if the assert contains a call to
6534 // a function pointer or literal
6535 if (const callExpFunc
= callExp
.f
)
6537 const callExpIdent
= callExpFunc
.ident
;
6538 isEqualsCallExpression
= callExpIdent
== Id
.__equals ||
6539 callExpIdent
== Id
.eq
;
6542 if (op
== EXP
.equal || op
== EXP
.notEqual ||
6543 op
== EXP
.lessThan || op
== EXP
.greaterThan ||
6544 op
== EXP
.lessOrEqual || op
== EXP
.greaterOrEqual ||
6545 op
== EXP
.identity || op
== EXP
.notIdentity ||
6547 isEqualsCallExpression
)
6549 es
= new Expressions(3);
6550 tiargs
= new Objects(1);
6552 if (isEqualsCallExpression
)
6554 auto callExp
= cast(CallExp
) exp
.e1
;
6555 auto args
= callExp
.arguments
;
6557 // structs with opEquals get rewritten to a DotVarExp:
6559 // https://issues.dlang.org/show_bug.cgi?id=20100
6560 if (args
.length
== 1)
6562 auto dv
= callExp
.e1
.isDotVarExp();
6566 (*es
)[1] = maybePromoteToTmp(dv
.e1
);
6567 (*es
)[2] = maybePromoteToTmp((*args
)[0]);
6572 (*es
)[1] = maybePromoteToTmp((*args
)[0]);
6573 (*es
)[2] = maybePromoteToTmp((*args
)[1]);
6578 auto binExp
= cast(EqualExp
) exp
.e1
;
6581 (*es
)[1] = maybePromoteToTmp(binExp
.e1
);
6582 (*es
)[2] = maybePromoteToTmp(binExp
.e2
);
6586 Expression comp
= new StringExp(loc
, isEqualsCallExpression ?
"==" : EXPtoString(exp
.e1
.op
));
6587 comp
= comp
.expressionSemantic(sc
);
6589 (*tiargs
)[0] = (*es
)[1].type
;
6592 // Format exp.e1 before any additional boolean conversion
6593 // Ignore &&/|| because "assert(...) failed" is more informative than "false != true"
6594 else if (op
!= EXP
.andAnd
&& op
!= EXP
.orOr
)
6596 es
= new Expressions(2);
6597 tiargs
= new Objects(1);
6599 if (auto ne
= exp
.e1
.isNotExp())
6601 // Fetch the (potential non-bool) expression and fold
6602 // (n) negations into (n % 2) negations, e.g. !!a => a
6603 for (bool neg = true; ; neg = !neg)
6605 if (auto ne2
= ne
.e1
.isNotExp())
6609 (*es
)[0] = new StringExp(loc
, neg ?
"!" : "");
6610 (*es
)[1] = maybePromoteToTmp(ne
.e1
);
6616 { // Simply format exp.e1
6617 (*es
)[0] = new StringExp(loc
, "");
6618 (*es
)[1] = maybePromoteToTmp(exp
.e1
);
6621 (*tiargs
)[0] = (*es
)[1].type
;
6623 // Passing __ctfe to auto ref infers ref and aborts compilation:
6624 // "cannot modify compiler-generated variable __ctfe"
6625 auto ve
= (*es
)[1].isVarExp();
6626 if (ve
&& ve
.var
.ident
== Id
.ctfe
)
6628 exp
.msg
= new StringExp(loc
, "assert(__ctfe) failed!");
6635 buf
.printf("%s failed", exp
.toChars());
6636 exp
.msg
= new StringExp(Loc
.initial
, buf
.extractSlice());
6640 Expression __assertFail
= new IdentifierExp(exp
.loc
, Id
.empty
);
6641 auto assertFail
= new DotIdExp(loc
, __assertFail
, Id
.object
);
6643 auto dt = new DotTemplateInstanceExp(loc
, assertFail
, Id
._d_assert_fail
, tiargs
);
6644 auto ec
= CallExp
.create(loc
, dt, es
);
6649 if (Expression ex
= unaSemantic(exp
, sc
))
6655 exp
.e1
= resolveProperties(sc
, exp
.e1
);
6656 // BUG: see if we can do compile time elimination of the Assert
6657 exp
.e1
= exp
.e1
.optimize(WANTvalue
);
6658 exp
.e1
= exp
.e1
.toBoolean(sc
);
6660 if (exp
.e1
.op
== EXP
.error
)
6668 exp
.msg
= expressionSemantic(exp
.msg
, sc
);
6669 exp
.msg
= resolveProperties(sc
, exp
.msg
);
6670 exp
.msg
= exp
.msg
.implicitCastTo(sc
, Type
.tchar
.constOf().arrayOf());
6671 exp
.msg
= exp
.msg
.optimize(WANTvalue
);
6672 checkParamArgumentEscape(sc
, null, null, null, STC
.undefined_
, exp
.msg
, true, false);
6675 if (exp
.msg
&& exp
.msg
.op
== EXP
.error
)
6681 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
6682 auto f2
= exp
.msg
&& checkNonAssignmentArrayOp(exp
.msg
);
6686 if (exp
.e1
.toBool().hasValue(false))
6688 /* This is an `assert(0)` which means halt program execution
6690 FuncDeclaration fd
= sc
.parent
.isFuncDeclaration();
6692 fd
.hasReturnExp |
= 4;
6693 sc
.ctorflow
.orCSX(CSX
.halt
);
6695 if (global
.params
.useAssert
== CHECKENABLE
.off
)
6697 Expression e
= new HaltExp(exp
.loc
);
6698 e
= e
.expressionSemantic(sc
);
6703 // Only override the type when it isn't already some flavour of noreturn,
6704 // e.g. when this assert was generated by defaultInitLiteral
6705 if (!exp
.type ||
!exp
.type
.isTypeNoreturn())
6706 exp
.type
= Type
.tnoreturn
;
6709 exp
.type
= Type
.tvoid
;
6711 result
= !temporariesPrefix
6713 : Expression
.combine(temporariesPrefix
, exp
).expressionSemantic(sc
);
6716 override void visit(ThrowExp te
)
6718 import dmd
.statementsem
;
6720 if (throwSemantic(te
.loc
, te
.e1
, sc
))
6726 override void visit(DotIdExp exp
)
6728 static if (LOGSEMANTIC
)
6730 printf("DotIdExp::semantic(this = %p, '%s')\n", exp
, exp
.toChars());
6731 //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op));
6734 if (sc
.flags
& SCOPE
.Cfile
)
6736 /* See if need to rewrite the AST because of cast/call ambiguity
6738 if (auto e
= castCallAmbiguity(exp
, sc
))
6740 result
= expressionSemantic(e
, sc
);
6744 if (exp
.arrow
) // ImportC only
6745 exp
.e1
= exp
.e1
.expressionSemantic(sc
).arrayFuncConv(sc
);
6747 if (exp
.ident
== Id
.__xalignof
&& exp
.e1
.isTypeExp())
6749 // C11 6.5.3 says _Alignof only applies to types
6753 dmd
.typesem
.resolve(exp
.e1
.type
, exp
.e1
.loc
, sc
, e
, t
, s
, true);
6756 exp
.e1
.error("argument to `_Alignof` must be a type");
6761 // Note similarity to getProperty() implementation of __xalignof
6762 const explicitAlignment
= t
.alignment();
6763 const naturalAlignment
= t
.alignsize();
6764 const actualAlignment
= (explicitAlignment
.isDefault() ? naturalAlignment
: explicitAlignment
.get());
6765 result
= new IntegerExp(exp
.loc
, actualAlignment
, Type
.tsize_t
);
6769 exp
.e1
.error("argument to `_Alignof` must be a type");
6777 if (exp
.ident
!= Id
.__sizeof
)
6779 result
= fieldLookup(exp
.e1
, sc
, exp
.ident
, exp
.arrow
);
6784 Expression e
= exp
.dotIdSemanticProp(sc
, 1);
6786 if (e
&& isDotOpDispatch(e
))
6789 uint errors
= global
.startGagging();
6790 e
= resolvePropertiesX(sc
, e
);
6791 // Any error or if 'e' is not resolved, go to UFCS
6792 if (global
.endGagging(errors
) || e
is ode
)
6793 e
= null; /* fall down to UFCS */
6800 if (!e
) // if failed to find the property
6802 /* If ident is not a valid property, rewrite:
6807 e
= resolveUFCSProperties(sc
, exp
);
6812 override void visit(DotTemplateExp e
)
6819 if (Expression ex
= unaSemantic(e
, sc
))
6824 // 'void' like TemplateExp
6825 e
.type
= Type
.tvoid
;
6829 override void visit(DotVarExp exp
)
6831 static if (LOGSEMANTIC
)
6833 printf("DotVarExp::semantic('%s')\n", exp
.toChars());
6841 exp
.var
= exp
.var
.toAlias().isDeclaration();
6843 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
6845 if (auto tup
= exp
.var
.isTupleDeclaration())
6850 * tuple(e1.a, e1.b, e1.c)
6853 Expression ev
= sc
.func ?
extractSideEffect(sc
, "__tup", e0
, exp
.e1
) : exp
.e1
;
6855 auto exps
= new Expressions();
6856 exps
.reserve(tup
.objects
.length
);
6857 for (size_t i
= 0; i
< tup
.objects
.length
; i
++)
6859 RootObject o
= (*tup
.objects
)[i
];
6862 switch (o
.dyncast()) with (DYNCAST
)
6865 e
= cast(Expression
)o
;
6866 if (auto se
= e
.isDsymbolExp())
6867 var
= se
.s
.isDeclaration();
6868 else if (auto ve
= e
.isVarExp())
6869 if (!ve
.var
.isFuncDeclaration())
6870 // Exempt functions for backwards compatibility reasons.
6871 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
6875 Dsymbol s
= cast(Dsymbol
) o
;
6876 Declaration d
= s
.isDeclaration();
6877 if (!d || d
.isFuncDeclaration())
6878 // Exempt functions for backwards compatibility reasons.
6879 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
6880 e
= new DsymbolExp(exp
.loc
, s
);
6885 e
= new TypeExp(exp
.loc
, cast(Type
)o
);
6888 exp
.error("`%s` is not an expression", o
.toChars());
6892 e
= new DotVarExp(exp
.loc
, ev
, var
);
6896 Expression e
= new TupleExp(exp
.loc
, e0
, exps
);
6897 e
= e
.expressionSemantic(sc
);
6901 else if (auto ad
= exp
.var
.isAliasDeclaration())
6903 if (auto t
= ad
.getType())
6905 result
= new TypeExp(exp
.loc
, t
).expressionSemantic(sc
);
6910 exp
.e1
= exp
.e1
.addDtorHook(sc
);
6912 Type t1
= exp
.e1
.type
;
6914 if (FuncDeclaration fd
= exp
.var
.isFuncDeclaration())
6916 // for functions, do checks after overload resolution
6917 if (!fd
.functionSemantic())
6920 /* https://issues.dlang.org/show_bug.cgi?id=13843
6921 * If fd obviously has no overloads, we should
6922 * normalize AST, and it will give a chance to wrap fd with FuncExp.
6924 if ((fd
.isNested() && !fd
.isThis()) || fd
.isFuncLiteralDeclaration())
6927 auto e
= symbolToExp(fd
, exp
.loc
, sc
, false);
6928 result
= Expression
.combine(exp
.e1
, e
);
6935 else if (OverDeclaration od
= exp
.var
.isOverDeclaration())
6937 exp
.type
= Type
.tvoid
; // ambiguous type?
6941 exp
.type
= exp
.var
.type
;
6942 if (!exp
.type
&& global
.errors
) // var is goofed up, just return error.
6946 if (t1
.ty
== Tpointer
)
6949 exp
.type
= exp
.type
.addMod(t1
.mod
);
6951 // https://issues.dlang.org/show_bug.cgi?id=23109
6952 // Run semantic on the DotVarExp type
6953 if (auto handle
= exp
.type
.isClassHandle())
6955 if (handle
.semanticRun
< PASS
.semanticdone
&& !handle
.isBaseInfoComplete())
6956 handle
.dsymbolSemantic(null);
6959 Dsymbol vparent
= exp
.var
.toParent();
6960 AggregateDeclaration ad
= vparent ? vparent
.isAggregateDeclaration() : null;
6961 if (Expression e1x
= getRightThis(exp
.loc
, sc
, ad
, exp
.e1
, exp
.var
, 1))
6965 /* Later checkRightThis will report correct error for invalid field variable access.
6967 Expression e
= new VarExp(exp
.loc
, exp
.var
);
6968 e
= e
.expressionSemantic(sc
);
6972 checkAccess(exp
.loc
, sc
, exp
.e1
, exp
.var
);
6974 VarDeclaration v
= exp
.var
.isVarDeclaration();
6975 if (v
&& (v
.isDataseg() ||
(v
.storage_class
& STC
.manifest
)))
6977 Expression e
= expandVar(WANTvalue
, v
);
6985 if (v
&& (v
.isDataseg() ||
// fix https://issues.dlang.org/show_bug.cgi?id=8238
6986 (!v
.needThis() && v
.semanticRun
> PASS
.initial
))) // fix https://issues.dlang.org/show_bug.cgi?id=17258
6989 checkAccess(exp
.loc
, sc
, exp
.e1
, v
);
6990 Expression e
= new VarExp(exp
.loc
, v
);
6991 e
= new CommaExp(exp
.loc
, exp
.e1
, e
);
6992 e
= e
.expressionSemantic(sc
);
6997 //printf("-DotVarExp::semantic('%s')\n", toChars());
7001 override void visit(DotTemplateInstanceExp exp
)
7003 static if (LOGSEMANTIC
)
7005 printf("DotTemplateInstanceExp::semantic('%s')\n", exp
.toChars());
7012 // Indicate we need to resolve by UFCS.
7013 Expression e
= exp
.dotTemplateSemanticProp(sc
, DotExpFlag
.gag
);
7015 e
= resolveUFCSProperties(sc
, exp
);
7017 e
.type
= Type
.tvoid
; // Unresolved type, because it needs inference
7021 override void visit(DelegateExp e
)
7023 static if (LOGSEMANTIC
)
7025 printf("DelegateExp::semantic('%s')\n", e
.toChars());
7033 e
.e1
= e
.e1
.expressionSemantic(sc
);
7035 e
.type
= new TypeDelegate(e
.func
.type
.isTypeFunction());
7036 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
7038 FuncDeclaration f
= e
.func
.toAliasFunc();
7039 AggregateDeclaration ad
= f
.isMemberLocal();
7041 e
.e1
= getRightThis(e
.loc
, sc
, ad
, e
.e1
, f
);
7043 if (f
.type
.ty
== Tfunction
)
7045 TypeFunction tf
= cast(TypeFunction
)f
.type
;
7046 if (!MODmethodConv(e
.e1
.type
.mod
, f
.type
.mod
))
7048 OutBuffer thisBuf
, funcBuf
;
7049 MODMatchToBuffer(&thisBuf
, e
.e1
.type
.mod
, tf
.mod
);
7050 MODMatchToBuffer(&funcBuf
, tf
.mod
, e
.e1
.type
.mod
);
7051 e
.error("%smethod `%s` is not callable using a %s`%s`",
7052 funcBuf
.peekChars(), f
.toPrettyChars(), thisBuf
.peekChars(), e
.e1
.toChars());
7056 if (ad
&& ad
.isClassDeclaration() && ad
.type
!= e
.e1
.type
)
7058 // A downcast is required for interfaces
7059 // https://issues.dlang.org/show_bug.cgi?id=3706
7060 e
.e1
= new CastExp(e
.loc
, e
.e1
, ad
.type
);
7061 e
.e1
= e
.e1
.expressionSemantic(sc
);
7064 // declare dual-context container
7065 if (f
.hasDualContext() && !sc
.intypeof
&& sc
.func
)
7067 // check access to second `this`
7068 if (AggregateDeclaration ad2
= f
.isMember2())
7070 Expression te
= new ThisExp(e
.loc
).expressionSemantic(sc
);
7071 if (te
.op
!= EXP
.error
)
7072 te
= getRightThis(e
.loc
, sc
, ad2
, te
, f
);
7073 if (te
.op
== EXP
.error
)
7075 e
.error("need `this` of type `%s` to make delegate from function `%s`", ad2
.toChars(), f
.toChars());
7079 VarDeclaration vthis2
= makeThis2Argument(e
.loc
, sc
, f
);
7081 Expression
de = new DeclarationExp(e
.loc
, vthis2
);
7082 result
= Expression
.combine(de, result
);
7083 result
= result
.expressionSemantic(sc
);
7087 override void visit(DotTypeExp exp
)
7089 static if (LOGSEMANTIC
)
7091 printf("DotTypeExp::semantic('%s')\n", exp
.toChars());
7099 if (auto e
= unaSemantic(exp
, sc
))
7105 exp
.type
= exp
.sym
.getType().addMod(exp
.e1
.type
.mod
);
7109 override void visit(AddrExp exp
)
7111 static if (LOGSEMANTIC
)
7113 printf("AddrExp::semantic('%s')\n", exp
.toChars());
7121 if (Expression ex
= unaSemantic(exp
, sc
))
7127 if (sc
.flags
& SCOPE
.Cfile
)
7129 /* Special handling for &"string"/&(T[]){0, 1}
7130 * since C regards string/array literals as lvalues
7133 if(e
.isStringExp() || e
.isArrayLiteralExp())
7135 e
.type
= typeSemantic(e
.type
, Loc
.initial
, sc
);
7136 // if type is already a pointer exp is an illegal expression of the form `&(&"")`
7137 if (!e
.type
.isTypePointer())
7139 e
.type
= e
.type
.pointerTo();
7145 // `toLvalue` call further below is upon exp.e1, omitting & from the error message
7146 exp
.toLvalue(sc
, null);
7152 int wasCond
= exp
.e1
.op
== EXP
.question
;
7154 if (exp
.e1
.op
== EXP
.dotTemplateInstance
)
7156 DotTemplateInstanceExp dti
= cast(DotTemplateInstanceExp
)exp
.e1
;
7157 TemplateInstance ti
= dti
.ti
;
7159 //assert(ti.needsTypeInference(sc));
7160 ti
.dsymbolSemantic(sc
);
7161 if (!ti
.inst || ti
.errors
) // if template failed to expand
7164 Dsymbol s
= ti
.toAlias();
7165 FuncDeclaration f
= s
.isFuncDeclaration();
7168 exp
.e1
= new DotVarExp(exp
.e1
.loc
, dti
.e1
, f
);
7169 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
7173 else if (exp
.e1
.op
== EXP
.scope_
)
7175 TemplateInstance ti
= (cast(ScopeExp
)exp
.e1
).sds
.isTemplateInstance();
7178 //assert(ti.needsTypeInference(sc));
7179 ti
.dsymbolSemantic(sc
);
7180 if (!ti
.inst || ti
.errors
) // if template failed to expand
7183 Dsymbol s
= ti
.toAlias();
7184 FuncDeclaration f
= s
.isFuncDeclaration();
7187 exp
.e1
= new VarExp(exp
.e1
.loc
, f
);
7188 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
7192 /* https://issues.dlang.org/show_bug.cgi?id=809
7194 * If the address of a lazy variable is taken,
7195 * the expression is rewritten so that the type
7196 * of it is the delegate type. This means that
7197 * the symbol is not going to represent a call
7198 * to the delegate anymore, but rather, the
7201 if (auto ve
= exp
.e1
.isVarExp())
7203 if (ve
.var
.storage_class
& STC
.lazy_
)
7205 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
7206 exp
.e1
= resolveProperties(sc
, exp
.e1
);
7207 if (auto callExp
= exp
.e1
.isCallExp())
7209 if (callExp
.e1
.type
.toBasetype().ty
== Tdelegate
)
7211 /* https://issues.dlang.org/show_bug.cgi?id=20551
7213 * Cannot take address of lazy parameter in @safe code
7214 * because it might end up being a pointer to undefined
7219 if (sc
.setUnsafe(false, exp
.loc
,
7220 "cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve
, sc
.func
))
7226 VarExp ve2
= callExp
.e1
.isVarExp();
7227 ve2
.delegateWasExtracted
= true;
7228 ve2
.var
.storage_class |
= STC
.scope_
;
7236 exp
.e1
= exp
.e1
.toLvalue(sc
, null);
7237 if (exp
.e1
.op
== EXP
.error
)
7242 if (checkNonAssignmentArrayOp(exp
.e1
))
7247 exp
.error("cannot take address of `%s`", exp
.e1
.toChars());
7250 if (!checkAddressable(exp
, sc
))
7254 if (auto f
= isFuncAddress(exp
, &hasOverloads
))
7256 if (!hasOverloads
&& f
.checkForwardRef(exp
.loc
))
7259 else if (!exp
.e1
.type
.deco
)
7261 // try to resolve the type
7262 exp
.e1
.type
= exp
.e1
.type
.typeSemantic(exp
.e1
.loc
, null);
7263 if (!exp
.e1
.type
.deco
) // still couldn't resolve it
7265 if (auto ve
= exp
.e1
.isVarExp())
7267 Declaration d
= ve
.var
;
7268 exp
.error("forward reference to %s `%s`", d
.kind(), d
.toChars());
7271 exp
.error("forward reference to type `%s` of expression `%s`", exp
.e1
.type
.toChars(), exp
.e1
.toChars());
7276 exp
.type
= exp
.e1
.type
.pointerTo();
7278 // See if this should really be a delegate
7279 if (exp
.e1
.op
== EXP
.dotVariable
)
7281 DotVarExp dve
= cast(DotVarExp
)exp
.e1
;
7282 FuncDeclaration f
= dve
.var
.isFuncDeclaration();
7285 f
= f
.toAliasFunc(); // FIXME, should see overloads
7286 // https://issues.dlang.org/show_bug.cgi?id=1983
7287 if (!dve
.hasOverloads
)
7292 e
= new DelegateExp(exp
.loc
, dve
.e1
, f
, dve
.hasOverloads
);
7293 else // It is a function pointer. Convert &v.f() --> (v, &V.f())
7294 e
= new CommaExp(exp
.loc
, dve
.e1
, new AddrExp(exp
.loc
, new VarExp(exp
.loc
, f
, dve
.hasOverloads
)));
7295 e
= e
.expressionSemantic(sc
);
7300 // Look for misaligned pointer in @safe mode
7301 if (checkUnsafeAccess(sc
, dve
, !exp
.type
.isMutable(), true))
7304 else if (exp
.e1
.op
== EXP
.variable
)
7306 VarExp ve
= cast(VarExp
)exp
.e1
;
7307 VarDeclaration v
= ve
.var
.isVarDeclaration();
7310 if (!checkAddressVar(sc
, exp
.e1
, v
))
7313 ve
.checkPurity(sc
, v
);
7315 FuncDeclaration f
= ve
.var
.isFuncDeclaration();
7318 /* Because nested functions cannot be overloaded,
7319 * mark here that we took its address because castTo()
7320 * may not be called with an exact match.
7322 * https://issues.dlang.org/show_bug.cgi?id=19285 :
7323 * We also need to make sure we aren't inside a typeof. Ideally the compiler
7324 * would do typeof(...) semantic analysis speculatively then collect information
7325 * about what it used rather than relying on what are effectively semantically-global
7326 * variables but it doesn't.
7328 if (!sc
.isFromSpeculativeSemanticContext() && (!ve
.hasOverloads ||
(f
.isNested() && !f
.needThis())))
7330 // TODO: Refactor to use a proper interface that can keep track of causes.
7334 if (f
.isNested() && !f
.needThis())
7336 if (f
.isFuncLiteralDeclaration())
7338 if (!f
.FuncDeclaration
.isNested())
7340 /* Supply a 'null' for a this pointer if no this is available
7342 Expression e
= new DelegateExp(exp
.loc
, new NullExp(exp
.loc
, Type
.tnull
), f
, ve
.hasOverloads
);
7343 e
= e
.expressionSemantic(sc
);
7348 Expression e
= new DelegateExp(exp
.loc
, exp
.e1
, f
, ve
.hasOverloads
);
7349 e
= e
.expressionSemantic(sc
);
7355 auto memberFunc
= hasThis(sc
);
7356 if (memberFunc
&& haveSameThis(memberFunc
, f
))
7358 /* Should probably supply 'this' after overload resolution,
7361 Expression ethis
= new ThisExp(exp
.loc
);
7362 Expression e
= new DelegateExp(exp
.loc
, ethis
, f
, ve
.hasOverloads
);
7363 e
= e
.expressionSemantic(sc
);
7367 if (sc
.func
&& !sc
.intypeof
&& !(sc
.flags
& SCOPE
.debug_
))
7369 sc
.setUnsafe(false, exp
.loc
,
7370 "`this` reference necessary to take address of member `%s` in `@safe` function `%s`",
7376 else if (exp
.e1
.op
== EXP
.index
)
7381 * check 'a' the same as for a regular variable
7383 if (VarDeclaration v
= expToVariable(exp
.e1
))
7385 exp
.e1
.checkPurity(sc
, v
);
7390 /* a ? b : c was transformed to *(a ? &b : &c), but we still
7391 * need to do safety checks
7393 assert(exp
.e1
.op
== EXP
.star
);
7394 PtrExp pe
= cast(PtrExp
)exp
.e1
;
7395 assert(pe
.e1
.op
== EXP
.question
);
7396 CondExp ce
= cast(CondExp
)pe
.e1
;
7397 assert(ce
.e1
.op
== EXP
.address
);
7398 assert(ce
.e2
.op
== EXP
.address
);
7400 // Re-run semantic on the address expressions only
7402 ce
.e1
= ce
.e1
.expressionSemantic(sc
);
7404 ce
.e2
= ce
.e2
.expressionSemantic(sc
);
7406 result
= exp
.optimize(WANTvalue
);
7409 override void visit(PtrExp exp
)
7411 static if (LOGSEMANTIC
)
7413 printf("PtrExp::semantic('%s')\n", exp
.toChars());
7421 Expression e
= exp
.op_overload(sc
);
7428 exp
.e1
= exp
.e1
.arrayFuncConv(sc
);
7430 Type tb
= exp
.e1
.type
.toBasetype();
7434 exp
.type
= (cast(TypePointer
)tb
).next
;
7439 if (isNonAssignmentArrayOp(exp
.e1
))
7441 exp
.error("using `*` on an array is no longer supported; use `*(%s).ptr` instead", exp
.e1
.toChars());
7442 exp
.type
= (cast(TypeArray
)tb
).next
;
7443 exp
.e1
= exp
.e1
.castTo(sc
, exp
.type
.pointerTo());
7450 exp
.type
= Type
.tnoreturn
; // typeof(*null) is bottom type
7454 exp
.error("can only `*` a pointer, not a `%s`", exp
.e1
.type
.toChars());
7458 if (sc
.flags
& SCOPE
.Cfile
&& exp
.type
&& exp
.type
.toBasetype().ty
== Tvoid
)
7460 // https://issues.dlang.org/show_bug.cgi?id=23752
7461 // `&*((void*)(0))` is allowed in C
7466 if (exp
.checkValue())
7472 override void visit(NegExp exp
)
7474 static if (LOGSEMANTIC
)
7476 printf("NegExp::semantic('%s')\n", exp
.toChars());
7484 Expression e
= exp
.op_overload(sc
);
7492 exp
.type
= exp
.e1
.type
;
7493 Type tb
= exp
.type
.toBasetype();
7494 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
7496 if (!isArrayOpValid(exp
.e1
))
7498 result
= arrayOpInvalidError(exp
);
7504 if (!target
.isVectorOpSupported(tb
, exp
.op
))
7506 result
= exp
.incompatibleTypes();
7509 if (exp
.e1
.checkNoBool())
7511 if (exp
.e1
.checkArithmetic() ||
7512 exp
.e1
.checkSharedAccess(sc
))
7518 override void visit(UAddExp exp
)
7520 static if (LOGSEMANTIC
)
7522 printf("UAddExp::semantic('%s')\n", exp
.toChars());
7526 Expression e
= exp
.op_overload(sc
);
7534 if (!target
.isVectorOpSupported(exp
.e1
.type
.toBasetype(), exp
.op
))
7536 result
= exp
.incompatibleTypes();
7539 if (exp
.e1
.checkNoBool())
7541 if (exp
.e1
.checkArithmetic())
7543 if (exp
.e1
.checkSharedAccess(sc
))
7549 override void visit(ComExp exp
)
7557 Expression e
= exp
.op_overload(sc
);
7565 exp
.type
= exp
.e1
.type
;
7566 Type tb
= exp
.type
.toBasetype();
7567 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
7569 if (!isArrayOpValid(exp
.e1
))
7571 result
= arrayOpInvalidError(exp
);
7577 if (!target
.isVectorOpSupported(tb
, exp
.op
))
7579 result
= exp
.incompatibleTypes();
7582 if (exp
.e1
.checkNoBool())
7584 if (exp
.e1
.checkIntegral() ||
7585 exp
.e1
.checkSharedAccess(sc
))
7591 override void visit(NotExp e
)
7599 e
.setNoderefOperand();
7601 // Note there is no operator overload
7602 if (Expression ex
= unaSemantic(e
, sc
))
7608 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
7609 if (e
.e1
.op
== EXP
.type
)
7610 e
.e1
= resolveAliasThis(sc
, e
.e1
);
7612 e
.e1
= resolveProperties(sc
, e
.e1
);
7613 e
.e1
= e
.e1
.toBoolean(sc
);
7614 if (e
.e1
.type
== Type
.terror
)
7620 if (!target
.isVectorOpSupported(e
.e1
.type
.toBasetype(), e
.op
))
7622 result
= e
.incompatibleTypes();
7624 // https://issues.dlang.org/show_bug.cgi?id=13910
7625 // Today NotExp can take an array as its operand.
7626 if (checkNonAssignmentArrayOp(e
.e1
))
7629 e
.type
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? Type
.tint32
: Type
.tbool
;
7633 override void visit(DeleteExp exp
)
7635 // @@@DEPRECATED_2.109@@@
7636 // 1. Deprecated since 2.079
7637 // 2. Error since 2.099
7638 // 3. Removal of keyword, "delete" can be used for other identities
7641 error(exp
.loc
, "the `delete` keyword is obsolete");
7642 errorSupplemental(exp
.loc
, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead");
7648 if (Expression ex
= unaSemantic(exp
, sc
))
7653 exp
.e1
= resolveProperties(sc
, exp
.e1
);
7654 exp
.e1
= exp
.e1
.modifiableLvalue(sc
, null);
7655 if (exp
.e1
.op
== EXP
.error
)
7660 exp
.type
= Type
.tvoid
;
7662 Type tb
= exp
.e1
.type
.toBasetype();
7664 /* Now that `delete` in user code is an error, we only get here when
7665 * `isRAII` has been set to true for the deletion of a `scope class`. */
7666 if (tb
.ty
!= Tclass
)
7668 exp
.error("cannot delete type `%s`", exp
.e1
.type
.toChars());
7672 ClassDeclaration cd
= (cast(TypeClass
)tb
).sym
;
7673 if (cd
.isCOMinterface())
7675 /* Because COM classes are deleted by IUnknown.Release()
7677 exp
.error("cannot `delete` instance of COM interface `%s`", cd
.toChars());
7684 err |
= !cd
.dtor
.functionSemantic();
7685 err |
= exp
.checkPurity(sc
, cd
.dtor
);
7686 err |
= exp
.checkSafety(sc
, cd
.dtor
);
7687 err |
= exp
.checkNogc(sc
, cd
.dtor
);
7695 override void visit(CastExp exp
)
7697 static if (LOGSEMANTIC
)
7699 printf("CastExp::semantic('%s')\n", exp
.toChars());
7701 //static int x; assert(++x < 10);
7708 if ((sc
&& sc
.flags
& SCOPE
.Cfile
) &&
7709 exp
.to
&& (exp
.to
.ty
== Tident || exp
.to
.ty
== Tsarray
) &&
7710 (exp
.e1
.op
== EXP
.address || exp
.e1
.op
== EXP
.star ||
7711 exp
.e1
.op
== EXP
.uadd || exp
.e1
.op
== EXP
.negate
))
7713 /* Ambiguous cases arise from CParser if type-name is just an identifier.
7714 * ( identifier ) cast-expression
7715 * ( identifier [expression]) cast-expression
7716 * If we determine that `identifier` is a variable, and cast-expression
7717 * is one of the unary operators (& * + -), then rewrite this cast
7718 * as a binary expression.
7724 exp
.to
.resolve(loc
, sc
, e
, t
, s
);
7727 if (auto ex
= exp
.e1
.isAddrExp()) // (ident) &exp -> (ident & exp)
7728 result
= new AndExp(loc
, e
, ex
.e1
);
7729 else if (auto ex
= exp
.e1
.isPtrExp()) // (ident) *exp -> (ident * exp)
7730 result
= new MulExp(loc
, e
, ex
.e1
);
7731 else if (auto ex
= exp
.e1
.isUAddExp()) // (ident) +exp -> (ident + exp)
7732 result
= new AddExp(loc
, e
, ex
.e1
);
7733 else if (auto ex
= exp
.e1
.isNegExp()) // (ident) -exp -> (ident - exp)
7734 result
= new MinExp(loc
, e
, ex
.e1
);
7737 result
= result
.expressionSemantic(sc
);
7744 exp
.to
= exp
.to
.typeSemantic(exp
.loc
, sc
);
7745 if (exp
.to
== Type
.terror
)
7748 if (!exp
.to
.hasPointers())
7749 exp
.setNoderefOperand();
7751 // When e1 is a template lambda, this cast may instantiate it with
7753 exp
.e1
= inferType(exp
.e1
, exp
.to
);
7756 if (auto e
= unaSemantic(exp
, sc
))
7762 if (exp
.to
&& !exp
.to
.isTypeSArray() && !exp
.to
.isTypeFunction())
7763 exp
.e1
= exp
.e1
.arrayFuncConv(sc
);
7765 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
7766 if (exp
.e1
.op
== EXP
.type
)
7767 exp
.e1
= resolveAliasThis(sc
, exp
.e1
);
7769 auto e1x
= resolveProperties(sc
, exp
.e1
);
7770 if (e1x
.op
== EXP
.error
)
7775 if (e1x
.checkType())
7781 exp
.error("cannot cast `%s`", exp
.e1
.toChars());
7785 // https://issues.dlang.org/show_bug.cgi?id=19954
7786 if (exp
.e1
.type
.ty
== Ttuple
)
7790 if (TypeTuple tt
= exp
.to
.isTypeTuple())
7792 if (exp
.e1
.type
.implicitConvTo(tt
))
7794 result
= exp
.e1
.castTo(sc
, tt
);
7799 TupleExp te
= exp
.e1
.isTupleExp();
7800 if (te
.exps
.length
== 1)
7801 exp
.e1
= (*te
.exps
)[0];
7804 // only allow S(x) rewrite if cast specified S explicitly.
7805 // See https://issues.dlang.org/show_bug.cgi?id=18545
7806 const bool allowImplicitConstruction
= exp
.to
!is null;
7808 if (!exp
.to
) // Handle cast(const) and cast(immutable), etc.
7810 exp
.to
= exp
.e1
.type
.castMod(exp
.mod
);
7811 exp
.to
= exp
.to
.typeSemantic(exp
.loc
, sc
);
7813 if (exp
.to
== Type
.terror
)
7817 if (exp
.to
.ty
== Ttuple
)
7819 exp
.error("cannot cast `%s` of type `%s` to type sequence `%s`", exp
.e1
.toChars(), exp
.e1
.type
.toChars(), exp
.to
.toChars());
7823 // cast(void) is used to mark e1 as unused, so it is safe
7824 if (exp
.to
.ty
== Tvoid
)
7831 if (!exp
.to
.equals(exp
.e1
.type
) && exp
.mod
== cast(ubyte)~0)
7833 if (Expression e
= exp
.op_overload(sc
))
7835 result
= e
.implicitCastTo(sc
, exp
.to
);
7840 Type t1b
= exp
.e1
.type
.toBasetype();
7841 Type tob
= exp
.to
.toBasetype();
7843 if (allowImplicitConstruction
&& tob
.ty
== Tstruct
&& !tob
.equals(t1b
))
7851 // Rewrite as to.call(e1)
7852 Expression e
= new TypeExp(exp
.loc
, exp
.to
);
7853 e
= new CallExp(exp
.loc
, e
, exp
.e1
);
7854 e
= e
.trySemantic(sc
);
7862 if (!t1b
.equals(tob
) && (t1b
.ty
== Tarray || t1b
.ty
== Tsarray
))
7864 if (checkNonAssignmentArrayOp(exp
.e1
))
7868 // Look for casting to a vector type
7869 if (tob
.ty
== Tvector
&& t1b
.ty
!= Tvector
)
7871 result
= new VectorExp(exp
.loc
, exp
.e1
, exp
.to
);
7872 result
= result
.expressionSemantic(sc
);
7876 Expression ex
= exp
.e1
.castTo(sc
, exp
.to
);
7877 if (ex
.op
== EXP
.error
)
7883 // Check for unsafe casts
7884 if (!isSafeCast(ex
, t1b
, tob
))
7886 if (sc
.setUnsafe(false, exp
.loc
, "cast from `%s` to `%s` not allowed in safe code", exp
.e1
.type
, exp
.to
))
7892 // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built
7893 // to handle certain casts. Those casts which `object.__ArrayCast` does not support are filtered out.
7894 // See `e2ir.toElemCast` for other types of casts. If `object.__ArrayCast` is improved to support more
7895 // casts these conditions and potentially some logic in `e2ir.toElemCast` can be removed.
7896 if (tob
.ty
== Tarray
)
7898 // https://issues.dlang.org/show_bug.cgi?id=19840
7899 if (auto ad
= isAggregate(t1b
))
7903 Expression e
= resolveAliasThis(sc
, exp
.e1
);
7904 e
= new CastExp(exp
.loc
, e
, exp
.to
);
7905 result
= e
.expressionSemantic(sc
);
7910 if(t1b
.ty
== Tarray
&& exp
.e1
.op
!= EXP
.arrayLiteral
&& sc
.needsCodegen())
7912 auto tFrom
= t1b
.nextOf();
7913 auto tTo
= tob
.nextOf();
7915 // https://issues.dlang.org/show_bug.cgi?id=20130
7916 if (exp
.e1
.op
!= EXP
.string_ ||
!ex
.isStringExp
)
7918 const uint fromSize
= cast(uint)tFrom
.size();
7919 const uint toSize
= cast(uint)tTo
.size();
7920 if (fromSize
== SIZE_INVALID || toSize
== SIZE_INVALID
)
7923 // If array element sizes do not match, we must adjust the dimensions
7924 if (fromSize
!= toSize
)
7926 if (!verifyHookExist(exp
.loc
, *sc
, Id
.__ArrayCast
, "casting array of structs"))
7929 // A runtime check is needed in case arrays don't line up. That check should
7930 // be done in the implementation of `object.__ArrayCast`
7931 if (toSize
== 0 ||
(fromSize
% toSize
) != 0)
7933 // lower to `object.__ArrayCast!(TFrom, TTo)(from)`
7935 // fully qualify as `object.__ArrayCast`
7936 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
7937 auto dotid
= new DotIdExp(exp
.loc
, id
, Id
.object
);
7939 auto tiargs
= new Objects();
7942 auto dt = new DotTemplateInstanceExp(exp
.loc
, dotid
, Id
.__ArrayCast
, tiargs
);
7944 auto arguments
= new Expressions();
7945 arguments
.push(exp
.e1
);
7946 Expression ce
= new CallExp(exp
.loc
, dt, arguments
);
7948 result
= expressionSemantic(ce
, sc
);
7956 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
7958 /* C11 6.5.4-5: A cast does not yield an lvalue.
7959 * So ensure that castTo does not strip away the cast so that this
7960 * can be enforced in other semantic visitor methods.
7962 if (!ex
.isCastExp())
7964 ex
= new CastExp(exp
.loc
, ex
, exp
.to
);
7971 override void visit(VectorExp exp
)
7973 static if (LOGSEMANTIC
)
7975 printf("VectorExp::semantic('%s')\n", exp
.toChars());
7983 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
7984 exp
.type
= exp
.to
.typeSemantic(exp
.loc
, sc
);
7985 if (exp
.e1
.op
== EXP
.error || exp
.type
.ty
== Terror
)
7991 Type tb
= exp
.type
.toBasetype();
7992 assert(tb
.ty
== Tvector
);
7993 TypeVector tv
= cast(TypeVector
)tb
;
7994 Type te
= tv
.elementType();
7995 exp
.dim
= cast(int)(tv
.size(exp
.loc
) / te
.size(exp
.loc
));
7997 bool checkElem(Expression elem
)
7999 if (elem
.isConst() == 1)
8002 exp
.error("constant expression expected, not `%s`", elem
.toChars());
8006 exp
.e1
= exp
.e1
.optimize(WANTvalue
);
8008 if (exp
.e1
.op
== EXP
.arrayLiteral
)
8010 foreach (i
; 0 .. exp
.dim
)
8012 // Do not stop on first error - check all AST nodes even if error found
8013 res |
= checkElem(exp
.e1
.isArrayLiteralExp()[i
]);
8016 else if (exp
.e1
.type
.ty
== Tvoid
)
8019 result
= res ? ErrorExp
.get() : exp
;
8022 override void visit(VectorArrayExp e
)
8024 static if (LOGSEMANTIC
)
8026 printf("VectorArrayExp::semantic('%s')\n", e
.toChars());
8031 e
.e1
= resolveProperties(sc
, e
.e1
);
8033 if (e
.e1
.op
== EXP
.error
)
8038 assert(e
.e1
.type
.ty
== Tvector
);
8039 e
.type
= e
.e1
.type
.isTypeVector().basetype
;
8044 override void visit(SliceExp exp
)
8046 static if (LOGSEMANTIC
)
8048 printf("SliceExp::semantic('%s')\n", exp
.toChars());
8056 // operator overloading should be handled in ArrayExp already.
8057 if (Expression ex
= unaSemantic(exp
, sc
))
8062 exp
.e1
= resolveProperties(sc
, exp
.e1
);
8063 if (exp
.e1
.op
== EXP
.type
&& exp
.e1
.type
.ty
!= Ttuple
)
8065 if (exp
.lwr || exp
.upr
)
8067 exp
.error("cannot slice type `%s`", exp
.e1
.toChars());
8070 Expression e
= new TypeExp(exp
.loc
, exp
.e1
.type
.arrayOf());
8071 result
= e
.expressionSemantic(sc
);
8074 if (!exp
.lwr
&& !exp
.upr
)
8076 if (exp
.e1
.op
== EXP
.arrayLiteral
)
8078 // Convert [a,b,c][] to [a,b,c]
8079 Type t1b
= exp
.e1
.type
.toBasetype();
8080 Expression e
= exp
.e1
;
8081 if (t1b
.ty
== Tsarray
)
8084 e
.type
= t1b
.nextOf().arrayOf();
8089 if (exp
.e1
.op
== EXP
.slice
)
8091 // Convert e[][] to e[]
8092 SliceExp se
= cast(SliceExp
)exp
.e1
;
8093 if (!se
.lwr
&& !se
.upr
)
8099 if (isArrayOpOperand(exp
.e1
))
8101 // Convert (a[]+b[])[] to a[]+b[]
8106 if (exp
.e1
.op
== EXP
.error
)
8111 if (exp
.e1
.type
.ty
== Terror
)
8114 Type t1b
= exp
.e1
.type
.toBasetype();
8115 if (auto tp
= t1b
.isTypePointer())
8117 if (t1b
.isPtrToFunction())
8119 exp
.error("cannot slice function pointer `%s`", exp
.e1
.toChars());
8122 if (!exp
.lwr ||
!exp
.upr
)
8124 exp
.error("upper and lower bounds are needed to slice a pointer");
8125 if (auto ad
= isAggregate(tp
.next
.toBasetype()))
8127 auto s
= search_function(ad
, Id
.index
);
8128 if (!s
) s
= search_function(ad
, Id
.slice
);
8131 auto fd
= s
.isFuncDeclaration();
8132 if ((fd
&& !fd
.getParameterList().length
) || s
.isTemplateDeclaration())
8134 exp
.errorSupplemental(
8135 "pointer `%s` points to an aggregate that defines an `%s`, perhaps you meant `(*%s)[]`",
8147 if (sc
.setUnsafe(false, exp
.loc
, "pointer slicing not allowed in safe functions"))
8150 else if (t1b
.ty
== Tarray
)
8153 else if (t1b
.ty
== Tsarray
)
8156 else if (t1b
.ty
== Ttuple
)
8158 if (!exp
.lwr
&& !exp
.upr
)
8163 if (!exp
.lwr ||
!exp
.upr
)
8165 exp
.error("need upper and lower bound to slice a sequence");
8169 else if (t1b
.ty
== Tvector
&& exp
.e1
.isLvalue())
8171 // Convert e1 to corresponding static array
8172 TypeVector tv1
= cast(TypeVector
)t1b
;
8174 t1b
= t1b
.castMod(tv1
.mod
);
8179 exp
.error("`%s` cannot be sliced with `[]`", t1b
.ty
== Tvoid ? exp
.e1
.toChars() : t1b
.toChars());
8183 /* Run semantic on lwr and upr.
8186 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray || t1b
.ty
== Ttuple
)
8188 // Create scope for 'length' variable
8189 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, exp
);
8190 sym
.parent
= sc
.scopesym
;
8195 if (t1b
.ty
== Ttuple
)
8196 sc
= sc
.startCTFE();
8197 exp
.lwr
= exp
.lwr
.expressionSemantic(sc
);
8198 exp
.lwr
= resolveProperties(sc
, exp
.lwr
);
8199 if (t1b
.ty
== Ttuple
)
8201 exp
.lwr
= exp
.lwr
.implicitCastTo(sc
, Type
.tsize_t
);
8205 if (t1b
.ty
== Ttuple
)
8206 sc
= sc
.startCTFE();
8207 exp
.upr
= exp
.upr
.expressionSemantic(sc
);
8208 exp
.upr
= resolveProperties(sc
, exp
.upr
);
8209 if (t1b
.ty
== Ttuple
)
8211 exp
.upr
= exp
.upr
.implicitCastTo(sc
, Type
.tsize_t
);
8215 if (exp
.lwr
&& exp
.lwr
.type
== Type
.terror || exp
.upr
&& exp
.upr
.type
== Type
.terror
)
8218 if (t1b
.ty
== Ttuple
)
8220 exp
.lwr
= exp
.lwr
.ctfeInterpret();
8221 exp
.upr
= exp
.upr
.ctfeInterpret();
8222 uinteger_t i1
= exp
.lwr
.toUInteger();
8223 uinteger_t i2
= exp
.upr
.toUInteger();
8228 if (exp
.e1
.op
== EXP
.tuple
) // slicing an expression tuple
8230 te
= cast(TupleExp
)exp
.e1
;
8232 length
= te
.exps
.length
;
8234 else if (exp
.e1
.op
== EXP
.type
) // slicing a type tuple
8237 tup
= cast(TypeTuple
)t1b
;
8238 length
= Parameter
.dim(tup
.arguments
);
8243 if (i2
< i1 || length
< i2
)
8245 exp
.error("string slice `[%llu .. %llu]` is out of bounds", i1
, i2
);
8249 size_t j1
= cast(size_t
)i1
;
8250 size_t j2
= cast(size_t
)i2
;
8252 if (exp
.e1
.op
== EXP
.tuple
)
8254 auto exps
= new Expressions(j2
- j1
);
8255 for (size_t i
= 0; i
< j2
- j1
; i
++)
8257 (*exps
)[i
] = (*te
.exps
)[j1
+ i
];
8259 e
= new TupleExp(exp
.loc
, te
.e0
, exps
);
8263 auto args
= new Parameters();
8264 args
.reserve(j2
- j1
);
8265 for (size_t i
= j1
; i
< j2
; i
++)
8267 Parameter arg
= Parameter
.getNth(tup
.arguments
, i
);
8270 e
= new TypeExp(exp
.e1
.loc
, new TypeTuple(args
));
8272 e
= e
.expressionSemantic(sc
);
8277 exp
.type
= t1b
.nextOf().arrayOf();
8278 // Allow typedef[] -> typedef[]
8279 if (exp
.type
.equals(t1b
))
8280 exp
.type
= exp
.e1
.type
;
8282 // We might know $ now
8283 setLengthVarIfKnown(exp
.lengthVar
, t1b
);
8285 if (exp
.lwr
&& exp
.upr
)
8287 exp
.lwr
= exp
.lwr
.optimize(WANTvalue
);
8288 exp
.upr
= exp
.upr
.optimize(WANTvalue
);
8290 IntRange lwrRange
= getIntRange(exp
.lwr
);
8291 IntRange uprRange
= getIntRange(exp
.upr
);
8293 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray
)
8295 Expression el
= new ArrayLengthExp(exp
.loc
, exp
.e1
);
8296 el
= el
.expressionSemantic(sc
);
8297 el
= el
.optimize(WANTvalue
);
8298 if (el
.op
== EXP
.int64
)
8300 // Array length is known at compile-time. Upper is in bounds if it fits length.
8301 dinteger_t length
= el
.toInteger();
8302 auto bounds
= IntRange(SignExtendedNumber(0), SignExtendedNumber(length
));
8303 exp
.upperIsInBounds
= bounds
.contains(uprRange
);
8305 else if (exp
.upr
.op
== EXP
.int64
&& exp
.upr
.toInteger() == 0)
8307 // Upper slice expression is '0'. Value is always in bounds.
8308 exp
.upperIsInBounds
= true;
8310 else if (exp
.upr
.op
== EXP
.variable
&& (cast(VarExp
)exp
.upr
).var
.ident
== Id
.dollar
)
8312 // Upper slice expression is '$'. Value is always in bounds.
8313 exp
.upperIsInBounds
= true;
8316 else if (t1b
.ty
== Tpointer
)
8318 exp
.upperIsInBounds
= true;
8323 exp
.lowerIsLessThanUpper
= (lwrRange
.imax
<= uprRange
.imin
);
8325 //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", exp.upperIsInBounds, exp.lowerIsLessThanUpper);
8331 override void visit(ArrayLengthExp e
)
8333 static if (LOGSEMANTIC
)
8335 printf("ArrayLengthExp::semantic('%s')\n", e
.toChars());
8343 if (Expression ex
= unaSemantic(e
, sc
))
8348 e
.e1
= resolveProperties(sc
, e
.e1
);
8350 e
.type
= Type
.tsize_t
;
8354 override void visit(ArrayExp exp
)
8356 static if (LOGSEMANTIC
)
8358 printf("ArrayExp::semantic('%s')\n", exp
.toChars());
8362 if (sc
.flags
& SCOPE
.Cfile
)
8364 /* See if need to rewrite the AST because of cast/call ambiguity
8366 if (auto e
= castCallAmbiguity(exp
, sc
))
8368 result
= expressionSemantic(e
, sc
);
8373 result
= exp
.carraySemantic(sc
); // C semantics
8377 Expression e
= exp
.op_overload(sc
);
8384 if (isAggregate(exp
.e1
.type
))
8385 exp
.error("no `[]` operator overload for type `%s`", exp
.e1
.type
.toChars());
8386 else if (exp
.e1
.op
== EXP
.type
&& exp
.e1
.type
.ty
!= Ttuple
)
8387 exp
.error("static array of `%s` with multiple lengths not allowed", exp
.e1
.type
.toChars());
8388 else if (isIndexableNonAggregate(exp
.e1
.type
))
8389 exp
.error("only one index allowed to index `%s`", exp
.e1
.type
.toChars());
8391 exp
.error("cannot use `[]` operator on expression of type `%s`", exp
.e1
.type
.toChars());
8393 result
= ErrorExp
.get();
8396 override void visit(DotExp exp
)
8398 static if (LOGSEMANTIC
)
8400 printf("DotExp::semantic('%s')\n", exp
.toChars());
8402 printf("\ttype = %s\n", exp
.type
.toChars());
8404 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
8405 exp
.e2
= exp
.e2
.expressionSemantic(sc
);
8407 if (exp
.e1
.op
== EXP
.type
)
8412 if (exp
.e2
.op
== EXP
.type
)
8417 if (auto te
= exp
.e2
.isTemplateExp())
8419 Expression e
= new DotTemplateExp(exp
.loc
, exp
.e1
, te
.td
);
8420 result
= e
.expressionSemantic(sc
);
8424 exp
.type
= exp
.e2
.type
;
8428 override void visit(CommaExp e
)
8430 //printf("Semantic.CommaExp() %s\n", e.toChars());
8437 // Allow `((a,b),(x,y))`
8438 if (e
.allowCommaExp
)
8440 CommaExp
.allow(e
.e1
);
8441 CommaExp
.allow(e
.e2
);
8444 if (Expression ex
= binSemanticProp(e
, sc
))
8449 e
.e1
= e
.e1
.addDtorHook(sc
);
8451 if (checkNonAssignmentArrayOp(e
.e1
))
8454 // Comma expressions trigger this conversion
8455 e
.e2
= e
.e2
.arrayFuncConv(sc
);
8460 if (sc
.flags
& SCOPE
.Cfile
)
8463 if (e
.type
is Type
.tvoid
)
8465 checkMustUse(e
.e1
, sc
);
8468 else if (!e
.allowCommaExp
&& !e
.isGenerated
)
8469 e
.error("using the result of a comma expression is not allowed");
8472 override void visit(IntervalExp e
)
8474 static if (LOGSEMANTIC
)
8476 printf("IntervalExp::semantic('%s')\n", e
.toChars());
8484 Expression le
= e
.lwr
;
8485 le
= le
.expressionSemantic(sc
);
8486 le
= resolveProperties(sc
, le
);
8488 Expression ue
= e
.upr
;
8489 ue
= ue
.expressionSemantic(sc
);
8490 ue
= resolveProperties(sc
, ue
);
8492 if (le
.op
== EXP
.error
)
8497 if (ue
.op
== EXP
.error
)
8506 e
.type
= Type
.tvoid
;
8510 override void visit(DelegatePtrExp e
)
8512 static if (LOGSEMANTIC
)
8514 printf("DelegatePtrExp::semantic('%s')\n", e
.toChars());
8519 e
.e1
= resolveProperties(sc
, e
.e1
);
8521 if (e
.e1
.op
== EXP
.error
)
8526 e
.type
= Type
.tvoidptr
;
8531 override void visit(DelegateFuncptrExp e
)
8533 static if (LOGSEMANTIC
)
8535 printf("DelegateFuncptrExp::semantic('%s')\n", e
.toChars());
8540 e
.e1
= resolveProperties(sc
, e
.e1
);
8541 if (e
.e1
.op
== EXP
.error
)
8546 e
.type
= e
.e1
.type
.nextOf().pointerTo();
8551 override void visit(IndexExp exp
)
8553 static if (LOGSEMANTIC
)
8555 printf("IndexExp::semantic('%s')\n", exp
.toChars());
8563 // operator overloading should be handled in ArrayExp already.
8565 exp
.e1
= exp
.e1
.expressionSemantic(sc
).arrayFuncConv(sc
);
8566 assert(exp
.e1
.type
); // semantic() should already be run on it
8567 if (exp
.e1
.op
== EXP
.type
&& exp
.e1
.type
.ty
!= Ttuple
)
8569 exp
.e2
= exp
.e2
.expressionSemantic(sc
);
8570 exp
.e2
= resolveProperties(sc
, exp
.e2
);
8572 if (exp
.e2
.op
== EXP
.type
)
8573 nt
= new TypeAArray(exp
.e1
.type
, exp
.e2
.type
);
8575 nt
= new TypeSArray(exp
.e1
.type
, exp
.e2
);
8576 Expression e
= new TypeExp(exp
.loc
, nt
);
8577 result
= e
.expressionSemantic(sc
);
8580 if (exp
.e1
.op
== EXP
.error
)
8585 if (exp
.e1
.type
.ty
== Terror
)
8588 // Note that unlike C we do not implement the int[ptr]
8590 Type t1b
= exp
.e1
.type
.toBasetype();
8592 if (TypeVector tv1
= t1b
.isTypeVector())
8594 // Convert e1 to corresponding static array
8596 t1b
= t1b
.castMod(tv1
.mod
);
8597 exp
.e1
= exp
.e1
.castTo(sc
, t1b
);
8599 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray
)
8601 if (!checkAddressable(exp
, sc
))
8605 /* Run semantic on e2
8608 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray || t1b
.ty
== Ttuple
)
8610 // Create scope for 'length' variable
8611 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, exp
);
8612 sym
.parent
= sc
.scopesym
;
8615 if (t1b
.ty
== Ttuple
)
8616 sc
= sc
.startCTFE();
8617 exp
.e2
= exp
.e2
.expressionSemantic(sc
).arrayFuncConv(sc
);
8618 exp
.e2
= resolveProperties(sc
, exp
.e2
);
8619 if (t1b
.ty
== Ttuple
)
8621 if (exp
.e2
.op
== EXP
.tuple
)
8623 TupleExp te
= cast(TupleExp
)exp
.e2
;
8624 if (te
.exps
&& te
.exps
.length
== 1)
8625 exp
.e2
= Expression
.combine(te
.e0
, (*te
.exps
)[0]); // bug 4444 fix
8629 if (exp
.e2
.type
== Type
.terror
)
8632 if (checkNonAssignmentArrayOp(exp
.e1
))
8638 if (t1b
.isPtrToFunction())
8640 exp
.error("cannot index function pointer `%s`", exp
.e1
.toChars());
8643 exp
.e2
= exp
.e2
.implicitCastTo(sc
, Type
.tsize_t
);
8644 if (exp
.e2
.type
== Type
.terror
)
8646 exp
.e2
= exp
.e2
.optimize(WANTvalue
);
8647 if (exp
.e2
.op
== EXP
.int64
&& exp
.e2
.toInteger() == 0)
8650 else if (sc
.setUnsafe(false, exp
.loc
, "`@safe` function `%s` cannot index pointer `%s`", sc
.func
, exp
.e1
))
8654 exp
.type
= (cast(TypeNext
)t1b
).next
;
8658 exp
.e2
= exp
.e2
.implicitCastTo(sc
, Type
.tsize_t
);
8659 if (exp
.e2
.type
== Type
.terror
)
8661 exp
.type
= (cast(TypeNext
)t1b
).next
;
8666 exp
.e2
= exp
.e2
.implicitCastTo(sc
, Type
.tsize_t
);
8667 if (exp
.e2
.type
== Type
.terror
)
8669 exp
.type
= t1b
.nextOf();
8674 TypeAArray taa
= cast(TypeAArray
)t1b
;
8675 /* We can skip the implicit conversion if they differ only by
8677 * https://issues.dlang.org/show_bug.cgi?id=2684
8678 * see also bug https://issues.dlang.org/show_bug.cgi?id=2954 b
8680 if (!arrayTypeCompatibleWithoutCasting(exp
.e2
.type
, taa
.index
))
8682 exp
.e2
= exp
.e2
.implicitCastTo(sc
, taa
.index
); // type checking
8683 if (exp
.e2
.type
== Type
.terror
)
8687 semanticTypeInfo(sc
, taa
);
8688 checkNewEscape(sc
, exp
.e2
, false);
8690 exp
.type
= taa
.next
;
8695 exp
.e2
= exp
.e2
.implicitCastTo(sc
, Type
.tsize_t
);
8696 if (exp
.e2
.type
== Type
.terror
)
8699 exp
.e2
= exp
.e2
.ctfeInterpret();
8700 uinteger_t index
= exp
.e2
.toUInteger();
8705 if (exp
.e1
.op
== EXP
.tuple
)
8707 te
= cast(TupleExp
)exp
.e1
;
8709 length
= te
.exps
.length
;
8711 else if (exp
.e1
.op
== EXP
.type
)
8714 tup
= cast(TypeTuple
)t1b
;
8715 length
= Parameter
.dim(tup
.arguments
);
8720 if (length
<= index
)
8722 exp
.error("array index `[%llu]` is outside array bounds `[0 .. %llu]`", index
, cast(ulong)length
);
8726 if (exp
.e1
.op
== EXP
.tuple
)
8728 e
= (*te
.exps
)[cast(size_t
)index
];
8729 e
= Expression
.combine(te
.e0
, e
);
8732 e
= new TypeExp(exp
.e1
.loc
, Parameter
.getNth(tup
.arguments
, cast(size_t
)index
).type
);
8737 exp
.error("`%s` must be an array or pointer type, not `%s`", exp
.e1
.toChars(), exp
.e1
.type
.toChars());
8741 // We might know $ now
8742 setLengthVarIfKnown(exp
.lengthVar
, t1b
);
8744 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray
)
8746 Expression el
= new ArrayLengthExp(exp
.loc
, exp
.e1
);
8747 el
= el
.expressionSemantic(sc
);
8748 el
= el
.optimize(WANTvalue
);
8749 if (el
.op
== EXP
.int64
)
8751 exp
.e2
= exp
.e2
.optimize(WANTvalue
);
8752 dinteger_t length
= el
.toInteger();
8755 auto bounds
= IntRange(SignExtendedNumber(0), SignExtendedNumber(length
- 1));
8756 // OR it in, because it might already be set for C array indexing
8757 exp
.indexIsInBounds |
= bounds
.contains(getIntRange(exp
.e2
));
8759 else if (sc
.flags
& SCOPE
.Cfile
&& t1b
.ty
== Tsarray
)
8761 if (auto ve
= exp
.e1
.isVarExp())
8763 /* Rewrite 0-length C array ve[exp.e2] as *(ve + exp.e2)
8765 auto vp
= ve
.castTo(sc
, t1b
.isTypeSArray().next
.pointerTo());
8766 auto e
= new AddExp(exp
.loc
, vp
, exp
.e2
);
8767 auto pe
= new PtrExp(exp
.loc
, e
);
8768 result
= pe
.expressionSemantic(sc
).optimize(WANTvalue
);
8778 override void visit(PostExp exp
)
8780 static if (LOGSEMANTIC
)
8782 printf("PostExp::semantic('%s')\n", exp
.toChars());
8790 if (sc
.flags
& SCOPE
.Cfile
)
8792 /* See if need to rewrite the AST because of cast/call ambiguity
8794 if (auto e
= castCallAmbiguity(exp
, sc
))
8796 result
= expressionSemantic(e
, sc
);
8801 if (Expression ex
= binSemantic(exp
, sc
))
8806 Expression e1x
= resolveProperties(sc
, exp
.e1
);
8807 if (e1x
.op
== EXP
.error
)
8814 Expression e
= exp
.op_overload(sc
);
8821 if (exp
.e1
.checkReadModifyWrite(exp
.op
))
8824 if (exp
.e1
.op
== EXP
.slice
)
8826 const(char)* s
= exp
.op
== EXP
.plusPlus ?
"increment" : "decrement";
8827 exp
.error("cannot post-%s array slice `%s`, use pre-%s instead", s
, exp
.e1
.toChars(), s
);
8831 Type t1
= exp
.e1
.type
.toBasetype();
8832 if (t1
.ty
== Tclass || t1
.ty
== Tstruct || exp
.e1
.op
== EXP
.arrayLength
)
8834 /* Check for operator overloading,
8835 * but rewrite in terms of ++e instead of e++
8838 /* If e1 is not trivial, take a reference to it
8840 Expression
de = null;
8841 if (exp
.e1
.op
!= EXP
.variable
&& exp
.e1
.op
!= EXP
.arrayLength
)
8844 auto v
= copyToTemp(STC
.ref_
, "__postref", exp
.e1
);
8845 de = new DeclarationExp(exp
.loc
, v
);
8846 exp
.e1
= new VarExp(exp
.e1
.loc
, v
);
8850 * auto tmp = e1; ++e1; tmp
8852 auto tmp
= copyToTemp(0, "__pitmp", exp
.e1
);
8853 Expression ea
= new DeclarationExp(exp
.loc
, tmp
);
8855 Expression eb
= exp
.e1
.syntaxCopy();
8856 eb
= new PreExp(exp
.op
== EXP
.plusPlus ? EXP
.prePlusPlus
: EXP
.preMinusMinus
, exp
.loc
, eb
);
8858 Expression ec
= new VarExp(exp
.loc
, tmp
);
8860 // Combine de,ea,eb,ec
8862 ea
= new CommaExp(exp
.loc
, de, ea
);
8863 e
= new CommaExp(exp
.loc
, ea
, eb
);
8864 e
= new CommaExp(exp
.loc
, e
, ec
);
8865 e
= e
.expressionSemantic(sc
);
8870 exp
.e1
= exp
.e1
.modifiableLvalue(sc
, exp
.e1
);
8871 exp
.e1
= exp
.e1
.optimize(WANTvalue
, /*keepLvalue*/ true);
8874 if (exp
.e1
.checkScalar() ||
8875 exp
.e1
.checkSharedAccess(sc
))
8877 if (exp
.e1
.checkNoBool())
8880 if (exp
.e1
.type
.ty
== Tpointer
)
8881 e
= scaleFactor(exp
, sc
);
8883 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
);
8884 e
.type
= exp
.e1
.type
;
8888 override void visit(PreExp exp
)
8890 Expression e
= exp
.op_overload(sc
);
8891 // printf("PreExp::semantic('%s')\n", toChars());
8898 // Rewrite as e1+=1 or e1-=1
8899 if (exp
.op
== EXP
.prePlusPlus
)
8900 e
= new AddAssignExp(exp
.loc
, exp
.e1
, IntegerExp
.literal
!1);
8902 e
= new MinAssignExp(exp
.loc
, exp
.e1
, IntegerExp
.literal
!1);
8903 result
= e
.expressionSemantic(sc
);
8907 * Get the expression initializer for a specific struct
8910 * sd = the struct for which the expression initializer is needed
8911 * loc = the location of the initializer
8912 * sc = the scope where the expression is located
8913 * t = the type of the expression
8916 * The expression initializer or error expression if any errors occured
8918 private Expression
getInitExp(StructDeclaration sd
, Loc loc
, Scope
* sc
, Type t
)
8920 if (sd
.zeroInit
&& !sd
.isNested())
8922 // https://issues.dlang.org/show_bug.cgi?id=14606
8923 // Always use BlitExp for the special expression: (struct = 0)
8924 return IntegerExp
.literal
!0;
8929 auto sle
= new StructLiteralExp(loc
, sd
, null, t
);
8930 if (!sd
.fill(loc
, *sle
.elements
, true))
8931 return ErrorExp
.get();
8932 if (checkFrameAccess(loc
, sc
, sd
, sle
.elements
.length
))
8933 return ErrorExp
.get();
8939 return t
.defaultInit(loc
);
8942 override void visit(AssignExp exp
)
8944 static if (LOGSEMANTIC
)
8946 if (exp
.op
== EXP
.blit
) printf("BlitExp.toElem('%s')\n", exp
.toChars());
8947 if (exp
.op
== EXP
.assign
) printf("AssignExp.toElem('%s')\n", exp
.toChars());
8948 if (exp
.op
== EXP
.construct
) printf("ConstructExp.toElem('%s')\n", exp
.toChars());
8951 void setResult(Expression e
, int line
= __LINE__
)
8953 //printf("line %d\n", line);
8959 return setResult(exp
);
8962 Expression e1old
= exp
.e1
;
8964 if (auto e2comma
= exp
.e2
.isCommaExp())
8966 if (!e2comma
.isGenerated
&& !(sc
.flags
& SCOPE
.Cfile
))
8967 exp
.error("using the result of a comma expression is not allowed");
8969 /* Rewrite to get rid of the comma from rvalue
8970 * e1=(e0,e2) => e0,(e1=e2)
8973 exp
.e2
= Expression
.extractLast(e2comma
, e0
);
8974 Expression e
= Expression
.combine(e0
, exp
);
8975 return setResult(e
.expressionSemantic(sc
));
8978 /* Look for operator overloading of a[arguments] = e2.
8979 * Do it before e1.expressionSemantic() otherwise the ArrayExp will have been
8980 * converted to unary operator overloading already.
8982 if (auto ae
= exp
.e1
.isArrayExp())
8986 ae
.e1
= ae
.e1
.expressionSemantic(sc
);
8987 ae
.e1
= resolveProperties(sc
, ae
.e1
);
8988 Expression ae1old
= ae
.e1
;
8990 const(bool) maybeSlice
=
8991 (ae
.arguments
.length
== 0 ||
8992 ae
.arguments
.length
== 1 && (*ae
.arguments
)[0].op
== EXP
.interval
);
8994 IntervalExp ie
= null;
8995 if (maybeSlice
&& ae
.arguments
.length
)
8997 assert((*ae
.arguments
)[0].op
== EXP
.interval
);
8998 ie
= cast(IntervalExp
)(*ae
.arguments
)[0];
9000 Type att
= null; // first cyclic `alias this` type
9003 if (ae
.e1
.op
== EXP
.error
)
9004 return setResult(ae
.e1
);
9006 Expression e0
= null;
9007 Expression ae1save
= ae
.e1
;
9008 ae
.lengthVar
= null;
9010 Type t1b
= ae
.e1
.type
.toBasetype();
9011 AggregateDeclaration ad
= isAggregate(t1b
);
9014 if (search_function(ad
, Id
.indexass
))
9017 res
= resolveOpDollar(sc
, ae
, &e0
);
9018 if (!res
) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
9020 if (res
.op
== EXP
.error
)
9021 return setResult(res
);
9023 res
= exp
.e2
.expressionSemantic(sc
);
9024 if (res
.op
== EXP
.error
)
9025 return setResult(res
);
9028 /* Rewrite (a[arguments] = e2) as:
9029 * a.opIndexAssign(e2, arguments)
9031 Expressions
* a
= ae
.arguments
.copy();
9032 a
.insert(0, exp
.e2
);
9033 res
= new DotIdExp(exp
.loc
, ae
.e1
, Id
.indexass
);
9034 res
= new CallExp(exp
.loc
, res
, a
);
9035 if (maybeSlice
) // a[] = e2 might be: a.opSliceAssign(e2)
9036 res
= res
.trySemantic(sc
);
9038 res
= res
.expressionSemantic(sc
);
9040 return setResult(Expression
.combine(e0
, res
));
9044 if (maybeSlice
&& search_function(ad
, Id
.sliceass
))
9047 res
= resolveOpDollar(sc
, ae
, ie
, &e0
);
9048 if (res
.op
== EXP
.error
)
9049 return setResult(res
);
9051 res
= exp
.e2
.expressionSemantic(sc
);
9052 if (res
.op
== EXP
.error
)
9053 return setResult(res
);
9057 /* Rewrite (a[i..j] = e2) as:
9058 * a.opSliceAssign(e2, i, j)
9060 auto a
= new Expressions();
9067 res
= new DotIdExp(exp
.loc
, ae
.e1
, Id
.sliceass
);
9068 res
= new CallExp(exp
.loc
, res
, a
);
9069 res
= res
.expressionSemantic(sc
);
9070 return setResult(Expression
.combine(e0
, res
));
9073 // No operator overloading member function found yet, but
9074 // there might be an alias this to try.
9075 if (ad
.aliasthis
&& !isRecursiveAliasThis(att
, ae
.e1
.type
))
9077 /* Rewrite (a[arguments] op e2) as:
9078 * a.aliasthis[arguments] op e2
9080 ae
.e1
= resolveAliasThis(sc
, ae1save
, true);
9086 ae
.e1
= ae1old
; // recovery
9087 ae
.lengthVar
= null;
9090 /* Run this.e1 semantic.
9093 Expression e1x
= exp
.e1
;
9095 /* With UFCS, e.f = value
9101 if (auto dti
= e1x
.isDotTemplateInstanceExp())
9103 Expression e
= dti
.dotTemplateSemanticProp(sc
, DotExpFlag
.gag
);
9106 return setResult(resolveUFCSProperties(sc
, e1x
, exp
.e2
));
9111 else if (sc
.flags
& SCOPE
.Cfile
&& e1x
.isDotIdExp())
9113 auto die
= e1x
.isDotIdExp();
9114 e1x
= fieldLookup(die
.e1
, sc
, die
.ident
, die
.arrow
);
9116 else if (auto die
= e1x
.isDotIdExp())
9118 Expression e
= die
.dotIdSemanticProp(sc
, 1);
9119 if (e
&& isDotOpDispatch(e
))
9121 /* https://issues.dlang.org/show_bug.cgi?id=19687
9123 * On this branch, e2 is semantically analyzed in resolvePropertiesX,
9124 * but that call is done with gagged errors. That is the only time when
9125 * semantic gets ran on e2, that is why the error never gets to be printed.
9126 * In order to make sure that UFCS is tried with correct parameters, e2
9127 * needs to have semantic ran on it.
9130 exp
.e2
= exp
.e2
.expressionSemantic(sc
);
9131 uint errors
= global
.startGagging();
9132 e
= resolvePropertiesX(sc
, e
, exp
.e2
);
9133 // Any error or if 'e' is not resolved, go to UFCS
9134 if (global
.endGagging(errors
) || e
is ode
)
9135 e
= null; /* fall down to UFCS */
9137 return setResult(e
);
9140 return setResult(resolveUFCSProperties(sc
, e1x
, exp
.e2
));
9145 if (auto se
= e1x
.isSliceExp())
9148 e1x
= e1x
.expressionSemantic(sc
);
9151 /* We have f = value.
9157 if (Expression e
= resolvePropertiesX(sc
, e1x
, exp
.e2
, exp
))
9158 return setResult(e
);
9160 if (e1x
.checkRightThis(sc
))
9165 assert(exp
.e1
.type
);
9167 Type t1
= exp
.e1
.type
.isTypeEnum() ? exp
.e1
.type
: exp
.e1
.type
.toBasetype();
9169 /* Run this.e2 semantic.
9170 * Different from other binary expressions, the analysis of e2
9171 * depends on the result of e1 in assignments.
9174 Expression e2x
= inferType(exp
.e2
, t1
.baseElemOf());
9175 e2x
= e2x
.expressionSemantic(sc
);
9176 if (!t1
.isTypeSArray())
9177 e2x
= e2x
.arrayFuncConv(sc
);
9178 e2x
= resolveProperties(sc
, e2x
);
9179 if (e2x
.op
== EXP
.type
)
9180 e2x
= resolveAliasThis(sc
, e2x
); //https://issues.dlang.org/show_bug.cgi?id=17684
9181 if (e2x
.op
== EXP
.error
)
9182 return setResult(e2x
);
9183 // We delay checking the value for structs/classes as these might have
9184 // an opAssign defined.
9185 if ((t1
.ty
!= Tstruct
&& t1
.ty
!= Tclass
&& e2x
.checkValue()) ||
9186 e2x
.checkSharedAccess(sc
))
9189 auto etmp
= checkNoreturnVarAccess(e2x
);
9191 return setResult(etmp
);
9196 /* Rewrite tuple assignment as a tuple of assignments.
9199 Expression e2x
= exp
.e2
;
9202 if (exp
.e1
.op
== EXP
.tuple
&& e2x
.op
== EXP
.tuple
)
9204 TupleExp tup1
= cast(TupleExp
)exp
.e1
;
9205 TupleExp tup2
= cast(TupleExp
)e2x
;
9206 size_t dim
= tup1
.exps
.length
;
9207 Expression e
= null;
9208 if (dim
!= tup2
.exps
.length
)
9210 exp
.error("mismatched sequence lengths, %d and %d", cast(int)dim
, cast(int)tup2
.exps
.length
);
9215 e
= IntegerExp
.literal
!0;
9216 e
= new CastExp(exp
.loc
, e
, Type
.tvoid
); // avoid "has no effect" error
9217 e
= Expression
.combine(tup1
.e0
, tup2
.e0
, e
);
9221 auto exps
= new Expressions(dim
);
9222 for (size_t i
= 0; i
< dim
; i
++)
9224 Expression ex1
= (*tup1
.exps
)[i
];
9225 Expression ex2
= (*tup2
.exps
)[i
];
9226 (*exps
)[i
] = new AssignExp(exp
.loc
, ex1
, ex2
);
9228 e
= new TupleExp(exp
.loc
, Expression
.combine(tup1
.e0
, tup2
.e0
), exps
);
9230 return setResult(e
.expressionSemantic(sc
));
9233 /* Look for form: e1 = e2.aliasthis.
9235 if (exp
.e1
.op
== EXP
.tuple
)
9237 TupleDeclaration td
= isAliasThisTuple(e2x
);
9241 assert(exp
.e1
.type
.ty
== Ttuple
);
9242 TypeTuple tt
= cast(TypeTuple
)exp
.e1
.type
;
9245 Expression ev
= extractSideEffect(sc
, "__tup", e0
, e2x
);
9247 auto iexps
= new Expressions();
9249 for (size_t u
= 0; u
< iexps
.length
; u
++)
9252 Expression e
= (*iexps
)[u
];
9254 Parameter arg
= Parameter
.getNth(tt
.arguments
, u
);
9255 //printf("[%d] iexps.length = %d, ", u, iexps.length);
9256 //printf("e = (%s %s, %s), ", Token.toChars[e.op], e.toChars(), e.type.toChars());
9257 //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
9259 if (!arg ||
!e
.type
.implicitConvTo(arg
.type
))
9261 // expand initializer to tuple
9262 if (expandAliasThisTuples(iexps
, u
) != -1)
9264 if (iexps
.length
<= u
)
9271 e2x
= new TupleExp(e2x
.loc
, e0
, iexps
);
9272 e2x
= e2x
.expressionSemantic(sc
);
9273 if (e2x
.op
== EXP
.error
)
9278 // Do not need to overwrite this.e2
9284 /* Inside constructor, if this is the first assignment of object field,
9285 * rewrite this to initializing the field.
9287 if (exp
.op
== EXP
.assign
9288 && exp
.e1
.checkModifiable(sc
) == Modifiable
.initialization
)
9290 //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars());
9292 exp
= new ConstructExp(exp
.loc
, exp
.e1
, exp
.e2
);
9295 // https://issues.dlang.org/show_bug.cgi?id=13515
9296 // set Index::modifiable flag for complex AA element initialization
9297 if (auto ie1
= exp
.e1
.isIndexExp())
9299 Expression e1x
= ie1
.markSettingAAElem();
9300 if (e1x
.op
== EXP
.error
)
9307 else if (exp
.op
== EXP
.construct
&& exp
.e1
.op
== EXP
.variable
&&
9308 (cast(VarExp
)exp
.e1
).var
.storage_class
& (STC
.out_ | STC
.ref_
))
9310 exp
.memset
= MemorySet
.referenceInit
;
9313 if (exp
.op
== EXP
.assign
) // skip EXP.blit and EXP.construct, which are initializations
9315 exp
.e1
.checkSharedAccess(sc
);
9316 checkUnsafeAccess(sc
, exp
.e1
, false, true);
9319 checkUnsafeAccess(sc
, exp
.e2
, true, true); // Initializer must always be checked
9321 /* If it is an assignment from a 'foreign' type,
9322 * check for operator overloading.
9324 if (exp
.memset
== MemorySet
.referenceInit
)
9326 // If this is an initialization of a reference,
9329 else if (t1
.ty
== Tstruct
)
9333 auto sd
= (cast(TypeStruct
)t1
).sym
;
9335 if (exp
.op
== EXP
.construct
)
9337 Type t2
= e2x
.type
.toBasetype();
9338 if (t2
.ty
== Tstruct
&& sd
== (cast(TypeStruct
)t2
).sym
)
9341 if (sd
.sizeok
!= Sizeok
.done
)
9344 sd
.ctor
= sd
.searchCtor();
9346 // https://issues.dlang.org/show_bug.cgi?id=15661
9347 // Look for the form from last of comma chain.
9348 auto e2y
= lastComma(e2x
);
9350 CallExp ce
= (e2y
.op
== EXP
.call) ?
cast(CallExp
)e2y
: null;
9351 DotVarExp dve
= (ce
&& ce
.e1
.op
== EXP
.dotVariable
)
9352 ?
cast(DotVarExp
)ce
.e1
: null;
9353 if (sd
.ctor
&& ce
&& dve
&& dve
.var
.isCtorDeclaration() &&
9354 // https://issues.dlang.org/show_bug.cgi?id=19389
9355 dve
.e1
.op
!= EXP
.dotVariable
&&
9356 e2y
.type
.implicitConvTo(t1
))
9358 /* Look for form of constructor call which is:
9359 * __ctmp.ctor(arguments...)
9362 /* Before calling the constructor, initialize
9363 * variable with a bit copy of the default
9366 Expression einit
= getInitExp(sd
, exp
.loc
, sc
, t1
);
9367 if (einit
.op
== EXP
.error
)
9373 auto ae
= new BlitExp(exp
.loc
, exp
.e1
, einit
);
9376 /* Replace __ctmp being constructed with e1.
9377 * We need to copy constructor call expression,
9378 * because it may be used in other place.
9380 auto dvx
= cast(DotVarExp
)dve
.copy();
9382 auto cx
= cast(CallExp
)ce
.copy();
9384 if (checkConstructorEscape(sc
, cx
, false))
9388 Expression
.extractLast(e2x
, e0
);
9390 auto e
= Expression
.combine(e0
, ae
, cx
);
9391 e
= e
.expressionSemantic(sc
);
9395 // https://issues.dlang.org/show_bug.cgi?id=21586
9396 // Rewrite CondExp or e1 will miss direct construction, e.g.
9397 // e1 = a ? S(1) : ...; -> AST: e1 = a ? (S(0)).this(1) : ...;
9398 // a temporary created and an extra destructor call.
9399 // AST will be rewritten to:
9400 // a ? e1 = 0, e1.this(1) : ...; -> blitting plus construction
9401 if (e2x
.op
== EXP
.question
)
9404 * a ? e1 = b : e1 = c;
9406 CondExp econd
= cast(CondExp
)e2x
;
9407 Expression ea1
= new ConstructExp(econd
.e1
.loc
, e1x
, econd
.e1
);
9408 Expression ea2
= new ConstructExp(econd
.e2
.loc
, e1x
, econd
.e2
);
9409 Expression e
= new CondExp(exp
.loc
, econd
.econd
, ea1
, ea2
);
9410 result
= e
.expressionSemantic(sc
);
9413 if (sd
.postblit || sd
.hasCopyCtor
)
9415 /* We have a copy constructor for this
9423 * e1 = init, e1.copyCtor(e2);
9425 Expression einit
= new BlitExp(exp
.loc
, exp
.e1
, getInitExp(sd
, exp
.loc
, sc
, t1
));
9426 einit
.type
= e1x
.type
;
9429 e
= new DotIdExp(exp
.loc
, e1x
, Id
.ctor
);
9430 e
= new CallExp(exp
.loc
, e
, e2x
);
9431 e
= new CommaExp(exp
.loc
, einit
, e
);
9433 //printf("e: %s\n", e.toChars());
9435 result
= e
.expressionSemantic(sc
);
9440 if (!e2x
.type
.implicitConvTo(e1x
.type
))
9442 exp
.error("conversion error from `%s` to `%s`",
9443 e2x
.type
.toChars(), e1x
.type
.toChars());
9448 * (e1 = e2).postblit();
9450 * Blit assignment e1 = e2 returns a reference to the original e1,
9451 * then call the postblit on it.
9453 Expression e
= e1x
.copy();
9454 e
.type
= e
.type
.mutableOf();
9455 if (e
.type
.isShared
&& !sd
.type
.isShared
)
9456 e
.type
= e
.type
.unSharedOf();
9457 e
= new BlitExp(exp
.loc
, e
, e2x
);
9458 e
= new DotVarExp(exp
.loc
, e
, sd
.postblit
, false);
9459 e
= new CallExp(exp
.loc
, e
);
9460 result
= e
.expressionSemantic(sc
);
9466 /* The struct value returned from the function is transferred
9467 * so should not call the destructor on it.
9469 e2x
= valueNoDtor(e2x
);
9473 // https://issues.dlang.org/show_bug.cgi?id=19251
9474 // if e2 cannot be converted to e1.type, maybe there is an alias this
9475 if (!e2x
.implicitConvTo(t1
))
9477 AggregateDeclaration ad2
= isAggregate(e2x
.type
);
9478 if (ad2
&& ad2
.aliasthis
&& !isRecursiveAliasThis(exp
.att2
, exp
.e2
.type
))
9480 /* Rewrite (e1 op e2) as:
9481 * (e1 op e2.aliasthis)
9483 exp
.e2
= new DotIdExp(exp
.e2
.loc
, exp
.e2
, ad2
.aliasthis
.ident
);
9484 result
= exp
.expressionSemantic(sc
);
9489 else if (!e2x
.implicitConvTo(t1
))
9492 if (sd
.sizeok
!= Sizeok
.done
)
9495 sd
.ctor
= sd
.searchCtor();
9499 /* Look for implicit constructor call
9501 * e1 = init, e1.ctor(e2)
9504 /* Fix Issue 5153 : https://issues.dlang.org/show_bug.cgi?id=5153
9505 * Using `new` to initialize a struct object is a common mistake, but
9506 * the error message from the compiler is not very helpful in that
9507 * case. If exp.e2 is a NewExp and the type of new is the same as
9508 * the type as exp.e1 (struct in this case), then we know for sure
9509 * that the user wants to instantiate a struct. This is done to avoid
9510 * issuing an error when the user actually wants to call a constructor
9511 * which receives a class object.
9513 * Foo f = new Foo2(0); is a valid expression if Foo has a constructor
9514 * which receives an instance of a Foo2 class
9516 if (exp
.e2
.op
== EXP
.new_
)
9518 auto newExp
= cast(NewExp
)(exp
.e2
);
9519 if (newExp
.newtype
&& newExp
.newtype
== t1
)
9521 error(exp
.loc
, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
9522 newExp
.toChars(), newExp
.type
.toChars(), t1
.toChars());
9523 errorSupplemental(exp
.loc
, "Perhaps remove the `new` keyword?");
9528 Expression einit
= new BlitExp(exp
.loc
, e1x
, getInitExp(sd
, exp
.loc
, sc
, t1
));
9529 einit
.type
= e1x
.type
;
9532 e
= new DotIdExp(exp
.loc
, e1x
, Id
.ctor
);
9533 e
= new CallExp(exp
.loc
, e
, e2x
);
9534 e
= new CommaExp(exp
.loc
, einit
, e
);
9535 e
= e
.expressionSemantic(sc
);
9539 if (search_function(sd
, Id
.call))
9541 /* Look for static opCall
9542 * https://issues.dlang.org/show_bug.cgi?id=2702
9544 * e1 = typeof(e1).opCall(arguments)
9546 e2x
= typeDotIdExp(e2x
.loc
, e1x
.type
, Id
.call);
9547 e2x
= new CallExp(exp
.loc
, e2x
, exp
.e2
);
9549 e2x
= e2x
.expressionSemantic(sc
);
9550 e2x
= resolveProperties(sc
, e2x
);
9551 if (e2x
.op
== EXP
.error
)
9556 if (e2x
.checkValue() || e2x
.checkSharedAccess(sc
))
9560 else // https://issues.dlang.org/show_bug.cgi?id=11355
9562 AggregateDeclaration ad2
= isAggregate(e2x
.type
);
9563 if (ad2
&& ad2
.aliasthis
&& !isRecursiveAliasThis(exp
.att2
, exp
.e2
.type
))
9565 /* Rewrite (e1 op e2) as:
9566 * (e1 op e2.aliasthis)
9568 exp
.e2
= new DotIdExp(exp
.e2
.loc
, exp
.e2
, ad2
.aliasthis
.ident
);
9569 result
= exp
.expressionSemantic(sc
);
9574 else if (exp
.op
== EXP
.assign
)
9576 if (e1x
.op
== EXP
.index
&& (cast(IndexExp
)e1x
).e1
.type
.toBasetype().ty
== Taarray
)
9583 * ref __aakey = key;
9585 * (__aakey in __aatmp
9586 * ? __aatmp[__aakey].opAssign(__aaval)
9587 * : ConstructExp(__aatmp[__aakey], __aaval));
9589 // ensure we keep the expr modifiable
9590 Expression esetting
= (cast(IndexExp
)e1x
).markSettingAAElem();
9591 if (esetting
.op
== EXP
.error
)
9596 assert(esetting
.op
== EXP
.index
);
9597 IndexExp ie
= cast(IndexExp
) esetting
;
9598 Type t2
= e2x
.type
.toBasetype();
9600 Expression e0
= null;
9601 Expression ea
= extractSideEffect(sc
, "__aatmp", e0
, ie
.e1
);
9602 Expression ek
= extractSideEffect(sc
, "__aakey", e0
, ie
.e2
);
9603 Expression ev
= extractSideEffect(sc
, "__aaval", e0
, e2x
);
9605 AssignExp ae
= cast(AssignExp
)exp
.copy();
9606 ae
.e1
= new IndexExp(exp
.loc
, ea
, ek
);
9607 ae
.e1
= ae
.e1
.expressionSemantic(sc
);
9608 ae
.e1
= ae
.e1
.optimize(WANTvalue
);
9610 Expression e
= ae
.op_overload(sc
);
9613 Expression ey
= null;
9614 if (t2
.ty
== Tstruct
&& sd
== t2
.toDsymbol(sc
))
9618 else if (!ev
.implicitConvTo(ie
.type
) && sd
.ctor
)
9620 // Look for implicit constructor call
9621 // Rewrite as S().ctor(e2)
9622 ey
= new StructLiteralExp(exp
.loc
, sd
, null);
9623 ey
= new DotIdExp(exp
.loc
, ey
, Id
.ctor
);
9624 ey
= new CallExp(exp
.loc
, ey
, ev
);
9625 ey
= ey
.trySemantic(sc
);
9630 ex
= new IndexExp(exp
.loc
, ea
, ek
);
9631 ex
= ex
.expressionSemantic(sc
);
9632 ex
= ex
.modifiableLvalue(sc
, ex
); // allocate new slot
9633 ex
= ex
.optimize(WANTvalue
);
9635 ey
= new ConstructExp(exp
.loc
, ex
, ey
);
9636 ey
= ey
.expressionSemantic(sc
);
9637 if (ey
.op
== EXP
.error
)
9644 // https://issues.dlang.org/show_bug.cgi?id=14144
9645 // The whole expression should have the common type
9646 // of opAssign() return and assigned AA entry.
9647 // Even if there's no common type, expression should be typed as void.
9648 if (!typeMerge(sc
, EXP
.question
, ex
, ey
))
9650 ex
= new CastExp(ex
.loc
, ex
, Type
.tvoid
);
9651 ey
= new CastExp(ey
.loc
, ey
, Type
.tvoid
);
9653 e
= new CondExp(exp
.loc
, new InExp(exp
.loc
, ek
, ea
), ex
, ey
);
9655 e
= Expression
.combine(e0
, e
);
9656 e
= e
.expressionSemantic(sc
);
9663 Expression e
= exp
.op_overload(sc
);
9672 assert(exp
.op
== EXP
.blit
);
9674 if (e2x
.checkValue())
9680 else if (t1
.ty
== Tclass
)
9682 // Disallow assignment operator overloads for same type
9683 if (exp
.op
== EXP
.assign
&& !exp
.e2
.implicitConvTo(exp
.e1
.type
))
9685 Expression e
= exp
.op_overload(sc
);
9692 if (exp
.e2
.checkValue())
9695 else if (t1
.ty
== Tsarray
)
9697 // SliceExp cannot have static array type without context inference.
9698 assert(exp
.e1
.op
!= EXP
.slice
);
9699 Expression e1x
= exp
.e1
;
9700 Expression e2x
= exp
.e2
;
9702 /* C strings come through as static arrays. May need to adjust the size of the
9703 * string to match the size of e1.
9705 Type t2
= e2x
.type
.toBasetype();
9706 if (sc
.flags
& SCOPE
.Cfile
&& e2x
.isStringExp() && t2
.isTypeSArray())
9708 uinteger_t dim1
= t1
.isTypeSArray().dim
.toInteger();
9709 uinteger_t dim2
= t2
.isTypeSArray().dim
.toInteger();
9710 if (dim1
+ 1 == dim2 || dim2
< dim1
)
9712 auto tsa2
= t2
.isTypeSArray();
9713 auto newt
= tsa2
.next
.sarrayOf(dim1
).immutableOf();
9714 e2x
= castTo(e2x
, sc
, newt
);
9719 if (e2x
.implicitConvTo(e1x
.type
))
9721 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()))
9723 if (e1x
.checkPostblit(sc
, t1
))
9727 // e2 matches to t1 because of the implicit length match, so
9728 if (isUnaArrayOp(e2x
.op
) ||
isBinArrayOp(e2x
.op
))
9730 // convert e1 to e1[]
9731 // e.g. e1[] = a[] + b[];
9732 auto sle
= new SliceExp(e1x
.loc
, e1x
, null, null);
9734 e1x
= sle
.expressionSemantic(sc
);
9738 // convert e2 to t1 later
9739 // e.g. e1 = [1, 2, 3];
9744 if (e2x
.implicitConvTo(t1
.nextOf().arrayOf()) > MATCH
.nomatch
)
9746 uinteger_t dim1
= (cast(TypeSArray
)t1
).dim
.toInteger();
9747 uinteger_t dim2
= dim1
;
9748 if (auto ale
= e2x
.isArrayLiteralExp())
9750 dim2
= ale
.elements ? ale
.elements
.length
: 0;
9752 else if (auto se
= e2x
.isSliceExp())
9754 Type tx
= toStaticArrayType(se
);
9756 dim2
= (cast(TypeSArray
)tx
).dim
.toInteger();
9760 exp
.error("mismatched array lengths, %d and %d", cast(int)dim1
, cast(int)dim2
);
9765 // May be block or element-wise assignment, so
9766 // convert e1 to e1[]
9767 if (exp
.op
!= EXP
.assign
)
9769 // If multidimensional static array, treat as one large array
9771 // Find the appropriate array type depending on the assignment, e.g.
9772 // int[3] = int => int[3]
9773 // int[3][2] = int => int[6]
9774 // int[3][2] = int[] => int[3][2]
9775 // int[3][2][4] + int => int[24]
9776 // int[3][2][4] + int[] => int[3][8]
9777 ulong dim
= t1
.isTypeSArray().dim
.toUInteger();
9778 auto type
= t1
.nextOf();
9780 for (TypeSArray tsa
; (tsa
= type
.isTypeSArray()) !is null; )
9782 import core
.checkedint
: mulu
;
9784 // Accumulate skipped dimensions
9785 bool overflow
= false;
9786 dim
= mulu(dim
, tsa
.dim
.toUInteger(), overflow
);
9787 if (overflow || dim
>= uint.max
)
9789 // dym exceeds maximum array size
9790 exp
.error("static array `%s` size overflowed to %llu",
9791 e1x
.type
.toChars(), cast(ulong) dim
);
9795 // Move to the element type
9796 type
= tsa
.nextOf().toBasetype();
9798 // Rewrite ex1 as a static array if a matching type was found
9799 if (e2x
.implicitConvTo(type
) > MATCH
.nomatch
)
9801 e1x
.type
= type
.sarrayOf(dim
);
9806 auto sle
= new SliceExp(e1x
.loc
, e1x
, null, null);
9808 e1x
= sle
.expressionSemantic(sc
);
9810 if (e1x
.op
== EXP
.error
)
9811 return setResult(e1x
);
9812 if (e2x
.op
== EXP
.error
)
9813 return setResult(e2x
);
9817 t1
= e1x
.type
.toBasetype();
9819 /* Check the mutability of e1.
9821 if (auto ale
= exp
.e1
.isArrayLengthExp())
9823 // e1 is not an lvalue, but we let code generator handle it
9825 auto ale1x
= ale
.e1
.modifiableLvalue(sc
, exp
.e1
);
9826 if (ale1x
.op
== EXP
.error
)
9827 return setResult(ale1x
);
9830 Type tn
= ale
.e1
.type
.toBasetype().nextOf();
9831 checkDefCtor(ale
.loc
, tn
);
9833 Identifier hook
= global
.params
.tracegc ? Id
._d_arraysetlengthTTrace
: Id
._d_arraysetlengthT
;
9834 if (!verifyHookExist(exp
.loc
, *sc
, Id
._d_arraysetlengthTImpl
, "resizing arrays"))
9837 exp
.e2
= exp
.e2
.expressionSemantic(sc
);
9838 auto lc
= lastComma(exp
.e2
);
9839 lc
= lc
.optimize(WANTvalue
);
9840 // use slice expression when arr.length = 0 to avoid runtime call
9841 if(lc
.op
== EXP
.int64
&& lc
.toInteger() == 0)
9843 Expression se
= new SliceExp(ale
.loc
, ale
.e1
, lc
, lc
);
9844 Expression as
= new AssignExp(ale
.loc
, ale
.e1
, se
);
9845 as
= as
.expressionSemantic(sc
);
9846 auto res
= Expression
.combine(as
, exp
.e2
);
9847 res
.type
= ale
.type
;
9848 return setResult(res
);
9851 if (!sc
.needsCodegen()) // if compile time creature only
9853 exp
.type
= Type
.tsize_t
;
9854 return setResult(exp
);
9857 // Lower to object._d_arraysetlengthTImpl!(typeof(e1))._d_arraysetlengthT{,Trace}(e1, e2)
9858 Expression id
= new IdentifierExp(ale
.loc
, Id
.empty
);
9859 id
= new DotIdExp(ale
.loc
, id
, Id
.object
);
9860 auto tiargs
= new Objects();
9861 tiargs
.push(ale
.e1
.type
);
9862 id
= new DotTemplateInstanceExp(ale
.loc
, id
, Id
._d_arraysetlengthTImpl
, tiargs
);
9863 id
= new DotIdExp(ale
.loc
, id
, hook
);
9864 id
= id
.expressionSemantic(sc
);
9866 auto arguments
= new Expressions();
9867 arguments
.reserve(5);
9868 if (global
.params
.tracegc
)
9870 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ? sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
9871 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
9872 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
9873 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
9875 arguments
.push(ale
.e1
);
9876 arguments
.push(exp
.e2
);
9878 Expression ce
= new CallExp(ale
.loc
, id
, arguments
).expressionSemantic(sc
);
9879 auto res
= new LoweredAssignExp(exp
, ce
);
9880 // if (global.params.verbose)
9881 // message("lowered %s =>\n %s", exp.toChars(), res.toChars());
9882 res
.type
= Type
.tsize_t
;
9883 return setResult(res
);
9885 else if (auto se
= exp
.e1
.isSliceExp())
9887 Type tn
= se
.type
.nextOf();
9888 const fun
= sc
.func
;
9889 if (exp
.op
== EXP
.assign
&& !tn
.isMutable() &&
9890 // allow modifiation in module ctor, see
9891 // https://issues.dlang.org/show_bug.cgi?id=9884
9892 (!fun ||
(fun
&& !fun
.isStaticCtorDeclaration())))
9894 exp
.error("slice `%s` is not mutable", se
.toChars());
9898 if (exp
.op
== EXP
.assign
&& !tn
.baseElemOf().isAssignable())
9900 exp
.error("slice `%s` is not mutable, struct `%s` has immutable members",
9901 exp
.e1
.toChars(), tn
.baseElemOf().toChars());
9902 result
= ErrorExp
.get();
9906 // For conditional operator, both branches need conversion.
9907 while (se
.e1
.op
== EXP
.slice
)
9908 se
= cast(SliceExp
)se
.e1
;
9909 if (se
.e1
.op
== EXP
.question
&& se
.e1
.type
.toBasetype().ty
== Tsarray
)
9911 se
.e1
= se
.e1
.modifiableLvalue(sc
, exp
.e1
);
9912 if (se
.e1
.op
== EXP
.error
)
9913 return setResult(se
.e1
);
9918 if (t1
.ty
== Tsarray
&& exp
.op
== EXP
.assign
)
9920 Type tn
= exp
.e1
.type
.nextOf();
9921 if (tn
&& !tn
.baseElemOf().isAssignable())
9923 exp
.error("array `%s` is not mutable, struct `%s` has immutable members",
9924 exp
.e1
.toChars(), tn
.baseElemOf().toChars());
9925 result
= ErrorExp
.get();
9930 Expression e1x
= exp
.e1
;
9932 // Try to do a decent error message with the expression
9933 // before it gets constant folded
9934 if (exp
.op
== EXP
.assign
)
9935 e1x
= e1x
.modifiableLvalue(sc
, e1old
);
9937 e1x
= e1x
.optimize(WANTvalue
, /*keepLvalue*/ true);
9939 if (e1x
.op
== EXP
.error
)
9947 /* Tweak e2 based on the type of e1.
9949 Expression e2x
= exp
.e2
;
9950 Type t2
= e2x
.type
.toBasetype();
9952 // If it is a array, get the element type. Note that it may be
9953 // multi-dimensional.
9955 while (telem
.ty
== Tarray
)
9956 telem
= telem
.nextOf();
9958 if (exp
.e1
.op
== EXP
.slice
&& t1
.nextOf() &&
9959 (telem
.ty
!= Tvoid || e2x
.op
== EXP
.null_
) &&
9960 e2x
.implicitConvTo(t1
.nextOf()))
9962 // Check for block assignment. If it is of type void[], void[][], etc,
9963 // '= null' is the only allowable block assignment (Bug 7493)
9964 exp
.memset
= MemorySet
.blockAssign
; // make it easy for back end to tell what this is
9965 e2x
= e2x
.implicitCastTo(sc
, t1
.nextOf());
9966 if (exp
.op
!= EXP
.blit
&& e2x
.isLvalue() && exp
.e1
.checkPostblit(sc
, t1
.nextOf()))
9969 else if (exp
.e1
.op
== EXP
.slice
&&
9970 (t2
.ty
== Tarray || t2
.ty
== Tsarray
) &&
9971 t2
.nextOf().implicitConvTo(t1
.nextOf()))
9973 // Check element-wise assignment.
9975 /* If assigned elements number is known at compile time,
9976 * check the mismatch.
9978 SliceExp se1
= cast(SliceExp
)exp
.e1
;
9979 TypeSArray tsa1
= cast(TypeSArray
)toStaticArrayType(se1
);
9980 TypeSArray tsa2
= null;
9981 if (auto ale
= e2x
.isArrayLiteralExp())
9982 tsa2
= cast(TypeSArray
)t2
.nextOf().sarrayOf(ale
.elements
.length
);
9983 else if (auto se
= e2x
.isSliceExp())
9984 tsa2
= cast(TypeSArray
)toStaticArrayType(se
);
9986 tsa2
= t2
.isTypeSArray();
9990 uinteger_t dim1
= tsa1
.dim
.toInteger();
9991 uinteger_t dim2
= tsa2
.dim
.toInteger();
9994 exp
.error("mismatched array lengths %d and %d for assignment `%s`", cast(int)dim1
, cast(int)dim2
, exp
.toChars());
9999 if (exp
.op
!= EXP
.blit
&&
10000 (e2x
.op
== EXP
.slice
&& (cast(UnaExp
)e2x
).e1
.isLvalue() ||
10001 e2x
.op
== EXP
.cast_
&& (cast(UnaExp
)e2x
).e1
.isLvalue() ||
10002 e2x
.op
!= EXP
.slice
&& e2x
.isLvalue()))
10004 if (exp
.e1
.checkPostblit(sc
, t1
.nextOf()))
10008 if (0 && global
.params
.warnings
!= DiagnosticReporting
.off
&& !global
.gag
&& exp
.op
== EXP
.assign
&&
10009 e2x
.op
!= EXP
.slice
&& e2x
.op
!= EXP
.assign
&&
10010 e2x
.op
!= EXP
.arrayLiteral
&& e2x
.op
!= EXP
.string_
&&
10011 !(e2x
.op
== EXP
.add || e2x
.op
== EXP
.min ||
10012 e2x
.op
== EXP
.mul || e2x
.op
== EXP
.div ||
10013 e2x
.op
== EXP
.mod || e2x
.op
== EXP
.xor ||
10014 e2x
.op
== EXP
.and || e2x
.op
== EXP
.or ||
10015 e2x
.op
== EXP
.pow ||
10016 e2x
.op
== EXP
.tilde || e2x
.op
== EXP
.negate
))
10018 const(char)* e1str
= exp
.e1
.toChars();
10019 const(char)* e2str
= e2x
.toChars();
10020 exp
.warning("explicit element-wise assignment `%s = (%s)[]` is better than `%s = %s`", e1str
, e2str
, e1str
, e2str
);
10023 Type t2n
= t2
.nextOf();
10024 Type t1n
= t1
.nextOf();
10026 if (t2n
.equivalent(t1n
) ||
10027 t1n
.isBaseOf(t2n
, &offset
) && offset
== 0)
10029 /* Allow copy of distinct qualifier elements.
10031 * char[] dst; const(char)[] src;
10034 * class C {} class D : C {}
10038 if (isArrayOpValid(e2x
))
10040 // Don't add CastExp to keep AST for array operations
10042 e2x
.type
= exp
.e1
.type
.constOf();
10045 e2x
= e2x
.castTo(sc
, exp
.e1
.type
.constOf());
10049 /* https://issues.dlang.org/show_bug.cgi?id=15778
10050 * A string literal has an array type of immutable
10051 * elements by default, and normally it cannot be convertible to
10052 * array type of mutable elements. But for element-wise assignment,
10053 * elements need to be const at best. So we should give a chance
10054 * to change code unit size for polysemous string literal.
10056 if (e2x
.op
== EXP
.string_
)
10057 e2x
= e2x
.implicitCastTo(sc
, exp
.e1
.type
.constOf());
10059 e2x
= e2x
.implicitCastTo(sc
, exp
.e1
.type
);
10061 if (t1n
.toBasetype
.ty
== Tvoid
&& t2n
.toBasetype
.ty
== Tvoid
)
10063 if (sc
.setUnsafe(false, exp
.loc
, "cannot copy `void[]` to `void[]` in `@safe` code"))
10069 if (0 && global
.params
.warnings
!= DiagnosticReporting
.off
&& !global
.gag
&& exp
.op
== EXP
.assign
&&
10070 t1
.ty
== Tarray
&& t2
.ty
== Tsarray
&&
10071 e2x
.op
!= EXP
.slice
&&
10072 t2
.implicitConvTo(t1
))
10074 // Disallow ar[] = sa (Converted to ar[] = sa[])
10075 // Disallow da = sa (Converted to da = sa[])
10076 const(char)* e1str
= exp
.e1
.toChars();
10077 const(char)* e2str
= e2x
.toChars();
10078 const(char)* atypestr
= exp
.e1
.op
== EXP
.slice ?
"element-wise" : "slice";
10079 exp
.warning("explicit %s assignment `%s = (%s)[]` is better than `%s = %s`", atypestr
, e1str
, e2str
, e1str
, e2str
);
10081 if (exp
.op
== EXP
.blit
)
10082 e2x
= e2x
.castTo(sc
, exp
.e1
.type
);
10085 e2x
= e2x
.implicitCastTo(sc
, exp
.e1
.type
);
10087 // Fix Issue 13435: https://issues.dlang.org/show_bug.cgi?id=13435
10089 // If the implicit cast has failed and the assign expression is
10090 // the initialization of a struct member field
10091 if (e2x
.op
== EXP
.error
&& exp
.op
== EXP
.construct
&& t1
.ty
== Tstruct
)
10093 scope sd
= (cast(TypeStruct
)t1
).sym
;
10094 Dsymbol opAssign
= search_function(sd
, Id
.assign
);
10096 // and the struct defines an opAssign
10099 // offer more information about the cause of the problem
10100 errorSupplemental(exp
.loc
,
10101 "`%s` is the first assignment of `%s` therefore it represents its initialization",
10102 exp
.toChars(), exp
.e1
.toChars());
10103 errorSupplemental(exp
.loc
,
10104 "`opAssign` methods are not used for initialization, but for subsequent assignments");
10109 if (e2x
.op
== EXP
.error
)
10115 t2
= exp
.e2
.type
.toBasetype();
10117 /* Look for array operations
10119 if ((t2
.ty
== Tarray || t2
.ty
== Tsarray
) && isArrayOpValid(exp
.e2
))
10121 // Look for valid array operations
10122 if (exp
.memset
!= MemorySet
.blockAssign
&&
10123 exp
.e1
.op
== EXP
.slice
&&
10124 (isUnaArrayOp(exp
.e2
.op
) ||
isBinArrayOp(exp
.e2
.op
)))
10126 exp
.type
= exp
.e1
.type
;
10127 if (exp
.op
== EXP
.construct
) // https://issues.dlang.org/show_bug.cgi?id=10282
10128 // tweak mutability of e1 element
10129 exp
.e1
.type
= exp
.e1
.type
.nextOf().mutableOf().arrayOf();
10130 result
= arrayOp(exp
, sc
);
10134 // Drop invalid array operations in e2
10135 // d = a[] + b[], d = (a[] + b[])[0..2], etc
10136 if (checkNonAssignmentArrayOp(exp
.e2
, exp
.memset
!= MemorySet
.blockAssign
&& exp
.op
== EXP
.assign
))
10139 // Remains valid array assignments
10140 // d = d[], d = [1,2,3], etc
10143 /* Don't allow assignment to classes that were allocated on the stack with:
10144 * scope Class c = new Class();
10146 if (exp
.e1
.op
== EXP
.variable
&& exp
.op
== EXP
.assign
)
10148 VarExp ve
= cast(VarExp
)exp
.e1
;
10149 VarDeclaration vd
= ve
.var
.isVarDeclaration();
10150 if (vd
&& vd
.onstack
)
10152 assert(t1
.ty
== Tclass
);
10153 exp
.error("cannot rebind scope variables");
10157 if (exp
.e1
.op
== EXP
.variable
&& (cast(VarExp
)exp
.e1
).var
.ident
== Id
.ctfe
)
10159 exp
.error("cannot modify compiler-generated variable `__ctfe`");
10162 exp
.type
= exp
.e1
.type
;
10164 auto assignElem
= exp
.e2
;
10165 auto res
= exp
.op
== EXP
.assign ? exp
.reorderSettingAAElem(sc
) : exp
;
10166 /* https://issues.dlang.org/show_bug.cgi?id=22366
10168 * `reorderSettingAAElem` creates a tree of comma expressions, however,
10169 * `checkAssignExp` expects only AssignExps.
10171 if (res
== exp
) // no `AA[k] = v` rewrite was performed
10172 checkAssignEscape(sc
, res
, false, false);
10174 checkNewEscape(sc
, assignElem
, false); // assigning to AA puts it on heap
10176 if (auto ae
= res
.isConstructExp())
10178 Type t1b
= ae
.e1
.type
.toBasetype();
10179 if (t1b
.ty
!= Tsarray
&& t1b
.ty
!= Tarray
)
10180 return setResult(res
);
10182 // only non-trivial array constructions may need to be lowered (non-POD elements basically)
10183 Type t1e
= t1b
.nextOf();
10184 TypeStruct ts
= t1e
.baseElemOf().isTypeStruct();
10185 if (!ts ||
(!ts
.sym
.postblit
&& !ts
.sym
.hasCopyCtor
&& !ts
.sym
.dtor
))
10186 return setResult(res
);
10188 // don't lower ref-constructions etc.
10189 if (!(t1b
.ty
== Tsarray || ae
.e1
.isSliceExp
) ||
10190 (ae
.e1
.isVarExp
&& ae
.e1
.isVarExp
.var
.isVarDeclaration
.isReference
))
10191 return setResult(res
);
10193 // Construction from an equivalent other array?
10194 // Only lower with lvalue RHS elements; let the glue layer move rvalue elements.
10195 Type t2b
= ae
.e2
.type
.toBasetype();
10196 // skip over a (possibly implicit) cast of a static array RHS to a slice
10197 Expression rhs
= ae
.e2
;
10198 Type rhsType
= t2b
;
10199 if (t2b
.ty
== Tarray
)
10201 if (auto ce
= rhs
.isCastExp())
10203 auto ct
= ce
.e1
.type
.toBasetype();
10204 if (ct
.ty
== Tsarray
)
10212 if (!sc
.needsCodegen()) // interpreter can handle these
10213 return setResult(res
);
10215 const lowerToArrayCtor
=
10216 ( (rhsType
.ty
== Tarray
&& !rhs
.isArrayLiteralExp
) ||
10217 (rhsType
.ty
== Tsarray
&& rhs
.isLvalue
) ) &&
10218 t1e
.equivalent(t2b
.nextOf
);
10220 // Construction from a single element?
10221 // If the RHS is an rvalue, then we'll need to make a temporary for it (copied multiple times).
10222 const lowerToArraySetCtor
= !lowerToArrayCtor
&& t1e
.equivalent(t2b
);
10224 if (lowerToArrayCtor || lowerToArraySetCtor
)
10226 auto func
= lowerToArrayCtor ? Id
._d_arrayctor
: Id
._d_arraysetctor
;
10227 const other
= lowerToArrayCtor ?
"other array" : "value";
10228 if (!verifyHookExist(exp
.loc
, *sc
, func
, "construct array with " ~ other
, Id
.object
))
10231 // Lower to object._d_array{,set}ctor(e1, e2)
10232 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
10233 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
10234 id
= new DotIdExp(exp
.loc
, id
, func
);
10236 auto arguments
= new Expressions();
10237 arguments
.push(new CastExp(ae
.loc
, ae
.e1
, t1e
.arrayOf
).expressionSemantic(sc
));
10238 if (lowerToArrayCtor
)
10240 arguments
.push(new CastExp(ae
.loc
, rhs
, t2b
.nextOf
.arrayOf
).expressionSemantic(sc
));
10241 Expression ce
= new CallExp(exp
.loc
, id
, arguments
);
10242 res
= ce
.expressionSemantic(sc
);
10247 // promote an rvalue RHS element to a temporary, it's passed by ref to _d_arraysetctor
10248 if (!ae
.e2
.isLvalue
)
10250 auto vd
= copyToTemp(STC
.scope_
, "__setctor", ae
.e2
);
10251 e0
= new DeclarationExp(vd
.loc
, vd
).expressionSemantic(sc
);
10252 arguments
.push(new VarExp(vd
.loc
, vd
).expressionSemantic(sc
));
10255 arguments
.push(ae
.e2
);
10257 Expression ce
= new CallExp(exp
.loc
, id
, arguments
);
10258 res
= Expression
.combine(e0
, ce
).expressionSemantic(sc
);
10261 if (global
.params
.verbose
)
10262 message("lowered %s =>\n %s", exp
.toChars(), res
.toChars());
10265 else if (auto ae
= res
.isAssignExp())
10266 res
= lowerArrayAssign(ae
);
10267 else if (auto ce
= res
.isCommaExp())
10269 if (auto ae1
= ce
.e1
.isAssignExp())
10270 ce
.e1
= lowerArrayAssign(ae1
, true);
10271 if (auto ae2
= ce
.e2
.isAssignExp())
10272 ce
.e2
= lowerArrayAssign(ae2
, true);
10275 return setResult(res
);
10278 /***************************************
10279 * Lower AssignExp to `_d_array{setassign,assign_l,assign_r}` if needed.
10282 * ae = the AssignExp to be lowered
10283 * fromCommaExp = indicates whether `ae` is part of a CommaExp or not,
10284 * so no unnecessary temporay variable is created.
10286 * a CommaExp contiaining call a to `_d_array{setassign,assign_l,assign_r}`
10287 * if needed or `ae` otherwise
10289 private Expression
lowerArrayAssign(AssignExp ae
, bool fromCommaExp
= false)
10291 Type t1b
= ae
.e1
.type
.toBasetype();
10292 if (t1b
.ty
!= Tsarray
&& t1b
.ty
!= Tarray
)
10295 const isArrayAssign
= (ae
.e1
.isSliceExp() || ae
.e1
.type
.ty
== Tsarray
) &&
10296 (ae
.e2
.type
.ty
== Tsarray || ae
.e2
.type
.ty
== Tarray
) &&
10297 (ae
.e1
.type
.nextOf() && ae
.e2
.type
.nextOf() && ae
.e1
.type
.nextOf
.mutableOf
.equals(ae
.e2
.type
.nextOf
.mutableOf()));
10299 const isArraySetAssign
= (ae
.e1
.isSliceExp() || ae
.e1
.type
.ty
== Tsarray
) &&
10300 (ae
.e1
.type
.nextOf() && ae
.e2
.type
.implicitConvTo(ae
.e1
.type
.nextOf()));
10302 if (!isArrayAssign
&& !isArraySetAssign
)
10305 const ts
= t1b
.nextOf().baseElemOf().isTypeStruct();
10306 if (!ts ||
(!ts
.sym
.postblit
&& !ts
.sym
.dtor
))
10310 Identifier func
= isArraySetAssign ? Id
._d_arraysetassign
:
10311 ae
.e2
.isLvalue() || ae
.e2
.isSliceExp() ? Id
._d_arrayassign_l
: Id
._d_arrayassign_r
;
10313 // Lower to `.object._d_array{setassign,assign_l,assign_r}(e1, e2)``
10314 Expression id
= new IdentifierExp(ae
.loc
, Id
.empty
);
10315 id
= new DotIdExp(ae
.loc
, id
, Id
.object
);
10316 id
= new DotIdExp(ae
.loc
, id
, func
);
10318 auto arguments
= new Expressions();
10319 arguments
.push(new CastExp(ae
.loc
, ae
.e1
, ae
.e1
.type
.nextOf
.arrayOf
)
10320 .expressionSemantic(sc
));
10322 Expression eValue2
, value2
= ae
.e2
;
10323 if (isArrayAssign
&& value2
.isLvalue())
10324 value2
= new CastExp(ae
.loc
, ae
.e2
, ae
.e2
.type
.nextOf
.arrayOf())
10325 .expressionSemantic(sc
);
10326 else if (!fromCommaExp
&&
10327 (isArrayAssign ||
(isArraySetAssign
&& !value2
.isLvalue())))
10329 // Rvalues from CommaExps were introduced in `visit(AssignExp)`
10330 // and are temporary variables themselves. Rvalues from trivial
10331 // SliceExps are simply passed by reference without any copying.
10333 // `__assigntmp` will be destroyed together with the array `ae.e1`.
10334 // When `ae.e2` is a variadic arg array, it is also `scope`, so
10335 // `__assigntmp` may also be scope.
10336 StorageClass
stc = STC
.nodtor
;
10338 stc |
= STC
.rvalue | STC
.scope_
;
10340 auto vd
= copyToTemp(stc, "__assigntmp", ae
.e2
);
10341 eValue2
= new DeclarationExp(vd
.loc
, vd
).expressionSemantic(sc
);
10342 value2
= new VarExp(vd
.loc
, vd
).expressionSemantic(sc
);
10344 arguments
.push(value2
);
10346 Expression ce
= new CallExp(ae
.loc
, id
, arguments
);
10347 res
= Expression
.combine(eValue2
, ce
).expressionSemantic(sc
);
10349 res
= Expression
.combine(res
, ae
.e1
).expressionSemantic(sc
);
10351 if (global
.params
.verbose
)
10352 message("lowered %s =>\n %s", ae
.toChars(), res
.toChars());
10354 res
= new LoweredAssignExp(ae
, res
);
10355 res
.type
= ae
.type
;
10360 override void visit(PowAssignExp exp
)
10368 Expression e
= exp
.op_overload(sc
);
10375 if (exp
.e1
.checkReadModifyWrite(exp
.op
, exp
.e2
))
10378 assert(exp
.e1
.type
&& exp
.e2
.type
);
10379 if (exp
.e1
.op
== EXP
.slice || exp
.e1
.type
.ty
== Tarray || exp
.e1
.type
.ty
== Tsarray
)
10381 if (checkNonAssignmentArrayOp(exp
.e1
))
10385 if (exp
.e2
.implicitConvTo(exp
.e1
.type
.nextOf()))
10388 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
.nextOf());
10390 else if (Expression ex
= typeCombine(exp
, sc
))
10396 // Check element types are arithmetic
10397 Type tb1
= exp
.e1
.type
.nextOf().toBasetype();
10398 Type tb2
= exp
.e2
.type
.toBasetype();
10399 if (tb2
.ty
== Tarray || tb2
.ty
== Tsarray
)
10400 tb2
= tb2
.nextOf().toBasetype();
10401 if ((tb1
.isintegral() || tb1
.isfloating()) && (tb2
.isintegral() || tb2
.isfloating()))
10403 exp
.type
= exp
.e1
.type
;
10404 result
= arrayOp(exp
, sc
);
10410 exp
.e1
= exp
.e1
.modifiableLvalue(sc
, exp
.e1
);
10413 if ((exp
.e1
.type
.isintegral() || exp
.e1
.type
.isfloating()) && (exp
.e2
.type
.isintegral() || exp
.e2
.type
.isfloating()))
10415 Expression e0
= null;
10416 e
= exp
.reorderSettingAAElem(sc
);
10417 e
= Expression
.extractLast(e
, e0
);
10420 if (exp
.e1
.op
== EXP
.variable
)
10422 // Rewrite: e1 = e1 ^^ e2
10423 e
= new PowExp(exp
.loc
, exp
.e1
.syntaxCopy(), exp
.e2
);
10424 e
= new AssignExp(exp
.loc
, exp
.e1
, e
);
10428 // Rewrite: ref tmp = e1; tmp = tmp ^^ e2
10429 auto v
= copyToTemp(STC
.ref_
, "__powtmp", exp
.e1
);
10430 auto de = new DeclarationExp(exp
.e1
.loc
, v
);
10431 auto ve
= new VarExp(exp
.e1
.loc
, v
);
10432 e
= new PowExp(exp
.loc
, ve
, exp
.e2
);
10433 e
= new AssignExp(exp
.loc
, new VarExp(exp
.e1
.loc
, v
), e
);
10434 e
= new CommaExp(exp
.loc
, de, e
);
10436 e
= Expression
.combine(e0
, e
);
10437 e
= e
.expressionSemantic(sc
);
10441 result
= exp
.incompatibleTypes();
10444 override void visit(CatAssignExp exp
)
10452 //printf("CatAssignExp::semantic() %s\n", exp.toChars());
10453 Expression e
= exp
.op_overload(sc
);
10460 if (SliceExp se
= exp
.e1
.isSliceExp())
10462 if (se
.e1
.type
.toBasetype().ty
== Tsarray
)
10464 exp
.error("cannot append to static array `%s`", se
.e1
.type
.toChars());
10469 exp
.e1
= exp
.e1
.modifiableLvalue(sc
, exp
.e1
);
10470 if (exp
.e1
.op
== EXP
.error
)
10475 if (exp
.e2
.op
== EXP
.error
)
10481 if (checkNonAssignmentArrayOp(exp
.e2
))
10484 Type tb1
= exp
.e1
.type
.toBasetype();
10485 Type tb1next
= tb1
.nextOf();
10486 Type tb2
= exp
.e2
.type
.toBasetype();
10489 * EXP.concatenateAssign: appending T[] to T[]
10490 * EXP.concatenateElemAssign: appending T to T[]
10491 * EXP.concatenateDcharAssign: appending dchar to T[]
10493 if ((tb1
.ty
== Tarray
) &&
10494 (tb2
.ty
== Tarray || tb2
.ty
== Tsarray
) &&
10495 (exp
.e2
.implicitConvTo(exp
.e1
.type
) ||
10496 (tb2
.nextOf().implicitConvTo(tb1next
) &&
10497 (tb2
.nextOf().size(Loc
.initial
) == tb1next
.size(Loc
.initial
)))))
10499 // EXP.concatenateAssign
10500 assert(exp
.op
== EXP
.concatenateAssign
);
10501 if (exp
.e1
.checkPostblit(sc
, tb1next
))
10504 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
);
10506 else if ((tb1
.ty
== Tarray
) && exp
.e2
.implicitConvTo(tb1next
))
10508 /* https://issues.dlang.org/show_bug.cgi?id=19782
10510 * If e2 is implicitly convertible to tb1next, the conversion
10511 * might be done through alias this, in which case, e2 needs to
10512 * be modified accordingly (e2 => e2.aliasthis).
10514 if (tb2
.ty
== Tstruct
&& (cast(TypeStruct
)tb2
).implicitConvToThroughAliasThis(tb1next
))
10516 if (tb2
.ty
== Tclass
&& (cast(TypeClass
)tb2
).implicitConvToThroughAliasThis(tb1next
))
10519 if (exp
.e2
.checkPostblit(sc
, tb2
))
10522 if (checkNewEscape(sc
, exp
.e2
, false))
10525 exp
= new CatElemAssignExp(exp
.loc
, exp
.type
, exp
.e1
, exp
.e2
.castTo(sc
, tb1next
));
10526 exp
.e2
= doCopyOrMove(sc
, exp
.e2
);
10528 else if (tb1
.ty
== Tarray
&&
10529 (tb1next
.ty
== Tchar || tb1next
.ty
== Twchar
) &&
10530 exp
.e2
.type
.ty
!= tb1next
.ty
&&
10531 exp
.e2
.implicitConvTo(Type
.tdchar
))
10533 // Append dchar to char[] or wchar[]
10534 exp
= new CatDcharAssignExp(exp
.loc
, exp
.type
, exp
.e1
, exp
.e2
.castTo(sc
, Type
.tdchar
));
10536 /* Do not allow appending wchar to char[] because if wchar happens
10537 * to be a surrogate pair, nothing good can result.
10542 // Try alias this on first operand
10543 static Expression
tryAliasThisForLhs(BinAssignExp exp
, Scope
* sc
)
10545 AggregateDeclaration ad1
= isAggregate(exp
.e1
.type
);
10546 if (!ad1 ||
!ad1
.aliasthis
)
10549 /* Rewrite (e1 op e2) as:
10550 * (e1.aliasthis op e2)
10552 if (isRecursiveAliasThis(exp
.att1
, exp
.e1
.type
))
10554 //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
10555 Expression e1
= new DotIdExp(exp
.loc
, exp
.e1
, ad1
.aliasthis
.ident
);
10556 BinExp be
= cast(BinExp
)exp
.copy();
10558 return be
.trySemantic(sc
);
10561 // Try alias this on second operand
10562 static Expression
tryAliasThisForRhs(BinAssignExp exp
, Scope
* sc
)
10564 AggregateDeclaration ad2
= isAggregate(exp
.e2
.type
);
10565 if (!ad2 ||
!ad2
.aliasthis
)
10567 /* Rewrite (e1 op e2) as:
10568 * (e1 op e2.aliasthis)
10570 if (isRecursiveAliasThis(exp
.att2
, exp
.e2
.type
))
10572 //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
10573 Expression e2
= new DotIdExp(exp
.loc
, exp
.e2
, ad2
.aliasthis
.ident
);
10574 BinExp be
= cast(BinExp
)exp
.copy();
10576 return be
.trySemantic(sc
);
10580 result
= tryAliasThisForLhs(exp
, sc
);
10584 result
= tryAliasThisForRhs(exp
, sc
);
10588 exp
.error("cannot append type `%s` to type `%s`", tb2
.toChars(), tb1
.toChars());
10592 if (exp
.e2
.checkValue() || exp
.e2
.checkSharedAccess(sc
))
10595 exp
.type
= exp
.e1
.type
;
10596 auto assignElem
= exp
.e2
;
10597 auto res
= exp
.reorderSettingAAElem(sc
);
10598 if (res
!= exp
) // `AA[k] = v` rewrite was performed
10599 checkNewEscape(sc
, assignElem
, false);
10600 else if (exp
.op
== EXP
.concatenateElemAssign || exp
.op
== EXP
.concatenateDcharAssign
)
10601 checkAssignEscape(sc
, res
, false, false);
10605 if ((exp
.op
== EXP
.concatenateAssign || exp
.op
== EXP
.concatenateElemAssign
) &&
10608 // if aa ordering is triggered, `res` will be a CommaExp
10609 // and `.e2` will be the rewritten original expression.
10611 // `output` will point to the expression that the lowering will overwrite
10612 Expression
* output
;
10613 if (auto comma
= res
.isCommaExp())
10615 output
= &comma
.e2
;
10616 // manual cast because it could be either CatAssignExp or CatElemAssignExp
10617 exp
= cast(CatAssignExp
)comma
.e2
;
10622 exp
= cast(CatAssignExp
)result
;
10625 if (exp
.op
== EXP
.concatenateAssign
)
10627 Identifier hook
= global
.params
.tracegc ? Id
._d_arrayappendTTrace
: Id
._d_arrayappendT
;
10629 if (!verifyHookExist(exp
.loc
, *sc
, hook
, "appending array to arrays", Id
.object
))
10632 // Lower to object._d_arrayappendT{,Trace}({file, line, funcname}, e1, e2)
10633 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
10634 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
10635 id
= new DotIdExp(exp
.loc
, id
, hook
);
10637 auto arguments
= new Expressions();
10638 arguments
.reserve(5);
10639 if (global
.params
.tracegc
)
10641 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ? sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
10642 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
10643 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
10644 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
10647 arguments
.push(exp
.e1
);
10648 arguments
.push(exp
.e2
);
10649 Expression ce
= new CallExp(exp
.loc
, id
, arguments
);
10650 *output
= ce
.expressionSemantic(sc
);
10652 else if (exp
.op
== EXP
.concatenateElemAssign
)
10654 /* Do not lower concats to the indices array returned by
10655 *`static foreach`, as this array is only used at compile-time.
10657 if (auto ve
= exp
.e1
.isVarExp
)
10659 import core
.stdc
.ctype
: isdigit
;
10660 // The name of the indices array that static foreach loops uses.
10661 // See dmd.cond.lowerNonArrayAggregate
10662 enum varName
= "__res";
10663 const(char)[] id
= ve
.var
.ident
.toString
;
10664 if (ve
.var
.storage_class
& STC
.temp
&& id
.length
> varName
.length
&&
10665 id
[0 .. varName
.length
] == varName
&& id
[varName
.length
].isdigit
)
10669 Identifier hook
= global
.params
.tracegc ? Id
._d_arrayappendcTXTrace
: Id
._d_arrayappendcTX
;
10670 if (!verifyHookExist(exp
.loc
, *sc
, Id
._d_arrayappendcTXImpl
, "appending element to arrays", Id
.object
))
10673 // Lower to object._d_arrayappendcTXImpl!(typeof(e1))._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2
10674 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
10675 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
10676 auto tiargs
= new Objects();
10677 tiargs
.push(exp
.e1
.type
);
10678 id
= new DotTemplateInstanceExp(exp
.loc
, id
, Id
._d_arrayappendcTXImpl
, tiargs
);
10679 id
= new DotIdExp(exp
.loc
, id
, hook
);
10681 auto arguments
= new Expressions();
10682 arguments
.reserve(5);
10683 if (global
.params
.tracegc
)
10685 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ? sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
10686 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
10687 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
10688 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
10691 Expression eValue1
;
10692 Expression value1
= extractSideEffect(sc
, "__appendtmp", eValue1
, exp
.e1
);
10694 arguments
.push(value1
);
10695 arguments
.push(new IntegerExp(exp
.loc
, 1, Type
.tsize_t
));
10697 Expression ce
= new CallExp(exp
.loc
, id
, arguments
);
10699 Expression eValue2
;
10700 Expression value2
= exp
.e2
;
10701 if (!value2
.isVarExp() && !value2
.isConst())
10703 /* Before the template hook, this check was performed in e2ir.d
10704 * for expressions like `a ~= a[$-1]`. Here, $ will be modified
10705 * by calling `_d_arrayappendcT`, so we need to save `a[$-1]` in
10706 * a temporary variable.
10708 value2
= extractSideEffect(sc
, "__appendtmp", eValue2
, value2
, true);
10711 // `__appendtmp*` will be destroyed together with the array `exp.e1`.
10712 auto vd
= eValue2
.isDeclarationExp().declaration
.isVarDeclaration();
10713 vd
.storage_class |
= STC
.nodtor
;
10714 // Be more explicit that this "declaration" is local to the expression
10715 vd
.storage_class |
= STC
.exptemp
;
10718 auto ale
= new ArrayLengthExp(exp
.loc
, value1
);
10719 auto elem
= new IndexExp(exp
.loc
, value1
, new MinExp(exp
.loc
, ale
, IntegerExp
.literal
!1));
10720 auto ae
= new ConstructExp(exp
.loc
, elem
, value2
);
10722 auto e0
= Expression
.combine(ce
, ae
).expressionSemantic(sc
);
10723 e0
= Expression
.combine(e0
, value1
);
10724 e0
= Expression
.combine(eValue1
, e0
);
10726 e0
= Expression
.combine(eValue2
, e0
);
10728 *output
= e0
.expressionSemantic(sc
);
10734 override void visit(AddExp exp
)
10736 static if (LOGSEMANTIC
)
10738 printf("AddExp::semantic('%s')\n", exp
.toChars());
10746 if (Expression ex
= binSemanticProp(exp
, sc
))
10751 Expression e
= exp
.op_overload(sc
);
10758 /* ImportC: convert arrays to pointers, functions to pointers to functions
10760 exp
.e1
= exp
.e1
.arrayFuncConv(sc
);
10761 exp
.e2
= exp
.e2
.arrayFuncConv(sc
);
10763 Type tb1
= exp
.e1
.type
.toBasetype();
10764 Type tb2
= exp
.e2
.type
.toBasetype();
10767 if (tb1
.ty
== Tdelegate || tb1
.isPtrToFunction())
10769 err |
= exp
.e1
.checkArithmetic() || exp
.e1
.checkSharedAccess(sc
);
10771 if (tb2
.ty
== Tdelegate || tb2
.isPtrToFunction())
10773 err |
= exp
.e2
.checkArithmetic() || exp
.e2
.checkSharedAccess(sc
);
10778 if (tb1
.ty
== Tpointer
&& exp
.e2
.type
.isintegral() || tb2
.ty
== Tpointer
&& exp
.e1
.type
.isintegral())
10780 result
= scaleFactor(exp
, sc
);
10784 if (tb1
.ty
== Tpointer
&& tb2
.ty
== Tpointer
)
10786 result
= exp
.incompatibleTypes();
10790 if (Expression ex
= typeCombine(exp
, sc
))
10796 Type tb
= exp
.type
.toBasetype();
10797 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
10799 if (!isArrayOpValid(exp
))
10801 result
= arrayOpInvalidError(exp
);
10808 tb1
= exp
.e1
.type
.toBasetype();
10809 if (!target
.isVectorOpSupported(tb1
, exp
.op
, tb2
))
10811 result
= exp
.incompatibleTypes();
10814 if ((tb1
.isreal() && exp
.e2
.type
.isimaginary()) ||
(tb1
.isimaginary() && exp
.e2
.type
.isreal()))
10816 switch (exp
.type
.toBasetype().ty
)
10820 exp
.type
= Type
.tcomplex32
;
10825 exp
.type
= Type
.tcomplex64
;
10830 exp
.type
= Type
.tcomplex80
;
10840 override void visit(MinExp exp
)
10842 static if (LOGSEMANTIC
)
10844 printf("MinExp::semantic('%s')\n", exp
.toChars());
10852 if (Expression ex
= binSemanticProp(exp
, sc
))
10857 Expression e
= exp
.op_overload(sc
);
10864 /* ImportC: convert arrays to pointers, functions to pointers to functions
10866 exp
.e1
= exp
.e1
.arrayFuncConv(sc
);
10867 exp
.e2
= exp
.e2
.arrayFuncConv(sc
);
10869 Type t1
= exp
.e1
.type
.toBasetype();
10870 Type t2
= exp
.e2
.type
.toBasetype();
10873 if (t1
.ty
== Tdelegate || t1
.isPtrToFunction())
10875 err |
= exp
.e1
.checkArithmetic() || exp
.e1
.checkSharedAccess(sc
);
10877 if (t2
.ty
== Tdelegate || t2
.isPtrToFunction())
10879 err |
= exp
.e2
.checkArithmetic() || exp
.e2
.checkSharedAccess(sc
);
10884 if (t1
.ty
== Tpointer
)
10886 if (t2
.ty
== Tpointer
)
10888 // https://dlang.org/spec/expression.html#add_expressions
10889 // "If both operands are pointers, and the operator is -, the pointers are
10890 // subtracted and the result is divided by the size of the type pointed to
10891 // by the operands. It is an error if the pointers point to different types."
10892 Type p1
= t1
.nextOf();
10893 Type p2
= t2
.nextOf();
10895 if (!p1
.equivalent(p2
))
10897 // Deprecation to remain for at least a year, after which this should be
10898 // changed to an error
10899 // See https://github.com/dlang/dmd/pull/7332
10900 deprecation(exp
.loc
,
10901 "cannot subtract pointers to different types: `%s` and `%s`.",
10902 t1
.toChars(), t2
.toChars());
10905 // Need to divide the result by the stride
10906 // Replace (ptr - ptr) with (ptr - ptr) / stride
10909 // make sure pointer types are compatible
10910 if (Expression ex
= typeCombine(exp
, sc
))
10916 exp
.type
= Type
.tptrdiff_t
;
10917 stride
= t2
.nextOf().size();
10920 e
= new IntegerExp(exp
.loc
, 0, Type
.tptrdiff_t
);
10922 else if (stride
== cast(long)SIZE_INVALID
)
10923 e
= ErrorExp
.get();
10926 e
= new DivExp(exp
.loc
, exp
, new IntegerExp(Loc
.initial
, stride
, Type
.tptrdiff_t
));
10927 e
.type
= Type
.tptrdiff_t
;
10930 else if (t2
.isintegral())
10931 e
= scaleFactor(exp
, sc
);
10934 exp
.error("can't subtract `%s` from pointer", t2
.toChars());
10935 e
= ErrorExp
.get();
10940 if (t2
.ty
== Tpointer
)
10942 exp
.type
= exp
.e2
.type
;
10943 exp
.error("can't subtract pointer from `%s`", exp
.e1
.type
.toChars());
10947 if (Expression ex
= typeCombine(exp
, sc
))
10953 Type tb
= exp
.type
.toBasetype();
10954 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
10956 if (!isArrayOpValid(exp
))
10958 result
= arrayOpInvalidError(exp
);
10965 t1
= exp
.e1
.type
.toBasetype();
10966 t2
= exp
.e2
.type
.toBasetype();
10967 if (!target
.isVectorOpSupported(t1
, exp
.op
, t2
))
10969 result
= exp
.incompatibleTypes();
10972 if ((t1
.isreal() && t2
.isimaginary()) ||
(t1
.isimaginary() && t2
.isreal()))
10974 switch (exp
.type
.ty
)
10978 exp
.type
= Type
.tcomplex32
;
10983 exp
.type
= Type
.tcomplex64
;
10988 exp
.type
= Type
.tcomplex80
;
11000 * If the given expression is a `CatExp`, the function tries to lower it to
11001 * `_d_arraycatnTX`.
11004 * ee = the `CatExp` to lower
11006 * `_d_arraycatnTX(e1, e2, ..., en)` if `ee` is `e1 ~ e2 ~ ... en`
11009 private Expression
lowerToArrayCat(CatExp exp
)
11011 // String literals are concatenated by the compiler. No lowering is needed.
11012 if ((exp
.e1
.isStringExp() && (exp
.e2
.isIntegerExp() || exp
.e2
.isStringExp())) ||
11013 (exp
.e2
.isStringExp() && (exp
.e1
.isIntegerExp() || exp
.e1
.isStringExp())))
11016 Identifier hook
= global
.params
.tracegc ? Id
._d_arraycatnTXTrace
: Id
._d_arraycatnTX
;
11017 if (!verifyHookExist(exp
.loc
, *sc
, hook
, "concatenating arrays"))
11023 void handleCatArgument(Expressions
*arguments
, Expression e
)
11025 if (auto ce
= e
.isCatExp())
11027 Expression lowering
= ce
.lowering
;
11029 /* Skip `file`, `line`, and `funcname` if the hook of the parent
11030 * `CatExp` is `_d_arraycatnTXTrace`.
11032 if (auto callExp
= isRuntimeHook(lowering
, hook
))
11034 if (hook
== Id
._d_arraycatnTX
)
11035 arguments
.pushSlice((*callExp
.arguments
)[]);
11037 arguments
.pushSlice((*callExp
.arguments
)[3 .. $]);
11044 auto arguments
= new Expressions();
11045 if (global
.params
.tracegc
)
11047 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ?
11048 sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
11049 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
11050 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
11051 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
11054 handleCatArgument(arguments
, exp
.e1
);
11055 handleCatArgument(arguments
, exp
.e2
);
11057 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
11058 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
11060 auto tiargs
= new Objects();
11061 tiargs
.push(exp
.type
);
11062 id
= new DotTemplateInstanceExp(exp
.loc
, id
, hook
, tiargs
);
11063 id
= new CallExp(exp
.loc
, id
, arguments
);
11064 return id
.expressionSemantic(sc
);
11067 void trySetCatExpLowering(Expression exp
)
11069 /* `_d_arraycatnTX` canot be used with `-betterC`, but `CatExp`s may be
11070 * used with `-betterC`, but only during CTFE.
11072 if (!global
.params
.useGC ||
!sc
.needsCodegen())
11075 if (auto ce
= exp
.isCatExp())
11076 ce
.lowering
= lowerToArrayCat(ce
);
11079 override void visit(CatExp exp
)
11081 // https://dlang.org/spec/expression.html#cat_expressions
11082 //printf("CatExp.semantic() %s\n", toChars());
11089 if (Expression ex
= binSemanticProp(exp
, sc
))
11094 Expression e
= exp
.op_overload(sc
);
11101 Type tb1
= exp
.e1
.type
.toBasetype();
11102 Type tb2
= exp
.e2
.type
.toBasetype();
11104 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
11105 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
11109 Type tb1next
= tb1
.nextOf();
11110 Type tb2next
= tb2
.nextOf();
11112 // Check for: array ~ array
11113 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
)))
11115 /* https://issues.dlang.org/show_bug.cgi?id=9248
11116 * Here to avoid the case of:
11117 * void*[] a = [cast(void*)1];
11118 * void*[] b = [cast(void*)2];
11121 * a ~ [cast(void*)b];
11124 /* https://issues.dlang.org/show_bug.cgi?id=14682
11125 * Also to avoid the case of:
11129 * a ~ cast(int[])[];
11134 // Check for: array ~ element
11135 if ((tb1
.ty
== Tsarray || tb1
.ty
== Tarray
) && tb2
.ty
!= Tvoid
)
11137 if (exp
.e1
.op
== EXP
.arrayLiteral
)
11139 exp
.e2
= doCopyOrMove(sc
, exp
.e2
);
11140 // https://issues.dlang.org/show_bug.cgi?id=14686
11141 // Postblit call appears in AST, and this is
11142 // finally translated to an ArrayLiteralExp in below optimize().
11144 else if (exp
.e1
.op
== EXP
.string_
)
11146 // No postblit call exists on character (integer) value.
11150 if (exp
.e2
.checkPostblit(sc
, tb2
))
11152 // Postblit call will be done in runtime helper function
11155 if (exp
.e1
.op
== EXP
.arrayLiteral
&& exp
.e1
.implicitConvTo(tb2
.arrayOf()))
11157 exp
.e1
= exp
.e1
.implicitCastTo(sc
, tb2
.arrayOf());
11158 exp
.type
= tb2
.arrayOf();
11161 if (exp
.e2
.implicitConvTo(tb1next
) >= MATCH
.convert
)
11163 exp
.e2
= exp
.e2
.implicitCastTo(sc
, tb1next
);
11164 exp
.type
= tb1next
.arrayOf();
11166 if (checkNewEscape(sc
, exp
.e2
, false))
11168 result
= exp
.optimize(WANTvalue
);
11169 trySetCatExpLowering(result
);
11173 // Check for: element ~ array
11174 if ((tb2
.ty
== Tsarray || tb2
.ty
== Tarray
) && tb1
.ty
!= Tvoid
)
11176 if (exp
.e2
.op
== EXP
.arrayLiteral
)
11178 exp
.e1
= doCopyOrMove(sc
, exp
.e1
);
11180 else if (exp
.e2
.op
== EXP
.string_
)
11185 if (exp
.e1
.checkPostblit(sc
, tb1
))
11189 if (exp
.e2
.op
== EXP
.arrayLiteral
&& exp
.e2
.implicitConvTo(tb1
.arrayOf()))
11191 exp
.e2
= exp
.e2
.implicitCastTo(sc
, tb1
.arrayOf());
11192 exp
.type
= tb1
.arrayOf();
11195 if (exp
.e1
.implicitConvTo(tb2next
) >= MATCH
.convert
)
11197 exp
.e1
= exp
.e1
.implicitCastTo(sc
, tb2next
);
11198 exp
.type
= tb2next
.arrayOf();
11200 if (checkNewEscape(sc
, exp
.e1
, false))
11202 result
= exp
.optimize(WANTvalue
);
11203 trySetCatExpLowering(result
);
11209 if ((tb1
.ty
== Tsarray || tb1
.ty
== Tarray
) && (tb2
.ty
== Tsarray || tb2
.ty
== Tarray
) && (tb1next
.mod || tb2next
.mod
) && (tb1next
.mod
!= tb2next
.mod
))
11211 Type t1
= tb1next
.mutableOf().constOf().arrayOf();
11212 Type t2
= tb2next
.mutableOf().constOf().arrayOf();
11213 if (exp
.e1
.op
== EXP
.string_
&& !(cast(StringExp
)exp
.e1
).committed
)
11216 exp
.e1
= exp
.e1
.castTo(sc
, t1
);
11217 if (exp
.e2
.op
== EXP
.string_
&& !(cast(StringExp
)exp
.e2
).committed
)
11220 exp
.e2
= exp
.e2
.castTo(sc
, t2
);
11223 if (Expression ex
= typeCombine(exp
, sc
))
11226 trySetCatExpLowering(result
);
11229 exp
.type
= exp
.type
.toHeadMutable();
11231 Type tb
= exp
.type
.toBasetype();
11232 if (tb
.ty
== Tsarray
)
11233 exp
.type
= tb
.nextOf().arrayOf();
11234 if (exp
.type
.ty
== Tarray
&& tb1next
&& tb2next
&& tb1next
.mod
!= tb2next
.mod
)
11236 exp
.type
= exp
.type
.nextOf().toHeadMutable().arrayOf();
11238 if (Type tbn
= tb
.nextOf())
11240 if (exp
.checkPostblit(sc
, tbn
))
11243 Type t1
= exp
.e1
.type
.toBasetype();
11244 Type t2
= exp
.e2
.type
.toBasetype();
11245 if ((t1
.ty
== Tarray || t1
.ty
== Tsarray
) &&
11246 (t2
.ty
== Tarray || t2
.ty
== Tsarray
))
11248 // Normalize to ArrayLiteralExp or StringExp as far as possible
11249 e
= exp
.optimize(WANTvalue
);
11253 //printf("(%s) ~ (%s)\n", e1.toChars(), e2.toChars());
11254 result
= exp
.incompatibleTypes();
11259 trySetCatExpLowering(result
);
11262 override void visit(MulExp exp
)
11266 printf("MulExp::semantic() %s\n", exp
.toChars());
11274 if (Expression ex
= binSemanticProp(exp
, sc
))
11279 Expression e
= exp
.op_overload(sc
);
11286 if (Expression ex
= typeCombine(exp
, sc
))
11292 Type tb
= exp
.type
.toBasetype();
11293 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
11295 if (!isArrayOpValid(exp
))
11297 result
= arrayOpInvalidError(exp
);
11304 if (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
))
11307 if (exp
.type
.isfloating())
11309 Type t1
= exp
.e1
.type
;
11310 Type t2
= exp
.e2
.type
;
11316 else if (t2
.isreal())
11320 else if (t1
.isimaginary())
11322 if (t2
.isimaginary())
11324 switch (t1
.toBasetype().ty
)
11327 exp
.type
= Type
.tfloat32
;
11331 exp
.type
= Type
.tfloat64
;
11335 exp
.type
= Type
.tfloat80
;
11343 exp
.e1
.type
= exp
.type
;
11344 exp
.e2
.type
= exp
.type
;
11345 e
= new NegExp(exp
.loc
, exp
);
11346 e
= e
.expressionSemantic(sc
);
11351 exp
.type
= t2
; // t2 is complex
11353 else if (t2
.isimaginary())
11355 exp
.type
= t1
; // t1 is complex
11358 else if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
11360 result
= exp
.incompatibleTypes();
11366 override void visit(DivExp exp
)
11374 if (Expression ex
= binSemanticProp(exp
, sc
))
11379 Expression e
= exp
.op_overload(sc
);
11386 if (Expression ex
= typeCombine(exp
, sc
))
11392 Type tb
= exp
.type
.toBasetype();
11393 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
11395 if (!isArrayOpValid(exp
))
11397 result
= arrayOpInvalidError(exp
);
11404 if (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
))
11407 if (exp
.type
.isfloating())
11409 Type t1
= exp
.e1
.type
;
11410 Type t2
= exp
.e2
.type
;
11415 if (t2
.isimaginary())
11419 e
= new NegExp(exp
.loc
, exp
);
11420 e
= e
.expressionSemantic(sc
);
11425 else if (t2
.isreal())
11429 else if (t1
.isimaginary())
11431 if (t2
.isimaginary())
11433 switch (t1
.toBasetype().ty
)
11436 exp
.type
= Type
.tfloat32
;
11440 exp
.type
= Type
.tfloat64
;
11444 exp
.type
= Type
.tfloat80
;
11452 exp
.type
= t2
; // t2 is complex
11454 else if (t2
.isimaginary())
11456 exp
.type
= t1
; // t1 is complex
11459 else if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
11461 result
= exp
.incompatibleTypes();
11467 override void visit(ModExp exp
)
11475 if (Expression ex
= binSemanticProp(exp
, sc
))
11480 Expression e
= exp
.op_overload(sc
);
11487 if (Expression ex
= typeCombine(exp
, sc
))
11493 Type tb
= exp
.type
.toBasetype();
11494 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
11496 if (!isArrayOpValid(exp
))
11498 result
= arrayOpInvalidError(exp
);
11504 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
11506 result
= exp
.incompatibleTypes();
11510 if (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
))
11513 if (exp
.type
.isfloating())
11515 exp
.type
= exp
.e1
.type
;
11516 if (exp
.e2
.type
.iscomplex())
11518 exp
.error("cannot perform modulo complex arithmetic");
11525 override void visit(PowExp exp
)
11533 //printf("PowExp::semantic() %s\n", toChars());
11534 if (Expression ex
= binSemanticProp(exp
, sc
))
11539 Expression e
= exp
.op_overload(sc
);
11546 if (Expression ex
= typeCombine(exp
, sc
))
11552 Type tb
= exp
.type
.toBasetype();
11553 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
11555 if (!isArrayOpValid(exp
))
11557 result
= arrayOpInvalidError(exp
);
11564 if (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
))
11567 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
11569 result
= exp
.incompatibleTypes();
11573 // First, attempt to fold the expression.
11574 e
= exp
.optimize(WANTvalue
);
11575 if (e
.op
!= EXP
.pow
)
11577 e
= e
.expressionSemantic(sc
);
11582 Module mmath
= Module
.loadStdMath();
11585 e
.error("`%s` requires `std.math` for `^^` operators", e
.toChars());
11588 e
= new ScopeExp(exp
.loc
, mmath
);
11590 if (exp
.e2
.op
== EXP
.float64
&& exp
.e2
.toReal() == CTFloat
.half
)
11592 // Replace e1 ^^ 0.5 with .std.math.sqrt(e1)
11593 e
= new CallExp(exp
.loc
, new DotIdExp(exp
.loc
, e
, Id
._sqrt
), exp
.e1
);
11597 // Replace e1 ^^ e2 with .std.math.pow(e1, e2)
11598 e
= new CallExp(exp
.loc
, new DotIdExp(exp
.loc
, e
, Id
._pow
), exp
.e1
, exp
.e2
);
11600 e
= e
.expressionSemantic(sc
);
11605 override void visit(ShlExp exp
)
11607 //printf("ShlExp::semantic(), type = %p\n", type);
11614 if (Expression ex
= binSemanticProp(exp
, sc
))
11619 Expression e
= exp
.op_overload(sc
);
11626 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
11629 if (!target
.isVectorOpSupported(exp
.e1
.type
.toBasetype(), exp
.op
, exp
.e2
.type
.toBasetype()))
11631 result
= exp
.incompatibleTypes();
11634 exp
.e1
= integralPromotions(exp
.e1
, sc
);
11635 if (exp
.e2
.type
.toBasetype().ty
!= Tvector
)
11636 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tshiftcnt
);
11638 exp
.type
= exp
.e1
.type
;
11642 override void visit(ShrExp exp
)
11650 if (Expression ex
= binSemanticProp(exp
, sc
))
11655 Expression e
= exp
.op_overload(sc
);
11662 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
11665 if (!target
.isVectorOpSupported(exp
.e1
.type
.toBasetype(), exp
.op
, exp
.e2
.type
.toBasetype()))
11667 result
= exp
.incompatibleTypes();
11670 exp
.e1
= integralPromotions(exp
.e1
, sc
);
11671 if (exp
.e2
.type
.toBasetype().ty
!= Tvector
)
11672 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tshiftcnt
);
11674 exp
.type
= exp
.e1
.type
;
11678 override void visit(UshrExp exp
)
11686 if (Expression ex
= binSemanticProp(exp
, sc
))
11691 Expression e
= exp
.op_overload(sc
);
11698 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
11701 if (!target
.isVectorOpSupported(exp
.e1
.type
.toBasetype(), exp
.op
, exp
.e2
.type
.toBasetype()))
11703 result
= exp
.incompatibleTypes();
11706 exp
.e1
= integralPromotions(exp
.e1
, sc
);
11707 if (exp
.e2
.type
.toBasetype().ty
!= Tvector
)
11708 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tshiftcnt
);
11710 exp
.type
= exp
.e1
.type
;
11714 override void visit(AndExp exp
)
11722 if (Expression ex
= binSemanticProp(exp
, sc
))
11727 Expression e
= exp
.op_overload(sc
);
11734 if (exp
.e1
.type
.toBasetype().ty
== Tbool
&& exp
.e2
.type
.toBasetype().ty
== Tbool
)
11736 exp
.type
= exp
.e1
.type
;
11741 if (Expression ex
= typeCombine(exp
, sc
))
11747 Type tb
= exp
.type
.toBasetype();
11748 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
11750 if (!isArrayOpValid(exp
))
11752 result
= arrayOpInvalidError(exp
);
11758 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
11760 result
= exp
.incompatibleTypes();
11763 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
11769 override void visit(OrExp exp
)
11777 if (Expression ex
= binSemanticProp(exp
, sc
))
11782 Expression e
= exp
.op_overload(sc
);
11789 if (exp
.e1
.type
.toBasetype().ty
== Tbool
&& exp
.e2
.type
.toBasetype().ty
== Tbool
)
11791 exp
.type
= exp
.e1
.type
;
11796 if (Expression ex
= typeCombine(exp
, sc
))
11802 Type tb
= exp
.type
.toBasetype();
11803 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
11805 if (!isArrayOpValid(exp
))
11807 result
= arrayOpInvalidError(exp
);
11813 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
11815 result
= exp
.incompatibleTypes();
11818 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
11824 override void visit(XorExp exp
)
11832 if (Expression ex
= binSemanticProp(exp
, sc
))
11837 Expression e
= exp
.op_overload(sc
);
11844 if (exp
.e1
.type
.toBasetype().ty
== Tbool
&& exp
.e2
.type
.toBasetype().ty
== Tbool
)
11846 exp
.type
= exp
.e1
.type
;
11851 if (Expression ex
= typeCombine(exp
, sc
))
11857 Type tb
= exp
.type
.toBasetype();
11858 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
11860 if (!isArrayOpValid(exp
))
11862 result
= arrayOpInvalidError(exp
);
11868 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
11870 result
= exp
.incompatibleTypes();
11873 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
11879 override void visit(LogicalExp exp
)
11881 static if (LOGSEMANTIC
)
11883 printf("LogicalExp::semantic() %s\n", exp
.toChars());
11892 exp
.setNoderefOperands();
11894 Expression e1x
= exp
.e1
.expressionSemantic(sc
);
11896 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
11897 if (e1x
.op
== EXP
.type
)
11898 e1x
= resolveAliasThis(sc
, e1x
);
11900 e1x
= resolveProperties(sc
, e1x
);
11901 e1x
= e1x
.toBoolean(sc
);
11903 if (sc
.flags
& SCOPE
.condition
)
11905 /* If in static if, don't evaluate e2 if we don't have to.
11907 e1x
= e1x
.optimize(WANTvalue
);
11908 if (e1x
.toBool().hasValue(exp
.op
== EXP
.orOr
))
11910 if (sc
.flags
& SCOPE
.Cfile
)
11911 result
= new IntegerExp(exp
.op
== EXP
.orOr
);
11913 result
= IntegerExp
.createBool(exp
.op
== EXP
.orOr
);
11918 CtorFlow ctorflow
= sc
.ctorflow
.clone();
11919 Expression e2x
= exp
.e2
.expressionSemantic(sc
);
11920 sc
.merge(exp
.loc
, ctorflow
);
11921 ctorflow
.freeFieldinit();
11923 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
11924 if (e2x
.op
== EXP
.type
)
11925 e2x
= resolveAliasThis(sc
, e2x
);
11927 e2x
= resolveProperties(sc
, e2x
);
11929 auto f1
= checkNonAssignmentArrayOp(e1x
);
11930 auto f2
= checkNonAssignmentArrayOp(e2x
);
11934 // Unless the right operand is 'void', the expression is converted to 'bool'.
11935 if (e2x
.type
.ty
!= Tvoid
)
11936 e2x
= e2x
.toBoolean(sc
);
11938 if (e2x
.op
== EXP
.type || e2x
.op
== EXP
.scope_
)
11940 exp
.error("`%s` is not an expression", exp
.e2
.toChars());
11943 if (e1x
.op
== EXP
.error || e1x
.type
.ty
== Tnoreturn
)
11948 if (e2x
.op
== EXP
.error
)
11954 // The result type is 'bool', unless the right operand has type 'void'.
11955 if (e2x
.type
.ty
== Tvoid
)
11956 exp
.type
= Type
.tvoid
;
11958 exp
.type
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? Type
.tint32
: Type
.tbool
;
11966 override void visit(CmpExp exp
)
11968 static if (LOGSEMANTIC
)
11970 printf("CmpExp::semantic('%s')\n", exp
.toChars());
11978 exp
.setNoderefOperands();
11980 if (Expression ex
= binSemanticProp(exp
, sc
))
11985 Type t1
= exp
.e1
.type
.toBasetype();
11986 Type t2
= exp
.e2
.type
.toBasetype();
11987 if (t1
.ty
== Tclass
&& exp
.e2
.op
== EXP
.null_ || t2
.ty
== Tclass
&& exp
.e1
.op
== EXP
.null_
)
11989 exp
.error("do not use `null` when comparing class types");
11994 EXP cmpop
= exp
.op
;
11995 if (auto e
= exp
.op_overload(sc
, &cmpop
))
11997 if (!e
.type
.isscalar() && e
.type
.equals(exp
.e1
.type
))
11999 exp
.error("recursive `opCmp` expansion");
12002 if (e
.op
== EXP
.call)
12005 if (t1
.ty
== Tclass
&& t2
.ty
== Tclass
)
12007 // Lower to object.__cmp(e1, e2)
12008 Expression cl
= new IdentifierExp(exp
.loc
, Id
.empty
);
12009 cl
= new DotIdExp(exp
.loc
, cl
, Id
.object
);
12010 cl
= new DotIdExp(exp
.loc
, cl
, Id
.__cmp
);
12011 cl
= cl
.expressionSemantic(sc
);
12013 auto arguments
= new Expressions();
12014 // Check if op_overload found a better match by calling e2.opCmp(e1)
12015 // If the operands were swapped, then the result must be reversed
12016 // e1.opCmp(e2) == -e2.opCmp(e1)
12017 // cmpop takes care of this
12018 if (exp
.op
== cmpop
)
12020 arguments
.push(exp
.e1
);
12021 arguments
.push(exp
.e2
);
12025 // Use better match found by op_overload
12026 arguments
.push(exp
.e2
);
12027 arguments
.push(exp
.e1
);
12030 cl
= new CallExp(exp
.loc
, cl
, arguments
);
12031 cl
= new CmpExp(cmpop
, exp
.loc
, cl
, new IntegerExp(0));
12032 result
= cl
.expressionSemantic(sc
);
12036 e
= new CmpExp(cmpop
, exp
.loc
, e
, IntegerExp
.literal
!0);
12037 e
= e
.expressionSemantic(sc
);
12044 if (Expression ex
= typeCombine(exp
, sc
))
12050 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
12051 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
12055 exp
.type
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? Type
.tint32
: Type
.tbool
;
12057 // Special handling for array comparisons
12058 Expression arrayLowering
= null;
12059 t1
= exp
.e1
.type
.toBasetype();
12060 t2
= exp
.e2
.type
.toBasetype();
12061 if ((t1
.ty
== Tarray || t1
.ty
== Tsarray || t1
.ty
== Tpointer
) && (t2
.ty
== Tarray || t2
.ty
== Tsarray || t2
.ty
== Tpointer
))
12063 Type t1next
= t1
.nextOf();
12064 Type t2next
= t2
.nextOf();
12065 if (t1next
.implicitConvTo(t2next
) < MATCH
.constant
&& t2next
.implicitConvTo(t1next
) < MATCH
.constant
&& (t1next
.ty
!= Tvoid
&& t2next
.ty
!= Tvoid
))
12067 exp
.error("array comparison type mismatch, `%s` vs `%s`", t1next
.toChars(), t2next
.toChars());
12071 if (sc
.needsCodegen() &&
12072 (t1
.ty
== Tarray || t1
.ty
== Tsarray
) &&
12073 (t2
.ty
== Tarray || t2
.ty
== Tsarray
))
12075 if (!verifyHookExist(exp
.loc
, *sc
, Id
.__cmp
, "comparing arrays"))
12078 // Lower to object.__cmp(e1, e2)
12079 Expression al
= new IdentifierExp(exp
.loc
, Id
.empty
);
12080 al
= new DotIdExp(exp
.loc
, al
, Id
.object
);
12081 al
= new DotIdExp(exp
.loc
, al
, Id
.__cmp
);
12082 al
= al
.expressionSemantic(sc
);
12084 auto arguments
= new Expressions(2);
12085 (*arguments
)[0] = exp
.e1
;
12086 (*arguments
)[1] = exp
.e2
;
12088 al
= new CallExp(exp
.loc
, al
, arguments
);
12089 al
= new CmpExp(exp
.op
, exp
.loc
, al
, IntegerExp
.literal
!0);
12091 arrayLowering
= al
;
12094 else if (t1
.ty
== Tstruct || t2
.ty
== Tstruct ||
(t1
.ty
== Tclass
&& t2
.ty
== Tclass
))
12096 if (t2
.ty
== Tstruct
)
12097 exp
.error("need member function `opCmp()` for %s `%s` to compare", t2
.toDsymbol(sc
).kind(), t2
.toChars());
12099 exp
.error("need member function `opCmp()` for %s `%s` to compare", t1
.toDsymbol(sc
).kind(), t1
.toChars());
12102 else if (t1
.iscomplex() || t2
.iscomplex())
12104 exp
.error("compare not defined for complex operands");
12107 else if (t1
.ty
== Taarray || t2
.ty
== Taarray
)
12109 exp
.error("`%s` is not defined for associative arrays", EXPtoString(exp
.op
).ptr
);
12112 else if (!target
.isVectorOpSupported(t1
, exp
.op
, t2
))
12114 result
= exp
.incompatibleTypes();
12119 bool r1
= exp
.e1
.checkValue() || exp
.e1
.checkSharedAccess(sc
);
12120 bool r2
= exp
.e2
.checkValue() || exp
.e2
.checkSharedAccess(sc
);
12125 //printf("CmpExp: %s, type = %s\n", e.toChars(), e.type.toChars());
12128 arrayLowering
= arrayLowering
.expressionSemantic(sc
);
12129 result
= arrayLowering
;
12133 if (auto tv
= t1
.isTypeVector())
12134 exp
.type
= tv
.toBooleanVector();
12140 override void visit(InExp exp
)
12148 if (Expression ex
= binSemanticProp(exp
, sc
))
12153 Expression e
= exp
.op_overload(sc
);
12160 Type t2b
= exp
.e2
.type
.toBasetype();
12165 TypeAArray ta
= cast(TypeAArray
)t2b
;
12167 // Special handling for array keys
12168 if (!arrayTypeCompatibleWithoutCasting(exp
.e1
.type
, ta
.index
))
12170 // Convert key to type of key
12171 exp
.e1
= exp
.e1
.implicitCastTo(sc
, ta
.index
);
12174 semanticTypeInfo(sc
, ta
.index
);
12176 // Return type is pointer to value
12177 exp
.type
= ta
.nextOf().pointerTo();
12184 case Tarray
, Tsarray
:
12185 result
= exp
.incompatibleTypes();
12186 exp
.errorSupplemental("`in` is only allowed on associative arrays");
12187 const(char)* slice
= (t2b
.ty
== Tsarray
) ?
"[]" : "";
12188 exp
.errorSupplemental("perhaps use `std.algorithm.find(%s, %s%s)` instead",
12189 exp
.e1
.toChars(), exp
.e2
.toChars(), slice
);
12193 result
= exp
.incompatibleTypes();
12199 override void visit(RemoveExp e
)
12201 if (Expression ex
= binSemantic(e
, sc
))
12209 override void visit(EqualExp exp
)
12211 //printf("EqualExp::semantic('%s')\n", exp.toChars());
12218 exp
.setNoderefOperands();
12220 if (auto e
= binSemanticProp(exp
, sc
))
12225 if (exp
.e1
.op
== EXP
.type || exp
.e2
.op
== EXP
.type
)
12227 /* https://issues.dlang.org/show_bug.cgi?id=12520
12228 * empty tuples are represented as types so special cases are added
12229 * so that they can be compared for equality with tuples of values.
12231 static auto extractTypeTupAndExpTup(Expression e
)
12233 static struct Result
{ bool ttEmpty
; bool te
; }
12234 auto tt
= e
.op
== EXP
.type ? e
.isTypeExp().type
.isTypeTuple() : null;
12235 return Result(tt
&& (!tt
.arguments ||
!tt
.arguments
.length
), e
.isTupleExp() !is null);
12237 auto tups1
= extractTypeTupAndExpTup(exp
.e1
);
12238 auto tups2
= extractTypeTupAndExpTup(exp
.e2
);
12239 // AliasSeq!() == AliasSeq!(<at least a value>)
12240 if (tups1
.ttEmpty
&& tups2
.te
)
12242 result
= IntegerExp
.createBool(exp
.op
!= EXP
.equal
);
12245 // AliasSeq!(<at least a value>) == AliasSeq!()
12246 else if (tups1
.te
&& tups2
.ttEmpty
)
12248 result
= IntegerExp
.createBool(exp
.op
!= EXP
.equal
);
12251 // AliasSeq!() == AliasSeq!()
12252 else if (tups1
.ttEmpty
&& tups2
.ttEmpty
)
12254 result
= IntegerExp
.createBool(exp
.op
== EXP
.equal
);
12257 // otherwise, two types are really not comparable
12258 result
= exp
.incompatibleTypes();
12263 auto t1
= exp
.e1
.type
;
12264 auto t2
= exp
.e2
.type
;
12265 if (t1
.ty
== Tenum
&& t2
.ty
== Tenum
&& !t1
.equivalent(t2
))
12266 exp
.error("comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`",
12267 t1
.toChars(), t2
.toChars());
12270 /* Before checking for operator overloading, check to see if we're
12271 * comparing the addresses of two statics. If so, we can just see
12272 * if they are the same symbol.
12274 if (exp
.e1
.op
== EXP
.address
&& exp
.e2
.op
== EXP
.address
)
12276 AddrExp ae1
= cast(AddrExp
)exp
.e1
;
12277 AddrExp ae2
= cast(AddrExp
)exp
.e2
;
12278 if (ae1
.e1
.op
== EXP
.variable
&& ae2
.e1
.op
== EXP
.variable
)
12280 VarExp ve1
= cast(VarExp
)ae1
.e1
;
12281 VarExp ve2
= cast(VarExp
)ae2
.e1
;
12282 if (ve1
.var
== ve2
.var
)
12284 // They are the same, result is 'true' for ==, 'false' for !=
12285 result
= IntegerExp
.createBool(exp
.op
== EXP
.equal
);
12291 Type t1
= exp
.e1
.type
.toBasetype();
12292 Type t2
= exp
.e2
.type
.toBasetype();
12294 // Indicates whether the comparison of the 2 specified array types
12295 // requires an object.__equals() lowering.
12296 static bool needsDirectEq(Type t1
, Type t2
, Scope
* sc
)
12298 Type t1n
= t1
.nextOf().toBasetype();
12299 Type t2n
= t2
.nextOf().toBasetype();
12300 if ((t1n
.ty
.isSomeChar
&& t2n
.ty
.isSomeChar
) ||
12301 (t1n
.ty
== Tvoid || t2n
.ty
== Tvoid
))
12305 if (t1n
.constOf() != t2n
.constOf())
12309 while (t
.toBasetype().nextOf())
12310 t
= t
.nextOf().toBasetype();
12311 if (auto ts
= t
.isTypeStruct())
12313 // semanticTypeInfo() makes sure hasIdentityEquals has been computed
12314 if (global
.params
.useTypeInfo
&& Type
.dtypeinfo
)
12315 semanticTypeInfo(sc
, ts
);
12317 return ts
.sym
.hasIdentityEquals
; // has custom opEquals
12323 if (auto e
= exp
.op_overload(sc
))
12330 const isArrayComparison
= (t1
.ty
== Tarray || t1
.ty
== Tsarray
) &&
12331 (t2
.ty
== Tarray || t2
.ty
== Tsarray
);
12332 const needsArrayLowering
= isArrayComparison
&& needsDirectEq(t1
, t2
, sc
);
12334 if (!needsArrayLowering
)
12336 // https://issues.dlang.org/show_bug.cgi?id=23783
12337 if (exp
.e1
.checkSharedAccess(sc
) || exp
.e2
.checkSharedAccess(sc
))
12339 if (auto e
= typeCombine(exp
, sc
))
12346 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
12347 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
12351 exp
.type
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? Type
.tint32
: Type
.tbool
;
12353 if (!isArrayComparison
)
12355 if (exp
.e1
.type
!= exp
.e2
.type
&& exp
.e1
.type
.isfloating() && exp
.e2
.type
.isfloating())
12357 // Cast both to complex
12358 exp
.e1
= exp
.e1
.castTo(sc
, Type
.tcomplex80
);
12359 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tcomplex80
);
12363 // lower some array comparisons to object.__equals(e1, e2)
12364 if (needsArrayLowering ||
(t1
.ty
== Tarray
&& t2
.ty
== Tarray
))
12366 //printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars());
12368 // https://issues.dlang.org/show_bug.cgi?id=22390
12369 // Equality comparison between array of noreturns simply lowers to length equality comparison
12370 if (t1
.nextOf
.isTypeNoreturn() && t2
.nextOf
.isTypeNoreturn())
12372 Expression exp_l1
= new DotIdExp(exp
.e1
.loc
, exp
.e1
, Id
.length
);
12373 Expression exp_l2
= new DotIdExp(exp
.e2
.loc
, exp
.e2
, Id
.length
);
12374 auto e
= new EqualExp(EXP
.equal
, exp
.loc
, exp_l1
, exp_l2
);
12375 result
= e
.expressionSemantic(sc
);
12379 if (!verifyHookExist(exp
.loc
, *sc
, Id
.__equals
, "equal checks on arrays"))
12382 Expression __equals
= new IdentifierExp(exp
.loc
, Id
.empty
);
12383 Identifier id
= Identifier
.idPool("__equals");
12384 __equals
= new DotIdExp(exp
.loc
, __equals
, Id
.object
);
12385 __equals
= new DotIdExp(exp
.loc
, __equals
, id
);
12387 /* https://issues.dlang.org/show_bug.cgi?id=23674
12389 * Optimize before creating the call expression to the
12390 * druntime hook as the optimizer may output errors
12391 * that will get swallowed otherwise.
12393 exp
.e1
= exp
.e1
.optimize(WANTvalue
);
12394 exp
.e2
= exp
.e2
.optimize(WANTvalue
);
12396 auto arguments
= new Expressions(2);
12397 (*arguments
)[0] = exp
.e1
;
12398 (*arguments
)[1] = exp
.e2
;
12400 __equals
= new CallExp(exp
.loc
, __equals
, arguments
);
12401 if (exp
.op
== EXP
.notEqual
)
12403 __equals
= new NotExp(exp
.loc
, __equals
);
12405 __equals
= __equals
.trySemantic(sc
); // for better error message
12408 exp
.error("incompatible types for array comparison: `%s` and `%s`",
12409 exp
.e1
.type
.toChars(), exp
.e2
.type
.toChars());
12410 __equals
= ErrorExp
.get();
12417 if (exp
.e1
.type
.toBasetype().ty
== Taarray
)
12418 semanticTypeInfo(sc
, exp
.e1
.type
.toBasetype());
12421 if (!target
.isVectorOpSupported(t1
, exp
.op
, t2
))
12423 result
= exp
.incompatibleTypes();
12427 if (auto tv
= t1
.isTypeVector())
12428 exp
.type
= tv
.toBooleanVector();
12433 override void visit(IdentityExp exp
)
12441 exp
.setNoderefOperands();
12443 if (auto e
= binSemanticProp(exp
, sc
))
12449 if (auto e
= typeCombine(exp
, sc
))
12455 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
12456 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
12460 if (exp
.e1
.op
== EXP
.type || exp
.e2
.op
== EXP
.type
)
12462 result
= exp
.incompatibleTypes();
12466 exp
.type
= Type
.tbool
;
12468 if (exp
.e1
.type
!= exp
.e2
.type
&& exp
.e1
.type
.isfloating() && exp
.e2
.type
.isfloating())
12470 // Cast both to complex
12471 exp
.e1
= exp
.e1
.castTo(sc
, Type
.tcomplex80
);
12472 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tcomplex80
);
12475 auto tb1
= exp
.e1
.type
.toBasetype();
12476 auto tb2
= exp
.e2
.type
.toBasetype();
12477 if (!target
.isVectorOpSupported(tb1
, exp
.op
, tb2
))
12479 result
= exp
.incompatibleTypes();
12483 if (exp
.e1
.op
== EXP
.call)
12484 exp
.e1
= (cast(CallExp
)exp
.e1
).addDtorHook(sc
);
12485 if (exp
.e2
.op
== EXP
.call)
12486 exp
.e2
= (cast(CallExp
)exp
.e2
).addDtorHook(sc
);
12488 if (exp
.e1
.type
.toBasetype().ty
== Tsarray ||
12489 exp
.e2
.type
.toBasetype().ty
== Tsarray
)
12490 exp
.deprecation("identity comparison of static arrays "
12491 ~ "implicitly coerces them to slices, "
12492 ~ "which are compared by reference");
12497 override void visit(CondExp exp
)
12499 static if (LOGSEMANTIC
)
12501 printf("CondExp::semantic('%s')\n", exp
.toChars());
12509 if (auto die
= exp
.econd
.isDotIdExp())
12510 die
.noderef
= true;
12512 Expression ec
= exp
.econd
.expressionSemantic(sc
);
12513 ec
= resolveProperties(sc
, ec
);
12514 ec
= ec
.toBoolean(sc
);
12516 CtorFlow ctorflow_root
= sc
.ctorflow
.clone();
12517 Expression e1x
= exp
.e1
.expressionSemantic(sc
).arrayFuncConv(sc
);
12518 e1x
= resolveProperties(sc
, e1x
);
12520 CtorFlow ctorflow1
= sc
.ctorflow
;
12521 sc
.ctorflow
= ctorflow_root
;
12522 Expression e2x
= exp
.e2
.expressionSemantic(sc
).arrayFuncConv(sc
);
12523 e2x
= resolveProperties(sc
, e2x
);
12525 sc
.merge(exp
.loc
, ctorflow1
);
12526 ctorflow1
.freeFieldinit();
12528 if (ec
.op
== EXP
.error
)
12533 if (ec
.type
== Type
.terror
)
12537 if (e1x
.op
== EXP
.error
)
12542 if (e1x
.type
== Type
.terror
)
12546 if (e2x
.op
== EXP
.error
)
12551 if (e2x
.type
== Type
.terror
)
12555 auto f0
= checkNonAssignmentArrayOp(exp
.econd
);
12556 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
12557 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
12558 if (f0 || f1 || f2
)
12561 Type t1
= exp
.e1
.type
;
12562 Type t2
= exp
.e2
.type
;
12564 // https://issues.dlang.org/show_bug.cgi?id=23767
12565 // `cast(void*) 0` should be treated as `null` so the ternary expression
12566 // gets the pointer type of the other branch
12567 if (sc
.flags
& SCOPE
.Cfile
)
12569 static void rewriteCNull(ref Expression e
, ref Type t
)
12571 if (!t
.isTypePointer())
12573 if (auto ie
= e
.optimize(WANTvalue
).isIntegerExp())
12575 if (ie
.getInteger() == 0)
12577 e
= new NullExp(e
.loc
, Type
.tnull
);
12582 rewriteCNull(exp
.e1
, t1
);
12583 rewriteCNull(exp
.e2
, t2
);
12586 if (t1
.ty
== Tnoreturn
)
12589 exp
.e1
= specialNoreturnCast(exp
.e1
, exp
.type
);
12591 else if (t2
.ty
== Tnoreturn
)
12594 exp
.e2
= specialNoreturnCast(exp
.e2
, exp
.type
);
12596 // If either operand is void the result is void, we have to cast both
12597 // the expression to void so that we explicitly discard the expression
12599 // https://issues.dlang.org/show_bug.cgi?id=16598
12600 else if (t1
.ty
== Tvoid || t2
.ty
== Tvoid
)
12602 exp
.type
= Type
.tvoid
;
12603 exp
.e1
= exp
.e1
.castTo(sc
, exp
.type
);
12604 exp
.e2
= exp
.e2
.castTo(sc
, exp
.type
);
12610 if (Expression ex
= typeCombine(exp
, sc
))
12616 switch (exp
.e1
.type
.toBasetype().ty
)
12621 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
);
12626 switch (exp
.e2
.type
.toBasetype().ty
)
12631 exp
.e1
= exp
.e1
.castTo(sc
, exp
.e2
.type
);
12636 if (exp
.type
.toBasetype().ty
== Tarray
)
12638 exp
.e1
= exp
.e1
.castTo(sc
, exp
.type
);
12639 exp
.e2
= exp
.e2
.castTo(sc
, exp
.type
);
12642 exp
.type
= exp
.type
.merge2();
12645 printf("res: %s\n", exp
.type
.toChars());
12646 printf("e1 : %s\n", exp
.e1
.type
.toChars());
12647 printf("e2 : %s\n", exp
.e2
.type
.toChars());
12650 /* https://issues.dlang.org/show_bug.cgi?id=14696
12651 * If either e1 or e2 contain temporaries which need dtor,
12652 * make them conditional.
12654 * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2)
12656 * (auto __cond = cond) ? (... __tmp1) : (... __tmp2)
12657 * and replace edtors of __tmp1 and __tmp2 with:
12658 * __tmp1.edtor --> __cond && __tmp1.dtor()
12659 * __tmp2.edtor --> __cond || __tmp2.dtor()
12666 override void visit(GenericExp exp
)
12668 static if (LOGSEMANTIC
)
12670 printf("GenericExp::semantic('%s')\n", exp
.toChars());
12672 // C11 6.5.1.1 Generic Selection
12674 auto ec
= exp
.cntlExp
.expressionSemantic(sc
).arrayFuncConv(sc
);
12675 bool errors
= ec
.isErrorExp() !is null;
12678 auto types
= (*exp
.types
)[];
12679 foreach (i
, ref t
; types
)
12682 continue; // `default:` case
12683 t
= t
.typeSemantic(ec
.loc
, sc
);
12684 if (t
.isTypeError())
12690 /* C11 6.5.1-2 duplicate check
12692 /* C11 distinguishes int, long, and long long. But D doesn't, so depending on the
12693 * C target, a long may have the same type as `int` in the D type system.
12694 * So, skip checks when this may be the case. Later pick the first match
12697 (t
.ty
== Tint32 || t
.ty
== Tuns32
) && target
.c
.longsize
== 4 ||
12698 (t
.ty
== Tint64 || t
.ty
== Tuns64
) && target
.c
.longsize
== 8 ||
12699 (t
.ty
== Tfloat64 || t
.ty
== Timaginary64 || t
.ty
== Tcomplex64
) && target
.c
.long_doublesize
== 8
12703 foreach (t2
; types
[0 .. i
])
12705 if (t2
&& t2
.equals(t
))
12707 error(ec
.loc
, "generic association type `%s` can only appear once", t
.toChars());
12714 auto exps
= (*exp
.exps
)[];
12715 foreach (ref e
; exps
)
12717 e
= e
.expressionSemantic(sc
);
12718 if (e
.isErrorExp())
12725 enum size_t None
= ~0;
12726 size_t imatch
= None
;
12727 size_t idefault
= None
;
12728 foreach (const i
, t
; types
)
12732 /* if tc is compatible with t, it's a match
12733 * C11 6.2.7 defines a compatible type as being the same type, including qualifiers
12737 assert(imatch
== None
);
12739 break; // pick first match
12743 idefault
= i
; // multiple defaults are not allowed, and are caught by cparse
12746 if (imatch
== None
)
12748 if (imatch
== None
)
12750 error(exp
.loc
, "no compatible generic association type for controlling expression type `%s`", tc
.toChars());
12754 result
= exps
[imatch
];
12757 override void visit(FileInitExp e
)
12759 //printf("FileInitExp::semantic()\n");
12760 e
.type
= Type
.tstring
;
12764 override void visit(LineInitExp e
)
12766 e
.type
= Type
.tint32
;
12770 override void visit(ModuleInitExp e
)
12772 //printf("ModuleInitExp::semantic()\n");
12773 e
.type
= Type
.tstring
;
12777 override void visit(FuncInitExp e
)
12779 //printf("FuncInitExp::semantic()\n");
12780 e
.type
= Type
.tstring
;
12783 result
= e
.resolveLoc(Loc
.initial
, sc
);
12789 override void visit(PrettyFuncInitExp e
)
12791 //printf("PrettyFuncInitExp::semantic()\n");
12792 e
.type
= Type
.tstring
;
12795 result
= e
.resolveLoc(Loc
.initial
, sc
);
12803 /**********************************
12804 * Try to run semantic routines.
12805 * If they fail, return NULL.
12807 Expression
trySemantic(Expression exp
, Scope
* sc
)
12809 //printf("+trySemantic(%s)\n", exp.toChars());
12810 uint errors
= global
.startGagging();
12811 Expression e
= expressionSemantic(exp
, sc
);
12812 if (global
.endGagging(errors
))
12816 //printf("-trySemantic(%s)\n", exp.toChars());
12820 /**************************
12821 * Helper function for easy error propagation.
12822 * If error occurs, returns ErrorExp. Otherwise returns NULL.
12824 Expression
unaSemantic(UnaExp e
, Scope
* sc
)
12826 static if (LOGSEMANTIC
)
12828 printf("UnaExp::semantic('%s')\n", e
.toChars());
12830 Expression e1x
= e
.e1
.expressionSemantic(sc
);
12831 if (e1x
.op
== EXP
.error
)
12837 /**************************
12838 * Helper function for easy error propagation.
12839 * If error occurs, returns ErrorExp. Otherwise returns NULL.
12841 Expression
binSemantic(BinExp e
, Scope
* sc
)
12843 static if (LOGSEMANTIC
)
12845 printf("BinExp::semantic('%s')\n", e
.toChars());
12847 Expression e1x
= e
.e1
.expressionSemantic(sc
);
12848 Expression e2x
= e
.e2
.expressionSemantic(sc
);
12850 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
12851 if (e1x
.op
== EXP
.type
)
12852 e1x
= resolveAliasThis(sc
, e1x
);
12853 if (e2x
.op
== EXP
.type
)
12854 e2x
= resolveAliasThis(sc
, e2x
);
12856 if (e1x
.op
== EXP
.error
)
12858 if (e2x
.op
== EXP
.error
)
12865 Expression
binSemanticProp(BinExp e
, Scope
* sc
)
12867 if (Expression ex
= binSemantic(e
, sc
))
12869 Expression e1x
= resolveProperties(sc
, e
.e1
);
12870 Expression e2x
= resolveProperties(sc
, e
.e2
);
12871 if (e1x
.op
== EXP
.error
)
12873 if (e2x
.op
== EXP
.error
)
12880 // entrypoint for semantic ExpressionSemanticVisitor
12881 extern (C
++) Expression
expressionSemantic(Expression e
, Scope
* sc
)
12883 scope v
= new ExpressionSemanticVisitor(sc
);
12888 private Expression
dotIdSemanticPropX(DotIdExp exp
, Scope
* sc
)
12890 //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars());
12891 if (Expression ex
= unaSemantic(exp
, sc
))
12894 if (!(sc
.flags
& SCOPE
.Cfile
) && exp
.ident
== Id
._mangleof
)
12898 // return mangleof as an Expression
12899 static Expression
dotMangleof(const ref Loc loc
, Scope
* sc
, Dsymbol
ds)
12902 if (auto f
= ds.isFuncDeclaration())
12904 if (f
.checkForwardRef(loc
))
12905 return ErrorExp
.get();
12907 if (f
.purityInprocess || f
.safetyInprocess || f
.nothrowInprocess || f
.nogcInprocess
)
12909 f
.error(loc
, "cannot retrieve its `.mangleof` while inferring attributes");
12910 return ErrorExp
.get();
12914 mangleToBuffer(ds, &buf
);
12915 Expression e
= new StringExp(loc
, buf
.extractSlice());
12916 return e
.expressionSemantic(sc
);
12922 case EXP
.scope_
: return dotMangleof(exp
.loc
, sc
, exp
.e1
.isScopeExp().sds
);
12923 case EXP
.variable
: return dotMangleof(exp
.loc
, sc
, exp
.e1
.isVarExp().var
);
12924 case EXP
.dotVariable
: return dotMangleof(exp
.loc
, sc
, exp
.e1
.isDotVarExp().var
);
12925 case EXP
.overloadSet
: return dotMangleof(exp
.loc
, sc
, exp
.e1
.isOverExp().vars
);
12926 case EXP
.template_
:
12928 TemplateExp te
= exp
.e1
.isTemplateExp();
12929 return dotMangleof(exp
.loc
, sc
, ds = te
.fd ? te
.fd
.isDsymbol() : te
.td
);
12937 if (exp
.e1
.isVarExp() && exp
.e1
.type
.toBasetype().isTypeSArray() && exp
.ident
== Id
.length
)
12939 // bypass checkPurity
12940 return exp
.e1
.type
.dotExp(sc
, exp
.e1
, exp
.ident
, cast(DotExpFlag
) (exp
.noderef
* DotExpFlag
.noDeref
));
12943 if (!exp
.e1
.isDotExp())
12945 exp
.e1
= resolvePropertiesX(sc
, exp
.e1
);
12948 if (auto te
= exp
.e1
.isTupleExp())
12950 if (exp
.ident
== Id
.offsetof
)
12952 /* 'distribute' the .offsetof to each of the tuple elements.
12954 auto exps
= new Expressions(te
.exps
.length
);
12955 foreach (i
, e
; (*te
.exps
)[])
12957 (*exps
)[i
] = new DotIdExp(e
.loc
, e
, Id
.offsetof
);
12959 // Don't evaluate te.e0 in runtime
12960 Expression e
= new TupleExp(exp
.loc
, null, exps
);
12961 e
= e
.expressionSemantic(sc
);
12964 if (exp
.ident
== Id
.length
)
12966 // Don't evaluate te.e0 in runtime
12967 return new IntegerExp(exp
.loc
, te
.exps
.length
, Type
.tsize_t
);
12971 // https://issues.dlang.org/show_bug.cgi?id=14416
12972 // Template has no built-in properties except for 'stringof'.
12973 if ((exp
.e1
.isDotTemplateExp() || exp
.e1
.isTemplateExp()) && exp
.ident
!= Id
.stringof
)
12975 exp
.error("template `%s` does not have property `%s`", exp
.e1
.toChars(), exp
.ident
.toChars());
12976 return ErrorExp
.get();
12980 exp
.error("expression `%s` does not have property `%s`", exp
.e1
.toChars(), exp
.ident
.toChars());
12981 return ErrorExp
.get();
12987 /******************************
12988 * Resolve properties, i.e. `e1.ident`, without seeing UFCS.
12990 * exp = expression to resolve
12992 * gag = do not emit error messages, just return `null`
12994 * resolved expression, null if error
12996 Expression
dotIdSemanticProp(DotIdExp exp
, Scope
* sc
, bool gag
)
12998 //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars());
13000 //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
13002 const cfile
= (sc
.flags
& SCOPE
.Cfile
) != 0;
13004 /* Special case: rewrite this.id and super.id
13005 * to be classtype.id and baseclasstype.id
13006 * if we have no this pointer.
13008 if ((exp
.e1
.isThisExp() || exp
.e1
.isSuperExp()) && !hasThis(sc
))
13010 if (AggregateDeclaration ad
= sc
.getStructClassScope())
13012 if (exp
.e1
.isThisExp())
13014 exp
.e1
= new TypeExp(exp
.e1
.loc
, ad
.type
);
13018 if (auto cd
= ad
.isClassDeclaration())
13021 exp
.e1
= new TypeExp(exp
.e1
.loc
, cd
.baseClass
.type
);
13028 Expression e
= dotIdSemanticPropX(exp
, sc
);
13035 if (auto de = exp
.e1
.isDotExp())
13046 Type t1b
= exp
.e1
.type
.toBasetype();
13048 if (auto ie
= eright
.isScopeExp()) // also used for template alias's
13050 auto flags
= SearchLocalsOnly
;
13051 /* Disable access to another module's private imports.
13052 * The check for 'is sds our current module' is because
13053 * the current module should have access to its own imports.
13055 if (ie
.sds
.isModule() && ie
.sds
!= sc
._module
)
13056 flags |
= IgnorePrivateImports
;
13057 if (sc
.flags
& SCOPE
.ignoresymbolvisibility
)
13058 flags |
= IgnoreSymbolVisibility
;
13059 Dsymbol s
= ie
.sds
.search(exp
.loc
, exp
.ident
, flags
);
13060 /* Check for visibility before resolving aliases because public
13061 * aliases to private symbols are public.
13063 if (s
&& !(sc
.flags
& SCOPE
.ignoresymbolvisibility
) && !symbolIsVisible(sc
._module
, s
))
13069 auto p
= s
.isPackage();
13070 if (p
&& checkAccess(sc
, p
))
13077 // if 's' is a tuple variable, the tuple is returned.
13080 exp
.checkDeprecated(sc
, s
);
13081 exp
.checkDisabled(sc
, s
);
13083 if (auto em
= s
.isEnumMember())
13085 return em
.getVarExp(exp
.loc
, sc
);
13087 if (auto v
= s
.isVarDeclaration())
13089 //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars());
13091 !v
.type
.deco
&& v
.inuse
)
13094 exp
.error("circular reference to %s `%s`", v
.kind(), v
.toPrettyChars());
13096 exp
.error("forward reference to %s `%s`", v
.kind(), v
.toPrettyChars());
13097 return ErrorExp
.get();
13099 if (v
.type
.isTypeError())
13100 return ErrorExp
.get();
13102 if ((v
.storage_class
& STC
.manifest
) && v
._init
&& !exp
.wantsym
)
13104 /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2().
13105 * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably
13106 * be reverted. `wantsym` is the hack to work around the problem.
13110 error(exp
.loc
, "circular initialization of %s `%s`", v
.kind(), v
.toPrettyChars());
13111 return ErrorExp
.get();
13113 auto e
= v
.expandInitializer(exp
.loc
);
13115 e
= e
.expressionSemantic(sc
);
13124 eleft
= new ThisExp(exp
.loc
);
13125 e
= new DotVarExp(exp
.loc
, eleft
, v
);
13126 e
= e
.expressionSemantic(sc
);
13130 e
= new VarExp(exp
.loc
, v
);
13133 e
= new CommaExp(exp
.loc
, eleft
, e
);
13138 return e
.expressionSemantic(sc
);
13141 if (auto f
= s
.isFuncDeclaration())
13143 //printf("it's a function\n");
13144 if (!f
.functionSemantic())
13145 return ErrorExp
.get();
13150 eleft
= new ThisExp(exp
.loc
);
13151 e
= new DotVarExp(exp
.loc
, eleft
, f
, true);
13152 e
= e
.expressionSemantic(sc
);
13156 e
= new VarExp(exp
.loc
, f
, true);
13159 e
= new CommaExp(exp
.loc
, eleft
, e
);
13165 if (auto td
= s
.isTemplateDeclaration())
13169 e
= new DotTemplateExp(exp
.loc
, eleft
, td
);
13171 e
= new TemplateExp(exp
.loc
, td
);
13172 e
= e
.expressionSemantic(sc
);
13175 if (OverDeclaration od
= s
.isOverDeclaration())
13177 Expression e
= new VarExp(exp
.loc
, od
, true);
13180 e
= new CommaExp(exp
.loc
, eleft
, e
);
13181 e
.type
= Type
.tvoid
; // ambiguous type?
13183 return e
.expressionSemantic(sc
);
13185 if (auto o
= s
.isOverloadSet())
13187 //printf("'%s' is an overload set\n", o.toChars());
13188 return new OverExp(exp
.loc
, o
);
13191 if (auto t
= s
.getType())
13193 return (new TypeExp(exp
.loc
, t
)).expressionSemantic(sc
);
13196 if (auto tup
= s
.isTupleDeclaration())
13200 Expression e
= new DotVarExp(exp
.loc
, eleft
, tup
);
13201 e
= e
.expressionSemantic(sc
);
13204 Expression e
= new TupleExp(exp
.loc
, tup
);
13205 e
= e
.expressionSemantic(sc
);
13209 if (auto sds
= s
.isScopeDsymbol())
13211 //printf("it's a ScopeDsymbol %s\n", ident.toChars());
13212 Expression e
= new ScopeExp(exp
.loc
, sds
);
13213 e
= e
.expressionSemantic(sc
);
13215 e
= new DotExp(exp
.loc
, eleft
, e
);
13219 if (auto imp
= s
.isImport())
13221 Expression se
= new ScopeExp(exp
.loc
, imp
.pkg
);
13222 return se
.expressionSemantic(sc
);
13225 if (auto attr
= s
.isAttribDeclaration())
13227 if (auto sm
= ie
.sds
.search(exp
.loc
, exp
.ident
, flags
))
13229 auto es
= new DsymbolExp(exp
.loc
, sm
);
13234 // BUG: handle other cases like in IdentifierExp::semantic()
13237 printf("s = %p '%s', kind = '%s'\n", s
, s
.toChars(), s
.kind());
13241 else if (exp
.ident
== Id
.stringof
)
13243 Expression e
= new StringExp(exp
.loc
, ie
.toString());
13244 e
= e
.expressionSemantic(sc
);
13247 if (ie
.sds
.isPackage() || ie
.sds
.isImport() || ie
.sds
.isModule())
13253 s
= ie
.sds
.search_correct(exp
.ident
);
13254 if (s
&& symbolIsVisible(sc
, s
))
13257 exp
.error("undefined identifier `%s` in %s `%s`, perhaps add `static import %s;`", exp
.ident
.toChars(), ie
.sds
.kind(), ie
.sds
.toPrettyChars(), s
.toPrettyChars());
13259 exp
.error("undefined identifier `%s` in %s `%s`, did you mean %s `%s`?", exp
.ident
.toChars(), ie
.sds
.kind(), ie
.sds
.toPrettyChars(), s
.kind(), s
.toChars());
13262 exp
.error("undefined identifier `%s` in %s `%s`", exp
.ident
.toChars(), ie
.sds
.kind(), ie
.sds
.toPrettyChars());
13263 return ErrorExp
.get();
13265 else if (t1b
.ty
== Tpointer
&& exp
.e1
.type
.ty
!= Tenum
&&
13267 exp
.ident
== Id
.__sizeof ||
13268 exp
.ident
== Id
.__xalignof ||
13270 (exp
.ident
== Id
._mangleof ||
13271 exp
.ident
== Id
.offsetof ||
13272 exp
.ident
== Id
._init ||
13273 exp
.ident
== Id
.stringof
)
13276 Type t1bn
= t1b
.nextOf();
13279 if (AggregateDeclaration ad
= isAggregate(t1bn
))
13281 if (!ad
.members
) // https://issues.dlang.org/show_bug.cgi?id=11312
13291 if (gag
&& t1bn
.ty
== Tvoid
)
13293 Expression e
= new PtrExp(exp
.loc
, exp
.e1
);
13294 e
= e
.expressionSemantic(sc
);
13295 const newFlag
= cast(DotExpFlag
) (gag
* DotExpFlag
.gag | exp
.noderef
* DotExpFlag
.noDeref
);
13296 return e
.type
.dotExp(sc
, e
, exp
.ident
, newFlag
);
13298 else if (exp
.ident
== Id
.__xalignof
&&
13299 exp
.e1
.isVarExp() &&
13300 exp
.e1
.isVarExp().var
.isVarDeclaration() &&
13301 !exp
.e1
.isVarExp().var
.isVarDeclaration().alignment
.isUnknown())
13303 // For `x.alignof` get the alignment of the variable, not the alignment of its type
13304 const explicitAlignment
= exp
.e1
.isVarExp().var
.isVarDeclaration().alignment
;
13305 const naturalAlignment
= exp
.e1
.type
.alignsize();
13306 const actualAlignment
= explicitAlignment
.isDefault() ? naturalAlignment
: explicitAlignment
.get();
13307 Expression e
= new IntegerExp(exp
.loc
, actualAlignment
, Type
.tsize_t
);
13310 else if ((exp
.ident
== Id
.max || exp
.ident
== Id
.min
) &&
13311 exp
.e1
.isVarExp() &&
13312 exp
.e1
.isVarExp().var
.isBitFieldDeclaration())
13314 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
13315 auto bf
= exp
.e1
.isVarExp().var
.isBitFieldDeclaration();
13316 return new IntegerExp(exp
.loc
, bf
.getMinMax(exp
.ident
), bf
.type
);
13318 else if ((exp
.ident
== Id
.max || exp
.ident
== Id
.min
) &&
13319 exp
.e1
.isDotVarExp() &&
13320 exp
.e1
.isDotVarExp().var
.isBitFieldDeclaration())
13322 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
13323 auto bf
= exp
.e1
.isDotVarExp().var
.isBitFieldDeclaration();
13324 return new IntegerExp(exp
.loc
, bf
.getMinMax(exp
.ident
), bf
.type
);
13328 if (exp
.e1
.isTypeExp() || exp
.e1
.isTemplateExp())
13331 const flag
= cast(DotExpFlag
) (exp
.noderef
* DotExpFlag
.noDeref | gag
* DotExpFlag
.gag
);
13333 Expression e
= exp
.e1
.type
.dotExp(sc
, exp
.e1
, exp
.ident
, flag
);
13336 e
= e
.expressionSemantic(sc
);
13343 * Resolve `e1.ident!tiargs` without seeing UFCS.
13345 * exp = the `DotTemplateInstanceExp` to resolve
13346 * sc = the semantic scope
13347 * gag = stop "not a property" error and return `null`.
13349 * `null` if error or not found, or the resolved expression.
13351 Expression
dotTemplateSemanticProp(DotTemplateInstanceExp exp
, Scope
* sc
, bool gag
)
13353 static if (LOGSEMANTIC
)
13355 printf("DotTemplateInstanceExpY::semantic('%s')\n", exp
.toChars());
13358 static Expression
errorExp()
13360 return ErrorExp
.get();
13363 Expression e1
= exp
.e1
;
13365 if (exp
.ti
.tempdecl
&& exp
.ti
.tempdecl
.parent
&& exp
.ti
.tempdecl
.parent
.isTemplateMixin())
13367 // if 'ti.tempdecl' happens to be found in a mixin template don't lose that info
13368 // and do the symbol search in that context (Issue: 19476)
13369 auto tm
= cast(TemplateMixin
)exp
.ti
.tempdecl
.parent
;
13370 e1
= new DotExp(exp
.e1
.loc
, exp
.e1
, new ScopeExp(tm
.loc
, tm
));
13373 auto die
= new DotIdExp(exp
.loc
, e1
, exp
.ti
.name
);
13375 Expression e
= die
.dotIdSemanticPropX(sc
);
13378 exp
.e1
= die
.e1
; // take back
13379 Type t1b
= exp
.e1
.type
.toBasetype();
13380 if (t1b
.ty
== Tarray || t1b
.ty
== Tsarray || t1b
.ty
== Taarray || t1b
.ty
== Tnull ||
(t1b
.isTypeBasic() && t1b
.ty
!= Tvoid
))
13382 /* No built-in type has templatized properties, so do shortcut.
13383 * It is necessary in: 1024.max!"a < b"
13388 e
= die
.dotIdSemanticProp(sc
, gag
);
13392 isDotOpDispatch(e
))
13394 /* opDispatch!tiargs would be a function template that needs IFTI,
13395 * so it's not a template
13403 if (e
.op
== EXP
.error
)
13405 if (DotVarExp dve
= e
.isDotVarExp())
13407 if (FuncDeclaration fd
= dve
.var
.isFuncDeclaration())
13409 if (TemplateDeclaration td
= fd
.findTemplateDeclRoot())
13411 e
= new DotTemplateExp(dve
.loc
, dve
.e1
, td
);
13412 e
= e
.expressionSemantic(sc
);
13415 else if (OverDeclaration od
= dve
.var
.isOverDeclaration())
13417 exp
.e1
= dve
.e1
; // pull semantic() result
13419 if (!exp
.findTempDecl(sc
))
13421 if (exp
.ti
.needsTypeInference(sc
))
13423 exp
.ti
.dsymbolSemantic(sc
);
13424 if (!exp
.ti
.inst || exp
.ti
.errors
) // if template failed to expand
13427 if (Declaration v
= exp
.ti
.toAlias().isDeclaration())
13429 if (v
.type
&& !v
.type
.deco
)
13430 v
.type
= v
.type
.typeSemantic(v
.loc
, sc
);
13431 return new DotVarExp(exp
.loc
, exp
.e1
, v
)
13432 .expressionSemantic(sc
);
13434 return new DotExp(exp
.loc
, exp
.e1
, new ScopeExp(exp
.loc
, exp
.ti
))
13435 .expressionSemantic(sc
);
13438 else if (e
.op
== EXP
.variable
)
13440 VarExp ve
= cast(VarExp
)e
;
13441 if (FuncDeclaration fd
= ve
.var
.isFuncDeclaration())
13443 if (TemplateDeclaration td
= fd
.findTemplateDeclRoot())
13445 e
= new TemplateExp(ve
.loc
, td
)
13446 .expressionSemantic(sc
);
13449 else if (OverDeclaration od
= ve
.var
.isOverDeclaration())
13451 exp
.ti
.tempdecl
= od
;
13452 return new ScopeExp(exp
.loc
, exp
.ti
)
13453 .expressionSemantic(sc
);
13457 if (DotTemplateExp dte
= e
.isDotTemplateExp())
13459 exp
.e1
= dte
.e1
; // pull semantic() result
13461 exp
.ti
.tempdecl
= dte
.td
;
13462 if (!exp
.ti
.semanticTiargs(sc
))
13464 if (exp
.ti
.needsTypeInference(sc
))
13466 exp
.ti
.dsymbolSemantic(sc
);
13467 if (!exp
.ti
.inst || exp
.ti
.errors
) // if template failed to expand
13470 if (Declaration v
= exp
.ti
.toAlias().isDeclaration())
13472 return new DotVarExp(exp
.loc
, exp
.e1
, v
)
13473 .expressionSemantic(sc
);
13475 return new DotExp(exp
.loc
, exp
.e1
, new ScopeExp(exp
.loc
, exp
.ti
))
13476 .expressionSemantic(sc
);
13478 else if (e
.op
== EXP
.template_
)
13480 exp
.ti
.tempdecl
= (cast(TemplateExp
)e
).td
;
13481 return new ScopeExp(exp
.loc
, exp
.ti
)
13482 .expressionSemantic(sc
);
13484 else if (DotExp
de = e
.isDotExp())
13486 if (de.e2
.op
== EXP
.overloadSet
)
13488 if (!exp
.findTempDecl(sc
) ||
!exp
.ti
.semanticTiargs(sc
))
13492 if (exp
.ti
.needsTypeInference(sc
))
13494 exp
.ti
.dsymbolSemantic(sc
);
13495 if (!exp
.ti
.inst || exp
.ti
.errors
) // if template failed to expand
13498 if (Declaration v
= exp
.ti
.toAlias().isDeclaration())
13500 if (v
.type
&& !v
.type
.deco
)
13501 v
.type
= v
.type
.typeSemantic(v
.loc
, sc
);
13502 return new DotVarExp(exp
.loc
, exp
.e1
, v
)
13503 .expressionSemantic(sc
);
13505 return new DotExp(exp
.loc
, exp
.e1
, new ScopeExp(exp
.loc
, exp
.ti
))
13506 .expressionSemantic(sc
);
13509 else if (OverExp oe
= e
.isOverExp())
13511 exp
.ti
.tempdecl
= oe
.vars
;
13512 return new ScopeExp(exp
.loc
, exp
.ti
)
13513 .expressionSemantic(sc
);
13517 exp
.error("`%s` isn't a template", e
.toChars());
13521 /***************************************
13522 * If expression is shared, check that we can access it.
13523 * Give error message if not.
13526 * e = expression to check
13528 * returnRef = Whether this expression is for a `return` statement
13529 * off a `ref` function, in which case a single level
13530 * of dereference is allowed (e.g. `shared(int)*`).
13534 bool checkSharedAccess(Expression e
, Scope
* sc
, bool returnRef
= false)
13536 if (global
.params
.noSharedAccess
!= FeatureState
.enabled ||
13539 sc
.flags
& SCOPE
.ctfe
)
13544 //printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef);
13546 bool check(Expression e
, bool allowRef
)
13548 bool sharedError(Expression e
)
13550 // https://dlang.org/phobos/core_atomic.html
13551 e
.error("direct access to shared `%s` is not allowed, see `core.atomic`", e
.toChars());
13555 // Error by default
13556 bool visit(Expression e
)
13558 // https://issues.dlang.org/show_bug.cgi?id=23639
13559 // Should be able to cast(shared)
13560 if (!e
.isCastExp() && e
.type
.isShared())
13561 return sharedError(e
);
13565 bool visitNew(NewExp e
)
13568 check(e
.thisexp
, false);
13572 bool visitVar(VarExp e
)
13574 // https://issues.dlang.org/show_bug.cgi?id=20908
13575 // direct access to init symbols is ok as they
13576 // cannot be modified.
13577 if (e
.var
.isSymbolDeclaration())
13580 // https://issues.dlang.org/show_bug.cgi?id=22626
13581 // Synchronized functions don't need to use core.atomic
13582 // when accessing `this`.
13583 if (sc
.func
&& sc
.func
.isSynchronized())
13585 if (e
.var
.isThisDeclaration())
13588 return sharedError(e
);
13590 else if (!allowRef
&& e
.var
.type
.isShared())
13591 return sharedError(e
);
13596 bool visitAddr(AddrExp e
)
13598 return check(e
.e1
, true);
13601 bool visitPtr(PtrExp e
)
13603 if (!allowRef
&& e
.type
.isShared())
13604 return sharedError(e
);
13606 if (e
.e1
.type
.isShared())
13607 return sharedError(e
);
13609 return check(e
.e1
, false);
13612 bool visitDotVar(DotVarExp e
)
13614 //printf("dotvarexp = %s\n", e.toChars());
13615 if (e
.type
.isShared())
13617 if (e
.e1
.isThisExp())
13619 // https://issues.dlang.org/show_bug.cgi?id=22626
13620 if (sc
.func
&& sc
.func
.isSynchronized())
13623 // https://issues.dlang.org/show_bug.cgi?id=23790
13624 if (e
.e1
.type
.isTypeStruct())
13628 auto fd
= e
.var
.isFuncDeclaration();
13629 const sharedFunc
= fd
&& fd
.type
.isShared
;
13630 if (!allowRef
&& !sharedFunc
)
13631 return sharedError(e
);
13633 // Allow using `DotVarExp` within value types
13634 if (e
.e1
.type
.isTypeSArray() || e
.e1
.type
.isTypeStruct())
13635 return check(e
.e1
, allowRef
);
13637 // If we end up with a single `VarExp`, it might be a `ref` param
13638 // `shared ref T` param == `shared(T)*`.
13639 if (auto ve
= e
.e1
.isVarExp())
13641 return check(e
.e1
, allowRef
&& (ve
.var
.storage_class
& STC
.ref_
));
13644 return sharedError(e
);
13647 return check(e
.e1
, false);
13650 bool visitIndex(IndexExp e
)
13652 if (!allowRef
&& e
.type
.isShared())
13653 return sharedError(e
);
13655 if (e
.e1
.type
.isShared())
13656 return sharedError(e
);
13658 return check(e
.e1
, false);
13661 bool visitComma(CommaExp e
)
13663 // Cannot be `return ref` since we can't use the return,
13664 // but it's better to show that error than an unrelated `shared` one
13665 return check(e
.e2
, true);
13670 default: return visit(e
);
13672 // Those have no indirections / can be ignored
13675 case EXP
.complex80
:
13677 case EXP
.null_
: return false;
13679 case EXP
.variable
: return visitVar(e
.isVarExp());
13680 case EXP
.new_
: return visitNew(e
.isNewExp());
13681 case EXP
.address
: return visitAddr(e
.isAddrExp());
13682 case EXP
.star
: return visitPtr(e
.isPtrExp());
13683 case EXP
.dotVariable
: return visitDotVar(e
.isDotVarExp());
13684 case EXP
.index
: return visitIndex(e
.isIndexExp());
13688 return check(e
, returnRef
);
13693 /****************************************************
13694 * Determine if `exp`, which gets its address taken, can do so safely.
13697 * exp = expression having its address taken
13698 * v = the variable getting its address taken
13700 * `true` if ok, `false` for error
13702 bool checkAddressVar(Scope
* sc
, Expression exp
, VarDeclaration v
)
13704 //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars());
13708 if (!v
.canTakeAddressOf())
13710 exp
.error("cannot take address of `%s`", exp
.toChars());
13713 if (sc
.func
&& !sc
.intypeof
&& !v
.isDataseg())
13715 if (global
.params
.useDIP1000
!= FeatureState
.enabled
&&
13716 !(v
.storage_class
& STC
.temp
) &&
13717 sc
.setUnsafe(false, exp
.loc
, "cannot take address of local `%s` in `@safe` function `%s`", v
, sc
.func
))
13725 /**************************************
13726 * This check ensures that the object in `exp` can have its address taken, or
13727 * issue a diagnostic error.
13729 * e = expression to check
13732 * true if the expression is addressable
13734 bool checkAddressable(Expression e
, Scope
* sc
)
13741 case EXP
.dotVariable
:
13742 // https://issues.dlang.org/show_bug.cgi?id=22749
13743 // Error about taking address of any bit-field, regardless of
13744 // whether SCOPE.Cfile is set.
13745 if (auto bf
= ex
.isDotVarExp().var
.isBitFieldDeclaration())
13747 e
.error("cannot take address of bit-field `%s`", bf
.toChars());
13750 goto case EXP
.cast_
;
13753 ex
= ex
.isBinExp().e1
;
13759 ex
= ex
.isUnaExp().e1
;
13763 if (sc
.flags
& SCOPE
.Cfile
)
13765 // C11 6.5.3.2: A variable that has its address taken cannot be
13766 // stored in a register.
13767 // C11 6.3.2.1: An array that has its address computed with `[]`
13768 // or cast to an lvalue pointer cannot be stored in a register.
13769 if (ex
.isVarExp().var
.storage_class
& STC
.register
)
13771 if (e
.isIndexExp())
13772 e
.error("cannot index through register variable `%s`", ex
.toChars());
13774 e
.error("cannot take address of register variable `%s`", ex
.toChars());
13789 /*******************************
13790 * Checks the attributes of a function.
13791 * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`)
13792 * and usage of `deprecated` and `@disabled`-ed symbols are checked.
13795 * exp = expression to check attributes for
13796 * sc = scope of the function
13797 * f = function to be checked
13798 * Returns: `true` if error occur.
13800 private bool checkFunctionAttributes(Expression exp
, Scope
* sc
, FuncDeclaration f
)
13804 bool error
= checkDisabled(sc
, f
);
13805 error |
= checkDeprecated(sc
, f
);
13806 error |
= checkPurity(sc
, f
);
13807 error |
= checkSafety(sc
, f
);
13808 error |
= checkNogc(sc
, f
);
13813 /*******************************
13814 * Helper function for `getRightThis()`.
13815 * Gets `this` of the next outer aggregate.
13817 * loc = location to use for error messages
13819 * s = the parent symbol of the existing `this`
13820 * ad = struct or class we need the correct `this` for
13821 * e1 = existing `this`
13822 * t = type of the existing `this`
13823 * var = the specific member of ad we're accessing
13824 * flag = if true, return `null` instead of throwing an error
13826 * Expression representing the `this` for the var
13828 Expression
getThisSkipNestedFuncs(const ref Loc loc
, Scope
* sc
, Dsymbol s
, AggregateDeclaration ad
, Expression e1
, Type t
, Dsymbol var
, bool flag
= false)
13831 while (s
&& s
.isFuncDeclaration())
13833 FuncDeclaration f
= s
.isFuncDeclaration();
13837 e1
= new VarExp(loc
, f
.vthis
);
13838 if (f
.hasDualContext())
13842 e1
= e1
.expressionSemantic(sc
);
13843 e1
= new PtrExp(loc
, e1
);
13844 uint i
= f
.followInstantiationContext(ad
);
13845 e1
= new IndexExp(loc
, e1
, new IntegerExp(i
));
13846 s
= f
.toParentP(ad
);
13854 e1
.error("need `this` of type `%s` to access member `%s` from static function `%s`", ad
.toChars(), var
.toChars(), f
.toChars());
13855 e1
= ErrorExp
.get();
13860 if (n
> 1 || e1
.op
== EXP
.index
)
13861 e1
= e1
.expressionSemantic(sc
);
13862 if (s
&& e1
.type
.equivalent(Type
.tvoidptr
))
13864 if (auto sad
= s
.isAggregateDeclaration())
13866 Type ta
= sad
.handleType();
13867 if (ta
.ty
== Tstruct
)
13868 ta
= ta
.pointerTo();
13872 e1
.type
= e1
.type
.addMod(t
.mod
);
13876 /*******************************
13877 * Make a dual-context container for use as a `this` argument.
13879 * loc = location to use for error messages
13880 * sc = current scope
13881 * fd = target function that will take the `this` argument
13883 * Temporary closure variable.
13885 * The function `fd` is added to the nested references of the
13886 * newly created variable such that a closure is made for the variable when
13887 * the address of `fd` is taken.
13889 VarDeclaration
makeThis2Argument(const ref Loc loc
, Scope
* sc
, FuncDeclaration fd
)
13891 Type tthis2
= Type
.tvoidptr
.sarrayOf(2);
13892 VarDeclaration vthis2
= new VarDeclaration(loc
, tthis2
, Identifier
.generateId("__this"), null);
13893 vthis2
.storage_class |
= STC
.temp
;
13894 vthis2
.dsymbolSemantic(sc
);
13895 vthis2
.parent
= sc
.parent
;
13896 // make it a closure var
13898 sc
.func
.closureVars
.push(vthis2
);
13899 // add `fd` to the nested refs
13900 vthis2
.nestedrefs
.push(fd
);
13904 /*******************************
13905 * Make sure that the runtime hook `id` exists.
13907 * loc = location to use for error messages
13908 * sc = current scope
13909 * id = the hook identifier
13910 * description = what the hook does
13911 * module_ = what module the hook is located in
13913 * a `bool` indicating if the hook is present.
13915 bool verifyHookExist(const ref Loc loc
, ref Scope sc
, Identifier id
, string description
, Identifier module_
= Id
.object
)
13917 auto rootSymbol
= sc
.search(loc
, Id
.empty
, null);
13918 if (auto moduleSymbol
= rootSymbol
.search(loc
, module_
))
13919 if (moduleSymbol
.search(loc
, id
))
13921 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
);
13925 /***************************************
13926 * Fit elements[] to the corresponding types of the `sd`'s fields.
13929 * sd = the struct declaration
13930 * loc = location to use for error messages
13932 * elements = explicit arguments used to construct object
13933 * stype = the constructed object type.
13935 * false if any errors occur,
13936 * otherwise true and elements[] are rewritten for the output.
13938 private bool fit(StructDeclaration sd
, const ref Loc loc
, Scope
* sc
, Expressions
* elements
, Type stype
)
13943 const nfields
= sd
.nonHiddenFields();
13945 for (size_t i
= 0; i
< elements
.length
; i
++)
13947 Expression e
= (*elements
)[i
];
13951 e
= resolveProperties(sc
, e
);
13954 if (i
< sd
.fields
.length
&& e
.op
== EXP
.null_
)
13956 // CTFE sometimes creates null as hidden pointer; we'll allow this.
13959 .error(loc
, "more initializers than fields (%llu) of `%s`", cast(ulong)nfields
, sd
.toChars());
13962 VarDeclaration v
= sd
.fields
[i
];
13963 if (v
.offset
< offset
)
13965 .error(loc
, "overlapping initialization for `%s`", v
.toChars());
13966 if (!sd
.isUnionDeclaration())
13968 enum errorMsg
= "`struct` initializers that contain anonymous unions" ~
13969 " must initialize only the first member of a `union`. All subsequent" ~
13970 " non-overlapping fields are default initialized";
13971 .errorSupplemental(loc
, errorMsg
);
13975 const vsize
= v
.type
.size();
13976 if (vsize
== SIZE_INVALID
)
13978 offset
= cast(uint)(v
.offset
+ vsize
);
13982 t
= t
.addMod(stype
.mod
);
13984 Type tb
= t
.toBasetype();
13986 const hasPointers
= tb
.hasPointers();
13989 if ((!stype
.alignment
.isDefault() && stype
.alignment
.get() < target
.ptrsize ||
13990 (v
.offset
& (target
.ptrsize
- 1))) &&
13991 (sc
.setUnsafe(false, loc
,
13992 "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd
, v
)))
13998 /* Look for case of initializing a static array with a too-short
13999 * string literal, such as:
14000 * char[5] foo = "abc";
14001 * Allow this by doing an explicit cast, which will lengthen the string
14004 if (e
.op
== EXP
.string_
&& tb
.ty
== Tsarray
)
14006 StringExp se
= cast(StringExp
)e
;
14007 Type typeb
= se
.type
.toBasetype();
14008 TY tynto
= tb
.nextOf().ty
;
14009 if (!se
.committed
&&
14010 (typeb
.ty
== Tarray || typeb
.ty
== Tsarray
) && tynto
.isSomeChar
&&
14011 se
.numberOfCodeUnits(tynto
) < (cast(TypeSArray
)tb
).dim
.toInteger())
14013 e
= se
.castTo(sc
, t
);
14018 while (!e
.implicitConvTo(t
) && tb
.ty
== Tsarray
)
14020 /* Static array initialization, as in:
14024 tb
= t
.toBasetype();
14026 if (!e
.implicitConvTo(t
))
14027 t
= origType
; // restore type for better diagnostic
14029 e
= e
.implicitCastTo(sc
, t
);
14031 if (e
.op
== EXP
.error
)
14034 (*elements
)[i
] = doCopyOrMove(sc
, e
);
14041 * Returns `em` as a VariableExp
14043 * em = the EnumMember to wrap
14044 * loc = location of use of em
14045 * sc = scope of use of em
14047 * VarExp referenceing `em` or ErrorExp if `em` if disabled/deprecated
14049 Expression
getVarExp(EnumMember em
, const ref Loc loc
, Scope
* sc
)
14051 dsymbolSemantic(em
, sc
);
14053 return ErrorExp
.get();
14054 em
.checkDisabled(loc
, sc
);
14056 if (em
.depdecl
&& !em
.depdecl
._scope
)
14057 em
.depdecl
._scope
= sc
;
14058 em
.checkDeprecated(loc
, sc
);
14061 return ErrorExp
.get();
14062 Expression e
= new VarExp(loc
, em
);
14063 e
= e
.expressionSemantic(sc
);
14064 if (!(sc
.flags
& SCOPE
.Cfile
) && em
.isCsymbol())
14066 /* C11 types them as int. But if in D file,
14067 * type qualified names as the enum
14069 e
.type
= em
.parent
.isEnumDeclaration().type
;
14076 /*****************************
14077 * Try to treat `exp` as a boolean,
14079 * exp = the expression
14080 * sc = scope to evalute `exp` in
14082 * Modified expression on success, ErrorExp on error
14084 Expression
toBoolean(Expression exp
, Scope
* sc
)
14089 exp
.error("`delete` does not give a boolean result");
14090 return ErrorExp
.get();
14093 auto ce
= exp
.isCommaExp();
14094 auto ex2
= ce
.e2
.toBoolean(sc
);
14095 if (ex2
.op
== EXP
.error
)
14098 ce
.type
= ce
.e2
.type
;
14102 case EXP
.construct
:
14104 case EXP
.loweredAssignExp
:
14105 if (sc
.flags
& SCOPE
.Cfile
)
14109 // are usually mistakes.
14110 exp
.error("assignment cannot be used as a condition, perhaps `==` was meant?");
14111 return ErrorExp
.get();
14116 auto le
= exp
.isLogicalExp();
14117 auto ex2
= le
.e2
.toBoolean(sc
);
14118 if (ex2
.op
== EXP
.error
)
14124 auto ce
= exp
.isCondExp();
14125 auto ex1
= ce
.e1
.toBoolean(sc
);
14126 auto ex2
= ce
.e2
.toBoolean(sc
);
14127 if (ex1
.op
== EXP
.error
)
14129 if (ex2
.op
== EXP
.error
)
14137 // Default is 'yes' - do nothing
14138 Expression e
= arrayFuncConv(exp
, sc
);
14140 Type tb
= t
.toBasetype();
14145 // Structs can be converted to bool using opCast(bool)()
14146 if (auto ts
= tb
.isTypeStruct())
14148 AggregateDeclaration ad
= ts
.sym
;
14149 /* Don't really need to check for opCast first, but by doing so we
14150 * get better error messages if it isn't there.
14152 if (Dsymbol fd
= search_function(ad
, Id
._cast
))
14154 e
= new CastExp(exp
.loc
, e
, Type
.tbool
);
14155 e
= e
.expressionSemantic(sc
);
14159 // Forward to aliasthis.
14160 if (ad
.aliasthis
&& !isRecursiveAliasThis(att
, tb
))
14162 e
= resolveAliasThis(sc
, e
);
14164 tb
= e
.type
.toBasetype();
14171 if (!t
.isBoolean())
14173 if (tb
!= Type
.terror
)
14174 exp
.error("expression `%s` of type `%s` does not have a boolean value",
14175 exp
.toChars(), t
.toChars());
14176 return ErrorExp
.get();