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 error(exp
.loc
, "`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 error(ae
.loc
, "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 error(ae
.loc
, "`%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 error(ae
.loc
, "`%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 * check e is exp.opDispatch!(tiargs) or not
487 * It's used to switch to UFCS the semantic analysis path
489 private bool isDotOpDispatch(Expression e
)
491 if (auto dtie
= e
.isDotTemplateInstanceExp())
492 return dtie
.ti
.name
== Id
.opDispatch
;
497 /******************************
498 * Pull out callable entity with UFCS.
500 private Expression
resolveUFCS(Scope
* sc
, CallExp ce
)
506 if (auto die
= ce
.e1
.isDotIdExp())
508 Identifier ident
= die
.ident
;
510 Expression ex
= die
.dotIdSemanticPropX(sc
);
518 Type t
= eleft
.type
.toBasetype();
519 if (t
.ty
== Tarray || t
.ty
== Tsarray || t
.ty
== Tnull ||
(t
.isTypeBasic() && t
.ty
!= Tvoid
))
521 /* Built-in types and arrays have no callable properties, so do shortcut.
522 * It is necessary in: e.init()
525 else if (t
.ty
== Taarray
)
527 if (ident
== Id
.remove
)
530 * aa.remove(arg) into delete aa[arg]
532 if (!ce
.arguments || ce
.arguments
.length
!= 1)
534 error(ce
.loc
, "expected key as argument to `aa.remove()`");
535 return ErrorExp
.get();
537 if (!eleft
.type
.isMutable())
539 error(ce
.loc
, "cannot remove key from `%s` associative array `%s`", MODtoChars(t
.mod
), eleft
.toChars());
540 return ErrorExp
.get();
542 Expression key
= (*ce
.arguments
)[0];
543 key
= key
.expressionSemantic(sc
);
544 key
= resolveProperties(sc
, key
);
546 TypeAArray taa
= t
.isTypeAArray();
547 key
= key
.implicitCastTo(sc
, taa
.index
);
549 if (key
.checkValue() || key
.checkSharedAccess(sc
))
550 return ErrorExp
.get();
552 semanticTypeInfo(sc
, taa
.index
);
554 return new RemoveExp(loc
, eleft
, key
);
559 if (Expression ey
= die
.dotIdSemanticProp(sc
, 1))
561 if (ey
.op
== EXP
.error
)
564 if (isDotOpDispatch(ey
))
566 // even opDispatch and UFCS must have valid arguments,
567 // so now that we've seen indication of a problem,
568 // check them for issues.
569 Expressions
* originalArguments
= Expression
.arraySyntaxCopy(ce
.arguments
);
571 uint errors
= global
.startGagging();
572 e
= ce
.expressionSemantic(sc
);
573 if (!global
.endGagging(errors
))
576 if (arrayExpressionSemantic(originalArguments
.peekSlice(), sc
))
577 return ErrorExp
.get();
579 /* fall down to UFCS */
586 /* https://issues.dlang.org/show_bug.cgi?id=13953
588 * If a struct has an alias this to an associative array
589 * and remove is used on a struct instance, we have to
590 * check first if there is a remove function that can be called
591 * on the struct. If not we must check the alias this.
605 const errors
= global
.startGagging();
606 e
= searchUFCS(sc
, die
, ident
);
607 // if there were any errors and the identifier was remove
608 if (global
.endGagging(errors
))
610 if (ident
== Id
.remove
)
613 Expression alias_e
= resolveAliasThis(sc
, die
.e1
, 1);
614 if (alias_e
&& alias_e
!= die
.e1
)
617 CallExp ce2
= ce
.syntaxCopy();
619 e
= ce2
.isCallExp().trySemantic(sc
);
624 // if alias this did not work out, print the initial errors
625 searchUFCS(sc
, die
, ident
);
628 else if (auto dti
= ce
.e1
.isDotTemplateInstanceExp())
630 if (Expression ey
= dti
.dotTemplateSemanticProp(sc
, DotExpFlag
.gag
))
636 e
= searchUFCS(sc
, dti
, dti
.ti
.name
);
644 ce
.arguments
= new Expressions();
645 ce
.arguments
.shift(eleft
);
647 ce
.names
= new Identifiers();
648 ce
.names
.shift(null);
649 ce
.isUfcsRewrite
= true;
653 int expandAliasThisTuples(Expressions
* exps
, size_t starti
= 0)
655 if (!exps || exps
.length
== 0)
658 for (size_t u
= starti
; u
< exps
.length
; u
++)
660 Expression exp
= (*exps
)[u
];
661 if (TupleDeclaration td
= exp
.isAliasThisTuple
)
667 auto d
= s
.isDeclaration();
668 auto e
= new DotVarExp(exp
.loc
, exp
, d
);
671 exps
.insert(u
+ i
, e
);
676 printf("expansion ->\n");
679 printf("\texps[%d] e = %s %s\n", i
, EXPtoString(e
.op
), e
.toChars());
688 /******************************
689 * Pull out property with UFCS.
691 private Expression
resolveUFCSProperties(Scope
* sc
, Expression e1
, Expression e2
= null)
697 if (auto die
= e1
.isDotIdExp())
700 e
= searchUFCS(sc
, die
, die
.ident
);
702 else if (auto dti
= e1
.isDotTemplateInstanceExp())
705 e
= searchUFCS(sc
, dti
, dti
.ti
.name
);
716 // run semantic without gagging
717 e2
= e2
.expressionSemantic(sc
);
721 Expression ex
= e
.copy();
722 auto a1
= new Expressions(1);
724 ex
= new CallExp(loc
, ex
, a1
);
725 auto e1PassSemantic
= ex
.trySemantic(sc
);
729 auto a2
= new Expressions(2);
732 e
= new CallExp(loc
, e
, a2
);
733 e
= e
.trySemantic(sc
);
734 if (!e1PassSemantic
&& !e
)
736 /* https://issues.dlang.org/show_bug.cgi?id=20448
738 * If both versions have failed to pass semantic,
739 * f(e1) = e2 gets priority in error printing
740 * because f might be a templated function that
741 * failed to instantiate and we have to print
742 * the instantiation errors.
744 return e1
.expressionSemantic(sc
);
748 ex
= new AssignExp(loc
, ex
, e2
);
749 return ex
.expressionSemantic(sc
);
753 // strict setter prints errors if fails
754 e
= e
.expressionSemantic(sc
);
762 auto arguments
= new Expressions(1);
763 (*arguments
)[0] = eleft
;
764 e
= new CallExp(loc
, e
, arguments
);
766 // https://issues.dlang.org/show_bug.cgi?id=24017
767 if (sc
.flags
& SCOPE
.debug_
)
768 e
.isCallExp().inDebugStatement
= true;
770 e
= e
.expressionSemantic(sc
);
775 /******************************
776 * If e1 is a property function (template), resolve it.
778 Expression
resolvePropertiesOnly(Scope
* sc
, Expression e1
)
780 //printf("e1 = %s %s\n", Token.toChars(e1.op), e1.toChars());
782 Expression
handleOverloadSet(OverloadSet os
)
787 auto fd
= s
.isFuncDeclaration();
788 auto td
= s
.isTemplateDeclaration();
791 if (fd
.type
.isTypeFunction().isproperty
)
792 return resolveProperties(sc
, e1
);
794 else if (td
&& td
.onemember
&& (fd
= td
.onemember
.isFuncDeclaration()) !is null)
796 if (fd
.type
.isTypeFunction().isproperty ||
797 (fd
.storage_class2
& STC
.property
) ||
798 (td
._scope
.stc & STC
.property
))
799 return resolveProperties(sc
, e1
);
805 Expression
handleTemplateDecl(TemplateDeclaration td
)
810 if (auto fd
= td
.onemember
.isFuncDeclaration())
812 if (fd
.type
.isTypeFunction().isproperty ||
813 (fd
.storage_class2
& STC
.property
) ||
814 (td
._scope
.stc & STC
.property
))
815 return resolveProperties(sc
, e1
);
821 Expression
handleFuncDecl(FuncDeclaration fd
)
824 if (fd
.type
.isTypeFunction().isproperty
)
825 return resolveProperties(sc
, e1
);
829 if (auto de = e1
.isDotExp())
831 if (auto os
= de.e2
.isOverExp())
832 return handleOverloadSet(os
.vars
);
834 else if (auto oe
= e1
.isOverExp())
835 return handleOverloadSet(oe
.vars
);
836 else if (auto dti
= e1
.isDotTemplateInstanceExp())
839 if (auto td
= dti
.ti
.tempdecl
.isTemplateDeclaration())
840 return handleTemplateDecl(td
);
842 else if (auto dte
= e1
.isDotTemplateExp())
843 return handleTemplateDecl(dte
.td
);
844 else if (auto se
= e1
.isScopeExp())
847 TemplateInstance ti
= s
.isTemplateInstance();
848 if (ti
&& !ti
.semanticRun
&& ti
.tempdecl
)
849 if (auto td
= ti
.tempdecl
.isTemplateDeclaration())
850 return handleTemplateDecl(td
);
852 else if (auto et
= e1
.isTemplateExp())
853 return handleTemplateDecl(et
.td
);
854 else if (e1
.isDotVarExp() && e1
.type
.isTypeFunction())
856 DotVarExp dve
= e1
.isDotVarExp();
857 return handleFuncDecl(dve
.var
.isFuncDeclaration());
859 else if (e1
.isVarExp() && e1
.type
&& e1
.type
.isTypeFunction() && (sc
.intypeof ||
!e1
.isVarExp().var
.needThis()))
860 return handleFuncDecl(e1
.isVarExp().var
.isFuncDeclaration());
864 /****************************************
865 * Turn symbol `s` into the expression it represents.
868 * s = symbol to resolve
869 * loc = location of use of `s`
871 * hasOverloads = applies if `s` represents a function.
872 * true means it's overloaded and will be resolved later,
873 * false means it's the exact function symbol.
875 * `s` turned into an expression, `ErrorExp` if an error occurred
877 Expression
symbolToExp(Dsymbol s
, const ref Loc loc
, Scope
*sc
, bool hasOverloads
)
879 static if (LOGSEMANTIC
)
881 printf("DsymbolExp::resolve(%s %s)\n", s
.kind(), s
.toChars());
887 //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars());
888 //printf("s = '%s', s.kind = '%s'\n", s.toChars(), s.kind());
890 Declaration d
= s
.isDeclaration();
891 if (d
&& (d
.storage_class
& STC
.templateparameter
))
897 // functions are checked after overloading
898 // templates are checked after matching constraints
899 if (!s
.isFuncDeclaration() && !s
.isTemplateDeclaration())
901 s
.checkDeprecated(loc
, sc
);
903 d
.checkDisabled(loc
, sc
);
906 // https://issues.dlang.org/show_bug.cgi?id=12023
907 // if 's' is a tuple variable, the tuple is returned.
910 //printf("s = '%s', s.kind = '%s', s.needThis() = %p\n", s.toChars(), s.kind(), s.needThis());
911 if (s
!= olds
&& !s
.isFuncDeclaration() && !s
.isTemplateDeclaration())
913 s
.checkDeprecated(loc
, sc
);
915 d
.checkDisabled(loc
, sc
);
918 if (auto sd
= s
.isDeclaration())
922 if (sc
.setUnsafePreview(global
.params
.systemVariables
, false, loc
,
923 "cannot access `@system` variable `%s` in @safe code", sd
))
925 if (auto v
= sd
.isVarDeclaration())
927 if (v
.systemInferred
)
928 errorSupplemental(v
.loc
, "`%s` is inferred to be `@system` from its initializer here", v
.toChars());
930 errorSupplemental(v
.loc
, "`%s` is declared here", v
.toChars());
932 return ErrorExp
.get();
938 if (auto em
= s
.isEnumMember())
940 return em
.getVarExp(loc
, sc
);
942 if (auto v
= s
.isVarDeclaration())
944 //printf("Identifier '%s' is a variable, type '%s'\n", s.toChars(), v.type.toChars());
945 if (sc
.intypeof
== 1 && !v
.inuse
)
946 v
.dsymbolSemantic(sc
);
947 if (!v
.type ||
// during variable type inference
948 !v
.type
.deco
&& v
.inuse
) // during variable type semantic
950 if (v
.inuse
) // variable type depends on the variable itself
951 error(loc
, "circular reference to %s `%s`", v
.kind(), v
.toPrettyChars());
952 else // variable type cannot be determined
953 error(loc
, "forward reference to %s `%s`", v
.kind(), v
.toPrettyChars());
954 return ErrorExp
.get();
956 if (v
.type
.ty
== Terror
)
957 return ErrorExp
.get();
959 if ((v
.storage_class
& STC
.manifest
) && v
._init
)
963 error(loc
, "circular initialization of %s `%s`", v
.kind(), v
.toPrettyChars());
964 return ErrorExp
.get();
966 e
= v
.expandInitializer(loc
);
968 e
= e
.expressionSemantic(sc
);
973 // We need to run semantics to correctly set 'STC.field' if it is a member variable
974 // that could be forward referenced. This is needed for 'v.needThis()' to work
976 v
.dsymbolSemantic(sc
);
978 // Change the ancestor lambdas to delegate before hasThis(sc) call.
979 if (v
.checkNestedReference(sc
, loc
))
980 return ErrorExp
.get();
982 if (v
.needThis() && hasThis(sc
))
983 e
= new DotVarExp(loc
, new ThisExp(loc
), v
);
985 e
= new VarExp(loc
, v
);
986 e
= e
.expressionSemantic(sc
);
989 if (auto fld = s
.isFuncLiteralDeclaration())
991 //printf("'%s' is a function literal\n", fld.toChars());
992 e
= new FuncExp(loc
, fld);
993 return e
.expressionSemantic(sc
);
995 if (auto f
= s
.isFuncDeclaration())
998 if (!f
.functionSemantic())
999 return ErrorExp
.get();
1001 if (!hasOverloads
&& f
.checkForwardRef(loc
))
1002 return ErrorExp
.get();
1004 auto fd
= s
.isFuncDeclaration();
1006 return new VarExp(loc
, fd
, hasOverloads
);
1008 if (OverDeclaration od
= s
.isOverDeclaration())
1010 e
= new VarExp(loc
, od
, true);
1011 e
.type
= Type
.tvoid
;
1014 if (OverloadSet o
= s
.isOverloadSet())
1016 //printf("'%s' is an overload set\n", o.toChars());
1017 return new OverExp(loc
, o
);
1020 if (Import imp
= s
.isImport())
1024 .error(loc
, "forward reference of import `%s`", imp
.toChars());
1025 return ErrorExp
.get();
1027 auto ie
= new ScopeExp(loc
, imp
.pkg
);
1028 return ie
.expressionSemantic(sc
);
1030 if (Package pkg
= s
.isPackage())
1032 auto ie
= new ScopeExp(loc
, pkg
);
1033 return ie
.expressionSemantic(sc
);
1035 if (Module mod
= s
.isModule())
1037 auto ie
= new ScopeExp(loc
, mod
);
1038 return ie
.expressionSemantic(sc
);
1040 if (Nspace ns
= s
.isNspace())
1042 auto ie
= new ScopeExp(loc
, ns
);
1043 return ie
.expressionSemantic(sc
);
1046 if (Type t
= s
.getType())
1048 return (new TypeExp(loc
, t
)).expressionSemantic(sc
);
1051 if (TupleDeclaration tup
= s
.isTupleDeclaration())
1053 if (tup
.needThis() && hasThis(sc
))
1054 e
= new DotVarExp(loc
, new ThisExp(loc
), tup
);
1056 e
= new TupleExp(loc
, tup
);
1057 e
= e
.expressionSemantic(sc
);
1061 if (TemplateInstance ti
= s
.isTemplateInstance())
1063 ti
.dsymbolSemantic(sc
);
1064 if (!ti
.inst || ti
.errors
)
1065 return ErrorExp
.get();
1067 if (!s
.isTemplateInstance())
1069 e
= new ScopeExp(loc
, ti
);
1070 e
= e
.expressionSemantic(sc
);
1073 if (TemplateDeclaration td
= s
.isTemplateDeclaration())
1075 Dsymbol p
= td
.toParentLocal();
1076 FuncDeclaration fdthis
= hasThis(sc
);
1077 AggregateDeclaration ad
= p ? p
.isAggregateDeclaration() : null;
1078 if (fdthis
&& ad
&& fdthis
.isMemberLocal() == ad
&& (td
._scope
.stc & STC
.static_
) == 0)
1080 e
= new DotTemplateExp(loc
, new ThisExp(loc
), td
);
1083 e
= new TemplateExp(loc
, td
);
1084 e
= e
.expressionSemantic(sc
);
1088 .error(loc
, "%s `%s` is not a variable", s
.kind(), s
.toChars());
1089 return ErrorExp
.get();
1092 /*************************************************************
1093 * Given var, get the
1094 * right `this` pointer if var is in an outer class, but our
1095 * existing `this` pointer is in an inner class.
1097 * loc = location to use for error messages
1099 * ad = struct or class we need the correct `this` for
1100 * e1 = existing `this`
1101 * var = the specific member of ad we're accessing
1102 * flag = if true, return `null` instead of throwing an error
1104 * Expression representing the `this` for the var
1106 private Expression
getRightThis(const ref Loc loc
, Scope
* sc
, AggregateDeclaration ad
, Expression e1
, Dsymbol var
, int flag
= 0)
1108 //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars());
1110 Type t
= e1
.type
.toBasetype();
1111 //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars());
1113 if (e1
.op
== EXP
.objcClassReference
)
1115 // We already have an Objective-C class reference, just use that as 'this'.
1118 else if (ad
&& ad
.isClassDeclaration
&& ad
.isClassDeclaration
.classKind
== ClassKind
.objc
&&
1119 var
.isFuncDeclaration
&& var
.isFuncDeclaration
.isStatic
&&
1120 var
.isFuncDeclaration
.objc
.selector
)
1122 return new ObjcClassReferenceExp(e1
.loc
, ad
.isClassDeclaration());
1125 /* Access of a member which is a template parameter in dual-scope scenario
1126 * class A { inc(alias m)() { ++m; } } // `m` needs `this` of `B`
1127 * class B {int m; inc() { new A().inc!m(); } }
1129 if (e1
.op
== EXP
.this_
)
1131 FuncDeclaration f
= hasThis(sc
);
1132 if (f
&& f
.hasDualContext())
1134 if (f
.followInstantiationContext(ad
))
1136 e1
= new VarExp(loc
, f
.vthis
);
1137 e1
= new PtrExp(loc
, e1
);
1138 e1
= new IndexExp(loc
, e1
, IntegerExp
.literal
!1);
1139 e1
= getThisSkipNestedFuncs(loc
, sc
, f
.toParent2(), ad
, e1
, t
, var
);
1140 if (e1
.op
== EXP
.error
)
1147 /* If e1 is not the 'this' pointer for ad
1150 !(t
.isTypePointer() && t
.nextOf().isTypeStruct() && t
.nextOf().isTypeStruct().sym
== ad
) &&
1151 !(t
.isTypeStruct() && t
.isTypeStruct().sym
== ad
))
1153 ClassDeclaration cd
= ad
.isClassDeclaration();
1154 ClassDeclaration tcd
= t
.isClassHandle();
1156 /* e1 is the right this if ad is a base class of e1
1158 if (!cd ||
!tcd ||
!(tcd
== cd || cd
.isBaseOf(tcd
, null)))
1160 /* Only classes can be inner classes with an 'outer'
1161 * member pointing to the enclosing class instance
1163 if (tcd
&& tcd
.isNested())
1165 /* e1 is the 'this' pointer for an inner class: tcd.
1166 * Rewrite it as the 'this' pointer for the outer class.
1168 auto vthis
= tcd
.followInstantiationContext(ad
) ? tcd
.vthis2
: tcd
.vthis
;
1169 e1
= new DotVarExp(loc
, e1
, vthis
);
1170 e1
.type
= vthis
.type
;
1171 e1
.type
= e1
.type
.addMod(t
.mod
);
1172 // Do not call ensureStaticLinkTo()
1173 //e1 = e1.semantic(sc);
1175 // Skip up over nested functions, and get the enclosing
1177 e1
= getThisSkipNestedFuncs(loc
, sc
, tcd
.toParentP(ad
), ad
, e1
, t
, var
);
1178 if (e1
.op
== EXP
.error
)
1183 /* Can't find a path from e1 to ad
1187 error(e1
.loc
, "`this` for `%s` needs to be type `%s` not type `%s`", var
.toChars(), ad
.toChars(), t
.toChars());
1188 return ErrorExp
.get();
1195 * Check whether `outerFunc` and `calledFunc` have the same `this`.
1196 * If `calledFunc` is the member of a base class of the class that contains
1197 * `outerFunc` we consider that they have the same this.
1199 * This function is used to test whether `this` needs to be prepended to
1200 * a function call or function symbol. For example:
1216 * When `fun` is called, `outerfunc` = `sun` and `calledFunc = `fun`.
1217 * `sun` is a member of `A` and `fun` is also a member of `A`, therefore
1218 * `this` can be prepended to `fun`. When `gun` is called (it will result
1219 * in an error, but that is not relevant here), which is a member of `X`,
1220 * no `this` is needed because the outer function does not have the same
1224 * `true` if outerFunc and calledFunc may use the same `this` pointer.
1225 * `false` otherwise.
1227 private bool haveSameThis(FuncDeclaration outerFunc
, FuncDeclaration calledFunc
)
1229 // https://issues.dlang.org/show_bug.cgi?id=24013
1230 // traits(getOverloads) inserts an alias to select the overload.
1231 // When searching for the right this we need to use the aliased
1232 // overload/function, not the alias.
1233 outerFunc
= outerFunc
.toAliasFunc();
1234 calledFunc
= calledFunc
.toAliasFunc();
1236 auto thisAd
= outerFunc
.isMemberLocal();
1240 auto requiredAd
= calledFunc
.isMemberLocal();
1244 if (thisAd
== requiredAd
)
1247 // if outerfunc is the member of a nested aggregate, then let
1248 // getRightThis take care of this.
1249 if (thisAd
.isNested())
1252 // outerfunc is the member of a base class that contains calledFunc,
1253 // then we consider that they have the same this.
1254 auto cd
= requiredAd
.isClassDeclaration();
1258 if (cd
.isBaseOf2(thisAd
.isClassDeclaration()))
1264 /***************************************
1265 * Pull out any properties.
1267 private Expression
resolvePropertiesX(Scope
* sc
, Expression e1
, Expression e2
= null, BinExp saveAtts
= null)
1269 //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null);
1276 if (auto de = e1
.isDotExp())
1278 if (auto oe
= de.e2
.isOverExp())
1286 else if (e1
.isOverExp())
1290 os
= e1
.isOverExp().vars
;
1293 FuncDeclaration fd
= null;
1296 e2
= e2
.expressionSemantic(sc
);
1297 if (e2
.op
== EXP
.error
)
1298 return ErrorExp
.get();
1299 e2
= resolveProperties(sc
, e2
);
1301 Expressions
* a
= new Expressions();
1304 for (size_t i
= 0; i
< os
.a
.length
; i
++)
1306 if (FuncDeclaration f
= resolveFuncCall(loc
, sc
, os
.a
[i
], tiargs
, tthis
, ArgumentList(a
), FuncResolveFlag
.quiet
))
1309 return ErrorExp
.get();
1311 assert(fd
.type
.ty
== Tfunction
);
1316 Expression e
= new CallExp(loc
, e1
, e2
);
1317 return e
.expressionSemantic(sc
);
1321 for (size_t i
= 0; i
< os
.a
.length
; i
++)
1323 if (FuncDeclaration f
= resolveFuncCall(loc
, sc
, os
.a
[i
], tiargs
, tthis
, ArgumentList(), FuncResolveFlag
.quiet
))
1326 return ErrorExp
.get();
1328 assert(fd
.type
.ty
== Tfunction
);
1329 auto tf
= fd
.type
.isTypeFunction();
1330 if (!tf
.isref
&& e2
)
1332 error(loc
, "%s is not an lvalue", e1
.toChars());
1333 return ErrorExp
.get();
1339 Expression e
= new CallExp(loc
, e1
);
1342 e
= new AssignExp(loc
, e
, e2
);
1345 (cast(BinExp
)e
).att1
= saveAtts
.att1
;
1346 (cast(BinExp
)e
).att2
= saveAtts
.att2
;
1349 return e
.expressionSemantic(sc
);
1355 else if (auto dti
= e1
.isDotTemplateInstanceExp())
1357 if (!dti
.findTempDecl(sc
))
1359 if (!dti
.ti
.semanticTiargs(sc
))
1361 tiargs
= dti
.ti
.tiargs
;
1362 tthis
= dti
.e1
.type
;
1363 if ((os
= dti
.ti
.tempdecl
.isOverloadSet()) !is null)
1365 if ((s
= dti
.ti
.tempdecl
) !is null)
1368 else if (auto dte
= e1
.isDotTemplateExp())
1372 tthis
= dte
.e1
.type
;
1375 else if (auto se
= e1
.isScopeExp())
1378 TemplateInstance ti
= s
.isTemplateInstance();
1379 if (ti
&& !ti
.semanticRun
&& ti
.tempdecl
)
1381 //assert(ti.needsTypeInference(sc));
1382 if (!ti
.semanticTiargs(sc
))
1386 if ((os
= ti
.tempdecl
.isOverloadSet()) !is null)
1388 if ((s
= ti
.tempdecl
) !is null)
1392 else if (auto te
= e1
.isTemplateExp())
1399 else if (e1
.isDotVarExp() && e1
.type
&& (e1
.type
.toBasetype().isTypeFunction() || e1
.isDotVarExp().var
.isOverDeclaration()))
1401 DotVarExp dve
= e1
.isDotVarExp();
1404 tthis
= dve
.e1
.type
;
1407 else if (sc
&& sc
.flags
& SCOPE
.Cfile
&& e1
.isVarExp() && !e2
)
1409 // ImportC: do not implicitly call function if no ( ) are present
1411 else if (e1
.isVarExp() && e1
.type
&& (e1
.type
.toBasetype().isTypeFunction() || e1
.isVarExp().var
.isOverDeclaration()))
1413 s
= e1
.isVarExp().var
;
1420 e2
= e2
.expressionSemantic(sc
);
1421 if (e2
.op
== EXP
.error
)
1422 return ErrorExp
.get();
1423 e2
= resolveProperties(sc
, e2
);
1425 Expressions
* a
= new Expressions();
1428 FuncDeclaration fd
= resolveFuncCall(loc
, sc
, s
, tiargs
, tthis
, ArgumentList(a
), FuncResolveFlag
.quiet
);
1432 return ErrorExp
.get();
1433 assert(fd
.type
.ty
== Tfunction
);
1434 Expression e
= new CallExp(loc
, e1
, e2
);
1435 return e
.expressionSemantic(sc
);
1439 FuncDeclaration fd
= resolveFuncCall(loc
, sc
, s
, tiargs
, tthis
, ArgumentList(), FuncResolveFlag
.quiet
);
1443 return ErrorExp
.get();
1444 TypeFunction tf
= fd
.type
.isTypeFunction();
1445 if (!e2 || tf
.isref
)
1447 Expression e
= new CallExp(loc
, e1
);
1450 e
= new AssignExp(loc
, e
, e2
);
1453 (cast(BinExp
)e
).att1
= saveAtts
.att1
;
1454 (cast(BinExp
)e
).att2
= saveAtts
.att2
;
1457 return e
.expressionSemantic(sc
);
1461 if (FuncDeclaration fd
= s
.isFuncDeclaration())
1463 // Keep better diagnostic message for invalid property usage of functions
1464 assert(fd
.type
.ty
== Tfunction
);
1465 Expression e
= new CallExp(loc
, e1
, e2
);
1466 return e
.expressionSemantic(sc
);
1471 if (auto ve
= e1
.isVarExp())
1473 if (auto v
= ve
.var
.isVarDeclaration())
1475 if (ve
.checkPurity(sc
, v
))
1476 return ErrorExp
.get();
1482 if (e1
.type
&& !e1
.isTypeExp()) // function type is not a property
1484 /* Look for e1 being a lazy parameter; rewrite as delegate call
1485 * only if the symbol wasn't already treated as a delegate
1487 auto ve
= e1
.isVarExp();
1488 if (ve
&& ve
.var
.storage_class
& STC
.lazy_
&& !ve
.delegateWasExtracted
)
1490 Expression e
= new CallExp(loc
, e1
);
1491 return e
.expressionSemantic(sc
);
1493 else if (e1
.isDotVarExp())
1495 // Check for reading overlapped pointer field in @safe code.
1496 if (checkUnsafeAccess(sc
, e1
, true, true))
1497 return ErrorExp
.get();
1499 else if (auto ce
= e1
.isCallExp())
1501 // Check for reading overlapped pointer field in @safe code.
1502 if (checkUnsafeAccess(sc
, ce
.e1
, true, true))
1503 return ErrorExp
.get();
1509 error(loc
, "cannot resolve type for %s", e1
.toChars());
1510 e1
= ErrorExp
.get();
1515 error(loc
, "not a property %s", e1
.toChars());
1516 return ErrorExp
.get();
1519 extern (C
++) Expression
resolveProperties(Scope
* sc
, Expression e
)
1521 //printf("resolveProperties(%s)\n", e.toChars());
1522 e
= resolvePropertiesX(sc
, e
);
1523 if (e
.checkRightThis(sc
))
1524 return ErrorExp
.get();
1528 /****************************************
1529 * The common type is determined by applying ?: to each pair.
1531 * exps[] properties resolved, implicitly cast to common type, rewritten in place
1533 * The common type, or `null` if an error has occured
1535 private Type
arrayExpressionToCommonType(Scope
* sc
, ref Expressions exps
)
1537 /* Still have a problem with:
1538 * ubyte[][] = [ cast(ubyte[])"hello", [1]];
1539 * which works if the array literal is initialized top down with the ubyte[][]
1540 * type, but fails with this function doing bottom up typing.
1543 //printf("arrayExpressionToCommonType()\n");
1544 scope IntegerExp integerexp
= IntegerExp
.literal
!0;
1545 scope CondExp condexp
= new CondExp(Loc
.initial
, integerexp
, null, null);
1548 Expression e0
= null;
1551 for (size_t i
= 0; i
< exps
.length
; i
++)
1553 Expression e
= exps
[i
];
1557 e
= resolveProperties(sc
, e
);
1560 error(e
.loc
, "`%s` has no value", e
.toChars());
1564 if (e
.op
== EXP
.type
)
1566 foundType
= true; // do not break immediately, there might be more errors
1567 e
.checkValue(); // report an error "type T has no value"
1571 if (e
.type
.ty
== Tvoid
)
1573 // void expressions do not concur to the determination of the common
1577 if (checkNonAssignmentArrayOp(e
))
1583 e
= doCopyOrMove(sc
, e
);
1585 if (!foundType
&& t0
&& !t0
.equals(e
.type
))
1587 /* This applies ?: to merge the types. It's backwards;
1588 * ?: should call this function to merge types.
1590 condexp
.type
= null;
1593 condexp
.loc
= e
.loc
;
1594 Expression ex
= condexp
.expressionSemantic(sc
);
1595 if (ex
.op
== EXP
.error
)
1599 // Convert to common type
1600 exps
[i
] = condexp
.e1
.castTo(sc
, condexp
.type
);
1601 e
= condexp
.e2
.castTo(sc
, condexp
.type
);
1606 if (e
.op
!= EXP
.error
)
1610 // [] is typed as void[]
1614 // It's an error, don't do the cast
1615 if (t0
.ty
== Terror
)
1618 for (size_t i
= 0; i
< exps
.length
; i
++)
1620 Expression e
= exps
[i
];
1624 e
= e
.implicitCastTo(sc
, t0
);
1625 if (e
.op
== EXP
.error
)
1627 /* https://issues.dlang.org/show_bug.cgi?id=13024
1628 * a workaround for the bug in typeMerge -
1629 * it should paint e1 and e2 by deduced common type,
1630 * but doesn't in this particular case.
1639 private Expression
opAssignToOp(const ref Loc loc
, EXP op
, Expression e1
, Expression e2
) @safe
1645 e
= new AddExp(loc
, e1
, e2
);
1649 e
= new MinExp(loc
, e1
, e2
);
1653 e
= new MulExp(loc
, e1
, e2
);
1657 e
= new DivExp(loc
, e1
, e2
);
1661 e
= new ModExp(loc
, e1
, e2
);
1665 e
= new AndExp(loc
, e1
, e2
);
1669 e
= new OrExp(loc
, e1
, e2
);
1673 e
= new XorExp(loc
, e1
, e2
);
1676 case EXP
.leftShiftAssign
:
1677 e
= new ShlExp(loc
, e1
, e2
);
1680 case EXP
.rightShiftAssign
:
1681 e
= new ShrExp(loc
, e1
, e2
);
1684 case EXP
.unsignedRightShiftAssign
:
1685 e
= new UshrExp(loc
, e1
, e2
);
1694 /*********************
1696 * array.length op= e2
1698 private Expression
rewriteOpAssign(BinExp exp
)
1700 ArrayLengthExp ale
= exp
.e1
.isArrayLengthExp();
1701 if (ale
.e1
.isVarExp())
1703 // array.length = array.length op e2
1704 Expression e
= opAssignToOp(exp
.loc
, exp
.op
, ale
, exp
.e2
);
1705 e
= new AssignExp(exp
.loc
, ale
.syntaxCopy(), e
);
1710 // (ref tmp = array;), tmp.length = tmp.length op e2
1711 auto tmp
= copyToTemp(STC
.ref_
, "__arraylength", ale
.e1
);
1712 Expression e1
= new ArrayLengthExp(ale
.loc
, new VarExp(ale
.loc
, tmp
));
1713 Expression elvalue
= e1
.syntaxCopy();
1714 Expression e
= opAssignToOp(exp
.loc
, exp
.op
, e1
, exp
.e2
);
1715 e
= new AssignExp(exp
.loc
, elvalue
, e
);
1716 e
= new CommaExp(exp
.loc
, new DeclarationExp(ale
.loc
, tmp
), e
);
1721 /****************************************
1722 * Preprocess arguments to function.
1724 * Tuples in argumentList get expanded, properties resolved, rewritten in place
1728 * argumentList = arguments to function
1729 * reportErrors = whether or not to report errors here. Some callers are not
1730 * checking actual function params, so they'll do their own error reporting
1732 * `true` when a semantic error occurred
1734 private bool preFunctionParameters(Scope
* sc
, ArgumentList argumentList
, const bool reportErrors
= true)
1736 Expressions
* exps
= argumentList
.arguments
;
1740 expandTuples(exps
, argumentList
.names
);
1742 for (size_t i
= 0; i
< exps
.length
; i
++)
1744 Expression arg
= (*exps
)[i
];
1745 arg
= resolveProperties(sc
, arg
);
1746 arg
= arg
.arrayFuncConv(sc
);
1747 if (arg
.op
== EXP
.type
)
1749 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
1750 arg
= resolveAliasThis(sc
, arg
);
1752 if (arg
.op
== EXP
.type
)
1756 error(arg
.loc
, "cannot pass type `%s` as a function argument", arg
.toChars());
1757 arg
= ErrorExp
.get();
1762 else if (arg
.type
.toBasetype().ty
== Tfunction
)
1766 error(arg
.loc
, "cannot pass function `%s` as a function argument", arg
.toChars());
1767 arg
= ErrorExp
.get();
1771 else if (checkNonAssignmentArrayOp(arg
))
1773 arg
= ErrorExp
.get();
1782 /********************************************
1783 * Issue an error if default construction is disabled for type t.
1784 * Default construction is required for arrays and 'out' parameters.
1786 * true an error was issued
1788 private bool checkDefCtor(Loc loc
, Type t
)
1790 if (auto ts
= t
.baseElemOf().isTypeStruct())
1792 StructDeclaration sd
= ts
.sym
;
1793 if (sd
.noDefaultCtor
)
1795 .error(loc
, "%s `%s` default construction is disabled", sd
.kind
, sd
.toPrettyChars
);
1802 /****************************************
1803 * Now that we know the exact type of the function we're calling,
1804 * the arguments[] need to be adjusted:
1805 * 1. implicitly convert argument to the corresponding parameter type
1806 * 2. add default arguments for any missing arguments
1807 * 3. do default promotions on arguments corresponding to ...
1808 * 4. add hidden _arguments[] argument
1809 * 5. call copy constructor for struct value arguments
1811 * loc = location of function call
1813 * tf = type of the function
1814 * ethis = `this` argument, `null` if none or not known
1815 * tthis = type of `this` argument, `null` if no `this` argument
1816 * argumentsList = array of actual arguments to function call
1817 * fd = the function being called, `null` if called indirectly
1818 * prettype = set to return type of function
1819 * peprefix = set to expression to execute before `arguments[]` are evaluated, `null` if none
1821 * true errors happened
1823 private bool functionParameters(const ref Loc loc
, Scope
* sc
,
1824 TypeFunction tf
, Expression ethis
, Type tthis
, ArgumentList argumentList
, FuncDeclaration fd
,
1825 Type
* prettype
, Expression
* peprefix
)
1827 Expressions
* arguments
= argumentList
.arguments
;
1828 //printf("functionParameters() %s\n", fd ? fd.toChars() : "");
1830 assert(fd || tf
.next
);
1831 const size_t nparams
= tf
.parameterList
.length
;
1832 const olderrors
= global
.errors
;
1834 Expression eprefix
= null;
1837 if (argumentList
.names
)
1839 const(char)* msg
= null;
1840 auto resolvedArgs
= tf
.resolveNamedArgs(argumentList
, &msg
);
1843 // while errors are usually already caught by `tf.callMatch`,
1844 // this can happen when calling `typeof(freefunc)`
1846 error(loc
, "%s", msg
);
1849 // note: the argument list should be mutated with named arguments / default arguments,
1850 // so we can't simply change the pointer like `arguments = resolvedArgs;`
1851 arguments
.setDim(0);
1852 arguments
.pushSlice((*resolvedArgs
)[]);
1854 size_t nargs
= arguments ? arguments
.length
: 0;
1856 if (nargs
> nparams
&& tf
.parameterList
.varargs
== VarArg
.none
)
1858 error(loc
, "expected %llu arguments, not %llu for non-variadic function type `%s`", cast(ulong)nparams
, cast(ulong)nargs
, tf
.toChars());
1862 // If inferring return type, and semantic3() needs to be run if not already run
1863 if (!tf
.next
&& fd
.inferRetType
)
1865 fd
.functionSemantic();
1867 else if (fd
&& fd
.parent
)
1869 TemplateInstance ti
= fd
.parent
.isTemplateInstance();
1870 if (ti
&& ti
.tempdecl
)
1872 fd
.functionSemantic3();
1876 /* If calling a pragma(inline, true) function,
1877 * set flag to later scan for inlines.
1879 if (fd
&& fd
.inlining
== PINLINE
.always
)
1882 sc
._module
.hasAlwaysInlines
= true;
1884 sc
.func
.hasAlwaysInlines
= true;
1887 const isCtorCall
= fd
&& fd
.needThis() && fd
.isCtorDeclaration();
1889 const size_t n
= (nargs
> nparams
) ? nargs
: nparams
; // n = max(nargs, nparams)
1891 /* If the function return type has wildcards in it, we'll need to figure out the actual type
1892 * based on the actual argument types.
1893 * Start with the `this` argument, later on merge into wildmatch the mod bits of the rest
1896 MOD wildmatch
= (tthis
&& !isCtorCall
) ? tthis
.Type
.deduceWild(tf
, false) : 0;
1899 foreach (const i
; 0 .. n
)
1901 Expression arg
= (i
< nargs
) ?
(*arguments
)[i
] : null;
1907 error(loc
, "expected %llu function arguments, not %llu", cast(ulong)nparams
, cast(ulong)nargs
);
1911 Parameter p
= tf
.parameterList
[i
];
1917 if (tf
.parameterList
.varargs
== VarArg
.typesafe
&& i
+ 1 == nparams
)
1923 arg
= arg
.expressionSemantic(sc
);
1924 arg
= inlineCopy(arg
, sc
);
1925 // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
1926 arg
= arg
.resolveLoc(loc
, sc
);
1929 arguments
.push(arg
);
1933 (*arguments
)[i
] = arg
;
1937 if (arg
.isDefaultInitExp())
1939 arg
= arg
.resolveLoc(loc
, sc
);
1940 (*arguments
)[i
] = arg
;
1945 if (tf
.parameterList
.varargs
== VarArg
.typesafe
&& i
+ 1 == nparams
) // https://dlang.org/spec/function.html#variadic
1947 //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars());
1950 if ((m
= arg
.implicitConvTo(p
.type
)) > MATCH
.nomatch
)
1952 if (p
.type
.nextOf() && arg
.implicitConvTo(p
.type
.nextOf()) >= m
)
1954 else if (nargs
!= nparams
)
1960 Type tb
= p
.type
.toBasetype();
1966 /* Create a static array variable v of type arg.type:
1967 * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
1969 * The array literal in the initializer of the hidden variable
1971 * https://issues.dlang.org/show_bug.cgi?id=2356
1973 Type tbn
= (cast(TypeArray
)tb
).next
; // array element type
1974 Type tret
= p
.isLazyArray();
1976 auto elements
= new Expressions(nargs
- i
);
1977 foreach (u
; 0 .. elements
.length
)
1979 Expression a
= (*arguments
)[i
+ u
];
1980 if (tret
&& a
.implicitConvTo(tret
))
1982 // p is a lazy array of delegates, tret is return type of the delegates
1983 a
= a
.implicitCastTo(sc
, tret
)
1984 .optimize(WANTvalue
)
1985 .toDelegate(tret
, sc
);
1988 a
= a
.implicitCastTo(sc
, tbn
);
1989 a
= a
.addDtorHook(sc
);
1992 // https://issues.dlang.org/show_bug.cgi?id=14395
1993 // Convert to a static array literal, or its slice.
1994 arg
= new ArrayLiteralExp(loc
, tbn
.sarrayOf(nargs
- i
), elements
);
1995 if (tb
.ty
== Tarray
)
1997 arg
= new SliceExp(loc
, arg
, null, null);
2005 * new Tclass(arg0, arg1, ..., argn)
2007 auto args
= new Expressions(nargs
- i
);
2008 foreach (u
; i
.. nargs
)
2009 (*args
)[u
- i
] = (*arguments
)[u
];
2010 arg
= new NewExp(loc
, null, p
.type
, args
);
2016 error(loc
, "not enough arguments");
2021 arg
= arg
.expressionSemantic(sc
);
2022 //printf("\targ = '%s'\n", arg.toChars());
2023 arguments
.setDim(i
+ 1);
2024 (*arguments
)[i
] = arg
;
2030 if (!(p
.isLazy() && p
.type
.ty
== Tvoid
))
2032 if (ubyte wm
= arg
.type
.deduceWild(p
.type
, p
.isReference()))
2034 wildmatch
= wildmatch ?
MODmerge(wildmatch
, wm
) : wm
;
2035 //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p.type.toChars(), arg.type.toChars(), wm, wildmatch);
2042 if ((wildmatch
== MODFlags
.mutable || wildmatch
== MODFlags
.immutable_
) &&
2043 tf
.next
&& tf
.next
.hasWild() &&
2044 (tf
.isref ||
!tf
.next
.implicitConvTo(tf
.next
.immutableOf())))
2046 bool errorInout(MOD wildmatch
)
2048 const(char)* s
= wildmatch
== MODFlags
.mutable ?
"mutable" : MODtoChars(wildmatch
);
2049 error(loc
, "modify `inout` to `%s` is not allowed inside `inout` function", s
);
2055 /* If the called function may return the reference to
2056 * outer inout data, it should be rejected.
2058 * void foo(ref inout(int) x) {
2059 * ref inout(int) bar(inout(int)) { return x; }
2061 * ref inout(int) bar() inout { return x; }
2062 * ref inout(int) baz(alias a)() inout { return x; }
2064 * bar(int.init) = 1; // bad!
2065 * S().bar() = 1; // bad!
2070 * s.baz!a() = 1; // bad!
2074 bool checkEnclosingWild(Dsymbol s
)
2076 bool checkWild(Dsymbol s
)
2080 if (auto ad
= s
.isAggregateDeclaration())
2083 return checkEnclosingWild(s
);
2085 else if (auto ff
= s
.isFuncDeclaration())
2087 if (ff
.type
.isTypeFunction().iswild
)
2088 return errorInout(wildmatch
);
2090 if (ff
.isNested() || ff
.isThis())
2091 return checkEnclosingWild(s
);
2096 Dsymbol ctx0
= s
.toParent2();
2097 Dsymbol ctx1
= s
.toParentLocal();
2098 if (checkWild(ctx0
))
2101 return checkWild(ctx1
);
2104 if ((fd
.isThis() || fd
.isNested()) && checkEnclosingWild(fd
))
2107 else if (tf
.isWild())
2108 return errorInout(wildmatch
);
2111 Expression firstArg
= null;
2112 final switch (returnParamDest(tf
, tthis
))
2114 case ReturnParamDest
.returnVal
:
2116 case ReturnParamDest
.firstArg
:
2117 firstArg
= nargs
> 0 ?
(*arguments
)[0] : null;
2119 case ReturnParamDest
.this_
:
2124 assert(nargs
>= nparams
);
2125 foreach (const i
, arg
; (*arguments
)[0 .. nargs
])
2130 Parameter p
= tf
.parameterList
[i
];
2131 Type targ
= arg
.type
; // keep original type for isCopyable() because alias this
2132 // resolution may hide an uncopyable type
2134 if (!(p
.isLazy() && p
.type
.ty
== Tvoid
))
2136 Type tprm
= p
.type
.hasWild()
2137 ? p
.type
.substWildTo(wildmatch
)
2140 const hasCopyCtor
= arg
.type
.isTypeStruct() && arg
.type
.isTypeStruct().sym
.hasCopyCtor
;
2141 const typesMatch
= arg
.type
.mutableOf().unSharedOf().equals(tprm
.mutableOf().unSharedOf());
2142 if (!((hasCopyCtor
&& typesMatch
) || tprm
.equals(arg
.type
)))
2144 //printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars());
2145 arg
= arg
.implicitCastTo(sc
, tprm
);
2146 arg
= arg
.optimize(WANTvalue
, p
.isReference());
2150 // Support passing rvalue to `in` parameters
2151 if ((p
.storageClass
& (STC
.in_ | STC
.ref_
)) == (STC
.in_ | STC
.ref_
))
2153 if (!arg
.isLvalue())
2155 auto v
= copyToTemp(STC
.exptemp
, "__rvalue", arg
);
2156 Expression ev
= new DeclarationExp(arg
.loc
, v
);
2157 ev
= new CommaExp(arg
.loc
, ev
, new VarExp(arg
.loc
, v
));
2158 arg
= ev
.expressionSemantic(sc
);
2160 arg
= arg
.toLvalue(sc
, arg
);
2162 // Look for mutable misaligned pointer, etc., in @safe mode
2163 err |
= checkUnsafeAccess(sc
, arg
, false, true);
2165 else if (p
.storageClass
& STC
.ref_
)
2167 if (global
.params
.rvalueRefParam
== FeatureState
.enabled
&&
2170 { /* allow rvalues to be passed to ref parameters by copying
2171 * them to a temp, then pass the temp as the argument
2173 auto v
= copyToTemp(0, "__rvalue", arg
);
2174 Expression ev
= new DeclarationExp(arg
.loc
, v
);
2175 ev
= new CommaExp(arg
.loc
, ev
, new VarExp(arg
.loc
, v
));
2176 arg
= ev
.expressionSemantic(sc
);
2178 arg
= arg
.toLvalue(sc
, arg
);
2180 // Look for mutable misaligned pointer, etc., in @safe mode
2181 err |
= checkUnsafeAccess(sc
, arg
, false, true);
2183 else if (p
.storageClass
& STC
.out_
)
2186 if (!t
.isMutable() ||
!t
.isAssignable()) // check blit assignable
2188 error(arg
.loc
, "cannot modify struct `%s` with immutable members", arg
.toChars());
2193 // Look for misaligned pointer, etc., in @safe mode
2194 err |
= checkUnsafeAccess(sc
, arg
, false, true);
2195 err |
= checkDefCtor(arg
.loc
, t
); // t must be default constructible
2197 arg
= arg
.toLvalue(sc
, arg
);
2199 else if (p
.isLazy())
2201 // Convert lazy argument to a delegate
2202 auto t
= (p
.type
.ty
== Tvoid
) ? p
.type
: arg
.type
;
2203 arg
= toDelegate(arg
, t
, sc
);
2205 //printf("arg: %s\n", arg.toChars());
2206 //printf("type: %s\n", arg.type.toChars());
2207 //printf("param: %s\n", p.toChars());
2209 const pStc
= tf
.parameterStorageClass(tthis
, p
);
2211 if (firstArg
&& (pStc
& STC
.return_
))
2213 /* Argument value can be assigned to firstArg.
2214 * Check arg to see if it matters.
2216 err |
= checkParamArgumentReturn(sc
, firstArg
, arg
, p
, false);
2218 // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along
2219 // as lazy parameters to the next function, but that isn't escaping.
2220 // The arguments of `_d_arraycatnTX` are already handled in
2221 // expressionsem.d, via `checkNewEscape`. Without `-dip1000`, the
2222 // check does not return an error, so the lowering of `a ~ b` to
2223 // `_d_arraycatnTX(a, b)` still occurs.
2224 else if (!(pStc
& STC
.lazy_
) && (!fd || fd
.ident
!= Id
._d_arraycatnTX
))
2226 /* Argument value can escape from the called function.
2227 * Check arg to see if it matters.
2229 VarDeclaration vPar
= fd ?
(fd
.parameters ?
(*fd
.parameters
)[i
] : null) : null;
2230 err |
= checkParamArgumentEscape(sc
, fd
, p
.ident
, vPar
, cast(STC
) pStc
, arg
, false, false);
2233 // Turning heap allocations into stack allocations is dangerous without dip1000, since `scope` inference
2234 // may be unreliable when scope violations only manifest as deprecation warnings.
2235 // However, existing `@nogc` code may rely on it, so still do it when the parameter is explicitly marked `scope`
2236 const explicitScope
= p
.isLazy() ||
2237 ((p
.storageClass
& STC
.scope_
) && !(p
.storageClass
& STC
.scopeinferred
));
2238 if ((pStc
& (STC
.scope_ | STC
.lazy_
)) &&
2239 ((global
.params
.useDIP1000
== FeatureState
.enabled
) || explicitScope
) &&
2240 !(pStc
& STC
.return_
))
2242 /* Argument value cannot escape from the called function.
2245 if (auto ce
= a
.isCastExp())
2248 ArrayLiteralExp ale
;
2249 if (p
.type
.toBasetype().ty
== Tarray
&&
2250 (ale
= a
.isArrayLiteralExp()) !is null && ale
.elements
&& ale
.elements
.length
> 0)
2252 // allocate the array literal as temporary static array on the stack
2253 ale
.type
= ale
.type
.nextOf().sarrayOf(ale
.elements
.length
);
2254 auto tmp
= copyToTemp(0, "__arrayliteral_on_stack", ale
);
2255 tmp
.storage_class |
= STC
.exptemp
;
2256 auto declareTmp
= new DeclarationExp(ale
.loc
, tmp
);
2257 auto castToSlice
= new CastExp(ale
.loc
, new VarExp(ale
.loc
, tmp
),
2258 p
.type
.substWildTo(MODFlags
.mutable
));
2259 arg
= CommaExp
.combine(declareTmp
, castToSlice
);
2260 arg
= arg
.expressionSemantic(sc
);
2262 else if (auto fe
= a
.isFuncExp())
2264 /* Function literals can only appear once, so if this
2265 * appearance was scoped, there cannot be any others.
2267 fe
.fd
.tookAddressOf
= 0;
2269 else if (auto de = a
.isDelegateExp())
2271 /* For passing a delegate to a scoped parameter,
2272 * this doesn't count as taking the address of it.
2273 * We only worry about 'escaping' references to the function.
2275 if (auto ve
= de.e1
.isVarExp())
2277 if (auto f
= ve
.var
.isFuncDeclaration())
2279 if (f
.tookAddressOf
)
2281 //printf("--tookAddressOf = %d\n", f.tookAddressOf);
2286 if (!p
.isReference())
2287 err |
= arg
.checkSharedAccess(sc
);
2289 arg
= arg
.optimize(WANTvalue
, p
.isReference());
2293 // These will be the trailing ... arguments
2294 // If not D linkage, do promotions
2295 if (tf
.linkage
!= LINK
.d
)
2297 // Promote bytes, words, etc., to ints
2298 arg
= integralPromotions(arg
, sc
);
2300 // Promote floats to doubles
2301 switch (arg
.type
.ty
)
2304 arg
= arg
.castTo(sc
, Type
.tfloat64
);
2308 arg
= arg
.castTo(sc
, Type
.timaginary64
);
2314 if (tf
.parameterList
.varargs
== VarArg
.variadic ||
2315 tf
.parameterList
.varargs
== VarArg
.KRvariadic
)
2317 const(char)* p
= tf
.linkage
== LINK
.c ?
"extern(C)" : "extern(C++)";
2318 if (arg
.type
.ty
== Tarray
)
2320 error(arg
.loc
, "cannot pass dynamic arrays to `%s` vararg functions", p
);
2323 if (arg
.type
.ty
== Tsarray
)
2325 error(arg
.loc
, "cannot pass static arrays to `%s` vararg functions", p
);
2331 // Do not allow types that need destructors or copy constructors.
2332 if (arg
.type
.needsDestruction())
2334 error(arg
.loc
, "cannot pass types that need destruction as variadic arguments");
2337 if (arg
.type
.needsCopyOrPostblit())
2339 error(arg
.loc
, "cannot pass types with postblits or copy constructors as variadic arguments");
2343 // Convert static arrays to dynamic arrays
2344 // BUG: I don't think this is right for D2
2345 Type tb
= arg
.type
.toBasetype();
2346 if (auto ts
= tb
.isTypeSArray())
2348 Type ta
= ts
.next
.arrayOf();
2349 if (ts
.size(arg
.loc
) == 0)
2350 arg
= new NullExp(arg
.loc
, ta
);
2352 arg
= arg
.castTo(sc
, ta
);
2354 if (tb
.ty
== Tstruct
)
2356 //arg = callCpCtor(sc, arg);
2358 // Give error for overloaded function addresses
2359 if (auto se
= arg
.isSymOffExp())
2361 if (se
.hasOverloads
&& !se
.var
.isFuncDeclaration().isUnique())
2363 error(arg
.loc
, "function `%s` is overloaded", arg
.toChars());
2367 err |
= arg
.checkValue();
2368 err |
= arg
.checkSharedAccess(sc
);
2369 err |
= checkParamArgumentEscape(sc
, fd
, Id
.dotdotdot
, null, cast(STC
) tf
.parameterList
.stc, arg
, false, false);
2370 arg
= arg
.optimize(WANTvalue
);
2372 (*arguments
)[i
] = arg
;
2375 /* If calling C scanf(), printf(), or any variants, check the format string against the arguments
2377 const isVa_list
= tf
.parameterList
.varargs
== VarArg
.none
;
2378 if (fd
&& fd
.printf
)
2380 if (auto se
= (*arguments
)[nparams
- 1 - isVa_list
].isStringExp())
2382 checkPrintfFormat(se
.loc
, se
.peekString(), (*arguments
)[nparams
.. nargs
], isVa_list
, sc
.eSink
);
2385 else if (fd
&& fd
.scanf
)
2387 if (auto se
= (*arguments
)[nparams
- 1 - isVa_list
].isStringExp())
2389 checkScanfFormat(se
.loc
, se
.peekString(), (*arguments
)[nparams
.. nargs
], isVa_list
, sc
.eSink
);
2394 // TODO: not checking the "v" functions yet (for those, check format string only, not args)
2397 /* Remaining problems:
2398 * 1. value structs (or static arrays of them) that need to be copy constructed
2399 * 2. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
2400 * function gets called.
2401 * 3. value structs need to be destructed after the function call for platforms where the caller destroys the arguments.
2402 * Those are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
2403 * up properly. Pushing arguments on the stack then cannot fail.
2406 /* Does Problem (3) apply?
2408 const bool callerDestroysArgs
= !target
.isCalleeDestroyingArgs(tf
);
2410 /* Compute indices of last throwing argument and first arg needing destruction.
2411 * Used to not set up destructors unless an arg needs destruction on a throw
2412 * in a later argument.
2414 ptrdiff_t lastthrow
= -1; // last argument that may throw
2415 ptrdiff_t firstdtor
= -1; // first argument that needs destruction
2416 ptrdiff_t lastdtor
= -1; // last argument that needs destruction
2417 for (ptrdiff_t i
= 0; i
!= nargs
; i
++)
2419 Expression arg
= (*arguments
)[i
];
2420 if (canThrow(arg
, sc
.func
, null))
2422 if (arg
.type
.needsDestruction())
2424 Parameter p
= (i
>= nparams ?
null : tf
.parameterList
[i
]);
2425 if (!(p
&& (p
.isLazy() || p
.isReference())))
2427 if (firstdtor
== -1)
2434 /* Do we need 'eprefix' for problems 2 or 3?
2436 const bool needsPrefix
= callerDestroysArgs
2437 ? firstdtor
>= 0 // true if any argument needs destruction
2438 : firstdtor
>= 0 && lastthrow
>= 0 &&
2439 (lastthrow
- firstdtor
) > 0; // last throw after first destruction
2440 const ptrdiff_t lastPrefix
= callerDestroysArgs
2441 ? lastdtor
// up to last argument requiring destruction
2442 : lastthrow
; // up to last potentially throwing argument
2444 /* Problem 3: initialize 'eprefix' by declaring the gate
2446 VarDeclaration gate
;
2447 if (needsPrefix
&& !callerDestroysArgs
)
2449 // eprefix => bool __gate [= false]
2450 Identifier idtmp
= Identifier
.generateId("__gate");
2451 gate
= new VarDeclaration(loc
, Type
.tbool
, idtmp
, null);
2452 gate
.storage_class |
= STC
.temp | STC
.ctfe | STC
.volatile_
;
2453 gate
.dsymbolSemantic(sc
);
2455 auto ae
= new DeclarationExp(loc
, gate
);
2456 eprefix
= ae
.expressionSemantic(sc
);
2459 for (ptrdiff_t i
= 0; i
!= nargs
; i
++)
2461 Expression arg
= (*arguments
)[i
];
2462 //printf("arg[%d]: %s\n", cast(int)i, arg.toChars());
2464 Parameter parameter
= (i
>= nparams ?
null : tf
.parameterList
[i
]);
2465 const bool isRef
= parameter
&& parameter
.isReference();
2466 const bool isLazy
= parameter
&& parameter
.isLazy();
2468 /* Skip lazy parameters
2473 /* Do we have 'eprefix' and aren't past 'lastPrefix' yet?
2474 * Then declare a temporary variable for this arg and append that declaration
2475 * to 'eprefix', which will implicitly take care of potential problem 1) for
2477 * 'eprefix' will therefore finally contain all args up to and including 'lastPrefix',
2478 * excluding all lazy parameters.
2480 if (needsPrefix
&& (lastPrefix
- i
) >= 0)
2482 const bool needsDtor
= !isRef
&& arg
.type
.needsDestruction() &&
2483 // Problem 3: last throwing arg doesn't require dtor patching
2484 (callerDestroysArgs || i
!= lastPrefix
);
2486 /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
2488 auto tmp
= copyToTemp(
2489 (parameter ? parameter
.storageClass
: tf
.parameterList
.stc) & (STC
.scope_
),
2490 needsDtor ?
"__pfx" : "__pfy",
2491 !isRef ? arg
: arg
.addressOf());
2492 tmp
.dsymbolSemantic(sc
);
2494 if (callerDestroysArgs
)
2496 /* Problem 4: Normal temporary, destructed after the call
2499 tmp
.isArgDtorVar
= true; // mark it so that the backend passes it by ref to the function being called
2503 /* Problem 2: Modify the destructor so it only runs if gate==false,
2504 * i.e., only if there was a throw while constructing the args
2510 assert(i
== lastPrefix
);
2516 // edtor => (__gate || edtor)
2518 Expression e
= tmp
.edtor
;
2519 e
= new LogicalExp(e
.loc
, EXP
.orOr
, new VarExp(e
.loc
, gate
), e
);
2520 tmp
.edtor
= e
.expressionSemantic(sc
);
2521 //printf("edtor: %s\n", tmp.edtor.toChars());
2525 // eprefix => (eprefix, auto __pfx/y = arg)
2526 auto ae
= new DeclarationExp(loc
, tmp
);
2527 eprefix
= Expression
.combine(eprefix
, ae
.expressionSemantic(sc
));
2530 arg
= new VarExp(loc
, tmp
);
2531 arg
= arg
.expressionSemantic(sc
);
2534 arg
= new PtrExp(loc
, arg
);
2535 arg
= arg
.expressionSemantic(sc
);
2538 /* Problem 2: Last throwing arg?
2539 * Then finalize eprefix => (eprefix, gate = true), i.e., disable the
2540 * dtors right after constructing the last throwing arg.
2541 * From now on, the callee will take care of destructing the args because
2542 * the args are implicitly moved into function parameters.
2544 if (!callerDestroysArgs
&& i
== lastPrefix
)
2546 auto e
= new AssignExp(gate
.loc
, new VarExp(gate
.loc
, gate
), IntegerExp
.createBool(true));
2547 eprefix
= Expression
.combine(eprefix
, e
.expressionSemantic(sc
));
2550 else // not part of 'eprefix'
2552 /* Handle problem 1) by calling the copy constructor for value structs
2553 * (or static arrays of them) if appropriate.
2555 Type tv
= arg
.type
.baseElemOf();
2556 if (!isRef
&& tv
.ty
== Tstruct
)
2557 arg
= doCopyOrMove(sc
, arg
, parameter ? parameter
.type
: null);
2560 (*arguments
)[i
] = arg
;
2563 //if (eprefix) printf("eprefix: %s\n", eprefix.toChars());
2565 /* Test compliance with DIP1021 Argument Ownership and Function Calls
2567 if (global
.params
.useDIP1021
&& (tf
.trust
== TRUST
.safe || tf
.trust
== TRUST
.default_
) ||
2569 err |
= checkMutableArguments(sc
, fd
, tf
, ethis
, arguments
, false);
2571 // If D linkage and variadic, add _arguments[] as first argument
2572 if (tf
.isDstyleVariadic())
2574 assert(arguments
.length
>= nparams
);
2576 auto args
= new Parameters(arguments
.length
- nparams
);
2577 for (size_t i
= 0; i
< arguments
.length
- nparams
; i
++)
2579 Expression earg
= (*arguments
)[nparams
+ i
];
2580 auto arg
= new Parameter(earg
.loc
, STC
.in_
, earg
.type
, null, null, null);
2583 auto tup
= new TypeTuple(args
);
2584 Expression e
= (new TypeidExp(loc
, tup
)).expressionSemantic(sc
);
2585 arguments
.insert(0, e
);
2588 /* Determine function return type: tret
2590 Type tret
= tf
.next
;
2593 //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd.toChars(), fd.type.toChars(),
2594 // wildmatch, tf.isWild(), fd.isReturnIsolated());
2597 assert(sc
.intypeof || global
.errors
);
2598 tthis
= fd
.isThis().type
.addMod(fd
.type
.mod
);
2600 if (tf
.isWild() && !fd
.isReturnIsolated())
2603 tret
= tret
.substWildTo(wildmatch
);
2605 if (!tret
.implicitConvTo(tthis
) && !(MODimplicitConv(tret
.mod
, tthis
.mod
) && tret
.isBaseOf(tthis
, &offset
) && offset
== 0))
2607 const(char)* s1
= tret
.isNaked() ?
" mutable" : tret
.modToChars();
2608 const(char)* s2
= tthis
.isNaked() ?
" mutable" : tthis
.modToChars();
2609 .error(loc
, "`inout` constructor `%s` creates%s object, not%s", fd
.toPrettyChars(), s1
, s2
);
2615 else if (wildmatch
&& tret
)
2617 /* Adjust function return type based on wildmatch
2619 //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret.toChars());
2620 tret
= tret
.substWildTo(wildmatch
);
2624 *peprefix
= eprefix
;
2625 return (err || olderrors
!= global
.errors
);
2629 * Determines whether a symbol represents a module or package
2630 * (Used as a helper for is(type == module) and is(type == package))
2633 * sym = the symbol to be checked
2636 * the symbol which `sym` represents (or `null` if it doesn't represent a `Package`)
2638 Package
resolveIsPackage(Dsymbol sym
)
2641 if (Import imp
= sym
.isImport())
2643 if (imp
.pkg
is null)
2645 .error(sym
.loc
, "internal compiler error: unable to process forward-referenced import `%s`",
2651 else if (auto mod
= sym
.isModule())
2652 pkg
= mod
.isPackageFile ? mod
.pkg
: sym
.isPackage();
2654 pkg
= sym
.isPackage();
2656 pkg
.resolvePKGunknown();
2661 private extern (C
++) final class ExpressionSemanticVisitor
: Visitor
2663 alias visit
= Visitor
.visit
;
2668 this(Scope
* sc
) scope @safe
2673 private void setError()
2675 result
= ErrorExp
.get();
2678 private void needThisError(Loc loc
, FuncDeclaration f
)
2680 auto t
= f
.isThis();
2682 .error(loc
, "calling non-static function `%s` requires an instance of type `%s`", f
.toChars(), t
.toChars());
2686 /**************************
2687 * Semantically analyze Expression.
2688 * Determine types, fold constants, etc.
2690 override void visit(Expression e
)
2692 static if (LOGSEMANTIC
)
2694 printf("Expression::semantic() %s\n", e
.toChars());
2697 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
2699 e
.type
= Type
.tvoid
;
2703 override void visit(IntegerExp e
)
2706 if (e
.type
.ty
== Terror
)
2709 assert(e
.type
.deco
);
2710 e
.setInteger(e
.getInteger());
2714 override void visit(RealExp e
)
2717 e
.type
= Type
.tfloat64
;
2718 else if (e
.type
.isimaginary
&& sc
.flags
& SCOPE
.Cfile
)
2720 /* Convert to core.stdc.config.complex
2722 Type t
= getComplexLibraryType(e
.loc
, sc
, e
.type
.ty
);
2729 case Timaginary32
: tf
= Type
.tfloat32
; break;
2730 case Timaginary64
: tf
= Type
.tfloat64
; break;
2731 case Timaginary80
: tf
= Type
.tfloat80
; break;
2736 /* Construct ts{re : 0.0, im : e}
2738 TypeStruct ts
= t
.isTypeStruct
;
2739 Expressions
* elements
= new Expressions(2);
2740 (*elements
)[0] = new RealExp(e
.loc
, CTFloat
.zero
, tf
);
2741 (*elements
)[1] = new RealExp(e
.loc
, e
.toImaginary(), tf
);
2742 Expression sle
= new StructLiteralExp(e
.loc
, ts
.sym
, elements
);
2743 result
= sle
.expressionSemantic(sc
);
2747 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
2751 override void visit(ComplexExp e
)
2754 e
.type
= Type
.tcomplex80
;
2756 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
2760 override void visit(IdentifierExp exp
)
2762 static if (LOGSEMANTIC
)
2764 printf("IdentifierExp::semantic('%s')\n", exp
.ident
.toChars());
2766 if (exp
.type
) // This is used as the dummy expression
2773 Dsymbol s
= sc
.search(exp
.loc
, exp
.ident
, &scopesym
);
2781 /* See if the symbol was a member of an enclosing 'with'
2783 WithScopeSymbol withsym
= scopesym
.isWithScopeSymbol();
2784 if (withsym
&& withsym
.withstate
.wthis
&& symbolIsVisible(sc
, s
))
2786 /* Disallow shadowing
2788 // First find the scope of the with
2790 while (scwith
.scopesym
!= scopesym
)
2792 scwith
= scwith
.enclosing
;
2795 // Look at enclosing scopes for symbols with the same name,
2796 // in the same function
2797 for (Scope
* scx
= scwith
; scx
&& scx
.func
== scwith
.func
; scx
= scx
.enclosing
)
2800 if (scx
.scopesym
&& scx
.scopesym
.symtab
&& (s2
= scx
.scopesym
.symtab
.lookup(s
.ident
)) !is null && s
!= s2
)
2802 error(exp
.loc
, "with symbol `%s` is shadowing local symbol `%s`", s
.toPrettyChars(), s2
.toPrettyChars());
2808 // Same as wthis.ident
2809 // TODO: DotIdExp.semantic will find 'ident' from 'wthis' again.
2810 // The redudancy should be removed.
2811 e
= new VarExp(exp
.loc
, withsym
.withstate
.wthis
);
2812 e
= new DotIdExp(exp
.loc
, e
, exp
.ident
);
2813 e
= e
.expressionSemantic(sc
);
2819 if (withsym
.withstate
.exp
.type
.ty
!= Tvoid
)
2821 // 'with (exp)' is a type expression
2822 // or 's' is not visible there (for error message)
2823 e
= new TypeExp(exp
.loc
, withsym
.withstate
.exp
.type
);
2827 // 'with (exp)' is a Package/Module
2828 e
= withsym
.withstate
.exp
;
2830 e
= new DotIdExp(exp
.loc
, e
, exp
.ident
);
2831 result
= e
.expressionSemantic(sc
);
2835 /* If f is really a function template,
2836 * then replace f with the function template declaration.
2838 FuncDeclaration f
= s
.isFuncDeclaration();
2841 TemplateDeclaration td
= getFuncTemplateDecl(f
);
2844 if (td
.overroot
) // if not start of overloaded list of TemplateDeclaration's
2845 td
= td
.overroot
; // then get the start
2846 e
= new TemplateExp(exp
.loc
, td
, f
);
2847 e
= e
.expressionSemantic(sc
);
2853 if (global
.params
.fixAliasThis
)
2855 ExpressionDsymbol expDsym
= scopesym
.isExpressionDsymbol();
2858 //printf("expDsym = %s\n", expDsym.exp.toChars());
2859 result
= expDsym
.exp
.expressionSemantic(sc
);
2863 // Haven't done overload resolution yet, so pass 1
2864 e
= symbolToExp(s
, exp
.loc
, sc
, true);
2870 if (!global
.params
.fixAliasThis
&& hasThis(sc
))
2872 for (AggregateDeclaration ad
= sc
.getStructClassScope(); ad
;)
2877 e
= new ThisExp(exp
.loc
);
2878 e
= new DotIdExp(exp
.loc
, e
, ad
.aliasthis
.ident
);
2879 e
= new DotIdExp(exp
.loc
, e
, exp
.ident
);
2880 e
= e
.trySemantic(sc
);
2888 auto cd
= ad
.isClassDeclaration();
2889 if (cd
&& cd
.baseClass
&& cd
.baseClass
!= ClassDeclaration
.object
)
2898 if (exp
.ident
== Id
.ctfe
)
2900 if (sc
.flags
& SCOPE
.ctfe
)
2902 error(exp
.loc
, "variable `__ctfe` cannot be read at compile time");
2906 // Create the magic __ctfe bool variable
2907 auto vd
= new VarDeclaration(exp
.loc
, Type
.tbool
, Id
.ctfe
, null);
2908 vd
.storage_class |
= STC
.temp
;
2909 vd
.semanticRun
= PASS
.semanticdone
;
2910 Expression e
= new VarExp(exp
.loc
, vd
);
2911 e
= e
.expressionSemantic(sc
);
2916 // If we've reached this point and are inside a with() scope then we may
2917 // try one last attempt by checking whether the 'wthis' object supports
2918 // dynamic dispatching via opDispatch.
2919 // This is done by rewriting this expression as wthis.ident.
2920 // The innermost with() scope of the hierarchy to satisfy the condition
2922 // https://issues.dlang.org/show_bug.cgi?id=6400
2923 for (Scope
* sc2
= sc
; sc2
; sc2
= sc2
.enclosing
)
2928 if (auto ss
= sc2
.scopesym
.isWithScopeSymbol())
2930 if (ss
.withstate
.wthis
)
2933 e
= new VarExp(exp
.loc
, ss
.withstate
.wthis
);
2934 e
= new DotIdExp(exp
.loc
, e
, exp
.ident
);
2935 e
= e
.trySemantic(sc
);
2942 // Try Type.opDispatch (so the static version)
2943 else if (ss
.withstate
.exp
&& ss
.withstate
.exp
.op
== EXP
.type
)
2945 if (Type t
= ss
.withstate
.exp
.isTypeExp().type
)
2948 e
= new TypeExp(exp
.loc
, t
);
2949 e
= new DotIdExp(exp
.loc
, e
, exp
.ident
);
2950 e
= e
.trySemantic(sc
);
2961 /* Look for what user might have meant
2963 if (const n
= importHint(exp
.ident
.toString()))
2964 error(exp
.loc
, "`%s` is not defined, perhaps `import %.*s;` is needed?", exp
.ident
.toChars(), cast(int)n
.length
, n
.ptr
);
2965 else if (auto s2
= sc
.search_correct(exp
.ident
))
2966 error(exp
.loc
, "undefined identifier `%s`, did you mean %s `%s`?", exp
.ident
.toChars(), s2
.kind(), s2
.toChars());
2967 else if (const p
= Scope
.search_correct_C(exp
.ident
))
2968 error(exp
.loc
, "undefined identifier `%s`, did you mean `%s`?", exp
.ident
.toChars(), p
);
2969 else if (exp
.ident
== Id
.dollar
)
2970 error(exp
.loc
, "undefined identifier `$`");
2972 error(exp
.loc
, "undefined identifier `%s`", exp
.ident
.toChars());
2974 result
= ErrorExp
.get();
2977 override void visit(DsymbolExp e
)
2979 result
= symbolToExp(e
.s
, e
.loc
, sc
, e
.hasOverloads
);
2982 override void visit(ThisExp e
)
2984 static if (LOGSEMANTIC
)
2986 printf("ThisExp::semantic()\n");
2994 FuncDeclaration fd
= hasThis(sc
); // fd is the uplevel function with the 'this' variable
2995 AggregateDeclaration ad
;
2997 /* Special case for typeof(this) and typeof(super) since both
2998 * should work even if they are not inside a non-static member function
3000 if (!fd
&& sc
.intypeof
== 1)
3002 // Find enclosing struct or class
3003 for (Dsymbol s
= sc
.getStructClassScope(); 1; s
= s
.parent
)
3007 error(e
.loc
, "`%s` is not in a class or struct scope", e
.toChars());
3010 ClassDeclaration cd
= s
.isClassDeclaration();
3017 StructDeclaration sd
= s
.isStructDeclaration();
3028 error(e
.loc
, "`this` is only defined in non-static member functions, not `%s`", sc
.parent
.toChars());
3034 assert(e
.var
.parent
);
3035 ad
= fd
.isMemberLocal();
3037 ad
= fd
.isMember2();
3039 e
.type
= ad
.type
.addMod(e
.var
.type
.mod
);
3041 if (e
.var
.checkNestedReference(sc
, e
.loc
))
3047 override void visit(SuperExp e
)
3049 static if (LOGSEMANTIC
)
3051 printf("SuperExp::semantic('%s')\n", e
.toChars());
3059 FuncDeclaration fd
= hasThis(sc
);
3060 ClassDeclaration cd
;
3063 /* Special case for typeof(this) and typeof(super) since both
3064 * should work even if they are not inside a non-static member function
3066 if (!fd
&& sc
.intypeof
== 1)
3068 // Find enclosing class
3069 for (s
= sc
.getStructClassScope(); 1; s
= s
.parent
)
3073 error(e
.loc
, "`%s` is not in a class scope", e
.toChars());
3076 cd
= s
.isClassDeclaration();
3082 error(e
.loc
, "class `%s` has no `super`", s
.toChars());
3095 assert(e
.var
&& e
.var
.parent
);
3097 s
= fd
.toParentDecl();
3098 if (s
.isTemplateDeclaration()) // allow inside template constraint
3101 cd
= s
.isClassDeclaration();
3102 //printf("parent is %s %s\n", fd.toParent().kind(), fd.toParent().toChars());
3107 error(e
.loc
, "no base class for `%s`", cd
.toChars());
3108 e
.type
= cd
.type
.addMod(e
.var
.type
.mod
);
3112 e
.type
= cd
.baseClass
.type
;
3113 e
.type
= e
.type
.castMod(e
.var
.type
.mod
);
3116 if (e
.var
.checkNestedReference(sc
, e
.loc
))
3123 error(e
.loc
, "`super` is only allowed in non-static class member functions");
3124 result
= ErrorExp
.get();
3127 override void visit(NullExp e
)
3129 static if (LOGSEMANTIC
)
3131 printf("NullExp::semantic('%s')\n", e
.toChars());
3133 // NULL is the same as (void *)0
3139 e
.type
= Type
.tnull
;
3143 override void visit(StringExp e
)
3145 static if (LOGSEMANTIC
)
3147 printf("StringExp::semantic() %s\n", e
.toChars());
3163 for (u
= 0; u
< e
.len
;)
3165 if (const p
= utf_decodeChar(e
.peekString(), u
, c
))
3167 error(e
.loc
, "%.*s", cast(int)p
.length
, p
.ptr
);
3177 e
.setData(buffer
.extractData(), newlen
, 4);
3178 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
3179 e
.type
= Type
.tuns32
.sarrayOf(e
.len
+ 1);
3181 e
.type
= Type
.tdchar
.immutableOf().arrayOf();
3186 for (u
= 0; u
< e
.len
;)
3188 if (const p
= utf_decodeChar(e
.peekString(), u
, c
))
3190 error(e
.loc
, "%.*s", cast(int)p
.length
, p
.ptr
);
3195 buffer
.writeUTF16(c
);
3201 buffer
.writeUTF16(0);
3202 e
.setData(buffer
.extractData(), newlen
, 2);
3203 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
3204 e
.type
= Type
.tuns16
.sarrayOf(e
.len
+ 1);
3206 e
.type
= Type
.twchar
.immutableOf().arrayOf();
3215 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
3216 e
.type
= Type
.tchar
.sarrayOf(e
.len
+ 1);
3218 e
.type
= Type
.tchar
.immutableOf().arrayOf();
3221 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
3222 //type = type.immutableOf();
3223 //printf("type = %s\n", type.toChars());
3228 override void visit(TupleExp exp
)
3230 static if (LOGSEMANTIC
)
3232 printf("+TupleExp::semantic(%s)\n", exp
.toChars());
3241 exp
.e0
= exp
.e0
.expressionSemantic(sc
);
3243 // Run semantic() on each argument
3245 for (size_t i
= 0; i
< exp
.exps
.length
; i
++)
3247 Expression e
= (*exp
.exps
)[i
];
3248 e
= e
.expressionSemantic(sc
);
3251 error(exp
.loc
, "`%s` has no value", e
.toChars());
3254 else if (e
.op
== EXP
.error
)
3262 expandTuples(exp
.exps
);
3264 exp
.type
= new TypeTuple(exp
.exps
);
3265 exp
.type
= exp
.type
.typeSemantic(exp
.loc
, sc
);
3266 //printf("-TupleExp::semantic(%s)\n", toChars());
3270 override void visit(ArrayLiteralExp e
)
3272 static if (LOGSEMANTIC
)
3274 printf("ArrayLiteralExp::semantic('%s')\n", e
.toChars());
3282 /* Perhaps an empty array literal [ ] should be rewritten as null?
3286 e
.basis
= e
.basis
.expressionSemantic(sc
);
3287 if (arrayExpressionSemantic(e
.elements
.peekSlice(), sc
) ||
(e
.basis
&& e
.basis
.op
== EXP
.error
))
3290 expandTuples(e
.elements
);
3293 e
.elements
.push(e
.basis
);
3294 Type t0
= arrayExpressionToCommonType(sc
, *e
.elements
);
3296 e
.basis
= e
.elements
.pop();
3300 e
.type
= t0
.arrayOf();
3301 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
3303 /* Disallow array literals of type void being used.
3305 if (e
.elements
.length
> 0 && t0
.ty
== Tvoid
)
3307 error(e
.loc
, "`%s` of type `%s` has no value", e
.toChars(), e
.type
.toChars());
3311 if (global
.params
.useTypeInfo
&& Type
.dtypeinfo
)
3312 semanticTypeInfo(sc
, e
.type
);
3317 override void visit(AssocArrayLiteralExp e
)
3319 static if (LOGSEMANTIC
)
3321 printf("AssocArrayLiteralExp::semantic('%s')\n", e
.toChars());
3329 // Run semantic() on each element
3330 bool err_keys
= arrayExpressionSemantic(e
.keys
.peekSlice(), sc
);
3331 bool err_vals
= arrayExpressionSemantic(e
.values
.peekSlice(), sc
);
3332 if (err_keys || err_vals
)
3335 expandTuples(e
.keys
);
3336 expandTuples(e
.values
);
3337 if (e
.keys
.length
!= e
.values
.length
)
3339 error(e
.loc
, "number of keys is %llu, must match number of values %llu",
3340 cast(ulong) e
.keys
.length
, cast(ulong) e
.values
.length
);
3344 Type tkey
= arrayExpressionToCommonType(sc
, *e
.keys
);
3345 Type tvalue
= arrayExpressionToCommonType(sc
, *e
.values
);
3346 if (tkey
is null || tvalue
is null)
3349 e
.type
= new TypeAArray(tvalue
, tkey
);
3350 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
3352 semanticTypeInfo(sc
, e
.type
);
3354 if (checkAssocArrayLiteralEscape(sc
, e
, false))
3360 override void visit(StructLiteralExp e
)
3362 static if (LOGSEMANTIC
)
3364 printf("StructLiteralExp::semantic('%s')\n", e
.toChars());
3373 if (e
.sd
.sizeok
!= Sizeok
.done
)
3376 // run semantic() on each element
3377 if (arrayExpressionSemantic(e
.elements
.peekSlice(), sc
))
3380 expandTuples(e
.elements
);
3382 /* Fit elements[] to the corresponding type of field[].
3384 if (!e
.sd
.fit(e
.loc
, sc
, e
.elements
, e
.stype
))
3387 /* Fill out remainder of elements[] with default initializers for fields[]
3389 if (!e
.sd
.fill(e
.loc
, *e
.elements
, false))
3391 /* An error in the initializer needs to be recorded as an error
3392 * in the enclosing function or template, since the initializer
3393 * will be part of the stuct declaration.
3395 global
.increaseErrorCount();
3399 if (checkFrameAccess(e
.loc
, sc
, e
.sd
, e
.elements
.length
))
3402 e
.type
= e
.stype ? e
.stype
: e
.sd
.type
;
3406 override void visit(CompoundLiteralExp cle
)
3408 static if (LOGSEMANTIC
)
3410 printf("CompoundLiteralExp::semantic('%s')\n", cle
.toChars());
3412 Type t
= cle
.type
.typeSemantic(cle
.loc
, sc
);
3413 auto init
= initializerSemantic(cle
.initializer
, sc
, t
, INITnointerpret
);
3414 auto e
= initializerToExpression(init
, t
, (sc
.flags
& SCOPE
.Cfile
) != 0);
3417 error(cle
.loc
, "cannot convert initializer `%s` to expression", init
.toChars());
3424 override void visit(TypeExp exp
)
3426 if (exp
.type
.ty
== Terror
)
3429 //printf("TypeExp::semantic(%s)\n", exp.type.toChars());
3434 dmd
.typesem
.resolve(exp
.type
, exp
.loc
, sc
, e
, t
, s
, true);
3437 // `(Type)` is actually `(var)` so if `(var)` is a member requiring `this`
3438 // then rewrite as `(this.var)` in case it would be followed by a DotVar
3439 // to fix https://issues.dlang.org/show_bug.cgi?id=9490
3440 VarExp ve
= e
.isVarExp();
3441 if (ve
&& ve
.var
&& exp
.parens
&& !ve
.var
.isStatic() && !(sc
.stc & STC
.static_
) &&
3442 sc
.func
&& sc
.func
.needThis
&& ve
.var
.isMember2())
3444 // printf("apply fix for bugzilla issue 9490: add `this.` to `%s`...\n", e.toChars());
3445 e
= new DotVarExp(exp
.loc
, new ThisExp(exp
.loc
), ve
.var
, false);
3447 //printf("e = %s %s\n", Token.toChars(e.op), e.toChars());
3448 e
= e
.expressionSemantic(sc
);
3452 //printf("t = %d %s\n", t.ty, t.toChars());
3453 exp
.type
= t
.typeSemantic(exp
.loc
, sc
);
3458 //printf("s = %s %s\n", s.kind(), s.toChars());
3459 e
= symbolToExp(s
, exp
.loc
, sc
, true);
3464 exp
.type
.checkComplexTransition(exp
.loc
, sc
);
3469 override void visit(ScopeExp exp
)
3471 static if (LOGSEMANTIC
)
3473 printf("+ScopeExp::semantic(%p '%s')\n", exp
, exp
.toChars());
3481 ScopeDsymbol sds2
= exp
.sds
;
3482 TemplateInstance ti
= sds2
.isTemplateInstance();
3485 WithScopeSymbol withsym
;
3486 if (!ti
.findTempDecl(sc
, &withsym
) ||
!ti
.semanticTiargs(sc
))
3488 if (withsym
&& withsym
.withstate
.wthis
)
3490 Expression e
= new VarExp(exp
.loc
, withsym
.withstate
.wthis
);
3491 e
= new DotTemplateInstanceExp(exp
.loc
, e
, ti
);
3492 result
= e
.expressionSemantic(sc
);
3495 if (ti
.needsTypeInference(sc
))
3497 if (TemplateDeclaration td
= ti
.tempdecl
.isTemplateDeclaration())
3499 Dsymbol p
= td
.toParentLocal();
3500 FuncDeclaration fdthis
= hasThis(sc
);
3501 AggregateDeclaration ad
= p ? p
.isAggregateDeclaration() : null;
3502 if (fdthis
&& ad
&& fdthis
.isMemberLocal() == ad
&& (td
._scope
.stc & STC
.static_
) == 0)
3504 Expression e
= new DotTemplateInstanceExp(exp
.loc
, new ThisExp(exp
.loc
), ti
);
3505 result
= e
.expressionSemantic(sc
);
3509 else if (OverloadSet os
= ti
.tempdecl
.isOverloadSet())
3511 FuncDeclaration fdthis
= hasThis(sc
);
3512 AggregateDeclaration ad
= os
.parent
.isAggregateDeclaration();
3513 if (fdthis
&& ad
&& fdthis
.isMemberLocal() == ad
)
3515 Expression e
= new DotTemplateInstanceExp(exp
.loc
, new ThisExp(exp
.loc
), ti
);
3516 result
= e
.expressionSemantic(sc
);
3520 // ti is an instance which requires IFTI.
3522 exp
.type
= Type
.tvoid
;
3526 ti
.dsymbolSemantic(sc
);
3527 if (!ti
.inst || ti
.errors
)
3530 Dsymbol s
= ti
.toAlias();
3534 exp
.type
= Type
.tvoid
;
3538 sds2
= s
.isScopeDsymbol();
3541 ti
= sds2
.isTemplateInstance();
3542 //printf("+ sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
3546 if (auto v
= s
.isVarDeclaration())
3550 error(exp
.loc
, "forward reference of %s `%s`", v
.kind(), v
.toChars());
3553 if ((v
.storage_class
& STC
.manifest
) && v
._init
)
3555 /* When an instance that will be converted to a constant exists,
3556 * the instance representation "foo!tiargs" is treated like a
3557 * variable name, and its recursive appearance check (note that
3558 * it's equivalent with a recursive instantiation of foo) is done
3559 * separately from the circular initialization check for the
3560 * eponymous enum variable declaration.
3563 * enum bool foo = foo; // recursive definition check (v.inuse)
3566 * enum bool bar = bar!T; // recursive instantiation check (ti.inuse)
3571 error(exp
.loc
, "recursive expansion of %s `%s`", ti
.kind(), ti
.toPrettyChars());
3574 v
.checkDeprecated(exp
.loc
, sc
);
3575 auto e
= v
.expandInitializer(exp
.loc
);
3577 e
= e
.expressionSemantic(sc
);
3584 //printf("s = %s, '%s'\n", s.kind(), s.toChars());
3585 auto e
= symbolToExp(s
, exp
.loc
, sc
, true);
3586 //printf("-1ScopeExp::semantic()\n");
3591 //printf("sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
3592 //printf("\tparent = '%s'\n", sds2.parent.toChars());
3593 sds2
.dsymbolSemantic(sc
);
3595 // (Aggregate|Enum)Declaration
3596 if (auto t
= sds2
.getType())
3598 result
= (new TypeExp(exp
.loc
, t
)).expressionSemantic(sc
);
3602 if (auto td
= sds2
.isTemplateDeclaration())
3604 result
= (new TemplateExp(exp
.loc
, td
)).expressionSemantic(sc
);
3609 exp
.type
= Type
.tvoid
;
3610 //printf("-2ScopeExp::semantic() %s\n", toChars());
3615 * Sets the `lowering` field of a `NewExp` to a call to `_d_newitemT` unless
3616 * compiling with `-betterC` or within `__traits(compiles)`.
3619 * ne = the `NewExp` to lower
3621 private void tryLowerToNewItem(NewExp ne
)
3623 if (!global
.params
.useGC ||
!sc
.needsCodegen())
3626 auto hook
= global
.params
.tracegc ? Id
._d_newitemTTrace
: Id
._d_newitemT
;
3627 if (!verifyHookExist(ne
.loc
, *sc
, hook
, "new struct"))
3630 /* Lower the memory allocation and initialization of `new T()` to
3631 * `_d_newitemT!T()`.
3633 Expression id
= new IdentifierExp(ne
.loc
, Id
.empty
);
3634 id
= new DotIdExp(ne
.loc
, id
, Id
.object
);
3635 auto tiargs
= new Objects();
3637 * Remove `inout`, `const`, `immutable` and `shared` to reduce the
3638 * number of generated `_d_newitemT` instances.
3640 auto t
= ne
.type
.nextOf
.unqualify(MODFlags
.wild | MODFlags
.const_ |
3641 MODFlags
.immutable_ | MODFlags
.shared_
);
3643 id
= new DotTemplateInstanceExp(ne
.loc
, id
, hook
, tiargs
);
3645 auto arguments
= new Expressions();
3646 if (global
.params
.tracegc
)
3648 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ?
3649 sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
3650 arguments
.push(new StringExp(ne
.loc
, ne
.loc
.filename
.toDString()));
3651 arguments
.push(new IntegerExp(ne
.loc
, ne
.loc
.linnum
, Type
.tint32
));
3652 arguments
.push(new StringExp(ne
.loc
, funcname
.toDString()));
3654 id
= new CallExp(ne
.loc
, id
, arguments
);
3656 ne
.lowering
= id
.expressionSemantic(sc
);
3659 override void visit(NewExp exp
)
3661 static if (LOGSEMANTIC
)
3663 printf("NewExp::semantic() %s\n", exp
.toChars());
3665 printf("\tthisexp = %s\n", exp
.thisexp
.toChars());
3666 printf("\tnewtype: %s\n", exp
.newtype
.toChars());
3668 if (exp
.type
) // if semantic() already run
3674 //for error messages if the argument in [] is not convertible to size_t
3675 const originalNewtype
= exp
.newtype
;
3677 // https://issues.dlang.org/show_bug.cgi?id=11581
3678 // With the syntax `new T[edim]` or `thisexp.new T[edim]`,
3679 // T should be analyzed first and edim should go into arguments iff it's
3681 Expression edim
= null;
3682 if (!exp
.arguments
&& exp
.newtype
.isTypeSArray())
3684 auto ts
= exp
.newtype
.isTypeSArray();
3685 // check `new Value[Key]`
3686 ts
.dim
= ts
.dim
.expressionSemantic(sc
);
3687 if (ts
.dim
.op
== EXP
.type
)
3689 exp
.newtype
= new TypeAArray(ts
.next
, ts
.dim
.isTypeExp().type
);
3694 exp
.newtype
= ts
.next
;
3698 ClassDeclaration cdthis
= null;
3701 exp
.thisexp
= exp
.thisexp
.expressionSemantic(sc
);
3702 if (exp
.thisexp
.op
== EXP
.error
)
3705 cdthis
= exp
.thisexp
.type
.isClassHandle();
3708 error(exp
.loc
, "`this` for nested class must be a class type, not `%s`", exp
.thisexp
.type
.toChars());
3712 sc
= sc
.push(cdthis
);
3713 exp
.type
= exp
.newtype
.typeSemantic(exp
.loc
, sc
);
3718 exp
.type
= exp
.newtype
.typeSemantic(exp
.loc
, sc
);
3720 if (exp
.type
.ty
== Terror
)
3725 if (exp
.type
.toBasetype().ty
== Ttuple
)
3728 exp
.type
= new TypeSArray(exp
.type
, edim
);
3729 exp
.type
= exp
.type
.typeSemantic(exp
.loc
, sc
);
3730 if (exp
.type
.ty
== Terror
)
3735 // --> new T[](edim)
3736 exp
.arguments
= new Expressions();
3737 exp
.arguments
.push(edim
);
3738 exp
.type
= exp
.type
.arrayOf();
3742 exp
.newtype
= exp
.type
; // in case type gets cast to something else
3743 Type tb
= exp
.type
.toBasetype();
3744 //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco);
3745 if (arrayExpressionSemantic(exp
.arguments
.peekSlice(), sc
))
3749 if (preFunctionParameters(sc
, exp
.argumentList
))
3754 if (exp
.thisexp
&& tb
.ty
!= Tclass
)
3756 error(exp
.loc
, "`.new` is only for allocating nested classes, not `%s`", tb
.toChars());
3760 const size_t nargs
= exp
.arguments ? exp
.arguments
.length
: 0;
3761 Expression newprefix
= null;
3763 if (auto tc
= tb
.isTypeClass())
3769 if (cd
.sizeok
!= Sizeok
.done
)
3772 cd
.ctor
= cd
.searchCtor();
3773 if (cd
.noDefaultCtor
&& !nargs
&& !cd
.defaultCtor
)
3775 error(exp
.loc
, "default construction is disabled for type `%s`", cd
.type
.toChars());
3779 if (cd
.isInterfaceDeclaration())
3781 error(exp
.loc
, "cannot create instance of interface `%s`", cd
.toChars());
3785 if (cd
.isAbstract())
3787 error(exp
.loc
, "cannot create instance of abstract class `%s`", cd
.toChars());
3788 errorSupplemental(cd
.loc
, "class `%s` is declared here", cd
.toChars());
3789 for (size_t i
= 0; i
< cd
.vtbl
.length
; i
++)
3791 FuncDeclaration fd
= cd
.vtbl
[i
].isFuncDeclaration();
3792 if (fd
&& fd
.isAbstract())
3794 errorSupplemental(fd
.loc
, "function `%s` is not implemented",
3795 fd
.toFullSignature());
3800 // checkDeprecated() is already done in newtype.typeSemantic().
3804 /* We need a 'this' pointer for the nested class.
3805 * Ensure we have the right one.
3807 Dsymbol s
= cd
.toParentLocal();
3809 //printf("cd isNested, parent = %s '%s'\n", s.kind(), s.toPrettyChars());
3810 if (auto cdn
= s
.isClassDeclaration())
3814 void noReferenceToOuterClass()
3817 error(exp
.loc
, "cannot construct anonymous nested class because no implicit `this` reference to outer class is available");
3819 error(exp
.loc
, "cannot construct nested class `%s` because no implicit `this` reference to outer class `%s` is available",
3820 cd
.toChars(), cdn
.toChars());
3825 return noReferenceToOuterClass();
3827 // Supply an implicit 'this' and try again
3828 exp
.thisexp
= new ThisExp(exp
.loc
);
3829 for (Dsymbol sp
= sc
.parent
; 1; sp
= sp
.toParentLocal())
3832 return noReferenceToOuterClass();
3833 ClassDeclaration cdp
= sp
.isClassDeclaration();
3836 if (cdp
== cdn || cdn
.isBaseOf(cdp
, null))
3838 // Add a '.outer' and try again
3839 exp
.thisexp
= new DotIdExp(exp
.loc
, exp
.thisexp
, Id
.outer
);
3842 exp
.thisexp
= exp
.thisexp
.expressionSemantic(sc
);
3843 if (exp
.thisexp
.op
== EXP
.error
)
3845 cdthis
= exp
.thisexp
.type
.isClassHandle();
3847 if (cdthis
!= cdn
&& !cdn
.isBaseOf(cdthis
, null))
3849 //printf("cdthis = %s\n", cdthis.toChars());
3850 error(exp
.loc
, "`this` for nested class must be of type `%s`, not `%s`",
3851 cdn
.toChars(), exp
.thisexp
.type
.toChars());
3854 if (!MODimplicitConv(exp
.thisexp
.type
.mod
, exp
.newtype
.mod
))
3856 error(exp
.loc
, "nested type `%s` should have the same or weaker constancy as enclosing type `%s`",
3857 exp
.newtype
.toChars(), exp
.thisexp
.type
.toChars());
3861 else if (exp
.thisexp
)
3863 error(exp
.loc
, "`.new` is only for allocating nested classes");
3866 else if (auto fdn
= s
.isFuncDeclaration())
3868 // make sure the parent context fdn of cd is reachable from sc
3869 if (!ensureStaticLinkTo(sc
.parent
, fdn
))
3871 error(exp
.loc
, "outer function context of `%s` is needed to `new` nested class `%s`",
3872 fdn
.toPrettyChars(), cd
.toPrettyChars());
3879 else if (exp
.thisexp
)
3881 error(exp
.loc
, "`.new` is only for allocating nested classes");
3887 if (AggregateDeclaration ad2
= cd
.isMember2())
3889 Expression te
= new ThisExp(exp
.loc
).expressionSemantic(sc
);
3890 if (te
.op
!= EXP
.error
)
3891 te
= getRightThis(exp
.loc
, sc
, ad2
, te
, cd
);
3892 if (te
.op
== EXP
.error
)
3894 error(exp
.loc
, "need `this` of type `%s` needed to `new` nested class `%s`", ad2
.toChars(), cd
.toChars());
3900 if (cd
.disableNew
&& !exp
.onstack
)
3902 error(exp
.loc
, "cannot allocate `class %s` with `new` because it is annotated with `@disable new()`",
3903 originalNewtype
.toChars());
3909 FuncDeclaration f
= resolveFuncCall(exp
.loc
, sc
, cd
.ctor
, null, tb
, exp
.argumentList
, FuncResolveFlag
.standard
);
3913 checkFunctionAttributes(exp
, sc
, f
);
3914 checkAccess(cd
, exp
.loc
, sc
, f
);
3916 TypeFunction tf
= f
.type
.isTypeFunction();
3918 exp
.arguments
= new Expressions();
3919 if (functionParameters(exp
.loc
, sc
, tf
, null, exp
.type
, exp
.argumentList
, f
, &exp
.type
, &exp
.argprefix
))
3922 exp
.member
= f
.isCtorDeclaration();
3929 error(exp
.loc
, "no constructor for `%s`", cd
.toChars());
3933 // https://issues.dlang.org/show_bug.cgi?id=19941
3934 // Run semantic on all field initializers to resolve any forward
3935 // references. This is the same as done for structs in sd.fill().
3936 for (ClassDeclaration c
= cd
; c
; c
= c
.baseClass
)
3938 foreach (v
; c
.fields
)
3940 if (v
.inuse || v
._scope
is null || v
._init
is null ||
3941 v
._init
.isVoidInitializer() || v
.semanticRun
>= PASS
.semantic2done
)
3944 v
._init
= v
._init
.initializerSemantic(v
._scope
, v
.type
, INITinterpret
);
3945 import dmd
.semantic2
: lowerStaticAAs
;
3946 lowerStaticAAs(v
, sc
);
3952 // When using `@nogc` exception handling, lower `throw new E(args)` to
3953 // `throw (__tmp = _d_newThrowable!E(), __tmp.__ctor(args), __tmp)`.
3954 if (global
.params
.ehnogc
&& exp
.thrownew
&&
3955 !cd
.isCOMclass() && !cd
.isCPPclass())
3959 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
3960 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
3962 auto tiargs
= new Objects();
3963 tiargs
.push(exp
.newtype
);
3964 id
= new DotTemplateInstanceExp(exp
.loc
, id
, Id
._d_newThrowable
, tiargs
);
3965 id
= new CallExp(exp
.loc
, id
).expressionSemantic(sc
);
3968 Expression tmp
= extractSideEffect(sc
, "__tmpThrowable", idVal
, id
, true);
3969 // auto castTmp = new CastExp(exp.loc, tmp, exp.type);
3971 auto ctor
= new DotIdExp(exp
.loc
, tmp
, Id
.ctor
).expressionSemantic(sc
);
3972 auto ctorCall
= new CallExp(exp
.loc
, ctor
, exp
.arguments
);
3974 id
= Expression
.combine(idVal
, exp
.argprefix
).expressionSemantic(sc
);
3975 id
= Expression
.combine(id
, ctorCall
).expressionSemantic(sc
);
3976 // id = Expression.combine(id, castTmp).expressionSemantic(sc);
3978 result
= id
.expressionSemantic(sc
);
3981 else if (sc
.needsCodegen() && // interpreter doesn't need this lowered
3982 !exp
.onstack
&& !exp
.type
.isscope()) // these won't use the GC
3984 /* replace `new T(arguments)` with `core.lifetime._d_newclassT!T(arguments)`
3985 * or `_d_newclassTTrace`
3987 auto hook
= global
.params
.tracegc ? Id
._d_newclassTTrace
: Id
._d_newclassT
;
3988 if (!verifyHookExist(exp
.loc
, *sc
, hook
, "new class"))
3991 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
3992 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
3994 auto tiargs
= new Objects();
3995 auto t
= exp
.newtype
.unqualify(MODFlags
.wild
); // remove `inout`
3997 id
= new DotTemplateInstanceExp(exp
.loc
, id
, hook
, tiargs
);
3998 auto arguments
= new Expressions();
3999 if (global
.params
.tracegc
)
4001 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ?
4002 sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
4003 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
4004 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
4005 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
4007 id
= new CallExp(exp
.loc
, id
, arguments
);
4009 exp
.lowering
= id
.expressionSemantic(sc
);
4012 else if (auto ts
= tb
.isTypeStruct())
4016 if (sd
.sizeok
!= Sizeok
.done
)
4019 sd
.ctor
= sd
.searchCtor();
4020 if (sd
.noDefaultCtor
&& !nargs
)
4022 error(exp
.loc
, "default construction is disabled for type `%s`", sd
.type
.toChars());
4025 // checkDeprecated() is already done in newtype.typeSemantic().
4029 error(exp
.loc
, "cannot allocate `struct %s` with `new` because it is annotated with `@disable new()`",
4030 originalNewtype
.toChars());
4034 // https://issues.dlang.org/show_bug.cgi?id=22639
4035 // If the new expression has arguments, we either should call a
4036 // regular constructor of a copy constructor if the first argument
4037 // is the same type as the struct
4038 if (nargs
&& (sd
.hasRegularCtor() ||
(sd
.ctor
&& (*exp
.arguments
)[0].type
.mutableOf() == sd
.type
.mutableOf())))
4040 FuncDeclaration f
= resolveFuncCall(exp
.loc
, sc
, sd
.ctor
, null, tb
, exp
.argumentList
, FuncResolveFlag
.standard
);
4044 checkFunctionAttributes(exp
, sc
, f
);
4045 checkAccess(sd
, exp
.loc
, sc
, f
);
4047 TypeFunction tf
= f
.type
.isTypeFunction();
4049 exp
.arguments
= new Expressions();
4050 if (functionParameters(exp
.loc
, sc
, tf
, null, exp
.type
, exp
.argumentList
, f
, &exp
.type
, &exp
.argprefix
))
4053 exp
.member
= f
.isCtorDeclaration();
4056 if (checkFrameAccess(exp
.loc
, sc
, sd
, sd
.fields
.length
))
4063 exp
.arguments
= resolveStructLiteralNamedArgs(sd
, exp
.type
, sc
, exp
.loc
,
4064 exp
.names ?
(*exp
.names
)[] : null,
4065 (size_t i
, Type t
) => (*exp
.arguments
)[i
],
4066 i
=> (*exp
.arguments
)[i
].loc
4071 else if (!exp
.arguments
)
4073 exp
.arguments
= new Expressions();
4076 if (!sd
.fit(exp
.loc
, sc
, exp
.arguments
, tb
))
4079 if (!sd
.fill(exp
.loc
, *exp
.arguments
, false))
4082 if (checkFrameAccess(exp
.loc
, sc
, sd
, exp
.arguments ? exp
.arguments
.length
: 0))
4085 /* Since a `new` allocation may escape, check each of the arguments for escaping
4087 foreach (arg
; *exp
.arguments
)
4089 if (arg
&& checkNewEscape(sc
, arg
, false))
4094 exp
.type
= exp
.type
.pointerTo();
4095 tryLowerToNewItem(exp
);
4097 else if (tb
.ty
== Tarray
)
4101 // https://issues.dlang.org/show_bug.cgi?id=20422
4102 // Without this check the compiler would give a misleading error
4103 error(exp
.loc
, "missing length argument for array");
4107 Type tn
= tb
.nextOf().baseElemOf();
4108 Dsymbol s
= tn
.toDsymbol(sc
);
4109 AggregateDeclaration ad
= s ? s
.isAggregateDeclaration() : null;
4110 if (ad
&& ad
.noDefaultCtor
)
4112 error(exp
.loc
, "default construction is disabled for type `%s`", tb
.nextOf().toChars());
4115 for (size_t i
= 0; i
< nargs
; i
++)
4117 if (tb
.ty
!= Tarray
)
4119 error(exp
.loc
, "too many arguments for array");
4123 Expression arg
= (*exp
.arguments
)[i
];
4124 if (exp
.names
&& (*exp
.names
)[i
])
4126 error(exp
.loc
, "no named argument `%s` allowed for array dimension", (*exp
.names
)[i
].toChars());
4130 arg
= resolveProperties(sc
, arg
);
4131 arg
= arg
.implicitCastTo(sc
, Type
.tsize_t
);
4132 if (arg
.op
== EXP
.error
)
4134 arg
= arg
.optimize(WANTvalue
);
4135 if (arg
.op
== EXP
.int64
&& (target
.isLP64 ?
4136 cast(sinteger_t
)arg
.toInteger() : cast(int)arg
.toInteger()) < 0)
4138 error(exp
.loc
, "negative array dimension `%s`", (*exp
.arguments
)[i
].toChars());
4141 (*exp
.arguments
)[i
] = arg
;
4142 tb
= tb
.isTypeDArray().next
.toBasetype();
4145 else if (tb
.isscalar())
4150 else if (nargs
== 1)
4152 if (exp
.names
&& (*exp
.names
)[0])
4154 error(exp
.loc
, "no named argument `%s` allowed for scalar", (*exp
.names
)[0].toChars());
4157 Expression e
= (*exp
.arguments
)[0];
4158 e
= e
.implicitCastTo(sc
, tb
);
4159 (*exp
.arguments
)[0] = e
;
4163 error(exp
.loc
, "more than one argument for construction of `%s`", exp
.type
.toChars());
4167 exp
.type
= exp
.type
.pointerTo();
4168 tryLowerToNewItem(exp
);
4170 else if (tb
.ty
== Taarray
)
4172 // e.g. `new Alias(args)`
4175 error(exp
.loc
, "`new` cannot take arguments for an associative array");
4181 error(exp
.loc
, "cannot create a `%s` with `new`", exp
.type
.toChars());
4185 //printf("NewExp: '%s'\n", toChars());
4186 //printf("NewExp:type '%s'\n", type.toChars());
4187 semanticTypeInfo(sc
, exp
.type
);
4191 result
= Expression
.combine(newprefix
, exp
);
4197 override void visit(NewAnonClassExp e
)
4199 static if (LOGSEMANTIC
)
4201 printf("NewAnonClassExp::semantic() %s\n", e
.toChars());
4202 //printf("thisexp = %p\n", thisexp);
4203 //printf("type: %s\n", type.toChars());
4206 Expression d
= new DeclarationExp(e
.loc
, e
.cd
);
4207 sc
= sc
.push(); // just create new scope
4208 sc
.flags
&= ~SCOPE
.ctfe
; // temporary stop CTFE
4209 d
= d
.expressionSemantic(sc
);
4212 if (!e
.cd
.errors
&& sc
.intypeof
&& !sc
.parent
.inNonRoot())
4214 ScopeDsymbol sds
= sc
.tinst ?
cast(ScopeDsymbol
)sc
.tinst
: sc
._module
;
4216 sds
.members
= new Dsymbols();
4217 sds
.members
.push(e
.cd
);
4220 Expression n
= new NewExp(e
.loc
, e
.thisexp
, e
.cd
.type
, e
.arguments
);
4222 Expression c
= new CommaExp(e
.loc
, d
, n
);
4223 result
= c
.expressionSemantic(sc
);
4226 override void visit(SymOffExp e
)
4228 static if (LOGSEMANTIC
)
4230 printf("SymOffExp::semantic('%s')\n", e
.toChars());
4232 //var.dsymbolSemantic(sc);
4234 e
.type
= e
.var
.type
.pointerTo();
4236 if (auto v
= e
.var
.isVarDeclaration())
4238 if (v
.checkNestedReference(sc
, e
.loc
))
4241 else if (auto f
= e
.var
.isFuncDeclaration())
4243 if (f
.checkNestedReference(sc
, e
.loc
))
4250 override void visit(VarExp e
)
4252 static if (LOGSEMANTIC
)
4254 printf("VarExp::semantic(%s)\n", e
.toChars());
4257 auto vd
= e
.var
.isVarDeclaration();
4258 auto fd
= e
.var
.isFuncDeclaration();
4262 //printf("L%d fd = %s\n", __LINE__, f.toChars());
4263 if (!fd
.functionSemantic())
4268 e
.type
= e
.var
.type
;
4269 if (e
.type
&& !e
.type
.deco
)
4271 auto decl
= e
.var
.isDeclaration();
4274 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
4279 /* Fix for 1161 doesn't work because it causes visibility
4280 * problems when instantiating imported templates passing private
4281 * variables as alias template parameters.
4283 //checkAccess(loc, sc, NULL, var);
4287 if (vd
.checkNestedReference(sc
, e
.loc
))
4290 // https://issues.dlang.org/show_bug.cgi?id=12025
4291 // If the variable is not actually used in runtime code,
4292 // the purity violation error is redundant.
4293 //checkPurity(sc, vd);
4297 // TODO: If fd isn't yet resolved its overload, the checkNestedReference
4298 // call would cause incorrect validation.
4299 // Maybe here should be moved in CallExp, or AddrExp for functions.
4300 if (fd
.checkNestedReference(sc
, e
.loc
))
4303 else if (auto od
= e
.var
.isOverDeclaration())
4305 e
.type
= Type
.tvoid
; // ambiguous type?
4311 override void visit(FuncExp exp
)
4313 static if (LOGSEMANTIC
)
4315 printf("FuncExp::semantic(%s)\n", exp
.toChars());
4317 printf(" treq = %s\n", exp
.fd
.treq
.toChars());
4329 sc
= sc
.push(); // just create new scope
4330 sc
.flags
&= ~SCOPE
.ctfe
; // temporary stop CTFE
4331 sc
.visibility
= Visibility(Visibility
.Kind
.public_
); // https://issues.dlang.org/show_bug.cgi?id=12506
4333 /* fd.treq might be incomplete type,
4334 * so should not semantic it.
4335 * void foo(T)(T delegate(int) dg){}
4336 * foo(a=>a); // in IFTI, treq == T delegate(int)
4339 // fd.treq = fd.treq.dsymbolSemantic(loc, sc);
4343 // Set target of return type inference
4344 if (exp
.fd
.treq
&& !exp
.fd
.type
.nextOf())
4346 TypeFunction tfv
= null;
4347 if (exp
.fd
.treq
.ty
== Tdelegate || exp
.fd
.treq
.isPtrToFunction())
4348 tfv
= cast(TypeFunction
)exp
.fd
.treq
.nextOf();
4351 TypeFunction tfl
= cast(TypeFunction
)exp
.fd
.type
;
4352 tfl
.next
= tfv
.nextOf();
4356 //printf("td = %p, treq = %p\n", td, fd.treq);
4359 assert(exp
.td
.parameters
&& exp
.td
.parameters
.length
);
4360 exp
.td
.dsymbolSemantic(sc
);
4361 exp
.type
= Type
.tvoid
; // temporary type
4363 if (exp
.fd
.treq
) // defer type determination
4366 if (exp
.matchType(exp
.fd
.treq
, sc
, &fe
, sc
.eSink
) > MATCH
.nomatch
)
4374 olderrors
= global
.errors
;
4375 exp
.fd
.dsymbolSemantic(sc
);
4376 if (olderrors
== global
.errors
)
4378 exp
.fd
.semantic2(sc
);
4379 if (olderrors
== global
.errors
)
4380 exp
.fd
.semantic3(sc
);
4382 if (olderrors
!= global
.errors
)
4384 if (exp
.fd
.type
&& exp
.fd
.type
.ty
== Tfunction
&& !exp
.fd
.type
.nextOf())
4385 (cast(TypeFunction
)exp
.fd
.type
).next
= Type
.terror
;
4390 // Type is a "delegate to" or "pointer to" the function literal
4391 if ((exp
.fd
.isNested() && exp
.fd
.tok
== TOK
.delegate_
) ||
(exp
.tok
== TOK
.reserved
&& exp
.fd
.treq
&& exp
.fd
.treq
.ty
== Tdelegate
))
4393 // https://issues.dlang.org/show_bug.cgi?id=22686
4394 // if the delegate return type is an error
4395 // abort semantic of the FuncExp and propagate
4397 if (exp
.fd
.type
.isTypeError())
4402 exp
.type
= new TypeDelegate(exp
.fd
.type
.isTypeFunction());
4403 exp
.type
= exp
.type
.typeSemantic(exp
.loc
, sc
);
4405 exp
.fd
.tok
= TOK
.delegate_
;
4409 exp
.type
= new TypePointer(exp
.fd
.type
);
4410 exp
.type
= exp
.type
.typeSemantic(exp
.loc
, sc
);
4411 //type = fd.type.pointerTo();
4413 /* A lambda expression deduced to function pointer might become
4414 * to a delegate literal implicitly.
4416 * auto foo(void function() fp) { return 1; }
4417 * assert(foo({}) == 1);
4419 * So, should keep fd.tok == TOK.reserve if fd.treq == NULL.
4421 if (exp
.fd
.treq
&& exp
.fd
.treq
.ty
== Tpointer
)
4423 // change to non-nested
4424 exp
.fd
.tok
= TOK
.function_
;
4425 exp
.fd
.vthis
= null;
4428 exp
.fd
.tookAddressOf
++;
4436 * Perform semantic analysis on function literals
4438 * Test the following construct:
4440 * (x, y, z) { return x + y + z; }(42, 84, 1992);
4443 Expression
callExpSemantic(FuncExp exp
, Scope
* sc
, Expressions
* arguments
)
4445 if ((!exp
.type || exp
.type
== Type
.tvoid
) && exp
.td
&& arguments
&& arguments
.length
)
4447 for (size_t k
= 0; k
< arguments
.length
; k
++)
4449 Expression checkarg
= (*arguments
)[k
];
4450 if (checkarg
.op
== EXP
.error
)
4456 assert(exp
.td
.parameters
&& exp
.td
.parameters
.length
);
4457 exp
.td
.dsymbolSemantic(sc
);
4459 TypeFunction tfl
= cast(TypeFunction
)exp
.fd
.type
;
4460 size_t dim
= tfl
.parameterList
.length
;
4461 if (arguments
.length
< dim
)
4463 // Default arguments are always typed, so they don't need inference.
4464 Parameter p
= tfl
.parameterList
[arguments
.length
];
4466 dim
= arguments
.length
;
4469 if ((tfl
.parameterList
.varargs
== VarArg
.none
&& arguments
.length
> dim
) ||
4470 arguments
.length
< dim
)
4473 foreach (idx
, ref arg
; *arguments
)
4474 buf
.printf("%s%s", (idx ?
", ".ptr
: "".ptr
), arg
.type
.toChars());
4475 error(exp
.loc
, "function literal `%s%s` is not callable using argument types `(%s)`",
4476 exp
.fd
.toChars(), parametersTypeToChars(tfl
.parameterList
),
4478 errorSupplemental(exp
.loc
, "too %s arguments, expected %d, got %d",
4479 arguments
.length
< dim ?
"few".ptr
: "many".ptr
,
4480 cast(int)dim
, cast(int)arguments
.length
);
4481 return ErrorExp
.get();
4484 auto tiargs
= new Objects();
4485 tiargs
.reserve(exp
.td
.parameters
.length
);
4487 for (size_t i
= 0; i
< exp
.td
.parameters
.length
; i
++)
4489 TemplateParameter tp
= (*exp
.td
.parameters
)[i
];
4490 assert(dim
<= tfl
.parameterList
.length
);
4491 foreach (u
, p
; tfl
.parameterList
)
4496 if (p
.type
.ty
== Tident
&& (cast(TypeIdentifier
)p
.type
).ident
== tp
.ident
)
4498 Expression e
= (*arguments
)[u
];
4499 tiargs
.push(e
.type
);
4505 auto ti
= new TemplateInstance(exp
.loc
, exp
.td
, tiargs
);
4506 return (new ScopeExp(exp
.loc
, ti
)).expressionSemantic(sc
);
4508 return exp
.expressionSemantic(sc
);
4511 override void visit(CallExp exp
)
4513 static if (LOGSEMANTIC
)
4515 printf("CallExp::semantic() %s\n", exp
.toChars());
4520 return; // semantic() already run
4523 Objects
* tiargs
= null; // initial list of template arguments
4524 Expression ethis
= null;
4526 Expression e1org
= exp
.e1
;
4528 if (auto ce
= exp
.e1
.isCommaExp())
4530 /* Rewrite (a,b)(args) as (a,(b(args)))
4534 result
= ce
.expressionSemantic(sc
);
4537 if (DelegateExp
de = exp
.e1
.isDelegateExp())
4539 exp
.e1
= new DotVarExp(de.loc
, de.e1
, de.func
, de.hasOverloads
);
4543 if (FuncExp fe
= exp
.e1
.isFuncExp())
4545 if (arrayExpressionSemantic(exp
.arguments
.peekSlice(), sc
) ||
4546 preFunctionParameters(sc
, exp
.argumentList
))
4549 // Run e1 semantic even if arguments have any errors
4550 exp
.e1
= callExpSemantic(fe
, sc
, exp
.arguments
);
4551 if (exp
.e1
.op
== EXP
.error
)
4557 if (sc
.flags
& SCOPE
.Cfile
)
4559 /* See if need to rewrite the AST because of cast/call ambiguity
4561 if (auto e
= castCallAmbiguity(exp
, sc
))
4563 result
= expressionSemantic(e
, sc
);
4568 if (Expression ex
= resolveUFCS(sc
, exp
))
4575 * foo!(tiargs)(funcargs)
4577 if (ScopeExp se
= exp
.e1
.isScopeExp())
4579 TemplateInstance ti
= se
.sds
.isTemplateInstance();
4582 /* Attempt to instantiate ti. If that works, go with it.
4583 * If not, go with partial explicit specialization.
4585 WithScopeSymbol withsym
;
4586 if (!ti
.findTempDecl(sc
, &withsym
) ||
!ti
.semanticTiargs(sc
))
4588 if (withsym
&& withsym
.withstate
.wthis
)
4590 exp
.e1
= new VarExp(exp
.e1
.loc
, withsym
.withstate
.wthis
);
4591 exp
.e1
= new DotTemplateInstanceExp(exp
.e1
.loc
, exp
.e1
, ti
);
4594 if (ti
.needsTypeInference(sc
, 1))
4596 /* Go with partial explicit specialization
4599 assert(ti
.tempdecl
);
4600 if (TemplateDeclaration td
= ti
.tempdecl
.isTemplateDeclaration())
4601 exp
.e1
= new TemplateExp(exp
.loc
, td
);
4602 else if (OverDeclaration od
= ti
.tempdecl
.isOverDeclaration())
4603 exp
.e1
= new VarExp(exp
.loc
, od
);
4605 exp
.e1
= new OverExp(exp
.loc
, ti
.tempdecl
.isOverloadSet());
4609 Expression e1x
= exp
.e1
.expressionSemantic(sc
);
4610 if (e1x
.op
== EXP
.error
)
4621 * expr.foo!(tiargs)(funcargs)
4624 if (DotTemplateInstanceExp se
= exp
.e1
.isDotTemplateInstanceExp())
4626 TemplateInstance ti
= se
.ti
;
4628 /* Attempt to instantiate ti. If that works, go with it.
4629 * If not, go with partial explicit specialization.
4631 if (!se
.findTempDecl(sc
) ||
!ti
.semanticTiargs(sc
))
4633 if (ti
.needsTypeInference(sc
, 1))
4635 /* Go with partial explicit specialization
4638 assert(ti
.tempdecl
);
4639 if (TemplateDeclaration td
= ti
.tempdecl
.isTemplateDeclaration())
4640 exp
.e1
= new DotTemplateExp(exp
.loc
, se
.e1
, td
);
4641 else if (OverDeclaration od
= ti
.tempdecl
.isOverDeclaration())
4643 exp
.e1
= new DotVarExp(exp
.loc
, se
.e1
, od
, true);
4646 exp
.e1
= new DotExp(exp
.loc
, se
.e1
, new OverExp(exp
.loc
, ti
.tempdecl
.isOverloadSet()));
4650 Expression e1x
= exp
.e1
.expressionSemantic(sc
);
4651 if (e1x
.op
== EXP
.error
)
4663 //printf("Lagain: %s\n", toChars());
4665 if (exp
.e1
.op
== EXP
.this_ || exp
.e1
.op
== EXP
.super_
)
4667 // semantic() run later for these
4671 if (DotIdExp die
= exp
.e1
.isDotIdExp())
4673 exp
.e1
= die
.expressionSemantic(sc
);
4674 /* Look for e1 having been rewritten to expr.opDispatch!(string)
4675 * We handle such earlier, so go back.
4676 * Note that in the rewrite, we carefully did not run semantic() on e1
4678 if (exp
.e1
.op
== EXP
.dotTemplateInstance
)
4686 if (++nest
> global
.recursionLimit
)
4688 error(exp
.loc
, "recursive evaluation of `%s`", exp
.toChars());
4692 Expression ex
= unaSemantic(exp
, sc
);
4701 /* Look for e1 being a lazy parameter
4703 if (VarExp ve
= exp
.e1
.isVarExp())
4705 if (ve
.var
.storage_class
& STC
.lazy_
)
4707 // lazy parameters can be called without violating purity and safety
4708 Type tw
= ve
.var
.type
;
4709 Type tc
= ve
.var
.type
.substWildTo(MODFlags
.const_
);
4710 auto tf
= new TypeFunction(ParameterList(), tc
, LINK
.d
, STC
.safe | STC
.pure_
);
4711 (tf
= cast(TypeFunction
)tf
.typeSemantic(exp
.loc
, sc
)).next
= tw
; // hack for bug7757
4712 auto t
= new TypeDelegate(tf
);
4713 ve
.type
= t
.typeSemantic(exp
.loc
, sc
);
4715 VarDeclaration v
= ve
.var
.isVarDeclaration();
4716 if (v
&& ve
.checkPurity(sc
, v
))
4720 if (exp
.e1
.op
== EXP
.symbolOffset
&& (cast(SymOffExp
)exp
.e1
).hasOverloads
)
4722 SymOffExp se
= cast(SymOffExp
)exp
.e1
;
4723 exp
.e1
= new VarExp(se
.loc
, se
.var
, true);
4724 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
4726 else if (DotExp
de = exp
.e1
.isDotExp())
4728 if (de.e2
.op
== EXP
.overloadSet
)
4735 else if (exp
.e1
.op
== EXP
.star
&& exp
.e1
.type
.ty
== Tfunction
)
4737 // Rewrite (*fp)(arguments) to fp(arguments)
4738 exp
.e1
= (cast(PtrExp
)exp
.e1
).e1
;
4740 else if (exp
.e1
.op
== EXP
.type
&& (sc
&& sc
.flags
& SCOPE
.Cfile
))
4742 const numArgs
= exp
.arguments ? exp
.arguments
.length
: 0;
4744 /* Ambiguous cases arise from CParser where there is not enough
4745 * information to determine if we have a function call or declaration.
4746 * type-name ( identifier ) ;
4747 * identifier ( identifier ) ;
4748 * If exp.e1 is a type-name, then this is a declaration. C11 does not
4749 * have type construction syntax, so don't convert this to a cast().
4753 Expression arg
= (*exp
.arguments
)[0];
4754 if (auto ie
= (*exp
.arguments
)[0].isIdentifierExp())
4756 TypeExp te
= cast(TypeExp
)exp
.e1
;
4757 auto initializer
= new VoidInitializer(ie
.loc
);
4758 Dsymbol s
= new VarDeclaration(ie
.loc
, te
.type
, ie
.ident
, initializer
);
4759 auto decls
= new Dsymbols(1);
4761 s
= new LinkDeclaration(s
.loc
, LINK
.c
, decls
);
4762 result
= new DeclarationExp(exp
.loc
, s
);
4763 result
= result
.expressionSemantic(sc
);
4767 error(arg
.loc
, "identifier or `(` expected");
4768 result
= ErrorExp
.get();
4772 error(exp
.loc
, "identifier or `(` expected before `)`");
4773 result
= ErrorExp
.get();
4778 Type t1
= exp
.e1
.type ? exp
.e1
.type
.toBasetype() : null;
4780 if (exp
.e1
.op
== EXP
.error
)
4785 if (arrayExpressionSemantic(exp
.arguments
.peekSlice(), sc
) ||
4786 preFunctionParameters(sc
, exp
.argumentList
))
4789 // Check for call operator overload
4792 if (t1
.ty
== Tstruct
)
4794 auto sd
= (cast(TypeStruct
)t1
).sym
;
4795 sd
.size(exp
.loc
); // Resolve forward references to construct object
4796 if (sd
.sizeok
!= Sizeok
.done
)
4799 sd
.ctor
= sd
.searchCtor();
4800 /* If `sd.ctor` is a generated copy constructor, this means that it
4801 is the single constructor that this struct has. In order to not
4802 disable default construction, the ctor is nullified. The side effect
4803 of this is that the generated copy constructor cannot be called
4804 explicitly, but that is ok, because when calling a constructor the
4805 default constructor should have priority over the generated copy
4810 auto ctor
= sd
.ctor
.isCtorDeclaration();
4811 if (ctor
&& ctor
.isCpCtor
&& ctor
.isGenerated())
4815 // First look for constructor
4816 if (exp
.e1
.op
== EXP
.type
&& sd
.ctor
)
4818 if (!sd
.noDefaultCtor
&& !(exp
.arguments
&& exp
.arguments
.length
))
4821 /* https://issues.dlang.org/show_bug.cgi?id=20695
4822 If all constructors are copy constructors, then
4823 try default construction.
4825 if (!sd
.hasRegularCtor
&&
4826 // https://issues.dlang.org/show_bug.cgi?id=22639
4827 // we might still have a copy constructor that could be called
4828 (*exp
.arguments
)[0].type
.mutableOf
!= sd
.type
.mutableOf())
4831 auto sle
= new StructLiteralExp(exp
.loc
, sd
, null, exp
.e1
.type
);
4832 if (!sd
.fill(exp
.loc
, *sle
.elements
, true))
4834 if (checkFrameAccess(exp
.loc
, sc
, sd
, sle
.elements
.length
))
4837 // https://issues.dlang.org/show_bug.cgi?id=14556
4838 // Set concrete type to avoid further redundant semantic().
4839 sle
.type
= exp
.e1
.type
;
4841 /* Constructor takes a mutable object, so don't use
4842 * the immutable initializer symbol.
4844 sle
.useStaticInit
= false;
4847 if (auto cf
= sd
.ctor
.isCtorDeclaration())
4849 e
= new DotVarExp(exp
.loc
, e
, cf
, true);
4851 else if (auto td
= sd
.ctor
.isTemplateDeclaration())
4853 e
= new DotIdExp(exp
.loc
, e
, td
.ident
);
4855 else if (auto os
= sd
.ctor
.isOverloadSet())
4857 e
= new DotExp(exp
.loc
, e
, new OverExp(exp
.loc
, os
));
4861 e
= new CallExp(exp
.loc
, e
, exp
.arguments
);
4862 e
= e
.expressionSemantic(sc
);
4866 // No constructor, look for overload of opCall
4867 if (search_function(sd
, Id
.call))
4869 // overload of opCall, therefore it's a call
4870 if (exp
.e1
.op
!= EXP
.type
)
4872 if (sd
.aliasthis
&& !isRecursiveAliasThis(att
, exp
.e1
.type
))
4874 exp
.e1
= resolveAliasThis(sc
, exp
.e1
);
4877 error(exp
.loc
, "%s `%s` does not overload ()", sd
.kind(), sd
.toChars());
4881 /* It's a struct literal
4884 Expressions
* resolvedArgs
= exp
.arguments
;
4887 resolvedArgs
= resolveStructLiteralNamedArgs(sd
, exp
.e1
.type
, sc
, exp
.loc
,
4889 (size_t i
, Type t
) => (*exp
.arguments
)[i
],
4890 i
=> (*exp
.arguments
)[i
].loc
4894 result
= ErrorExp
.get();
4899 Expression e
= new StructLiteralExp(exp
.loc
, sd
, resolvedArgs
, exp
.e1
.type
);
4900 e
= e
.expressionSemantic(sc
);
4904 else if (t1
.ty
== Tclass
)
4907 // Rewrite as e1.call(arguments)
4908 Expression e
= new DotIdExp(exp
.loc
, exp
.e1
, Id
.call);
4909 e
= new CallExp(exp
.loc
, e
, exp
.arguments
, exp
.names
);
4910 e
= e
.expressionSemantic(sc
);
4914 else if (exp
.e1
.op
== EXP
.type
&& t1
.isscalar())
4918 // Make sure to use the enum type itself rather than its
4920 // https://issues.dlang.org/show_bug.cgi?id=16346
4921 if (exp
.e1
.type
.ty
== Tenum
)
4926 if (!exp
.arguments || exp
.arguments
.length
== 0)
4928 e
= t1
.defaultInitLiteral(exp
.loc
);
4930 else if (exp
.arguments
.length
== 1)
4932 e
= (*exp
.arguments
)[0];
4933 e
= e
.implicitCastTo(sc
, t1
);
4934 e
= new CastExp(exp
.loc
, e
, t1
);
4938 error(exp
.loc
, "more than one argument for construction of `%s`", t1
.toChars());
4941 e
= e
.expressionSemantic(sc
);
4947 FuncDeclaration
resolveOverloadSet(Loc loc
, Scope
* sc
,
4948 OverloadSet os
, Objects
* tiargs
, Type tthis
, ArgumentList argumentList
)
4950 FuncDeclaration f
= null;
4953 if (tiargs
&& s
.isFuncDeclaration())
4955 if (auto f2
= resolveFuncCall(loc
, sc
, s
, tiargs
, tthis
, argumentList
, FuncResolveFlag
.quiet
))
4961 /* Match in more than one overload set,
4962 * even if one is a 'better' match than the other.
4964 if (f
.isCsymbol() && f2
.isCsymbol())
4966 /* C has global name space, so just pick one, such as f.
4967 * If f and f2 are not compatible, that's how C rolls.
4971 ScopeDsymbol
.multiplyDefined(loc
, f
, f2
); // issue error
4979 .error(loc
, "no overload matches for `%s`", exp
.toChars());
4980 errorSupplemental(loc
, "Candidates are:");
4983 overloadApply(s
, (ds){
4984 if (auto fd
= ds.isFuncDeclaration())
4985 .errorSupplemental(ds.loc
, "%s%s", fd
.toChars(),
4986 fd
.type
.toTypeFunction().parameterList
.parametersTypeToChars());
4988 .errorSupplemental(ds.loc
, "%s", ds.toChars());
4998 bool isSuper
= false;
4999 if (exp
.e1
.op
== EXP
.dotVariable
&& t1
.ty
== Tfunction || exp
.e1
.op
== EXP
.dotTemplateDeclaration
)
5001 UnaExp ue
= cast(UnaExp
)exp
.e1
;
5003 Expression ue1old
= ue
.e1
; // need for 'right this' check
5007 if (exp
.e1
.op
== EXP
.dotVariable
)
5009 dve
= cast(DotVarExp
)exp
.e1
;
5017 dte
= cast(DotTemplateExp
)exp
.e1
;
5021 // Do overload resolution
5022 exp
.f
= resolveFuncCall(exp
.loc
, sc
, s
, tiargs
, ue
.e1
.type
, exp
.argumentList
, FuncResolveFlag
.standard
);
5023 if (!exp
.f || exp
.f
.errors || exp
.f
.type
.ty
== Terror
)
5026 if (exp
.f
.interfaceVirtual
)
5028 /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent
5030 auto b
= exp
.f
.interfaceVirtual
;
5032 ue
.e1
= ue
.e1
.castTo(sc
, ad2
.type
.addMod(ue
.e1
.type
.mod
));
5033 ue
.e1
= ue
.e1
.expressionSemantic(sc
);
5034 auto vi
= exp
.f
.findVtblIndex(&ad2
.vtbl
, cast(int)ad2
.vtbl
.length
);
5036 exp
.f
= ad2
.vtbl
[vi
].isFuncDeclaration();
5039 if (exp
.f
.needThis())
5041 AggregateDeclaration ad
= exp
.f
.isMemberLocal();
5042 ue
.e1
= getRightThis(exp
.loc
, sc
, ad
, ue
.e1
, exp
.f
);
5043 if (ue
.e1
.op
== EXP
.error
)
5050 if (!(exp
.f
.type
.ty
== Tfunction
&& (cast(TypeFunction
)exp
.f
.type
).isScopeQual
))
5052 if (checkParamArgumentEscape(sc
, exp
.f
, Id
.This
, exp
.f
.vthis
, STC
.undefined_
, ethis
, false, false))
5057 /* Cannot call public functions from inside invariant
5058 * (because then the invariant would have infinite recursion)
5060 if (sc
.func
&& sc
.func
.isInvariantDeclaration() && ue
.e1
.op
== EXP
.this_
&& exp
.f
.addPostInvariant())
5062 error(exp
.loc
, "cannot call `public`/`export` function `%s` from invariant", exp
.f
.toChars());
5066 if (!exp
.ignoreAttributes
)
5067 checkFunctionAttributes(exp
, sc
, exp
.f
);
5069 // Cut-down version of checkAccess() that doesn't use the "most visible" version of exp.f.
5070 // We've already selected an overload here.
5071 const parent
= exp
.f
.toParent();
5072 if (parent
&& parent
.isTemplateInstance())
5074 // already a deprecation
5076 else if (!checkSymbolAccess(sc
, exp
.f
))
5078 error(exp
.loc
, "%s `%s` of type `%s` is not accessible from module `%s`",
5079 exp
.f
.kind(), exp
.f
.toPrettyChars(), exp
.f
.type
.toChars(), sc
._module
.toChars
);
5083 if (!exp
.f
.needThis())
5085 exp
.e1
= Expression
.combine(ue
.e1
, new VarExp(exp
.loc
, exp
.f
, false));
5089 if (ue1old
.checkRightThis(sc
))
5091 if (exp
.e1
.op
== EXP
.dotVariable
)
5094 exp
.e1
.type
= exp
.f
.type
;
5098 exp
.e1
= new DotVarExp(exp
.loc
, dte
.e1
, exp
.f
, false);
5099 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
5100 if (exp
.e1
.op
== EXP
.error
)
5102 ue
= cast(UnaExp
)exp
.e1
;
5106 printf("ue.e1 = %s\n", ue
.e1
.toChars());
5107 printf("f = %s\n", exp
.f
.toChars());
5108 printf("t1 = %s\n", t1
.toChars());
5109 printf("e1 = %s\n", exp
.e1
.toChars());
5110 printf("e1.type = %s\n", exp
.e1
.type
.toChars());
5113 // See if we need to adjust the 'this' pointer
5114 AggregateDeclaration ad
= exp
.f
.isThis();
5115 ClassDeclaration cd
= ue
.e1
.type
.isClassHandle();
5116 if (ad
&& cd
&& ad
.isClassDeclaration())
5118 if (ue
.e1
.op
== EXP
.dotType
)
5120 ue
.e1
= (cast(DotTypeExp
)ue
.e1
).e1
;
5121 exp
.directcall
= true;
5123 else if (ue
.e1
.op
== EXP
.super_
)
5124 exp
.directcall
= true;
5125 else if ((cd
.storage_class
& STC
.final_
) != 0) // https://issues.dlang.org/show_bug.cgi?id=14211
5126 exp
.directcall
= true;
5130 ue
.e1
= ue
.e1
.castTo(sc
, ad
.type
.addMod(ue
.e1
.type
.mod
));
5131 ue
.e1
= ue
.e1
.expressionSemantic(sc
);
5135 // If we've got a pointer to a function then deference it
5136 // https://issues.dlang.org/show_bug.cgi?id=16483
5137 if (exp
.e1
.type
.isPtrToFunction())
5139 Expression e
= new PtrExp(exp
.loc
, exp
.e1
);
5140 e
.type
= exp
.e1
.type
.nextOf();
5145 else if (exp
.e1
.op
== EXP
.super_ || exp
.e1
.op
== EXP
.this_
)
5147 auto ad
= sc
.func ? sc
.func
.isThis() : null;
5148 auto cd
= ad ? ad
.isClassDeclaration() : null;
5150 isSuper
= exp
.e1
.op
== EXP
.super_
;
5153 // Base class constructor call
5154 if (!cd ||
!cd
.baseClass ||
!sc
.func
.isCtorDeclaration())
5156 error(exp
.loc
, "super class constructor call must be in a constructor");
5159 if (!cd
.baseClass
.ctor
)
5161 error(exp
.loc
, "no super class constructor for `%s`", cd
.baseClass
.toChars());
5167 // `this` call expression must be inside a
5169 if (!ad ||
!sc
.func
.isCtorDeclaration())
5171 error(exp
.loc
, "constructor call must be in a constructor");
5175 // https://issues.dlang.org/show_bug.cgi?id=18719
5176 // If `exp` is a call expression to another constructor
5177 // then it means that all struct/class fields will be
5178 // initialized after this call.
5179 foreach (ref field
; sc
.ctorflow
.fieldinit
)
5181 field
.csx |
= CSX
.this_ctor
;
5185 if (!sc
.intypeof
&& !(sc
.ctorflow
.callSuper
& CSX
.halt
))
5187 if (sc
.inLoop || sc
.ctorflow
.callSuper
& CSX
.label
)
5188 error(exp
.loc
, "constructor calls not allowed in loops or after labels");
5189 if (sc
.ctorflow
.callSuper
& (CSX
.super_ctor | CSX
.this_ctor
))
5190 error(exp
.loc
, "multiple constructor calls");
5191 if ((sc
.ctorflow
.callSuper
& CSX
.return_
) && !(sc
.ctorflow
.callSuper
& CSX
.any_ctor
))
5192 error(exp
.loc
, "an earlier `return` statement skips constructor");
5193 sc
.ctorflow
.callSuper |
= CSX
.any_ctor |
(isSuper ? CSX
.super_ctor
: CSX
.this_ctor
);
5196 tthis
= ad
.type
.addMod(sc
.func
.type
.mod
);
5197 auto ctor
= isSuper ? cd
.baseClass
.ctor
: ad
.ctor
;
5198 if (auto os
= ctor
.isOverloadSet())
5199 exp
.f
= resolveOverloadSet(exp
.loc
, sc
, os
, null, tthis
, exp
.argumentList
);
5201 exp
.f
= resolveFuncCall(exp
.loc
, sc
, ctor
, null, tthis
, exp
.argumentList
, FuncResolveFlag
.standard
);
5203 if (!exp
.f || exp
.f
.errors
)
5206 checkFunctionAttributes(exp
, sc
, exp
.f
);
5207 checkAccess(exp
.loc
, sc
, null, exp
.f
);
5209 exp
.e1
= new DotVarExp(exp
.e1
.loc
, exp
.e1
, exp
.f
, false);
5210 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
5211 // https://issues.dlang.org/show_bug.cgi?id=21095
5212 if (exp
.e1
.op
== EXP
.error
)
5216 // BUG: this should really be done by checking the static
5218 if (exp
.f
== sc
.func
)
5220 error(exp
.loc
, "cyclic constructor call");
5224 else if (auto oe
= exp
.e1
.isOverExp())
5226 exp
.f
= resolveOverloadSet(exp
.loc
, sc
, oe
.vars
, tiargs
, tthis
, exp
.argumentList
);
5230 exp
.e1
= new DotVarExp(exp
.loc
, ethis
, exp
.f
, false);
5232 exp
.e1
= new VarExp(exp
.loc
, exp
.f
, false);
5237 error(exp
.loc
, "function expected before `()`, not `%s`", exp
.e1
.toChars());
5240 else if (t1
.ty
== Terror
)
5244 else if (t1
.ty
!= Tfunction
)
5250 if (auto fe
= exp
.e1
.isFuncExp())
5252 // function literal that direct called is always inferred.
5255 tf
= cast(TypeFunction
)exp
.f
.type
;
5256 p
= "function literal";
5258 else if (t1
.ty
== Tdelegate
)
5260 TypeDelegate td
= cast(TypeDelegate
)t1
;
5261 assert(td
.next
.ty
== Tfunction
);
5262 tf
= cast(TypeFunction
)td
.next
;
5265 else if (auto tfx
= t1
.isPtrToFunction())
5268 p
= "function pointer";
5270 else if (exp
.e1
.op
== EXP
.dotVariable
&& (cast(DotVarExp
)exp
.e1
).var
.isOverDeclaration())
5272 DotVarExp dve
= cast(DotVarExp
)exp
.e1
;
5273 exp
.f
= resolveFuncCall(exp
.loc
, sc
, dve
.var
, tiargs
, dve
.e1
.type
, exp
.argumentList
, FuncResolveFlag
.overloadOnly
);
5276 if (exp
.f
.needThis())
5279 dve
.type
= exp
.f
.type
;
5280 dve
.hasOverloads
= false;
5283 exp
.e1
= new VarExp(dve
.loc
, exp
.f
, false);
5284 Expression e
= new CommaExp(exp
.loc
, dve
.e1
, exp
);
5285 result
= e
.expressionSemantic(sc
);
5288 else if (exp
.e1
.op
== EXP
.variable
&& (cast(VarExp
)exp
.e1
).var
.isOverDeclaration())
5290 s
= (cast(VarExp
)exp
.e1
).var
;
5293 else if (exp
.e1
.op
== EXP
.template_
)
5295 s
= (cast(TemplateExp
)exp
.e1
).td
;
5297 exp
.f
= resolveFuncCall(exp
.loc
, sc
, s
, tiargs
, null, exp
.argumentList
,
5298 exp
.isUfcsRewrite ? FuncResolveFlag
.ufcs
: FuncResolveFlag
.standard
);
5299 if (!exp
.f || exp
.f
.errors
)
5301 if (exp
.f
.needThis())
5305 // Supply an implicit 'this', as in
5307 exp
.e1
= new DotVarExp(exp
.loc
, (new ThisExp(exp
.loc
)).expressionSemantic(sc
), exp
.f
, false);
5310 else if (isNeedThisScope(sc
, exp
.f
))
5312 return needThisError(exp
.loc
, exp
.f
);
5315 exp
.e1
= new VarExp(exp
.e1
.loc
, exp
.f
, false);
5320 error(exp
.loc
, "function expected before `()`, not `%s` of type `%s`", exp
.e1
.toChars(), exp
.e1
.type
.toChars());
5324 const(char)* failMessage
;
5325 if (!tf
.callMatch(null, exp
.argumentList
, 0, &failMessage
, sc
))
5329 argExpTypesToCBuffer(buf
, exp
.arguments
);
5332 tthis
.modToBuffer(buf
);
5334 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
5335 .error(exp
.loc
, "%s `%s%s` is not callable using argument types `%s`",
5336 p
, exp
.e1
.toChars(), parametersTypeToChars(tf
.parameterList
), buf
.peekChars());
5338 errorSupplemental(exp
.loc
, "%s", failMessage
);
5341 // Purity and safety check should run after testing arguments matching
5344 exp
.checkPurity(sc
, exp
.f
);
5345 exp
.checkSafety(sc
, exp
.f
);
5346 exp
.checkNogc(sc
, exp
.f
);
5347 if (exp
.f
.checkNestedReference(sc
, exp
.loc
))
5350 else if (sc
.func
&& sc
.intypeof
!= 1 && !(sc
.flags
& (SCOPE
.ctfe | SCOPE
.debug_
)))
5353 if (!tf
.purity
&& sc
.func
.setImpure(exp
.loc
, "`pure` %s `%s` cannot call impure `%s`", exp
.e1
))
5355 error(exp
.loc
, "`pure` %s `%s` cannot call impure %s `%s`",
5356 sc
.func
.kind(), sc
.func
.toPrettyChars(), p
, exp
.e1
.toChars());
5359 if (!tf
.isnogc
&& sc
.func
.setGC(exp
.loc
, "`@nogc` %s `%s` cannot call non-@nogc `%s`", exp
.e1
))
5361 error(exp
.loc
, "`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
5362 sc
.func
.kind(), sc
.func
.toPrettyChars(), p
, exp
.e1
.toChars());
5365 if (tf
.trust
<= TRUST
.system
&& sc
.setUnsafe(true, exp
.loc
,
5366 "`@safe` function `%s` cannot call `@system` `%s`", sc
.func
, exp
.e1
))
5368 error(exp
.loc
, "`@safe` %s `%s` cannot call `@system` %s `%s`",
5369 sc
.func
.kind(), sc
.func
.toPrettyChars(), p
, exp
.e1
.toChars());
5376 if (t1
.ty
== Tpointer
)
5378 Expression e
= new PtrExp(exp
.loc
, exp
.e1
);
5384 else if (VarExp ve
= exp
.e1
.isVarExp())
5386 // Do overload resolution
5387 exp
.f
= ve
.var
.isFuncDeclaration();
5392 exp
.f
= resolveFuncCall(exp
.loc
, sc
, exp
.f
, tiargs
, null, exp
.argumentList
, FuncResolveFlag
.overloadOnly
);
5395 exp
.f
= exp
.f
.toAliasFunc();
5396 TypeFunction tf
= cast(TypeFunction
)exp
.f
.type
;
5397 const(char)* failMessage
;
5398 if (!tf
.callMatch(null, exp
.argumentList
, 0, &failMessage
, sc
))
5402 argExpTypesToCBuffer(buf
, exp
.arguments
);
5405 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
5406 if (exp
.isUfcsRewrite
)
5408 const arg
= (*exp
.argumentList
.arguments
)[0];
5409 .error(exp
.loc
, "no property `%s` for `%s` of type `%s`", exp
.f
.ident
.toChars(), arg
.toChars(), arg
.type
.toChars());
5410 .errorSupplemental(exp
.loc
, "the following error occured while looking for a UFCS match");
5413 .error(exp
.loc
, "%s `%s%s` is not callable using argument types `%s`",
5414 exp
.f
.kind(), exp
.f
.toPrettyChars(), parametersTypeToChars(tf
.parameterList
), buf
.peekChars());
5416 errorSupplemental(exp
.loc
, "%s", failMessage
);
5420 if (!exp
.f || exp
.f
.errors
)
5423 if (exp
.f
.needThis())
5425 // Change the ancestor lambdas to delegate before hasThis(sc) call.
5426 if (exp
.f
.checkNestedReference(sc
, exp
.loc
))
5429 auto memberFunc
= hasThis(sc
);
5430 if (memberFunc
&& haveSameThis(memberFunc
, exp
.f
))
5432 // Supply an implicit 'this', as in
5434 exp
.e1
= new DotVarExp(exp
.loc
, (new ThisExp(exp
.loc
)).expressionSemantic(sc
), ve
.var
);
5435 // Note: we cannot use f directly, because further overload resolution
5436 // through the supplied 'this' may cause different result.
5439 else if (isNeedThisScope(sc
, exp
.f
))
5441 // At this point it is possible that `exp.f` had an ambiguity error that was
5442 // silenced because the previous call to `resolveFuncCall` was done using
5443 // `FuncResolveFlag.overloadOnly`. To make sure that a proper error message
5444 // is printed, redo the call with `FuncResolveFlag.standard`.
5446 // https://issues.dlang.org/show_bug.cgi?id=22157
5448 exp
.f
= resolveFuncCall(exp
.loc
, sc
, exp
.f
, tiargs
, null, exp
.argumentList
, FuncResolveFlag
.standard
);
5450 if (!exp
.f || exp
.f
.errors
)
5453 // If no error is printed, it means that `f` is the single matching overload
5454 // and it needs `this`.
5455 return needThisError(exp
.loc
, exp
.f
);
5459 checkFunctionAttributes(exp
, sc
, exp
.f
);
5460 checkAccess(exp
.loc
, sc
, null, exp
.f
);
5461 if (exp
.f
.checkNestedReference(sc
, exp
.loc
))
5467 if (ve
.hasOverloads
)
5469 exp
.e1
= new VarExp(ve
.loc
, exp
.f
, false);
5470 exp
.e1
.type
= exp
.f
.type
;
5474 assert(t1
.ty
== Tfunction
);
5476 Expression argprefix
;
5478 exp
.arguments
= new Expressions();
5479 if (functionParameters(exp
.loc
, sc
, cast(TypeFunction
)t1
, ethis
, tthis
, exp
.argumentList
, exp
.f
, &exp
.type
, &argprefix
))
5484 exp
.e1
= e1org
; // https://issues.dlang.org/show_bug.cgi?id=10922
5485 // avoid recursive expression printing
5486 error(exp
.loc
, "forward reference to inferred return type of function call `%s`", exp
.toChars());
5490 if (exp
.f
&& exp
.f
.tintro
)
5494 TypeFunction tf
= cast(TypeFunction
)exp
.f
.tintro
;
5495 if (tf
.next
.isBaseOf(t
, &offset
) && offset
)
5498 result
= Expression
.combine(argprefix
, exp
.castTo(sc
, t
));
5503 // Handle the case of a direct lambda call
5504 if (exp
.f
&& exp
.f
.isFuncLiteralDeclaration() && sc
.func
&& !sc
.intypeof
)
5506 exp
.f
.tookAddressOf
= 0;
5509 result
= Expression
.combine(argprefix
, exp
);
5513 auto ad
= sc
.func ? sc
.func
.isThis() : null;
5514 auto cd
= ad ? ad
.isClassDeclaration() : null;
5515 if (cd
&& cd
.classKind
== ClassKind
.cpp
&& exp
.f
&& !exp
.f
.fbody
)
5517 // if super is defined in C++, it sets the vtable pointer to the base class
5518 // so we have to restore it, but still return 'this' from super() call:
5519 // (auto __vptrTmp = this.__vptr, auto __superTmp = super()), (this.__vptr = __vptrTmp, __superTmp)
5522 auto vptr
= new DotIdExp(loc
, new ThisExp(loc
), Id
.__vptr
);
5523 auto vptrTmpDecl
= copyToTemp(0, "__vptrTmp", vptr
);
5524 auto declareVptrTmp
= new DeclarationExp(loc
, vptrTmpDecl
);
5526 auto superTmpDecl
= copyToTemp(0, "__superTmp", result
);
5527 auto declareSuperTmp
= new DeclarationExp(loc
, superTmpDecl
);
5529 auto declareTmps
= new CommaExp(loc
, declareVptrTmp
, declareSuperTmp
);
5531 auto restoreVptr
= new AssignExp(loc
, vptr
.syntaxCopy(), new VarExp(loc
, vptrTmpDecl
));
5533 Expression e
= new CommaExp(loc
, declareTmps
, new CommaExp(loc
, restoreVptr
, new VarExp(loc
, superTmpDecl
)));
5534 result
= e
.expressionSemantic(sc
);
5538 // `super.fun()` with fun being abstract and unimplemented
5539 auto supDotFun
= exp
.e1
.isDotVarExp();
5540 if (supDotFun
&& supDotFun
.e1
.isSuperExp() && exp
.f
&& exp
.f
.isAbstract() && !exp
.f
.fbody
)
5542 error(exp
.loc
, "call to unimplemented abstract function `%s`", exp
.f
.toFullSignature());
5543 errorSupplemental(exp
.loc
, "declared here: %s", exp
.f
.loc
.toChars());
5546 // declare dual-context container
5547 if (exp
.f
&& exp
.f
.hasDualContext() && !sc
.intypeof
&& sc
.func
)
5549 // check access to second `this`
5550 if (AggregateDeclaration ad2
= exp
.f
.isMember2())
5552 Expression te
= new ThisExp(exp
.loc
).expressionSemantic(sc
);
5553 if (te
.op
!= EXP
.error
)
5554 te
= getRightThis(exp
.loc
, sc
, ad2
, te
, exp
.f
);
5555 if (te
.op
== EXP
.error
)
5557 error(exp
.loc
, "need `this` of type `%s` to call function `%s`", ad2
.toChars(), exp
.f
.toChars());
5561 exp
.vthis2
= makeThis2Argument(exp
.loc
, sc
, exp
.f
);
5562 Expression
de = new DeclarationExp(exp
.loc
, exp
.vthis2
);
5563 result
= Expression
.combine(de, result
);
5564 result
= result
.expressionSemantic(sc
);
5568 override void visit(DeclarationExp e
)
5575 static if (LOGSEMANTIC
)
5577 printf("DeclarationExp::semantic() %s\n", e
.toChars());
5580 uint olderrors
= global
.errors
;
5582 /* This is here to support extern(linkage) declaration,
5583 * where the extern(linkage) winds up being an AttribDeclaration
5586 Dsymbol s
= e
.declaration
;
5590 AttribDeclaration ad
= s
.isAttribDeclaration();
5593 if (ad
.decl
&& ad
.decl
.length
== 1)
5602 //printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc);
5603 // Insert into both local scope and function scope.
5604 // Must be unique in both.
5607 VarDeclaration v
= s
.isVarDeclaration();
5610 if (sc
.flags
& SCOPE
.Cfile
)
5612 /* Do semantic() on the type before inserting v into the symbol table
5614 if (!v
.originalType
)
5615 v
.originalType
= v
.type
.syntaxCopy();
5616 Scope
* sc2
= sc
.push();
5617 sc2
.stc |
= v
.storage_class
& STC
.FUNCATTR
;
5618 sc2
.linkage
= LINK
.c
; // account for the extern(C) in front of the declaration
5620 v
.type
= v
.type
.typeSemantic(v
.loc
, sc2
);
5626 /* Do semantic() on initializer first so this will be illegal:
5629 e
.declaration
.dsymbolSemantic(sc
);
5630 s
.parent
= sc
.parent
;
5636 auto conflict
= sc
.search(Loc
.initial
, s
.ident
, null);
5637 error(e
.loc
, "declaration `%s` is already defined", s
.toPrettyChars());
5638 errorSupplemental(conflict
.loc
, "`%s` `%s` is defined here",
5639 conflict
.kind(), conflict
.toChars());
5643 if (v
&& (sc
.flags
& SCOPE
.Cfile
))
5645 /* Do semantic() on initializer last so this will be legal:
5648 e
.declaration
.dsymbolSemantic(sc
);
5649 s
.parent
= sc
.parent
;
5654 // https://issues.dlang.org/show_bug.cgi?id=11720
5655 if ((s
.isFuncDeclaration() ||
5656 s
.isAggregateDeclaration() ||
5657 s
.isEnumDeclaration() ||
5658 s
.isTemplateDeclaration() ||
5660 ) && !sc
.func
.localsymtab
.insert(s
))
5662 // Get the previous symbol
5663 Dsymbol originalSymbol
= sc
.func
.localsymtab
.lookup(s
.ident
);
5665 // Perturb the name mangling so that the symbols can co-exist
5666 // instead of colliding
5667 s
.localNum
= cast(ushort)(originalSymbol
.localNum
+ 1);
5668 // 65535 should be enough for anyone
5671 error(e
.loc
, "more than 65535 symbols with name `%s` generated", s
.ident
.toChars());
5675 // Replace originalSymbol with s, which updates the localCount
5676 sc
.func
.localsymtab
.update(s
);
5678 // The mangling change only works for D mangling
5681 if (!(sc
.flags
& SCOPE
.Cfile
))
5683 /* https://issues.dlang.org/show_bug.cgi?id=21272
5684 * If we are in a foreach body we need to extract the
5685 * function containing the foreach
5687 FuncDeclaration fes_enclosing_func
;
5688 if (sc
.func
&& sc
.func
.fes
)
5689 fes_enclosing_func
= sc
.enclosing
.enclosing
.func
;
5691 // Disallow shadowing
5692 for (Scope
* scx
= sc
.enclosing
; scx
&& (scx
.func
== sc
.func ||
(fes_enclosing_func
&& scx
.func
== fes_enclosing_func
)); scx
= scx
.enclosing
)
5695 if (scx
.scopesym
&& scx
.scopesym
.symtab
&& (s2
= scx
.scopesym
.symtab
.lookup(s
.ident
)) !is null && s
!= s2
)
5697 // allow STC.local symbols to be shadowed
5698 // TODO: not really an optimal design
5699 auto decl
= s2
.isDeclaration();
5700 if (!decl ||
!(decl
.storage_class
& STC
.local
))
5704 deprecation(e
.loc
, "%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.", s
.kind(), s
.ident
.toChars(), s2
.kind(), s2
.toPrettyChars());
5708 error(e
.loc
, "%s `%s` is shadowing %s `%s`", s
.kind(), s
.ident
.toChars(), s2
.kind(), s2
.toPrettyChars());
5717 if (!s
.isVarDeclaration())
5720 if (sc2
.stc & (STC
.pure_ | STC
.nothrow_ | STC
.nogc
))
5722 sc2
.stc &= ~(STC
.pure_ | STC
.nothrow_ | STC
.nogc
);
5723 e
.declaration
.dsymbolSemantic(sc2
);
5726 s
.parent
= sc
.parent
;
5728 if (global
.errors
== olderrors
)
5730 e
.declaration
.semantic2(sc
);
5731 if (global
.errors
== olderrors
)
5733 e
.declaration
.semantic3(sc
);
5736 // todo: error in declaration should be propagated.
5738 e
.type
= Type
.tvoid
;
5742 override void visit(TypeidExp exp
)
5744 static if (LOGSEMANTIC
)
5746 printf("TypeidExp::semantic() %s\n", exp
.toChars());
5748 Type ta
= isType(exp
.obj
);
5749 Expression ea
= isExpression(exp
.obj
);
5750 Dsymbol sa
= isDsymbol(exp
.obj
);
5751 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
5755 dmd
.typesem
.resolve(ta
, exp
.loc
, sc
, ea
, ta
, sa
, true);
5760 if (auto sym
= getDsymbol(ea
))
5761 ea
= symbolToExp(sym
, exp
.loc
, sc
, false);
5763 ea
= ea
.expressionSemantic(sc
);
5764 ea
= resolveProperties(sc
, ea
);
5766 if (ea
.op
== EXP
.type
)
5772 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
5773 error(exp
.loc
, "no type for `typeid(%s)`", ea ? ea
.toChars() : (sa ? sa
.toChars() : ""));
5777 ta
.checkComplexTransition(exp
.loc
, sc
);
5780 auto tb
= ta
.toBasetype();
5781 if (ea
&& tb
.ty
== Tclass
)
5783 if (tb
.toDsymbol(sc
).isClassDeclaration().classKind
== ClassKind
.cpp
)
5785 error(exp
.loc
, "runtime type information is not supported for `extern(C++)` classes");
5788 else if (!Type
.typeinfoclass
)
5790 error(exp
.loc
, "`object.TypeInfo_Class` could not be found, but is implicitly used");
5795 /* Get the dynamic type, which is .classinfo
5797 ea
= ea
.expressionSemantic(sc
);
5798 e
= new TypeidExp(ea
.loc
, ea
);
5799 e
.type
= Type
.typeinfoclass
.type
;
5802 else if (ta
.ty
== Terror
)
5808 // Handle this in the glue layer
5809 e
= new TypeidExp(exp
.loc
, ta
);
5811 bool genObjCode
= true;
5813 // https://issues.dlang.org/show_bug.cgi?id=23650
5814 // We generate object code for typeinfo, required
5815 // by typeid, only if in non-speculative context
5816 if (sc
.flags
& SCOPE
.compile
)
5821 e
.type
= getTypeInfoType(exp
.loc
, ta
, sc
, genObjCode
);
5822 semanticTypeInfo(sc
, ta
);
5826 e
= new CommaExp(exp
.loc
, ea
, e
); // execute ea
5827 e
= e
.expressionSemantic(sc
);
5833 override void visit(TraitsExp e
)
5835 result
= semanticTraits(e
, sc
);
5838 override void visit(HaltExp e
)
5840 static if (LOGSEMANTIC
)
5842 printf("HaltExp::semantic()\n");
5844 e
.type
= Type
.tnoreturn
;
5848 override void visit(IsExp e
)
5850 /* is(targ id tok tspec)
5851 * is(targ id : tok2)
5852 * is(targ id == tok2)
5861 result
= IntegerExp
.createBool(true);
5866 Tuple tup
= isTuple(tded
);
5868 s
= new TupleDeclaration(e
.loc
, e
.id
, &tup
.objects
);
5870 s
= new AliasDeclaration(e
.loc
, e
.id
, tded
);
5871 s
.dsymbolSemantic(sc
);
5873 /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there.
5874 * More investigation is needed.
5876 if (!tup
&& !sc
.insert(s
))
5878 auto conflict
= sc
.search(Loc
.initial
, s
.ident
, null);
5879 error(e
.loc
, "declaration `%s` is already defined", s
.toPrettyChars());
5880 errorSupplemental(conflict
.loc
, "`%s` `%s` is defined here",
5881 conflict
.kind(), conflict
.toChars());
5884 unSpeculative(sc
, s
);
5886 result
= IntegerExp
.createBool(true);
5890 result
= IntegerExp
.createBool(false);
5894 static if (LOGSEMANTIC
)
5896 printf("IsExp::semantic(%s)\n", e
.toChars());
5898 if (e
.id
&& !(sc
.flags
& SCOPE
.condition
))
5900 error(e
.loc
, "can only declare type aliases within `static if` conditionals or `static assert`s");
5904 if (e
.tok2
== TOK
.package_ || e
.tok2
== TOK
.module_
) // These is() expressions are special because they can work on modules, not just types.
5906 const oldErrors
= global
.startGagging();
5907 Dsymbol sym
= e
.targ
.toDsymbol(sc
);
5908 global
.endGagging(oldErrors
);
5912 Package p
= resolveIsPackage(sym
);
5915 if (e
.tok2
== TOK
.package_
&& p
.isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module.
5917 else if(e
.tok2
== TOK
.module_
&& !(p
.isModule() || p
.isPackageMod()))
5924 Scope
* sc2
= sc
.copy(); // keep sc.flags
5927 sc2
.flags |
= SCOPE
.fullinst
;
5928 Type t
= e
.targ
.trySemantic(e
.loc
, sc2
);
5930 if (!t
) // errors, so condition is false
5935 if (e
.tok2
!= TOK
.reserved
)
5940 if (e
.targ
.ty
!= Tstruct
)
5942 if ((cast(TypeStruct
)e
.targ
).sym
.isUnionDeclaration())
5948 if (e
.targ
.ty
!= Tstruct
)
5950 if (!(cast(TypeStruct
)e
.targ
).sym
.isUnionDeclaration())
5956 if (e
.targ
.ty
!= Tclass
)
5958 if ((cast(TypeClass
)e
.targ
).sym
.isInterfaceDeclaration())
5963 case TOK
.interface_
:
5964 if (e
.targ
.ty
!= Tclass
)
5966 if (!(cast(TypeClass
)e
.targ
).sym
.isInterfaceDeclaration())
5972 if (!e
.targ
.isConst())
5977 case TOK
.immutable_
:
5978 if (!e
.targ
.isImmutable())
5984 if (!e
.targ
.isShared())
5990 if (!e
.targ
.isWild())
5996 // If class or interface, get the base class and interfaces
5997 if (e
.targ
.ty
!= Tclass
)
6001 ClassDeclaration cd
= (cast(TypeClass
)e
.targ
).sym
;
6002 auto args
= new Parameters();
6003 args
.reserve(cd
.baseclasses
.length
);
6004 if (cd
.semanticRun
< PASS
.semanticdone
)
6005 cd
.dsymbolSemantic(null);
6006 for (size_t i
= 0; i
< cd
.baseclasses
.length
; i
++)
6008 BaseClass
* b
= (*cd
.baseclasses
)[i
];
6009 args
.push(new Parameter(Loc
.initial
, STC
.in_
, b
.type
, null, null, null));
6011 tded
= new TypeTuple(args
);
6016 if (e
.targ
.ty
!= Tenum
)
6019 tded
= (cast(TypeEnum
)e
.targ
).sym
.getMemtype(e
.loc
);
6023 if (tded
.ty
== Terror
)
6028 if (e
.targ
.ty
!= Tdelegate
)
6030 tded
= (cast(TypeDelegate
)e
.targ
).next
; // the underlying function type
6034 if (e
.targ
.ty
!= Tfunction
)
6037 case TOK
.parameters
:
6039 if (auto tf
= e
.targ
.isFunction_Delegate_PtrToFunction())
6044 /* Generate tuple from function parameter types.
6046 auto args
= new Parameters();
6047 foreach (i
, arg
; tded
.isTypeFunction().parameterList
)
6049 assert(arg
&& arg
.type
);
6050 /* If one of the default arguments was an error,
6051 don't return an invalid tuple
6053 if (e
.tok2
== TOK
.parameters
&& arg
.defaultArg
&& arg
.defaultArg
.op
== EXP
.error
)
6055 args
.push(new Parameter(arg
.loc
, arg
.storageClass
, arg
.type
, (e
.tok2
== TOK
.parameters
) ? arg
.ident
: null, (e
.tok2
== TOK
.parameters
) ? arg
.defaultArg
: null, arg
.userAttribDecl
));
6057 tded
= new TypeTuple(args
);
6061 /* Get the 'return type' for the function,
6062 * delegate, or pointer to function.
6064 if (auto tf
= e
.targ
.isFunction_Delegate_PtrToFunction())
6070 case TOK
.argumentTypes
:
6071 /* Generate a type tuple of the equivalent types used to determine if a
6072 * function argument of this type can be passed in registers.
6073 * The results of this are highly platform dependent, and intended
6074 * primarly for use in implementing va_arg().
6076 tded
= target
.toArgTypes(e
.targ
);
6079 // not valid for a parameter
6083 if (e
.targ
.ty
!= Tvector
)
6085 tded
= (cast(TypeVector
)e
.targ
).basetype
;
6092 // https://issues.dlang.org/show_bug.cgi?id=18753
6097 else if (e
.tspec
&& !e
.id
&& !(e
.parameters
&& e
.parameters
.length
))
6099 /* Evaluate to true if targ matches tspec
6103 e
.tspec
= e
.tspec
.typeSemantic(e
.loc
, sc
);
6104 //printf("targ = %s, %s\n", e.targ.toChars(), e.targ.deco);
6105 //printf("tspec = %s, %s\n", e.tspec.toChars(), e.tspec.deco);
6107 if (e
.tok
== TOK
.colon
)
6109 // current scope is itself deprecated, or deprecations are not errors
6110 const bool deprecationAllowed
= sc
.isDeprecated
6111 || global
.params
.useDeprecated
!= DiagnosticReporting
.error
;
6112 const bool preventAliasThis
= e
.targ
.hasDeprecatedAliasThis
&& !deprecationAllowed
;
6114 if (preventAliasThis
&& e
.targ
.ty
== Tstruct
)
6116 if ((cast(TypeStruct
) e
.targ
).implicitConvToWithoutAliasThis(e
.tspec
))
6121 else if (preventAliasThis
&& e
.targ
.ty
== Tclass
)
6123 if ((cast(TypeClass
) e
.targ
).implicitConvToWithoutAliasThis(e
.tspec
))
6128 else if (e
.targ
.implicitConvTo(e
.tspec
))
6135 if (e
.targ
.equals(e
.tspec
))
6143 /* Evaluate to true if targ matches tspec.
6144 * If true, declare id as an alias for the specialized type.
6145 * is(targ == tspec, tpl)
6146 * is(targ : tspec, tpl)
6147 * is(targ id == tspec)
6148 * is(targ id : tspec)
6149 * is(targ id == tspec, tpl)
6150 * is(targ id : tspec, tpl)
6152 Identifier tid
= e
.id ? e
.id
: Identifier
.generateId("__isexp_id");
6153 e
.parameters
.insert(0, new TemplateTypeParameter(e
.loc
, tid
, null, null));
6155 Objects dedtypes
= Objects(e
.parameters
.length
);
6158 MATCH m
= deduceType(e
.targ
, sc
, e
.tspec
, e
.parameters
, &dedtypes
, null, 0, e
.tok
== TOK
.equal
);
6160 if (m
== MATCH
.nomatch ||
(m
!= MATCH
.exact
&& e
.tok
== TOK
.equal
))
6166 tded
= cast(Type
)dedtypes
[0];
6169 Objects tiargs
= Objects(1);
6172 /* Declare trailing parameters
6174 for (size_t i
= 1; i
< e
.parameters
.length
; i
++)
6176 TemplateParameter tp
= (*e
.parameters
)[i
];
6177 Declaration s
= null;
6179 m
= tp
.matchArg(e
.loc
, sc
, &tiargs
, i
, e
.parameters
, &dedtypes
, &s
);
6180 if (m
== MATCH
.nomatch
)
6182 s
.dsymbolSemantic(sc
);
6185 auto conflict
= sc
.search(Loc
.initial
, s
.ident
, null);
6186 error(e
.loc
, "declaration `%s` is already defined", s
.toPrettyChars());
6187 errorSupplemental(conflict
.loc
, "`%s` `%s` is defined here",
6188 conflict
.kind(), conflict
.toChars());
6191 unSpeculative(sc
, s
);
6198 /* Declare id as an alias for type targ. Evaluate to true
6206 override void visit(BinAssignExp exp
)
6214 Expression e
= exp
.op_overload(sc
);
6221 if (exp
.e1
.op
== EXP
.arrayLength
)
6223 // arr.length op= e2;
6224 e
= rewriteOpAssign(exp
);
6225 e
= e
.expressionSemantic(sc
);
6229 if (exp
.e1
.op
== EXP
.slice || exp
.e1
.type
.ty
== Tarray || exp
.e1
.type
.ty
== Tsarray
)
6231 if (checkNonAssignmentArrayOp(exp
.e1
))
6234 if (exp
.e1
.op
== EXP
.slice
)
6235 (cast(SliceExp
)exp
.e1
).arrayop
= true;
6238 if (exp
.e2
.implicitConvTo(exp
.e1
.type
.nextOf()))
6241 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
.nextOf());
6243 else if (Expression ex
= typeCombine(exp
, sc
))
6248 exp
.type
= exp
.e1
.type
;
6249 result
= arrayOp(exp
, sc
);
6253 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
6254 exp
.e1
= exp
.e1
.modifiableLvalue(sc
, exp
.e1
);
6255 exp
.e1
= exp
.e1
.optimize(WANTvalue
, /*keepLvalue*/ true);
6256 exp
.type
= exp
.e1
.type
;
6258 if (auto ad
= isAggregate(exp
.e1
.type
))
6260 if (const s
= search_function(ad
, Id
.opOpAssign
))
6262 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());
6266 if (exp
.e1
.checkScalar() ||
6267 exp
.e1
.checkReadModifyWrite(exp
.op
, exp
.e2
) ||
6268 exp
.e1
.checkSharedAccess(sc
))
6271 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
);
6272 int bitwise
= (exp
.op
== EXP
.andAssign || exp
.op
== EXP
.orAssign || exp
.op
== EXP
.xorAssign
);
6273 int shift
= (exp
.op
== EXP
.leftShiftAssign || exp
.op
== EXP
.rightShiftAssign || exp
.op
== EXP
.unsignedRightShiftAssign
);
6275 if (bitwise
&& exp
.type
.toBasetype().ty
== Tbool
)
6276 exp
.e2
= exp
.e2
.implicitCastTo(sc
, exp
.type
);
6277 else if (exp
.checkNoBool())
6280 if ((exp
.op
== EXP
.addAssign || exp
.op
== EXP
.minAssign
) && exp
.e1
.type
.toBasetype().ty
== Tpointer
&& exp
.e2
.type
.toBasetype().isintegral())
6282 result
= scaleFactor(exp
, sc
);
6286 if (Expression ex
= typeCombine(exp
, sc
))
6292 if (arith
&& (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
)))
6294 if ((bitwise || shift
) && (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
)))
6299 if (exp
.e2
.type
.toBasetype().ty
!= Tvector
)
6300 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tshiftcnt
);
6303 if (!target
.isVectorOpSupported(exp
.type
.toBasetype(), exp
.op
, exp
.e2
.type
.toBasetype()))
6305 result
= exp
.incompatibleTypes();
6309 if (exp
.e1
.op
== EXP
.error || exp
.e2
.op
== EXP
.error
)
6312 e
= exp
.checkOpAssignTypes(sc
);
6313 if (e
.op
== EXP
.error
)
6319 assert(e
.op
== EXP
.assign || e
== exp
);
6320 result
= (cast(BinExp
)e
).reorderSettingAAElem(sc
);
6323 private Expression
compileIt(MixinExp exp
)
6326 if (expressionsToString(buf
, sc
, exp
.exps
))
6329 uint errors
= global
.errors
;
6330 const len
= buf
.length
;
6331 const str = buf
.extractChars()[0 .. len
];
6332 const bool doUnittests
= global
.params
.useUnitTests || global
.params
.ddoc
.doOutput || global
.params
.dihdr
.doOutput
;
6333 auto loc
= adjustLocForMixin(str, exp
.loc
, global
.params
.mixinOut
);
6334 scope p
= new Parser
!ASTCodegen(loc
, sc
._module
, str, false, global
.errorSink
, &global
.compileEnv
, doUnittests
);
6335 p
.transitionIn
= global
.params
.v
.vin
;
6337 //printf("p.loc.linnum = %d\n", p.loc.linnum);
6339 Expression e
= p
.parseExpression();
6340 if (global
.errors
!= errors
)
6343 if (p
.token
.value
!= TOK
.endOfFile
)
6345 error(e
.loc
, "unexpected token `%s` after %s expression",
6346 p
.token
.toChars(), EXPtoString(e
.op
).ptr
);
6347 errorSupplemental(e
.loc
, "while parsing string mixin expression `%s`",
6354 override void visit(MixinExp exp
)
6356 /* https://dlang.org/spec/expression.html#mixin_expressions
6359 static if (LOGSEMANTIC
)
6361 printf("MixinExp::semantic('%s')\n", exp
.toChars());
6364 auto e
= compileIt(exp
);
6367 result
= e
.expressionSemantic(sc
);
6370 override void visit(ImportExp e
)
6372 static if (LOGSEMANTIC
)
6374 printf("ImportExp::semantic('%s')\n", e
.toChars());
6377 auto se
= semanticString(sc
, e
.e1
, "file name argument");
6382 auto namez
= se
.toStringz();
6383 if (!global
.filePath
)
6385 error(e
.loc
, "need `-J` switch to import text file `%s`", namez
.ptr
);
6389 /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
6390 * ('Path Traversal') attacks.
6391 * https://cwe.mitre.org/data/definitions/22.html
6394 if (FileName
.absolute(namez
))
6396 error(e
.loc
, "absolute path is not allowed in import expression: `%s`", se
.toChars());
6400 auto idxReserved
= FileName
.findReservedChar(namez
);
6401 if (idxReserved
!= size_t
.max
)
6403 error(e
.loc
, "`%s` is not a valid filename on this platform", se
.toChars());
6404 errorSupplemental(e
.loc
, "Character `'%c'` is reserved and cannot be used", namez
[idxReserved
]);
6408 if (FileName
.refersToParentDir(namez
))
6410 error(e
.loc
, "path refers to parent (`..`) directory: `%s`", se
.toChars());
6414 auto resolvedNamez
= FileName
.searchPath(global
.filePath
, namez
, false);
6417 error(e
.loc
, "file `%s` cannot be found or not in a path specified with `-J`", se
.toChars());
6418 errorSupplemental(e
.loc
, "Path(s) searched (as provided by `-J`):");
6419 foreach (idx
, path
; *global
.filePath
)
6421 const attr
= FileName
.exists(path
);
6422 const(char)* err
= attr
== 2 ?
"" :
6423 (attr
== 1 ?
" (not a directory)" : " (path not found)");
6424 errorSupplemental(e
.loc
, "[%llu]: `%s`%s", cast(ulong)idx
, path
, err
);
6429 sc
._module
.contentImportedFiles
.push(resolvedNamez
.ptr
);
6430 if (global
.params
.v
.verbose
)
6432 const slice
= se
.peekString();
6433 message("file %.*s\t(%s)", cast(int)slice
.length
, slice
.ptr
, resolvedNamez
.ptr
);
6435 if (global
.params
.moduleDeps
.buffer
!is null)
6437 OutBuffer
* ob
= global
.params
.moduleDeps
.buffer
;
6438 Module imod
= sc
._module
;
6440 if (!global
.params
.moduleDeps
.name
)
6441 ob
.writestring("depsFile ");
6442 ob
.writestring(imod
.toPrettyChars());
6443 ob
.writestring(" (");
6444 escapePath(ob
, imod
.srcfile
.toChars());
6445 ob
.writestring(") : ");
6446 if (global
.params
.moduleDeps
.name
)
6447 ob
.writestring("string : ");
6448 ob
.write(se
.peekString());
6449 ob
.writestring(" (");
6450 escapePath(ob
, resolvedNamez
.ptr
);
6451 ob
.writestring(")");
6454 if (global
.params
.makeDeps
.doOutput
)
6456 global
.params
.makeDeps
.files
.push(resolvedNamez
.ptr
);
6460 auto fileName
= FileName(resolvedNamez
);
6461 if (auto fmResult
= global
.fileManager
.lookup(fileName
))
6463 se
= new StringExp(e
.loc
, fmResult
);
6467 error(e
.loc
, "cannot read file `%s`", resolvedNamez
.ptr
);
6471 result
= se
.expressionSemantic(sc
);
6474 override void visit(AssertExp exp
)
6476 // https://dlang.org/spec/expression.html#assert_expressions
6477 static if (LOGSEMANTIC
)
6479 printf("AssertExp::semantic('%s')\n", exp
.toChars());
6482 const generateMsg
= !exp
.msg
&&
6483 sc
.needsCodegen() && // let ctfe interpreter handle the error message
6484 global
.params
.checkAction
== CHECKACTION
.context
&&
6485 global
.params
.useAssert
== CHECKENABLE
.on
&&
6486 !((exp
.e1
.isIntegerExp() && (exp
.e1
.toInteger() == 0)) ||
6487 exp
.e1
.isNullExp());
6488 Expression temporariesPrefix
;
6491 // no message - use assert expression as msg
6493 if (!verifyHookExist(exp
.loc
, *sc
, Id
._d_assert_fail
, "generating assert messages"))
6498 auto a = e1, b = e2;
6499 assert(a == b, _d_assert_fail!"=="(a, b));
6504 Stores the result of an operand expression into a temporary
6505 if necessary, e.g. if it is an impure fuction call containing side
6506 effects as in https://issues.dlang.org/show_bug.cgi?id=20114
6509 op = an expression which may require a temporary (added to
6510 `temporariesPrefix`: `auto tmp = op`) and will be replaced
6511 by `tmp` if necessary
6513 Returns: (possibly replaced) `op`
6515 Expression
maybePromoteToTmp(ref Expression op
)
6517 // https://issues.dlang.org/show_bug.cgi?id=20989
6518 // Flag that _d_assert_fail will never dereference `array.ptr` to avoid safety
6519 // errors for `assert(!array.ptr)` => `_d_assert_fail!"!"(array.ptr)`
6521 auto die
= op
.isDotIdExp();
6522 if (die
&& die
.ident
== Id
.ptr
)
6526 op
= op
.expressionSemantic(sc
);
6527 op
= resolveProperties(sc
, op
);
6529 // Detect assert's using static operator overloads (e.g. `"var" in environment`)
6530 if (auto te
= op
.isTypeExp())
6532 // Replace the TypeExp with it's textual representation
6533 // Including "..." in the error message isn't quite right but
6534 // proper solutions require more drastic changes, e.g. directly
6535 // using miniFormat and combine instead of calling _d_assert_fail
6536 auto name
= new StringExp(te
.loc
, te
.toString());
6537 return name
.expressionSemantic(sc
);
6540 // Create a temporary for expressions with side effects
6541 // Defensively assume that function calls may have side effects even
6542 // though it's not detected by hasSideEffect (e.g. `debug puts("Hello")` )
6543 // Rewriting CallExp's also avoids some issues with the inliner/debug generation
6544 if (op
.hasSideEffect(true))
6546 // Don't create an invalid temporary for void-expressions
6547 // Further semantic will issue an appropriate error
6548 if (op
.type
.ty
== Tvoid
)
6551 // https://issues.dlang.org/show_bug.cgi?id=21590
6552 // Don't create unnecessary temporaries and detect `assert(a = b)`
6553 if (op
.isAssignExp() || op
.isBinAssignExp())
6555 auto left
= (cast(BinExp
) op
).e1
;
6557 // Find leftmost expression to handle other rewrites,
6558 // e.g. --(++a) => a += 1 -= 1
6559 while (left
.isAssignExp() || left
.isBinAssignExp())
6560 left
= (cast(BinExp
) left
).e1
;
6562 // Only use the assignee if it's a variable and skip
6563 // other lvalues (e.g. ref's returned by functions)
6564 if (left
.isVarExp())
6567 // Sanity check that `op` can be converted to boolean
6568 // But don't raise errors for assignments enclosed in another expression
6573 // Tuples with side-effects already receive a temporary during semantic
6574 if (op
.type
.isTypeTuple())
6576 auto te
= op
.isTupleExp();
6579 // Create a new tuple without the associated temporary
6580 auto res
= new TupleExp(op
.loc
, te
.exps
);
6581 return res
.expressionSemantic(sc
);
6584 const stc = op
.isLvalue() ? STC
.ref_
: 0;
6585 auto tmp
= copyToTemp(stc, "__assertOp", op
);
6586 tmp
.dsymbolSemantic(sc
);
6588 auto decl
= new DeclarationExp(op
.loc
, tmp
);
6589 temporariesPrefix
= Expression
.combine(temporariesPrefix
, decl
);
6591 op
= new VarExp(op
.loc
, tmp
);
6592 op
= op
.expressionSemantic(sc
);
6597 // if the assert condition is a mixin expression, try to compile it
6598 if (auto ce
= exp
.e1
.isMixinExp())
6600 if (auto e1
= compileIt(ce
))
6606 Loc loc
= exp
.e1
.loc
;
6608 const op
= exp
.e1
.op
;
6609 bool isEqualsCallExpression
;
6610 if (const callExp
= exp
.e1
.isCallExp())
6612 // https://issues.dlang.org/show_bug.cgi?id=20331
6613 // callExp.f may be null if the assert contains a call to
6614 // a function pointer or literal
6615 if (const callExpFunc
= callExp
.f
)
6617 const callExpIdent
= callExpFunc
.ident
;
6618 isEqualsCallExpression
= callExpIdent
== Id
.__equals ||
6619 callExpIdent
== Id
.eq
;
6622 if (op
== EXP
.equal || op
== EXP
.notEqual ||
6623 op
== EXP
.lessThan || op
== EXP
.greaterThan ||
6624 op
== EXP
.lessOrEqual || op
== EXP
.greaterOrEqual ||
6625 op
== EXP
.identity || op
== EXP
.notIdentity ||
6627 isEqualsCallExpression
)
6629 es
= new Expressions(3);
6630 tiargs
= new Objects(1);
6632 if (isEqualsCallExpression
)
6634 auto callExp
= cast(CallExp
) exp
.e1
;
6635 auto args
= callExp
.arguments
;
6637 // structs with opEquals get rewritten to a DotVarExp:
6639 // https://issues.dlang.org/show_bug.cgi?id=20100
6640 if (args
.length
== 1)
6642 auto dv
= callExp
.e1
.isDotVarExp();
6646 (*es
)[1] = maybePromoteToTmp(dv
.e1
);
6647 (*es
)[2] = maybePromoteToTmp((*args
)[0]);
6652 (*es
)[1] = maybePromoteToTmp((*args
)[0]);
6653 (*es
)[2] = maybePromoteToTmp((*args
)[1]);
6658 auto binExp
= cast(EqualExp
) exp
.e1
;
6661 (*es
)[1] = maybePromoteToTmp(binExp
.e1
);
6662 (*es
)[2] = maybePromoteToTmp(binExp
.e2
);
6666 Expression comp
= new StringExp(loc
, isEqualsCallExpression ?
"==" : EXPtoString(exp
.e1
.op
));
6667 comp
= comp
.expressionSemantic(sc
);
6669 (*tiargs
)[0] = (*es
)[1].type
;
6672 // Format exp.e1 before any additional boolean conversion
6673 // Ignore &&/|| because "assert(...) failed" is more informative than "false != true"
6674 else if (op
!= EXP
.andAnd
&& op
!= EXP
.orOr
)
6676 es
= new Expressions(2);
6677 tiargs
= new Objects(1);
6679 if (auto ne
= exp
.e1
.isNotExp())
6681 // Fetch the (potential non-bool) expression and fold
6682 // (n) negations into (n % 2) negations, e.g. !!a => a
6683 for (bool neg = true; ; neg = !neg)
6685 if (auto ne2
= ne
.e1
.isNotExp())
6689 (*es
)[0] = new StringExp(loc
, neg ?
"!" : "");
6690 (*es
)[1] = maybePromoteToTmp(ne
.e1
);
6696 { // Simply format exp.e1
6697 (*es
)[0] = new StringExp(loc
, "");
6698 (*es
)[1] = maybePromoteToTmp(exp
.e1
);
6701 (*tiargs
)[0] = (*es
)[1].type
;
6703 // Passing __ctfe to auto ref infers ref and aborts compilation:
6704 // "cannot modify compiler-generated variable __ctfe"
6705 auto ve
= (*es
)[1].isVarExp();
6706 if (ve
&& ve
.var
.ident
== Id
.ctfe
)
6708 exp
.msg
= new StringExp(loc
, "assert(__ctfe) failed!");
6715 buf
.printf("`%s` failed", exp
.toChars());
6716 exp
.msg
= new StringExp(Loc
.initial
, buf
.extractSlice());
6720 Expression __assertFail
= new IdentifierExp(exp
.loc
, Id
.empty
);
6721 auto assertFail
= new DotIdExp(loc
, __assertFail
, Id
.object
);
6723 auto dt = new DotTemplateInstanceExp(loc
, assertFail
, Id
._d_assert_fail
, tiargs
);
6724 auto ec
= CallExp
.create(loc
, dt, es
);
6729 if (Expression ex
= unaSemantic(exp
, sc
))
6735 exp
.e1
= resolveProperties(sc
, exp
.e1
);
6736 // BUG: see if we can do compile time elimination of the Assert
6737 exp
.e1
= exp
.e1
.optimize(WANTvalue
);
6738 exp
.e1
= exp
.e1
.toBoolean(sc
);
6740 if (exp
.e1
.op
== EXP
.error
)
6748 exp
.msg
= expressionSemantic(exp
.msg
, sc
);
6749 exp
.msg
= resolveProperties(sc
, exp
.msg
);
6750 exp
.msg
= exp
.msg
.implicitCastTo(sc
, Type
.tchar
.constOf().arrayOf());
6751 exp
.msg
= exp
.msg
.optimize(WANTvalue
);
6752 checkParamArgumentEscape(sc
, null, null, null, STC
.undefined_
, exp
.msg
, true, false);
6755 if (exp
.msg
&& exp
.msg
.op
== EXP
.error
)
6761 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
6762 auto f2
= exp
.msg
&& checkNonAssignmentArrayOp(exp
.msg
);
6766 if (exp
.e1
.toBool().hasValue(false))
6768 /* This is an `assert(0)` which means halt program execution
6770 FuncDeclaration fd
= sc
.parent
.isFuncDeclaration();
6772 fd
.hasReturnExp |
= 4;
6773 sc
.ctorflow
.orCSX(CSX
.halt
);
6775 if (global
.params
.useAssert
== CHECKENABLE
.off
)
6777 Expression e
= new HaltExp(exp
.loc
);
6778 e
= e
.expressionSemantic(sc
);
6783 // Only override the type when it isn't already some flavour of noreturn,
6784 // e.g. when this assert was generated by defaultInitLiteral
6785 if (!exp
.type ||
!exp
.type
.isTypeNoreturn())
6786 exp
.type
= Type
.tnoreturn
;
6789 exp
.type
= Type
.tvoid
;
6791 result
= !temporariesPrefix
6793 : Expression
.combine(temporariesPrefix
, exp
).expressionSemantic(sc
);
6796 override void visit(ThrowExp te
)
6798 import dmd
.statementsem
;
6800 if (throwSemantic(te
.loc
, te
.e1
, sc
))
6806 override void visit(DotIdExp exp
)
6808 static if (LOGSEMANTIC
)
6810 printf("DotIdExp::semantic(this = %p, '%s')\n", exp
, exp
.toChars());
6811 //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op));
6814 if (sc
.flags
& SCOPE
.Cfile
)
6816 /* See if need to rewrite the AST because of cast/call ambiguity
6818 if (auto e
= castCallAmbiguity(exp
, sc
))
6820 result
= expressionSemantic(e
, sc
);
6824 if (exp
.arrow
) // ImportC only
6825 exp
.e1
= exp
.e1
.expressionSemantic(sc
).arrayFuncConv(sc
);
6827 if (exp
.ident
== Id
.__xalignof
&& exp
.e1
.isTypeExp())
6829 // C11 6.5.3 says _Alignof only applies to types
6833 dmd
.typesem
.resolve(exp
.e1
.type
, exp
.e1
.loc
, sc
, e
, t
, s
, true);
6836 error(exp
.e1
.loc
, "argument to `_Alignof` must be a type");
6841 // Note similarity to getProperty() implementation of __xalignof
6842 const explicitAlignment
= t
.alignment();
6843 const naturalAlignment
= t
.alignsize();
6844 const actualAlignment
= (explicitAlignment
.isDefault() ? naturalAlignment
: explicitAlignment
.get());
6845 result
= new IntegerExp(exp
.loc
, actualAlignment
, Type
.tsize_t
);
6849 error(exp
.e1
.loc
, "argument to `_Alignof` must be a type");
6857 if (exp
.ident
!= Id
.__sizeof
)
6859 result
= fieldLookup(exp
.e1
, sc
, exp
.ident
, exp
.arrow
);
6864 Expression e
= exp
.dotIdSemanticProp(sc
, 1);
6866 if (e
&& isDotOpDispatch(e
))
6869 uint errors
= global
.startGagging();
6870 e
= resolvePropertiesX(sc
, e
);
6871 // Any error or if 'e' is not resolved, go to UFCS
6872 if (global
.endGagging(errors
) || e
is ode
)
6873 e
= null; /* fall down to UFCS */
6880 if (!e
) // if failed to find the property
6882 /* If ident is not a valid property, rewrite:
6887 e
= resolveUFCSProperties(sc
, exp
);
6892 override void visit(DotTemplateExp e
)
6899 if (Expression ex
= unaSemantic(e
, sc
))
6904 // 'void' like TemplateExp
6905 e
.type
= Type
.tvoid
;
6909 override void visit(DotVarExp exp
)
6911 static if (LOGSEMANTIC
)
6913 printf("DotVarExp::semantic('%s')\n", exp
.toChars());
6921 exp
.var
= exp
.var
.toAlias().isDeclaration();
6923 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
6925 if (auto tup
= exp
.var
.isTupleDeclaration())
6930 * tuple(e1.a, e1.b, e1.c)
6933 Expression ev
= sc
.func ?
extractSideEffect(sc
, "__tup", e0
, exp
.e1
) : exp
.e1
;
6935 auto exps
= new Expressions();
6936 exps
.reserve(tup
.objects
.length
);
6937 for (size_t i
= 0; i
< tup
.objects
.length
; i
++)
6939 RootObject o
= (*tup
.objects
)[i
];
6942 switch (o
.dyncast()) with (DYNCAST
)
6945 e
= cast(Expression
)o
;
6946 if (auto se
= e
.isDsymbolExp())
6947 var
= se
.s
.isDeclaration();
6948 else if (auto ve
= e
.isVarExp())
6949 if (!ve
.var
.isFuncDeclaration())
6950 // Exempt functions for backwards compatibility reasons.
6951 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
6955 Dsymbol s
= cast(Dsymbol
) o
;
6956 Declaration d
= s
.isDeclaration();
6957 if (!d || d
.isFuncDeclaration())
6958 // Exempt functions for backwards compatibility reasons.
6959 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
6960 e
= new DsymbolExp(exp
.loc
, s
);
6965 e
= new TypeExp(exp
.loc
, cast(Type
)o
);
6968 error(exp
.loc
, "`%s` is not an expression", o
.toChars());
6972 e
= new DotVarExp(exp
.loc
, ev
, var
);
6976 Expression e
= new TupleExp(exp
.loc
, e0
, exps
);
6977 e
= e
.expressionSemantic(sc
);
6981 else if (auto ad
= exp
.var
.isAliasDeclaration())
6983 if (auto t
= ad
.getType())
6985 result
= new TypeExp(exp
.loc
, t
).expressionSemantic(sc
);
6990 exp
.e1
= exp
.e1
.addDtorHook(sc
);
6992 Type t1
= exp
.e1
.type
;
6994 if (FuncDeclaration fd
= exp
.var
.isFuncDeclaration())
6996 // for functions, do checks after overload resolution
6997 if (!fd
.functionSemantic())
7000 /* https://issues.dlang.org/show_bug.cgi?id=13843
7001 * If fd obviously has no overloads, we should
7002 * normalize AST, and it will give a chance to wrap fd with FuncExp.
7004 if ((fd
.isNested() && !fd
.isThis()) || fd
.isFuncLiteralDeclaration())
7007 auto e
= symbolToExp(fd
, exp
.loc
, sc
, false);
7008 result
= Expression
.combine(exp
.e1
, e
);
7015 else if (OverDeclaration od
= exp
.var
.isOverDeclaration())
7017 exp
.type
= Type
.tvoid
; // ambiguous type?
7021 exp
.type
= exp
.var
.type
;
7022 if (!exp
.type
&& global
.errors
) // var is goofed up, just return error.
7026 if (t1
.ty
== Tpointer
)
7029 exp
.type
= exp
.type
.addMod(t1
.mod
);
7031 // https://issues.dlang.org/show_bug.cgi?id=23109
7032 // Run semantic on the DotVarExp type
7033 if (auto handle
= exp
.type
.isClassHandle())
7035 if (handle
.semanticRun
< PASS
.semanticdone
&& !handle
.isBaseInfoComplete())
7036 handle
.dsymbolSemantic(null);
7039 Dsymbol vparent
= exp
.var
.toParent();
7040 AggregateDeclaration ad
= vparent ? vparent
.isAggregateDeclaration() : null;
7041 if (Expression e1x
= getRightThis(exp
.loc
, sc
, ad
, exp
.e1
, exp
.var
, 1))
7045 /* Later checkRightThis will report correct error for invalid field variable access.
7047 Expression e
= new VarExp(exp
.loc
, exp
.var
);
7048 e
= e
.expressionSemantic(sc
);
7052 checkAccess(exp
.loc
, sc
, exp
.e1
, exp
.var
);
7054 VarDeclaration v
= exp
.var
.isVarDeclaration();
7055 if (v
&& (v
.isDataseg() ||
(v
.storage_class
& STC
.manifest
)))
7057 Expression e
= expandVar(WANTvalue
, v
);
7065 if (v
&& (v
.isDataseg() ||
// fix https://issues.dlang.org/show_bug.cgi?id=8238
7066 (!v
.needThis() && v
.semanticRun
> PASS
.initial
))) // fix https://issues.dlang.org/show_bug.cgi?id=17258
7069 checkAccess(exp
.loc
, sc
, exp
.e1
, v
);
7070 Expression e
= new VarExp(exp
.loc
, v
);
7071 e
= new CommaExp(exp
.loc
, exp
.e1
, e
);
7072 e
= e
.expressionSemantic(sc
);
7077 //printf("-DotVarExp::semantic('%s')\n", toChars());
7081 override void visit(DotTemplateInstanceExp exp
)
7083 static if (LOGSEMANTIC
)
7085 printf("DotTemplateInstanceExp::semantic('%s')\n", exp
.toChars());
7092 // Indicate we need to resolve by UFCS.
7093 Expression e
= exp
.dotTemplateSemanticProp(sc
, DotExpFlag
.gag
);
7095 e
= resolveUFCSProperties(sc
, exp
);
7097 e
.type
= Type
.tvoid
; // Unresolved type, because it needs inference
7101 override void visit(DelegateExp e
)
7103 static if (LOGSEMANTIC
)
7105 printf("DelegateExp::semantic('%s')\n", e
.toChars());
7113 e
.e1
= e
.e1
.expressionSemantic(sc
);
7115 e
.type
= new TypeDelegate(e
.func
.type
.isTypeFunction());
7116 e
.type
= e
.type
.typeSemantic(e
.loc
, sc
);
7118 FuncDeclaration f
= e
.func
.toAliasFunc();
7119 AggregateDeclaration ad
= f
.isMemberLocal();
7121 e
.e1
= getRightThis(e
.loc
, sc
, ad
, e
.e1
, f
);
7123 if (f
.type
.ty
== Tfunction
)
7125 TypeFunction tf
= cast(TypeFunction
)f
.type
;
7126 if (!MODmethodConv(e
.e1
.type
.mod
, f
.type
.mod
))
7128 OutBuffer thisBuf
, funcBuf
;
7129 MODMatchToBuffer(&thisBuf
, e
.e1
.type
.mod
, tf
.mod
);
7130 MODMatchToBuffer(&funcBuf
, tf
.mod
, e
.e1
.type
.mod
);
7131 error(e
.loc
, "%smethod `%s` is not callable using a %s`%s`",
7132 funcBuf
.peekChars(), f
.toPrettyChars(), thisBuf
.peekChars(), e
.e1
.toChars());
7136 if (ad
&& ad
.isClassDeclaration() && ad
.type
!= e
.e1
.type
)
7138 // A downcast is required for interfaces
7139 // https://issues.dlang.org/show_bug.cgi?id=3706
7140 e
.e1
= new CastExp(e
.loc
, e
.e1
, ad
.type
);
7141 e
.e1
= e
.e1
.expressionSemantic(sc
);
7144 // declare dual-context container
7145 if (f
.hasDualContext() && !sc
.intypeof
&& sc
.func
)
7147 // check access to second `this`
7148 if (AggregateDeclaration ad2
= f
.isMember2())
7150 Expression te
= new ThisExp(e
.loc
).expressionSemantic(sc
);
7151 if (te
.op
!= EXP
.error
)
7152 te
= getRightThis(e
.loc
, sc
, ad2
, te
, f
);
7153 if (te
.op
== EXP
.error
)
7155 error(e
.loc
, "need `this` of type `%s` to make delegate from function `%s`", ad2
.toChars(), f
.toChars());
7159 VarDeclaration vthis2
= makeThis2Argument(e
.loc
, sc
, f
);
7161 Expression
de = new DeclarationExp(e
.loc
, vthis2
);
7162 result
= Expression
.combine(de, result
);
7163 result
= result
.expressionSemantic(sc
);
7167 override void visit(DotTypeExp exp
)
7169 static if (LOGSEMANTIC
)
7171 printf("DotTypeExp::semantic('%s')\n", exp
.toChars());
7179 if (auto e
= unaSemantic(exp
, sc
))
7185 exp
.type
= exp
.sym
.getType().addMod(exp
.e1
.type
.mod
);
7189 override void visit(AddrExp exp
)
7191 static if (LOGSEMANTIC
)
7193 printf("AddrExp::semantic('%s')\n", exp
.toChars());
7201 if (Expression ex
= unaSemantic(exp
, sc
))
7207 if (sc
.flags
& SCOPE
.Cfile
)
7209 /* Special handling for &"string"/&(T[]){0, 1}
7210 * since C regards string/array literals as lvalues
7213 if(e
.isStringExp() || e
.isArrayLiteralExp())
7215 e
.type
= typeSemantic(e
.type
, Loc
.initial
, sc
);
7216 // if type is already a pointer exp is an illegal expression of the form `&(&"")`
7217 if (!e
.type
.isTypePointer())
7219 e
.type
= e
.type
.pointerTo();
7225 // `toLvalue` call further below is upon exp.e1, omitting & from the error message
7226 exp
.toLvalue(sc
, null);
7232 int wasCond
= exp
.e1
.op
== EXP
.question
;
7234 if (exp
.e1
.op
== EXP
.dotTemplateInstance
)
7236 DotTemplateInstanceExp dti
= cast(DotTemplateInstanceExp
)exp
.e1
;
7237 TemplateInstance ti
= dti
.ti
;
7239 //assert(ti.needsTypeInference(sc));
7240 ti
.dsymbolSemantic(sc
);
7241 if (!ti
.inst || ti
.errors
) // if template failed to expand
7244 Dsymbol s
= ti
.toAlias();
7245 FuncDeclaration f
= s
.isFuncDeclaration();
7248 exp
.e1
= new DotVarExp(exp
.e1
.loc
, dti
.e1
, f
);
7249 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
7253 else if (exp
.e1
.op
== EXP
.scope_
)
7255 TemplateInstance ti
= (cast(ScopeExp
)exp
.e1
).sds
.isTemplateInstance();
7258 //assert(ti.needsTypeInference(sc));
7259 ti
.dsymbolSemantic(sc
);
7260 if (!ti
.inst || ti
.errors
) // if template failed to expand
7263 Dsymbol s
= ti
.toAlias();
7264 FuncDeclaration f
= s
.isFuncDeclaration();
7267 exp
.e1
= new VarExp(exp
.e1
.loc
, f
);
7268 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
7272 /* https://issues.dlang.org/show_bug.cgi?id=809
7274 * If the address of a lazy variable is taken,
7275 * the expression is rewritten so that the type
7276 * of it is the delegate type. This means that
7277 * the symbol is not going to represent a call
7278 * to the delegate anymore, but rather, the
7281 if (auto ve
= exp
.e1
.isVarExp())
7283 if (ve
.var
.storage_class
& STC
.lazy_
)
7285 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
7286 exp
.e1
= resolveProperties(sc
, exp
.e1
);
7287 if (auto callExp
= exp
.e1
.isCallExp())
7289 if (callExp
.e1
.type
.toBasetype().ty
== Tdelegate
)
7291 /* https://issues.dlang.org/show_bug.cgi?id=20551
7293 * Cannot take address of lazy parameter in @safe code
7294 * because it might end up being a pointer to undefined
7299 if (sc
.setUnsafe(false, exp
.loc
,
7300 "cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve
, sc
.func
))
7306 VarExp ve2
= callExp
.e1
.isVarExp();
7307 ve2
.delegateWasExtracted
= true;
7308 ve2
.var
.storage_class |
= STC
.scope_
;
7316 exp
.e1
= exp
.e1
.toLvalue(sc
, null);
7317 if (exp
.e1
.op
== EXP
.error
)
7322 if (checkNonAssignmentArrayOp(exp
.e1
))
7327 error(exp
.loc
, "cannot take address of `%s`", exp
.e1
.toChars());
7330 if (!checkAddressable(exp
, sc
))
7334 if (auto f
= isFuncAddress(exp
, &hasOverloads
))
7336 if (!hasOverloads
&& f
.checkForwardRef(exp
.loc
))
7339 else if (!exp
.e1
.type
.deco
)
7341 // try to resolve the type
7342 exp
.e1
.type
= exp
.e1
.type
.typeSemantic(exp
.e1
.loc
, sc
);
7343 if (!exp
.e1
.type
.deco
) // still couldn't resolve it
7345 if (auto ve
= exp
.e1
.isVarExp())
7347 Declaration d
= ve
.var
;
7348 error(exp
.loc
, "forward reference to %s `%s`", d
.kind(), d
.toChars());
7351 error(exp
.loc
, "forward reference to type `%s` of expression `%s`", exp
.e1
.type
.toChars(), exp
.e1
.toChars());
7356 exp
.type
= exp
.e1
.type
.pointerTo();
7358 // See if this should really be a delegate
7359 if (exp
.e1
.op
== EXP
.dotVariable
)
7361 DotVarExp dve
= cast(DotVarExp
)exp
.e1
;
7362 FuncDeclaration f
= dve
.var
.isFuncDeclaration();
7365 f
= f
.toAliasFunc(); // FIXME, should see overloads
7366 // https://issues.dlang.org/show_bug.cgi?id=1983
7367 if (!dve
.hasOverloads
)
7372 e
= new DelegateExp(exp
.loc
, dve
.e1
, f
, dve
.hasOverloads
);
7373 else // It is a function pointer. Convert &v.f() --> (v, &V.f())
7374 e
= new CommaExp(exp
.loc
, dve
.e1
, new AddrExp(exp
.loc
, new VarExp(exp
.loc
, f
, dve
.hasOverloads
)));
7375 e
= e
.expressionSemantic(sc
);
7380 // Look for misaligned pointer in @safe mode
7381 if (checkUnsafeAccess(sc
, dve
, !exp
.type
.isMutable(), true))
7384 else if (exp
.e1
.op
== EXP
.variable
)
7386 VarExp ve
= cast(VarExp
)exp
.e1
;
7387 VarDeclaration v
= ve
.var
.isVarDeclaration();
7390 if (!checkAddressVar(sc
, exp
.e1
, v
))
7393 ve
.checkPurity(sc
, v
);
7395 FuncDeclaration f
= ve
.var
.isFuncDeclaration();
7398 /* Because nested functions cannot be overloaded,
7399 * mark here that we took its address because castTo()
7400 * may not be called with an exact match.
7402 * https://issues.dlang.org/show_bug.cgi?id=19285 :
7403 * We also need to make sure we aren't inside a typeof. Ideally the compiler
7404 * would do typeof(...) semantic analysis speculatively then collect information
7405 * about what it used rather than relying on what are effectively semantically-global
7406 * variables but it doesn't.
7408 if (!sc
.isFromSpeculativeSemanticContext() && (!ve
.hasOverloads ||
(f
.isNested() && !f
.needThis())))
7410 // TODO: Refactor to use a proper interface that can keep track of causes.
7414 if (f
.isNested() && !f
.needThis())
7416 if (f
.isFuncLiteralDeclaration())
7418 if (!f
.FuncDeclaration
.isNested())
7420 /* Supply a 'null' for a this pointer if no this is available
7422 Expression e
= new DelegateExp(exp
.loc
, new NullExp(exp
.loc
, Type
.tnull
), f
, ve
.hasOverloads
);
7423 e
= e
.expressionSemantic(sc
);
7428 Expression e
= new DelegateExp(exp
.loc
, exp
.e1
, f
, ve
.hasOverloads
);
7429 e
= e
.expressionSemantic(sc
);
7435 auto memberFunc
= hasThis(sc
);
7436 if (memberFunc
&& haveSameThis(memberFunc
, f
))
7438 /* Should probably supply 'this' after overload resolution,
7441 Expression ethis
= new ThisExp(exp
.loc
);
7442 Expression e
= new DelegateExp(exp
.loc
, ethis
, f
, ve
.hasOverloads
);
7443 e
= e
.expressionSemantic(sc
);
7447 if (sc
.func
&& !sc
.intypeof
&& !(sc
.flags
& SCOPE
.debug_
))
7449 sc
.setUnsafe(false, exp
.loc
,
7450 "`this` reference necessary to take address of member `%s` in `@safe` function `%s`",
7456 else if (exp
.e1
.op
== EXP
.index
)
7461 * check 'a' the same as for a regular variable
7463 if (VarDeclaration v
= expToVariable(exp
.e1
))
7465 exp
.e1
.checkPurity(sc
, v
);
7470 /* a ? b : c was transformed to *(a ? &b : &c), but we still
7471 * need to do safety checks
7473 assert(exp
.e1
.op
== EXP
.star
);
7474 PtrExp pe
= cast(PtrExp
)exp
.e1
;
7475 assert(pe
.e1
.op
== EXP
.question
);
7476 CondExp ce
= cast(CondExp
)pe
.e1
;
7477 assert(ce
.e1
.op
== EXP
.address
);
7478 assert(ce
.e2
.op
== EXP
.address
);
7480 // Re-run semantic on the address expressions only
7482 ce
.e1
= ce
.e1
.expressionSemantic(sc
);
7484 ce
.e2
= ce
.e2
.expressionSemantic(sc
);
7486 result
= exp
.optimize(WANTvalue
);
7489 override void visit(PtrExp exp
)
7491 static if (LOGSEMANTIC
)
7493 printf("PtrExp::semantic('%s')\n", exp
.toChars());
7501 Expression e
= exp
.op_overload(sc
);
7508 exp
.e1
= exp
.e1
.arrayFuncConv(sc
);
7510 Type tb
= exp
.e1
.type
.toBasetype();
7514 exp
.type
= (cast(TypePointer
)tb
).next
;
7519 if (isNonAssignmentArrayOp(exp
.e1
))
7521 error(exp
.loc
, "using `*` on an array is no longer supported; use `*(%s).ptr` instead", exp
.e1
.toChars());
7522 exp
.type
= (cast(TypeArray
)tb
).next
;
7523 exp
.e1
= exp
.e1
.castTo(sc
, exp
.type
.pointerTo());
7530 exp
.type
= Type
.tnoreturn
; // typeof(*null) is bottom type
7534 error(exp
.loc
, "can only `*` a pointer, not a `%s`", exp
.e1
.type
.toChars());
7538 if (sc
.flags
& SCOPE
.Cfile
&& exp
.type
&& exp
.type
.toBasetype().ty
== Tvoid
)
7540 // https://issues.dlang.org/show_bug.cgi?id=23752
7541 // `&*((void*)(0))` is allowed in C
7546 if (exp
.checkValue())
7552 override void visit(NegExp exp
)
7554 static if (LOGSEMANTIC
)
7556 printf("NegExp::semantic('%s')\n", exp
.toChars());
7564 Expression e
= exp
.op_overload(sc
);
7572 exp
.type
= exp
.e1
.type
;
7573 Type tb
= exp
.type
.toBasetype();
7574 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
7576 if (!isArrayOpValid(exp
.e1
))
7578 result
= arrayOpInvalidError(exp
);
7584 if (!target
.isVectorOpSupported(tb
, exp
.op
))
7586 result
= exp
.incompatibleTypes();
7589 if (exp
.e1
.checkNoBool())
7591 if (exp
.e1
.checkArithmetic(exp
.op
) ||
7592 exp
.e1
.checkSharedAccess(sc
))
7598 override void visit(UAddExp exp
)
7600 static if (LOGSEMANTIC
)
7602 printf("UAddExp::semantic('%s')\n", exp
.toChars());
7606 Expression e
= exp
.op_overload(sc
);
7614 if (!target
.isVectorOpSupported(exp
.e1
.type
.toBasetype(), exp
.op
))
7616 result
= exp
.incompatibleTypes();
7619 if (exp
.e1
.checkNoBool())
7621 if (exp
.e1
.checkArithmetic(exp
.op
))
7623 if (exp
.e1
.checkSharedAccess(sc
))
7629 override void visit(ComExp exp
)
7637 Expression e
= exp
.op_overload(sc
);
7645 exp
.type
= exp
.e1
.type
;
7646 Type tb
= exp
.type
.toBasetype();
7647 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
7649 if (!isArrayOpValid(exp
.e1
))
7651 result
= arrayOpInvalidError(exp
);
7657 if (!target
.isVectorOpSupported(tb
, exp
.op
))
7659 result
= exp
.incompatibleTypes();
7662 if (exp
.e1
.checkNoBool())
7664 if (exp
.e1
.checkIntegral() ||
7665 exp
.e1
.checkSharedAccess(sc
))
7671 override void visit(NotExp e
)
7679 e
.setNoderefOperand();
7681 // Note there is no operator overload
7682 if (Expression ex
= unaSemantic(e
, sc
))
7688 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
7689 if (e
.e1
.op
== EXP
.type
)
7690 e
.e1
= resolveAliasThis(sc
, e
.e1
);
7692 e
.e1
= resolveProperties(sc
, e
.e1
);
7693 e
.e1
= e
.e1
.toBoolean(sc
);
7694 if (e
.e1
.type
== Type
.terror
)
7700 if (!target
.isVectorOpSupported(e
.e1
.type
.toBasetype(), e
.op
))
7702 result
= e
.incompatibleTypes();
7704 // https://issues.dlang.org/show_bug.cgi?id=13910
7705 // Today NotExp can take an array as its operand.
7706 if (checkNonAssignmentArrayOp(e
.e1
))
7709 e
.type
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? Type
.tint32
: Type
.tbool
;
7713 override void visit(DeleteExp exp
)
7715 // @@@DEPRECATED_2.109@@@
7716 // 1. Deprecated since 2.079
7717 // 2. Error since 2.099
7718 // 3. Removal of keyword, "delete" can be used for other identities
7721 error(exp
.loc
, "the `delete` keyword is obsolete");
7722 errorSupplemental(exp
.loc
, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead");
7728 if (Expression ex
= unaSemantic(exp
, sc
))
7733 exp
.e1
= resolveProperties(sc
, exp
.e1
);
7734 exp
.e1
= exp
.e1
.modifiableLvalue(sc
, null);
7735 if (exp
.e1
.op
== EXP
.error
)
7740 exp
.type
= Type
.tvoid
;
7742 Type tb
= exp
.e1
.type
.toBasetype();
7744 /* Now that `delete` in user code is an error, we only get here when
7745 * `isRAII` has been set to true for the deletion of a `scope class`. */
7746 if (tb
.ty
!= Tclass
)
7748 error(exp
.loc
, "cannot delete type `%s`", exp
.e1
.type
.toChars());
7752 ClassDeclaration cd
= (cast(TypeClass
)tb
).sym
;
7753 if (cd
.isCOMinterface())
7755 /* Because COM classes are deleted by IUnknown.Release()
7757 error(exp
.loc
, "cannot `delete` instance of COM interface `%s`", cd
.toChars());
7764 err |
= !cd
.dtor
.functionSemantic();
7765 err |
= exp
.checkPurity(sc
, cd
.dtor
);
7766 err |
= exp
.checkSafety(sc
, cd
.dtor
);
7767 err |
= exp
.checkNogc(sc
, cd
.dtor
);
7775 override void visit(CastExp exp
)
7777 static if (LOGSEMANTIC
)
7779 printf("CastExp::semantic('%s')\n", exp
.toChars());
7781 //static int x; assert(++x < 10);
7788 if ((sc
&& sc
.flags
& SCOPE
.Cfile
) &&
7789 exp
.to
&& (exp
.to
.ty
== Tident || exp
.to
.ty
== Tsarray
) &&
7790 (exp
.e1
.op
== EXP
.address || exp
.e1
.op
== EXP
.star ||
7791 exp
.e1
.op
== EXP
.uadd || exp
.e1
.op
== EXP
.negate
))
7793 /* Ambiguous cases arise from CParser if type-name is just an identifier.
7794 * ( identifier ) cast-expression
7795 * ( identifier [expression]) cast-expression
7796 * If we determine that `identifier` is a variable, and cast-expression
7797 * is one of the unary operators (& * + -), then rewrite this cast
7798 * as a binary expression.
7804 exp
.to
.resolve(loc
, sc
, e
, t
, s
);
7807 if (auto ex
= exp
.e1
.isAddrExp()) // (ident) &exp -> (ident & exp)
7808 result
= new AndExp(loc
, e
, ex
.e1
);
7809 else if (auto ex
= exp
.e1
.isPtrExp()) // (ident) *exp -> (ident * exp)
7810 result
= new MulExp(loc
, e
, ex
.e1
);
7811 else if (auto ex
= exp
.e1
.isUAddExp()) // (ident) +exp -> (ident + exp)
7812 result
= new AddExp(loc
, e
, ex
.e1
);
7813 else if (auto ex
= exp
.e1
.isNegExp()) // (ident) -exp -> (ident - exp)
7814 result
= new MinExp(loc
, e
, ex
.e1
);
7817 result
= result
.expressionSemantic(sc
);
7824 exp
.to
= exp
.to
.typeSemantic(exp
.loc
, sc
);
7825 if (exp
.to
== Type
.terror
)
7828 if (!exp
.to
.hasPointers())
7829 exp
.setNoderefOperand();
7831 // When e1 is a template lambda, this cast may instantiate it with
7833 exp
.e1
= inferType(exp
.e1
, exp
.to
);
7836 if (auto e
= unaSemantic(exp
, sc
))
7842 if (exp
.to
&& !exp
.to
.isTypeSArray() && !exp
.to
.isTypeFunction())
7843 exp
.e1
= exp
.e1
.arrayFuncConv(sc
);
7845 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
7846 if (exp
.e1
.op
== EXP
.type
)
7847 exp
.e1
= resolveAliasThis(sc
, exp
.e1
);
7849 auto e1x
= resolveProperties(sc
, exp
.e1
);
7850 if (e1x
.op
== EXP
.error
)
7855 if (e1x
.checkType())
7861 error(exp
.loc
, "cannot cast `%s`", exp
.e1
.toChars());
7865 // https://issues.dlang.org/show_bug.cgi?id=19954
7866 if (exp
.e1
.type
.ty
== Ttuple
)
7870 if (TypeTuple tt
= exp
.to
.isTypeTuple())
7872 if (exp
.e1
.type
.implicitConvTo(tt
))
7874 result
= exp
.e1
.castTo(sc
, tt
);
7879 TupleExp te
= exp
.e1
.isTupleExp();
7880 if (te
.exps
.length
== 1)
7881 exp
.e1
= (*te
.exps
)[0];
7884 // only allow S(x) rewrite if cast specified S explicitly.
7885 // See https://issues.dlang.org/show_bug.cgi?id=18545
7886 const bool allowImplicitConstruction
= exp
.to
!is null;
7888 if (!exp
.to
) // Handle cast(const) and cast(immutable), etc.
7890 exp
.to
= exp
.e1
.type
.castMod(exp
.mod
);
7891 exp
.to
= exp
.to
.typeSemantic(exp
.loc
, sc
);
7893 if (exp
.to
== Type
.terror
)
7897 if (exp
.to
.ty
== Ttuple
)
7899 error(exp
.loc
, "cannot cast `%s` of type `%s` to type sequence `%s`", exp
.e1
.toChars(), exp
.e1
.type
.toChars(), exp
.to
.toChars());
7903 // cast(void) is used to mark e1 as unused, so it is safe
7904 if (exp
.to
.ty
== Tvoid
)
7911 if (!exp
.to
.equals(exp
.e1
.type
) && exp
.mod
== cast(ubyte)~0)
7913 if (Expression e
= exp
.op_overload(sc
))
7915 result
= e
.implicitCastTo(sc
, exp
.to
);
7920 Type t1b
= exp
.e1
.type
.toBasetype();
7921 Type tob
= exp
.to
.toBasetype();
7923 if (allowImplicitConstruction
&& tob
.ty
== Tstruct
&& !tob
.equals(t1b
))
7931 // Rewrite as to.call(e1)
7932 Expression e
= new TypeExp(exp
.loc
, exp
.to
);
7933 e
= new CallExp(exp
.loc
, e
, exp
.e1
);
7934 e
= e
.trySemantic(sc
);
7942 if (!t1b
.equals(tob
) && (t1b
.ty
== Tarray || t1b
.ty
== Tsarray
))
7944 if (checkNonAssignmentArrayOp(exp
.e1
))
7948 // Look for casting to a vector type
7949 if (tob
.ty
== Tvector
&& t1b
.ty
!= Tvector
)
7951 result
= new VectorExp(exp
.loc
, exp
.e1
, exp
.to
);
7952 result
= result
.expressionSemantic(sc
);
7956 Expression ex
= exp
.e1
.castTo(sc
, exp
.to
);
7957 if (ex
.op
== EXP
.error
)
7963 // Check for unsafe casts
7964 if (!isSafeCast(ex
, t1b
, tob
))
7966 if (sc
.setUnsafe(false, exp
.loc
, "cast from `%s` to `%s` not allowed in safe code", exp
.e1
.type
, exp
.to
))
7972 // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built
7973 // to handle certain casts. Those casts which `object.__ArrayCast` does not support are filtered out.
7974 // See `e2ir.toElemCast` for other types of casts. If `object.__ArrayCast` is improved to support more
7975 // casts these conditions and potentially some logic in `e2ir.toElemCast` can be removed.
7976 if (tob
.ty
== Tarray
)
7978 // https://issues.dlang.org/show_bug.cgi?id=19840
7979 if (auto ad
= isAggregate(t1b
))
7983 Expression e
= resolveAliasThis(sc
, exp
.e1
);
7984 e
= new CastExp(exp
.loc
, e
, exp
.to
);
7985 result
= e
.expressionSemantic(sc
);
7990 if(t1b
.ty
== Tarray
&& exp
.e1
.op
!= EXP
.arrayLiteral
&& sc
.needsCodegen())
7992 auto tFrom
= t1b
.nextOf();
7993 auto tTo
= tob
.nextOf();
7995 // https://issues.dlang.org/show_bug.cgi?id=20130
7996 if (exp
.e1
.op
!= EXP
.string_ ||
!ex
.isStringExp
)
7998 const uint fromSize
= cast(uint)tFrom
.size();
7999 const uint toSize
= cast(uint)tTo
.size();
8000 if (fromSize
== SIZE_INVALID || toSize
== SIZE_INVALID
)
8003 // If array element sizes do not match, we must adjust the dimensions
8004 if (fromSize
!= toSize
)
8006 if (!verifyHookExist(exp
.loc
, *sc
, Id
.__ArrayCast
, "casting array of structs"))
8009 // A runtime check is needed in case arrays don't line up. That check should
8010 // be done in the implementation of `object.__ArrayCast`
8011 if (toSize
== 0 ||
(fromSize
% toSize
) != 0)
8013 // lower to `object.__ArrayCast!(TFrom, TTo)(from)`
8015 // fully qualify as `object.__ArrayCast`
8016 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
8017 auto dotid
= new DotIdExp(exp
.loc
, id
, Id
.object
);
8019 auto tiargs
= new Objects();
8022 auto dt = new DotTemplateInstanceExp(exp
.loc
, dotid
, Id
.__ArrayCast
, tiargs
);
8024 auto arguments
= new Expressions();
8025 arguments
.push(exp
.e1
);
8026 Expression ce
= new CallExp(exp
.loc
, dt, arguments
);
8028 result
= expressionSemantic(ce
, sc
);
8036 if (sc
&& sc
.flags
& SCOPE
.Cfile
)
8038 /* C11 6.5.4-5: A cast does not yield an lvalue.
8039 * So ensure that castTo does not strip away the cast so that this
8040 * can be enforced in other semantic visitor methods.
8042 if (!ex
.isCastExp())
8044 ex
= new CastExp(exp
.loc
, ex
, exp
.to
);
8051 override void visit(VectorExp exp
)
8053 static if (LOGSEMANTIC
)
8055 printf("VectorExp::semantic('%s')\n", exp
.toChars());
8063 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
8064 exp
.type
= exp
.to
.typeSemantic(exp
.loc
, sc
);
8065 if (exp
.e1
.op
== EXP
.error || exp
.type
.ty
== Terror
)
8071 Type tb
= exp
.type
.toBasetype();
8072 assert(tb
.ty
== Tvector
);
8073 TypeVector tv
= cast(TypeVector
)tb
;
8074 Type te
= tv
.elementType();
8075 exp
.dim
= cast(int)(tv
.size(exp
.loc
) / te
.size(exp
.loc
));
8077 bool checkElem(Expression elem
)
8079 if (elem
.isConst() == 1)
8082 error(exp
.loc
, "constant expression expected, not `%s`", elem
.toChars());
8086 exp
.e1
= exp
.e1
.optimize(WANTvalue
);
8088 if (exp
.e1
.op
== EXP
.arrayLiteral
)
8090 foreach (i
; 0 .. exp
.dim
)
8092 // Do not stop on first error - check all AST nodes even if error found
8093 res |
= checkElem(exp
.e1
.isArrayLiteralExp()[i
]);
8096 else if (exp
.e1
.type
.ty
== Tvoid
)
8099 result
= res ? ErrorExp
.get() : exp
;
8102 override void visit(VectorArrayExp e
)
8104 static if (LOGSEMANTIC
)
8106 printf("VectorArrayExp::semantic('%s')\n", e
.toChars());
8111 e
.e1
= resolveProperties(sc
, e
.e1
);
8113 if (e
.e1
.op
== EXP
.error
)
8118 assert(e
.e1
.type
.ty
== Tvector
);
8119 e
.type
= e
.e1
.type
.isTypeVector().basetype
;
8124 override void visit(SliceExp exp
)
8126 static if (LOGSEMANTIC
)
8128 printf("SliceExp::semantic('%s')\n", exp
.toChars());
8136 // operator overloading should be handled in ArrayExp already.
8137 if (Expression ex
= unaSemantic(exp
, sc
))
8142 exp
.e1
= resolveProperties(sc
, exp
.e1
);
8143 if (exp
.e1
.op
== EXP
.type
&& exp
.e1
.type
.ty
!= Ttuple
)
8145 if (exp
.lwr || exp
.upr
)
8147 error(exp
.loc
, "cannot slice type `%s`", exp
.e1
.toChars());
8150 Expression e
= new TypeExp(exp
.loc
, exp
.e1
.type
.arrayOf());
8151 result
= e
.expressionSemantic(sc
);
8154 if (!exp
.lwr
&& !exp
.upr
)
8156 if (exp
.e1
.op
== EXP
.arrayLiteral
)
8158 // Convert [a,b,c][] to [a,b,c]
8159 Type t1b
= exp
.e1
.type
.toBasetype();
8160 Expression e
= exp
.e1
;
8161 if (t1b
.ty
== Tsarray
)
8164 e
.type
= t1b
.nextOf().arrayOf();
8169 if (exp
.e1
.op
== EXP
.slice
)
8171 // Convert e[][] to e[]
8172 SliceExp se
= cast(SliceExp
)exp
.e1
;
8173 if (!se
.lwr
&& !se
.upr
)
8179 if (isArrayOpOperand(exp
.e1
))
8181 // Convert (a[]+b[])[] to a[]+b[]
8186 if (exp
.e1
.op
== EXP
.error
)
8191 if (exp
.e1
.type
.ty
== Terror
)
8194 Type t1b
= exp
.e1
.type
.toBasetype();
8195 if (auto tp
= t1b
.isTypePointer())
8197 if (t1b
.isPtrToFunction())
8199 error(exp
.loc
, "cannot slice function pointer `%s`", exp
.e1
.toChars());
8202 if (!exp
.lwr ||
!exp
.upr
)
8204 error(exp
.loc
, "upper and lower bounds are needed to slice a pointer");
8205 if (auto ad
= isAggregate(tp
.next
.toBasetype()))
8207 auto s
= search_function(ad
, Id
.index
);
8208 if (!s
) s
= search_function(ad
, Id
.slice
);
8211 auto fd
= s
.isFuncDeclaration();
8212 if ((fd
&& !fd
.getParameterList().length
) || s
.isTemplateDeclaration())
8214 errorSupplemental(exp
.loc
,
8215 "pointer `%s` points to an aggregate that defines an `%s`, perhaps you meant `(*%s)[]`",
8227 if (sc
.setUnsafe(false, exp
.loc
, "pointer slicing not allowed in safe functions"))
8230 else if (t1b
.ty
== Tarray
)
8233 else if (t1b
.ty
== Tsarray
)
8236 else if (t1b
.ty
== Ttuple
)
8238 if (!exp
.lwr
&& !exp
.upr
)
8243 if (!exp
.lwr ||
!exp
.upr
)
8245 error(exp
.loc
, "need upper and lower bound to slice a sequence");
8249 else if (t1b
.ty
== Tvector
&& exp
.e1
.isLvalue())
8251 // Convert e1 to corresponding static array
8252 TypeVector tv1
= cast(TypeVector
)t1b
;
8254 t1b
= t1b
.castMod(tv1
.mod
);
8259 error(exp
.loc
, "`%s` cannot be sliced with `[]`", t1b
.ty
== Tvoid ? exp
.e1
.toChars() : t1b
.toChars());
8263 /* Run semantic on lwr and upr.
8266 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray || t1b
.ty
== Ttuple
)
8268 // Create scope for 'length' variable
8269 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, exp
);
8270 sym
.parent
= sc
.scopesym
;
8275 if (t1b
.ty
== Ttuple
)
8276 sc
= sc
.startCTFE();
8277 exp
.lwr
= exp
.lwr
.expressionSemantic(sc
);
8278 exp
.lwr
= resolveProperties(sc
, exp
.lwr
);
8279 if (t1b
.ty
== Ttuple
)
8281 exp
.lwr
= exp
.lwr
.implicitCastTo(sc
, Type
.tsize_t
);
8285 if (t1b
.ty
== Ttuple
)
8286 sc
= sc
.startCTFE();
8287 exp
.upr
= exp
.upr
.expressionSemantic(sc
);
8288 exp
.upr
= resolveProperties(sc
, exp
.upr
);
8289 if (t1b
.ty
== Ttuple
)
8291 exp
.upr
= exp
.upr
.implicitCastTo(sc
, Type
.tsize_t
);
8295 if (exp
.lwr
&& exp
.lwr
.type
== Type
.terror || exp
.upr
&& exp
.upr
.type
== Type
.terror
)
8298 if (t1b
.ty
== Ttuple
)
8300 exp
.lwr
= exp
.lwr
.ctfeInterpret();
8301 exp
.upr
= exp
.upr
.ctfeInterpret();
8302 uinteger_t i1
= exp
.lwr
.toUInteger();
8303 uinteger_t i2
= exp
.upr
.toUInteger();
8308 if (exp
.e1
.op
== EXP
.tuple
) // slicing an expression tuple
8310 te
= cast(TupleExp
)exp
.e1
;
8312 length
= te
.exps
.length
;
8314 else if (exp
.e1
.op
== EXP
.type
) // slicing a type tuple
8317 tup
= cast(TypeTuple
)t1b
;
8318 length
= Parameter
.dim(tup
.arguments
);
8323 if (i2
< i1 || length
< i2
)
8325 error(exp
.loc
, "string slice `[%llu .. %llu]` is out of bounds", i1
, i2
);
8329 size_t j1
= cast(size_t
)i1
;
8330 size_t j2
= cast(size_t
)i2
;
8332 if (exp
.e1
.op
== EXP
.tuple
)
8334 auto exps
= new Expressions(j2
- j1
);
8335 for (size_t i
= 0; i
< j2
- j1
; i
++)
8337 (*exps
)[i
] = (*te
.exps
)[j1
+ i
];
8339 e
= new TupleExp(exp
.loc
, te
.e0
, exps
);
8343 auto args
= new Parameters();
8344 args
.reserve(j2
- j1
);
8345 for (size_t i
= j1
; i
< j2
; i
++)
8347 Parameter arg
= Parameter
.getNth(tup
.arguments
, i
);
8350 e
= new TypeExp(exp
.e1
.loc
, new TypeTuple(args
));
8352 e
= e
.expressionSemantic(sc
);
8357 exp
.type
= t1b
.nextOf().arrayOf();
8358 // Allow typedef[] -> typedef[]
8359 if (exp
.type
.equals(t1b
))
8360 exp
.type
= exp
.e1
.type
;
8362 // We might know $ now
8363 setLengthVarIfKnown(exp
.lengthVar
, t1b
);
8365 if (exp
.lwr
&& exp
.upr
)
8367 exp
.lwr
= exp
.lwr
.optimize(WANTvalue
);
8368 exp
.upr
= exp
.upr
.optimize(WANTvalue
);
8370 IntRange lwrRange
= getIntRange(exp
.lwr
);
8371 IntRange uprRange
= getIntRange(exp
.upr
);
8373 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray
)
8375 Expression el
= new ArrayLengthExp(exp
.loc
, exp
.e1
);
8376 el
= el
.expressionSemantic(sc
);
8377 el
= el
.optimize(WANTvalue
);
8378 if (el
.op
== EXP
.int64
)
8380 // Array length is known at compile-time. Upper is in bounds if it fits length.
8381 dinteger_t length
= el
.toInteger();
8382 auto bounds
= IntRange(SignExtendedNumber(0), SignExtendedNumber(length
));
8383 exp
.upperIsInBounds
= bounds
.contains(uprRange
);
8385 else if (exp
.upr
.op
== EXP
.int64
&& exp
.upr
.toInteger() == 0)
8387 // Upper slice expression is '0'. Value is always in bounds.
8388 exp
.upperIsInBounds
= true;
8390 else if (exp
.upr
.op
== EXP
.variable
&& (cast(VarExp
)exp
.upr
).var
.ident
== Id
.dollar
)
8392 // Upper slice expression is '$'. Value is always in bounds.
8393 exp
.upperIsInBounds
= true;
8396 else if (t1b
.ty
== Tpointer
)
8398 exp
.upperIsInBounds
= true;
8403 exp
.lowerIsLessThanUpper
= (lwrRange
.imax
<= uprRange
.imin
);
8405 //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", exp.upperIsInBounds, exp.lowerIsLessThanUpper);
8411 override void visit(ArrayLengthExp e
)
8413 static if (LOGSEMANTIC
)
8415 printf("ArrayLengthExp::semantic('%s')\n", e
.toChars());
8423 if (Expression ex
= unaSemantic(e
, sc
))
8428 e
.e1
= resolveProperties(sc
, e
.e1
);
8430 e
.type
= Type
.tsize_t
;
8434 override void visit(ArrayExp exp
)
8436 static if (LOGSEMANTIC
)
8438 printf("ArrayExp::semantic('%s')\n", exp
.toChars());
8442 if (sc
.flags
& SCOPE
.Cfile
)
8444 /* See if need to rewrite the AST because of cast/call ambiguity
8446 if (auto e
= castCallAmbiguity(exp
, sc
))
8448 result
= expressionSemantic(e
, sc
);
8453 result
= exp
.carraySemantic(sc
); // C semantics
8457 Expression e
= exp
.op_overload(sc
);
8464 if (isAggregate(exp
.e1
.type
))
8465 error(exp
.loc
, "no `[]` operator overload for type `%s`", exp
.e1
.type
.toChars());
8466 else if (exp
.e1
.op
== EXP
.type
&& exp
.e1
.type
.ty
!= Ttuple
)
8467 error(exp
.loc
, "static array of `%s` with multiple lengths not allowed", exp
.e1
.type
.toChars());
8468 else if (isIndexableNonAggregate(exp
.e1
.type
))
8469 error(exp
.loc
, "only one index allowed to index `%s`", exp
.e1
.type
.toChars());
8471 error(exp
.loc
, "cannot use `[]` operator on expression of type `%s`", exp
.e1
.type
.toChars());
8473 result
= ErrorExp
.get();
8476 override void visit(DotExp exp
)
8478 static if (LOGSEMANTIC
)
8480 printf("DotExp::semantic('%s')\n", exp
.toChars());
8482 printf("\ttype = %s\n", exp
.type
.toChars());
8484 exp
.e1
= exp
.e1
.expressionSemantic(sc
);
8485 exp
.e2
= exp
.e2
.expressionSemantic(sc
);
8487 if (exp
.e1
.op
== EXP
.type
)
8492 if (exp
.e2
.op
== EXP
.type
)
8497 if (auto te
= exp
.e2
.isTemplateExp())
8499 Expression e
= new DotTemplateExp(exp
.loc
, exp
.e1
, te
.td
);
8500 result
= e
.expressionSemantic(sc
);
8504 exp
.type
= exp
.e2
.type
;
8508 override void visit(CommaExp e
)
8510 //printf("Semantic.CommaExp() %s\n", e.toChars());
8517 // Allow `((a,b),(x,y))`
8518 if (e
.allowCommaExp
)
8520 CommaExp
.allow(e
.e1
);
8521 CommaExp
.allow(e
.e2
);
8524 if (Expression ex
= binSemanticProp(e
, sc
))
8529 e
.e1
= e
.e1
.addDtorHook(sc
);
8531 if (checkNonAssignmentArrayOp(e
.e1
))
8534 // Comma expressions trigger this conversion
8535 e
.e2
= e
.e2
.arrayFuncConv(sc
);
8540 if (sc
.flags
& SCOPE
.Cfile
)
8543 if (e
.type
is Type
.tvoid
)
8545 checkMustUse(e
.e1
, sc
);
8548 else if (!e
.allowCommaExp
&& !e
.isGenerated
)
8549 error(e
.loc
, "using the result of a comma expression is not allowed");
8552 override void visit(IntervalExp e
)
8554 static if (LOGSEMANTIC
)
8556 printf("IntervalExp::semantic('%s')\n", e
.toChars());
8564 Expression le
= e
.lwr
;
8565 le
= le
.expressionSemantic(sc
);
8566 le
= resolveProperties(sc
, le
);
8568 Expression ue
= e
.upr
;
8569 ue
= ue
.expressionSemantic(sc
);
8570 ue
= resolveProperties(sc
, ue
);
8572 if (le
.op
== EXP
.error
)
8577 if (ue
.op
== EXP
.error
)
8586 e
.type
= Type
.tvoid
;
8590 override void visit(DelegatePtrExp e
)
8592 static if (LOGSEMANTIC
)
8594 printf("DelegatePtrExp::semantic('%s')\n", e
.toChars());
8599 e
.e1
= resolveProperties(sc
, e
.e1
);
8601 if (e
.e1
.op
== EXP
.error
)
8606 e
.type
= Type
.tvoidptr
;
8611 override void visit(DelegateFuncptrExp e
)
8613 static if (LOGSEMANTIC
)
8615 printf("DelegateFuncptrExp::semantic('%s')\n", e
.toChars());
8620 e
.e1
= resolveProperties(sc
, e
.e1
);
8621 if (e
.e1
.op
== EXP
.error
)
8626 e
.type
= e
.e1
.type
.nextOf().pointerTo();
8631 override void visit(IndexExp exp
)
8633 static if (LOGSEMANTIC
)
8635 printf("IndexExp::semantic('%s')\n", exp
.toChars());
8643 // operator overloading should be handled in ArrayExp already.
8645 exp
.e1
= exp
.e1
.expressionSemantic(sc
).arrayFuncConv(sc
);
8646 assert(exp
.e1
.type
); // semantic() should already be run on it
8647 if (exp
.e1
.op
== EXP
.type
&& exp
.e1
.type
.ty
!= Ttuple
)
8649 exp
.e2
= exp
.e2
.expressionSemantic(sc
);
8650 exp
.e2
= resolveProperties(sc
, exp
.e2
);
8652 if (exp
.e2
.op
== EXP
.type
)
8653 nt
= new TypeAArray(exp
.e1
.type
, exp
.e2
.type
);
8655 nt
= new TypeSArray(exp
.e1
.type
, exp
.e2
);
8656 Expression e
= new TypeExp(exp
.loc
, nt
);
8657 result
= e
.expressionSemantic(sc
);
8660 if (exp
.e1
.op
== EXP
.error
)
8665 if (exp
.e1
.type
.ty
== Terror
)
8668 // Note that unlike C we do not implement the int[ptr]
8670 Type t1b
= exp
.e1
.type
.toBasetype();
8672 if (TypeVector tv1
= t1b
.isTypeVector())
8674 // Convert e1 to corresponding static array
8676 t1b
= t1b
.castMod(tv1
.mod
);
8677 exp
.e1
= exp
.e1
.castTo(sc
, t1b
);
8679 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray
)
8681 if (!checkAddressable(exp
, sc
))
8685 /* Run semantic on e2
8688 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray || t1b
.ty
== Ttuple
)
8690 // Create scope for 'length' variable
8691 ScopeDsymbol sym
= new ArrayScopeSymbol(sc
, exp
);
8692 sym
.parent
= sc
.scopesym
;
8695 if (t1b
.ty
== Ttuple
)
8696 sc
= sc
.startCTFE();
8697 exp
.e2
= exp
.e2
.expressionSemantic(sc
).arrayFuncConv(sc
);
8698 exp
.e2
= resolveProperties(sc
, exp
.e2
);
8699 if (t1b
.ty
== Ttuple
)
8701 if (exp
.e2
.op
== EXP
.tuple
)
8703 TupleExp te
= cast(TupleExp
)exp
.e2
;
8704 if (te
.exps
&& te
.exps
.length
== 1)
8705 exp
.e2
= Expression
.combine(te
.e0
, (*te
.exps
)[0]); // bug 4444 fix
8709 if (exp
.e2
.type
== Type
.terror
)
8712 if (checkNonAssignmentArrayOp(exp
.e1
))
8718 if (t1b
.isPtrToFunction())
8720 error(exp
.loc
, "cannot index function pointer `%s`", exp
.e1
.toChars());
8723 exp
.e2
= exp
.e2
.implicitCastTo(sc
, Type
.tsize_t
);
8724 if (exp
.e2
.type
== Type
.terror
)
8726 exp
.e2
= exp
.e2
.optimize(WANTvalue
);
8727 if (exp
.e2
.op
== EXP
.int64
&& exp
.e2
.toInteger() == 0)
8730 else if (sc
.setUnsafe(false, exp
.loc
, "`@safe` function `%s` cannot index pointer `%s`", sc
.func
, exp
.e1
))
8734 exp
.type
= (cast(TypeNext
)t1b
).next
;
8738 exp
.e2
= exp
.e2
.implicitCastTo(sc
, Type
.tsize_t
);
8739 if (exp
.e2
.type
== Type
.terror
)
8741 exp
.type
= (cast(TypeNext
)t1b
).next
;
8746 exp
.e2
= exp
.e2
.implicitCastTo(sc
, Type
.tsize_t
);
8747 if (exp
.e2
.type
== Type
.terror
)
8749 exp
.type
= t1b
.nextOf();
8754 TypeAArray taa
= cast(TypeAArray
)t1b
;
8755 /* We can skip the implicit conversion if they differ only by
8757 * https://issues.dlang.org/show_bug.cgi?id=2684
8758 * see also bug https://issues.dlang.org/show_bug.cgi?id=2954 b
8760 if (!arrayTypeCompatibleWithoutCasting(exp
.e2
.type
, taa
.index
))
8762 exp
.e2
= exp
.e2
.implicitCastTo(sc
, taa
.index
); // type checking
8763 if (exp
.e2
.type
== Type
.terror
)
8767 semanticTypeInfo(sc
, taa
);
8768 checkNewEscape(sc
, exp
.e2
, false);
8770 exp
.type
= taa
.next
;
8775 exp
.e2
= exp
.e2
.implicitCastTo(sc
, Type
.tsize_t
);
8776 if (exp
.e2
.type
== Type
.terror
)
8779 exp
.e2
= exp
.e2
.ctfeInterpret();
8780 uinteger_t index
= exp
.e2
.toUInteger();
8785 if (exp
.e1
.op
== EXP
.tuple
)
8787 te
= cast(TupleExp
)exp
.e1
;
8789 length
= te
.exps
.length
;
8791 else if (exp
.e1
.op
== EXP
.type
)
8794 tup
= cast(TypeTuple
)t1b
;
8795 length
= Parameter
.dim(tup
.arguments
);
8800 if (length
<= index
)
8802 error(exp
.loc
, "array index `[%llu]` is outside array bounds `[0 .. %llu]`", index
, cast(ulong)length
);
8806 if (exp
.e1
.op
== EXP
.tuple
)
8808 e
= (*te
.exps
)[cast(size_t
)index
];
8809 e
= Expression
.combine(te
.e0
, e
);
8812 e
= new TypeExp(exp
.e1
.loc
, Parameter
.getNth(tup
.arguments
, cast(size_t
)index
).type
);
8817 error(exp
.loc
, "`%s` must be an array or pointer type, not `%s`", exp
.e1
.toChars(), exp
.e1
.type
.toChars());
8821 // We might know $ now
8822 setLengthVarIfKnown(exp
.lengthVar
, t1b
);
8824 if (t1b
.ty
== Tsarray || t1b
.ty
== Tarray
)
8826 Expression el
= new ArrayLengthExp(exp
.loc
, exp
.e1
);
8827 el
= el
.expressionSemantic(sc
);
8828 el
= el
.optimize(WANTvalue
);
8829 if (el
.op
== EXP
.int64
)
8831 exp
.e2
= exp
.e2
.optimize(WANTvalue
);
8832 dinteger_t length
= el
.toInteger();
8835 auto bounds
= IntRange(SignExtendedNumber(0), SignExtendedNumber(length
- 1));
8836 // OR it in, because it might already be set for C array indexing
8837 exp
.indexIsInBounds |
= bounds
.contains(getIntRange(exp
.e2
));
8839 else if (sc
.flags
& SCOPE
.Cfile
&& t1b
.ty
== Tsarray
)
8841 if (auto ve
= exp
.e1
.isVarExp())
8843 /* Rewrite 0-length C array ve[exp.e2] as *(ve + exp.e2)
8845 auto vp
= ve
.castTo(sc
, t1b
.isTypeSArray().next
.pointerTo());
8846 auto e
= new AddExp(exp
.loc
, vp
, exp
.e2
);
8847 auto pe
= new PtrExp(exp
.loc
, e
);
8848 result
= pe
.expressionSemantic(sc
).optimize(WANTvalue
);
8858 override void visit(PostExp exp
)
8860 static if (LOGSEMANTIC
)
8862 printf("PostExp::semantic('%s')\n", exp
.toChars());
8870 if (sc
.flags
& SCOPE
.Cfile
)
8872 /* See if need to rewrite the AST because of cast/call ambiguity
8874 if (auto e
= castCallAmbiguity(exp
, sc
))
8876 result
= expressionSemantic(e
, sc
);
8881 if (Expression ex
= binSemantic(exp
, sc
))
8886 Expression e1x
= resolveProperties(sc
, exp
.e1
);
8887 if (e1x
.op
== EXP
.error
)
8894 Expression e
= exp
.op_overload(sc
);
8901 if (exp
.e1
.checkReadModifyWrite(exp
.op
))
8904 if (exp
.e1
.op
== EXP
.slice
)
8906 const(char)* s
= exp
.op
== EXP
.plusPlus ?
"increment" : "decrement";
8907 error(exp
.loc
, "cannot post-%s array slice `%s`, use pre-%s instead", s
, exp
.e1
.toChars(), s
);
8911 Type t1
= exp
.e1
.type
.toBasetype();
8912 if (t1
.ty
== Tclass || t1
.ty
== Tstruct || exp
.e1
.op
== EXP
.arrayLength
)
8914 /* Check for operator overloading,
8915 * but rewrite in terms of ++e instead of e++
8918 /* If e1 is not trivial, take a reference to it
8920 Expression
de = null;
8921 if (exp
.e1
.op
!= EXP
.variable
&& exp
.e1
.op
!= EXP
.arrayLength
)
8924 auto v
= copyToTemp(STC
.ref_
, "__postref", exp
.e1
);
8925 de = new DeclarationExp(exp
.loc
, v
);
8926 exp
.e1
= new VarExp(exp
.e1
.loc
, v
);
8930 * auto tmp = e1; ++e1; tmp
8932 auto tmp
= copyToTemp(0, "__pitmp", exp
.e1
);
8933 Expression ea
= new DeclarationExp(exp
.loc
, tmp
);
8935 Expression eb
= exp
.e1
.syntaxCopy();
8936 eb
= new PreExp(exp
.op
== EXP
.plusPlus ? EXP
.prePlusPlus
: EXP
.preMinusMinus
, exp
.loc
, eb
);
8938 Expression ec
= new VarExp(exp
.loc
, tmp
);
8940 // Combine de,ea,eb,ec
8942 ea
= new CommaExp(exp
.loc
, de, ea
);
8943 e
= new CommaExp(exp
.loc
, ea
, eb
);
8944 e
= new CommaExp(exp
.loc
, e
, ec
);
8945 e
= e
.expressionSemantic(sc
);
8950 exp
.e1
= exp
.e1
.modifiableLvalue(sc
, exp
.e1
);
8951 exp
.e1
= exp
.e1
.optimize(WANTvalue
, /*keepLvalue*/ true);
8954 if (exp
.e1
.checkScalar() ||
8955 exp
.e1
.checkSharedAccess(sc
))
8957 if (exp
.e1
.checkNoBool())
8960 if (exp
.e1
.type
.ty
== Tpointer
)
8961 e
= scaleFactor(exp
, sc
);
8963 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
);
8964 e
.type
= exp
.e1
.type
;
8968 override void visit(PreExp exp
)
8970 Expression e
= exp
.op_overload(sc
);
8971 // printf("PreExp::semantic('%s')\n", toChars());
8978 // Rewrite as e1+=1 or e1-=1
8979 if (exp
.op
== EXP
.prePlusPlus
)
8980 e
= new AddAssignExp(exp
.loc
, exp
.e1
, IntegerExp
.literal
!1);
8982 e
= new MinAssignExp(exp
.loc
, exp
.e1
, IntegerExp
.literal
!1);
8983 result
= e
.expressionSemantic(sc
);
8987 * Get the expression initializer for a specific struct
8990 * sd = the struct for which the expression initializer is needed
8991 * loc = the location of the initializer
8992 * sc = the scope where the expression is located
8993 * t = the type of the expression
8996 * The expression initializer or error expression if any errors occured
8998 private Expression
getInitExp(StructDeclaration sd
, Loc loc
, Scope
* sc
, Type t
)
9000 if (sd
.zeroInit
&& !sd
.isNested())
9002 // https://issues.dlang.org/show_bug.cgi?id=14606
9003 // Always use BlitExp for the special expression: (struct = 0)
9004 return IntegerExp
.literal
!0;
9009 auto sle
= new StructLiteralExp(loc
, sd
, null, t
);
9010 if (!sd
.fill(loc
, *sle
.elements
, true))
9011 return ErrorExp
.get();
9012 if (checkFrameAccess(loc
, sc
, sd
, sle
.elements
.length
))
9013 return ErrorExp
.get();
9019 return t
.defaultInit(loc
);
9022 override void visit(AssignExp exp
)
9024 static if (LOGSEMANTIC
)
9026 if (exp
.op
== EXP
.blit
) printf("BlitExp.toElem('%s')\n", exp
.toChars());
9027 if (exp
.op
== EXP
.assign
) printf("AssignExp.toElem('%s')\n", exp
.toChars());
9028 if (exp
.op
== EXP
.construct
) printf("ConstructExp.toElem('%s')\n", exp
.toChars());
9031 void setResult(Expression e
, int line
= __LINE__
)
9033 //printf("line %d\n", line);
9039 return setResult(exp
);
9042 Expression e1old
= exp
.e1
;
9044 if (auto e2comma
= exp
.e2
.isCommaExp())
9046 if (!e2comma
.isGenerated
&& !(sc
.flags
& SCOPE
.Cfile
))
9047 error(exp
.loc
, "using the result of a comma expression is not allowed");
9049 /* Rewrite to get rid of the comma from rvalue
9050 * e1=(e0,e2) => e0,(e1=e2)
9053 exp
.e2
= Expression
.extractLast(e2comma
, e0
);
9054 Expression e
= Expression
.combine(e0
, exp
);
9055 return setResult(e
.expressionSemantic(sc
));
9058 /* Look for operator overloading of a[arguments] = e2.
9059 * Do it before e1.expressionSemantic() otherwise the ArrayExp will have been
9060 * converted to unary operator overloading already.
9062 if (auto ae
= exp
.e1
.isArrayExp())
9066 ae
.e1
= ae
.e1
.expressionSemantic(sc
);
9067 ae
.e1
= resolveProperties(sc
, ae
.e1
);
9068 Expression ae1old
= ae
.e1
;
9070 const(bool) maybeSlice
=
9071 (ae
.arguments
.length
== 0 ||
9072 ae
.arguments
.length
== 1 && (*ae
.arguments
)[0].op
== EXP
.interval
);
9074 IntervalExp ie
= null;
9075 if (maybeSlice
&& ae
.arguments
.length
)
9077 assert((*ae
.arguments
)[0].op
== EXP
.interval
);
9078 ie
= cast(IntervalExp
)(*ae
.arguments
)[0];
9080 Type att
= null; // first cyclic `alias this` type
9083 if (ae
.e1
.op
== EXP
.error
)
9084 return setResult(ae
.e1
);
9086 Expression e0
= null;
9087 Expression ae1save
= ae
.e1
;
9088 ae
.lengthVar
= null;
9090 Type t1b
= ae
.e1
.type
.toBasetype();
9091 AggregateDeclaration ad
= isAggregate(t1b
);
9094 if (search_function(ad
, Id
.indexass
))
9097 res
= resolveOpDollar(sc
, ae
, &e0
);
9098 if (!res
) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
9100 if (res
.op
== EXP
.error
)
9101 return setResult(res
);
9103 res
= exp
.e2
.expressionSemantic(sc
);
9104 if (res
.op
== EXP
.error
)
9105 return setResult(res
);
9108 /* Rewrite (a[arguments] = e2) as:
9109 * a.opIndexAssign(e2, arguments)
9111 Expressions
* a
= ae
.arguments
.copy();
9112 a
.insert(0, exp
.e2
);
9113 res
= new DotIdExp(exp
.loc
, ae
.e1
, Id
.indexass
);
9114 res
= new CallExp(exp
.loc
, res
, a
);
9115 if (maybeSlice
) // a[] = e2 might be: a.opSliceAssign(e2)
9116 res
= res
.trySemantic(sc
);
9118 res
= res
.expressionSemantic(sc
);
9120 return setResult(Expression
.combine(e0
, res
));
9124 if (maybeSlice
&& search_function(ad
, Id
.sliceass
))
9127 res
= resolveOpDollar(sc
, ae
, ie
, &e0
);
9128 if (res
.op
== EXP
.error
)
9129 return setResult(res
);
9131 res
= exp
.e2
.expressionSemantic(sc
);
9132 if (res
.op
== EXP
.error
)
9133 return setResult(res
);
9137 /* Rewrite (a[i..j] = e2) as:
9138 * a.opSliceAssign(e2, i, j)
9140 auto a
= new Expressions();
9147 res
= new DotIdExp(exp
.loc
, ae
.e1
, Id
.sliceass
);
9148 res
= new CallExp(exp
.loc
, res
, a
);
9149 res
= res
.expressionSemantic(sc
);
9150 return setResult(Expression
.combine(e0
, res
));
9153 // No operator overloading member function found yet, but
9154 // there might be an alias this to try.
9155 if (ad
.aliasthis
&& !isRecursiveAliasThis(att
, ae
.e1
.type
))
9157 /* Rewrite (a[arguments] op e2) as:
9158 * a.aliasthis[arguments] op e2
9160 ae
.e1
= resolveAliasThis(sc
, ae1save
, true);
9166 ae
.e1
= ae1old
; // recovery
9167 ae
.lengthVar
= null;
9170 /* Run this.e1 semantic.
9173 Expression e1x
= exp
.e1
;
9175 /* With UFCS, e.f = value
9181 if (auto dti
= e1x
.isDotTemplateInstanceExp())
9183 Expression e
= dti
.dotTemplateSemanticProp(sc
, DotExpFlag
.gag
);
9186 return setResult(resolveUFCSProperties(sc
, e1x
, exp
.e2
));
9191 else if (sc
.flags
& SCOPE
.Cfile
&& e1x
.isDotIdExp())
9193 auto die
= e1x
.isDotIdExp();
9194 e1x
= fieldLookup(die
.e1
, sc
, die
.ident
, die
.arrow
);
9196 else if (auto die
= e1x
.isDotIdExp())
9198 Expression e
= die
.dotIdSemanticProp(sc
, 1);
9199 if (e
&& isDotOpDispatch(e
))
9201 /* https://issues.dlang.org/show_bug.cgi?id=19687
9203 * On this branch, e2 is semantically analyzed in resolvePropertiesX,
9204 * but that call is done with gagged errors. That is the only time when
9205 * semantic gets ran on e2, that is why the error never gets to be printed.
9206 * In order to make sure that UFCS is tried with correct parameters, e2
9207 * needs to have semantic ran on it.
9210 exp
.e2
= exp
.e2
.expressionSemantic(sc
);
9211 uint errors
= global
.startGagging();
9212 e
= resolvePropertiesX(sc
, e
, exp
.e2
);
9213 // Any error or if 'e' is not resolved, go to UFCS
9214 if (global
.endGagging(errors
) || e
is ode
)
9215 e
= null; /* fall down to UFCS */
9217 return setResult(e
);
9220 return setResult(resolveUFCSProperties(sc
, e1x
, exp
.e2
));
9225 if (auto se
= e1x
.isSliceExp())
9228 e1x
= e1x
.expressionSemantic(sc
);
9231 /* We have f = value.
9237 if (Expression e
= resolvePropertiesX(sc
, e1x
, exp
.e2
, exp
))
9238 return setResult(e
);
9240 if (e1x
.checkRightThis(sc
))
9245 assert(exp
.e1
.type
);
9247 Type t1
= exp
.e1
.type
.isTypeEnum() ? exp
.e1
.type
: exp
.e1
.type
.toBasetype();
9249 /* Run this.e2 semantic.
9250 * Different from other binary expressions, the analysis of e2
9251 * depends on the result of e1 in assignments.
9254 Expression e2x
= inferType(exp
.e2
, t1
.baseElemOf());
9255 e2x
= e2x
.expressionSemantic(sc
);
9256 if (!t1
.isTypeSArray())
9257 e2x
= e2x
.arrayFuncConv(sc
);
9258 e2x
= resolveProperties(sc
, e2x
);
9259 if (e2x
.op
== EXP
.type
)
9260 e2x
= resolveAliasThis(sc
, e2x
); //https://issues.dlang.org/show_bug.cgi?id=17684
9261 if (e2x
.op
== EXP
.error
)
9262 return setResult(e2x
);
9263 // We delay checking the value for structs/classes as these might have
9264 // an opAssign defined.
9265 if ((t1
.ty
!= Tstruct
&& t1
.ty
!= Tclass
&& e2x
.checkValue()) ||
9266 e2x
.checkSharedAccess(sc
))
9269 auto etmp
= checkNoreturnVarAccess(e2x
);
9271 return setResult(etmp
);
9276 /* Rewrite tuple assignment as a tuple of assignments.
9279 Expression e2x
= exp
.e2
;
9282 if (exp
.e1
.op
== EXP
.tuple
&& e2x
.op
== EXP
.tuple
)
9284 TupleExp tup1
= cast(TupleExp
)exp
.e1
;
9285 TupleExp tup2
= cast(TupleExp
)e2x
;
9286 size_t dim
= tup1
.exps
.length
;
9287 Expression e
= null;
9288 if (dim
!= tup2
.exps
.length
)
9290 error(exp
.loc
, "mismatched sequence lengths, %d and %d", cast(int)dim
, cast(int)tup2
.exps
.length
);
9295 e
= IntegerExp
.literal
!0;
9296 e
= new CastExp(exp
.loc
, e
, Type
.tvoid
); // avoid "has no effect" error
9297 e
= Expression
.combine(tup1
.e0
, tup2
.e0
, e
);
9301 auto exps
= new Expressions(dim
);
9302 for (size_t i
= 0; i
< dim
; i
++)
9304 Expression ex1
= (*tup1
.exps
)[i
];
9305 Expression ex2
= (*tup2
.exps
)[i
];
9306 (*exps
)[i
] = new AssignExp(exp
.loc
, ex1
, ex2
);
9308 e
= new TupleExp(exp
.loc
, Expression
.combine(tup1
.e0
, tup2
.e0
), exps
);
9310 return setResult(e
.expressionSemantic(sc
));
9313 /* Look for form: e1 = e2.aliasthis.
9315 if (exp
.e1
.op
== EXP
.tuple
)
9317 TupleDeclaration td
= isAliasThisTuple(e2x
);
9321 assert(exp
.e1
.type
.ty
== Ttuple
);
9322 TypeTuple tt
= cast(TypeTuple
)exp
.e1
.type
;
9325 Expression ev
= extractSideEffect(sc
, "__tup", e0
, e2x
);
9327 auto iexps
= new Expressions();
9329 for (size_t u
= 0; u
< iexps
.length
; u
++)
9332 Expression e
= (*iexps
)[u
];
9334 Parameter arg
= Parameter
.getNth(tt
.arguments
, u
);
9335 //printf("[%d] iexps.length = %d, ", u, iexps.length);
9336 //printf("e = (%s %s, %s), ", Token.toChars[e.op], e.toChars(), e.type.toChars());
9337 //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
9339 if (!arg ||
!e
.type
.implicitConvTo(arg
.type
))
9341 // expand initializer to tuple
9342 if (expandAliasThisTuples(iexps
, u
) != -1)
9344 if (iexps
.length
<= u
)
9351 e2x
= new TupleExp(e2x
.loc
, e0
, iexps
);
9352 e2x
= e2x
.expressionSemantic(sc
);
9353 if (e2x
.op
== EXP
.error
)
9358 // Do not need to overwrite this.e2
9364 /* Inside constructor, if this is the first assignment of object field,
9365 * rewrite this to initializing the field.
9367 if (exp
.op
== EXP
.assign
9368 && exp
.e1
.checkModifiable(sc
) == Modifiable
.initialization
)
9370 //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars());
9372 exp
= new ConstructExp(exp
.loc
, exp
.e1
, exp
.e2
);
9375 // https://issues.dlang.org/show_bug.cgi?id=13515
9376 // set Index::modifiable flag for complex AA element initialization
9377 if (auto ie1
= exp
.e1
.isIndexExp())
9379 Expression e1x
= ie1
.markSettingAAElem();
9380 if (e1x
.op
== EXP
.error
)
9387 else if (exp
.op
== EXP
.construct
&& exp
.e1
.op
== EXP
.variable
&&
9388 (cast(VarExp
)exp
.e1
).var
.storage_class
& (STC
.out_ | STC
.ref_
))
9390 exp
.memset
= MemorySet
.referenceInit
;
9393 if (exp
.op
== EXP
.assign
) // skip EXP.blit and EXP.construct, which are initializations
9395 exp
.e1
.checkSharedAccess(sc
);
9396 checkUnsafeAccess(sc
, exp
.e1
, false, true);
9399 checkUnsafeAccess(sc
, exp
.e2
, true, true); // Initializer must always be checked
9401 /* If it is an assignment from a 'foreign' type,
9402 * check for operator overloading.
9404 if (exp
.memset
== MemorySet
.referenceInit
)
9406 // If this is an initialization of a reference,
9409 else if (t1
.ty
== Tstruct
)
9413 auto sd
= (cast(TypeStruct
)t1
).sym
;
9415 if (exp
.op
== EXP
.construct
)
9417 Type t2
= e2x
.type
.toBasetype();
9418 if (t2
.ty
== Tstruct
&& sd
== (cast(TypeStruct
)t2
).sym
)
9421 if (sd
.sizeok
!= Sizeok
.done
)
9424 sd
.ctor
= sd
.searchCtor();
9426 // https://issues.dlang.org/show_bug.cgi?id=15661
9427 // Look for the form from last of comma chain.
9428 auto e2y
= lastComma(e2x
);
9430 CallExp ce
= (e2y
.op
== EXP
.call) ?
cast(CallExp
)e2y
: null;
9431 DotVarExp dve
= (ce
&& ce
.e1
.op
== EXP
.dotVariable
)
9432 ?
cast(DotVarExp
)ce
.e1
: null;
9433 if (sd
.ctor
&& ce
&& dve
&& dve
.var
.isCtorDeclaration() &&
9434 // https://issues.dlang.org/show_bug.cgi?id=19389
9435 dve
.e1
.op
!= EXP
.dotVariable
&&
9436 e2y
.type
.implicitConvTo(t1
))
9438 /* Look for form of constructor call which is:
9439 * __ctmp.ctor(arguments...)
9442 /* Before calling the constructor, initialize
9443 * variable with a bit copy of the default
9446 Expression einit
= getInitExp(sd
, exp
.loc
, sc
, t1
);
9447 if (einit
.op
== EXP
.error
)
9453 auto ae
= new BlitExp(exp
.loc
, exp
.e1
, einit
);
9456 /* Replace __ctmp being constructed with e1.
9457 * We need to copy constructor call expression,
9458 * because it may be used in other place.
9460 auto dvx
= cast(DotVarExp
)dve
.copy();
9462 auto cx
= cast(CallExp
)ce
.copy();
9464 if (checkConstructorEscape(sc
, cx
, false))
9468 Expression
.extractLast(e2x
, e0
);
9470 auto e
= Expression
.combine(e0
, ae
, cx
);
9471 e
= e
.expressionSemantic(sc
);
9475 // https://issues.dlang.org/show_bug.cgi?id=21586
9476 // Rewrite CondExp or e1 will miss direct construction, e.g.
9477 // e1 = a ? S(1) : ...; -> AST: e1 = a ? (S(0)).this(1) : ...;
9478 // a temporary created and an extra destructor call.
9479 // AST will be rewritten to:
9480 // a ? e1 = 0, e1.this(1) : ...; -> blitting plus construction
9481 if (e2x
.op
== EXP
.question
)
9484 * a ? e1 = b : e1 = c;
9486 CondExp econd
= cast(CondExp
)e2x
;
9487 Expression ea1
= new ConstructExp(econd
.e1
.loc
, e1x
, econd
.e1
);
9488 Expression ea2
= new ConstructExp(econd
.e2
.loc
, e1x
, econd
.e2
);
9489 Expression e
= new CondExp(exp
.loc
, econd
.econd
, ea1
, ea2
);
9490 result
= e
.expressionSemantic(sc
);
9493 if (sd
.postblit || sd
.hasCopyCtor
)
9495 /* We have a copy constructor for this
9503 * e1 = init, e1.copyCtor(e2);
9505 Expression einit
= new BlitExp(exp
.loc
, exp
.e1
, getInitExp(sd
, exp
.loc
, sc
, t1
));
9506 einit
.type
= e1x
.type
;
9509 e
= new DotIdExp(exp
.loc
, e1x
, Id
.ctor
);
9510 e
= new CallExp(exp
.loc
, e
, e2x
);
9511 e
= new CommaExp(exp
.loc
, einit
, e
);
9513 //printf("e: %s\n", e.toChars());
9515 result
= e
.expressionSemantic(sc
);
9520 if (!e2x
.type
.implicitConvTo(e1x
.type
))
9522 error(exp
.loc
, "conversion error from `%s` to `%s`",
9523 e2x
.type
.toChars(), e1x
.type
.toChars());
9528 * (e1 = e2).postblit();
9530 * Blit assignment e1 = e2 returns a reference to the original e1,
9531 * then call the postblit on it.
9533 Expression e
= e1x
.copy();
9534 e
.type
= e
.type
.mutableOf();
9535 if (e
.type
.isShared
&& !sd
.type
.isShared
)
9536 e
.type
= e
.type
.unSharedOf();
9537 e
= new BlitExp(exp
.loc
, e
, e2x
);
9538 e
= new DotVarExp(exp
.loc
, e
, sd
.postblit
, false);
9539 e
= new CallExp(exp
.loc
, e
);
9540 result
= e
.expressionSemantic(sc
);
9546 /* The struct value returned from the function is transferred
9547 * so should not call the destructor on it.
9549 e2x
= valueNoDtor(e2x
);
9553 // https://issues.dlang.org/show_bug.cgi?id=19251
9554 // if e2 cannot be converted to e1.type, maybe there is an alias this
9555 if (!e2x
.implicitConvTo(t1
))
9557 AggregateDeclaration ad2
= isAggregate(e2x
.type
);
9558 if (ad2
&& ad2
.aliasthis
&& !isRecursiveAliasThis(exp
.att2
, exp
.e2
.type
))
9560 /* Rewrite (e1 op e2) as:
9561 * (e1 op e2.aliasthis)
9563 exp
.e2
= new DotIdExp(exp
.e2
.loc
, exp
.e2
, ad2
.aliasthis
.ident
);
9564 result
= exp
.expressionSemantic(sc
);
9569 else if (!e2x
.implicitConvTo(t1
))
9572 if (sd
.sizeok
!= Sizeok
.done
)
9575 sd
.ctor
= sd
.searchCtor();
9579 /* Look for implicit constructor call
9581 * e1 = init, e1.ctor(e2)
9584 /* Fix Issue 5153 : https://issues.dlang.org/show_bug.cgi?id=5153
9585 * Using `new` to initialize a struct object is a common mistake, but
9586 * the error message from the compiler is not very helpful in that
9587 * case. If exp.e2 is a NewExp and the type of new is the same as
9588 * the type as exp.e1 (struct in this case), then we know for sure
9589 * that the user wants to instantiate a struct. This is done to avoid
9590 * issuing an error when the user actually wants to call a constructor
9591 * which receives a class object.
9593 * Foo f = new Foo2(0); is a valid expression if Foo has a constructor
9594 * which receives an instance of a Foo2 class
9596 if (exp
.e2
.op
== EXP
.new_
)
9598 auto newExp
= cast(NewExp
)(exp
.e2
);
9599 if (newExp
.newtype
&& newExp
.newtype
== t1
)
9601 error(exp
.loc
, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
9602 newExp
.toChars(), newExp
.type
.toChars(), t1
.toChars());
9603 errorSupplemental(exp
.loc
, "Perhaps remove the `new` keyword?");
9608 Expression einit
= new BlitExp(exp
.loc
, e1x
, getInitExp(sd
, exp
.loc
, sc
, t1
));
9609 einit
.type
= e1x
.type
;
9612 e
= new DotIdExp(exp
.loc
, e1x
, Id
.ctor
);
9613 e
= new CallExp(exp
.loc
, e
, e2x
);
9614 e
= new CommaExp(exp
.loc
, einit
, e
);
9615 e
= e
.expressionSemantic(sc
);
9619 if (search_function(sd
, Id
.call))
9621 /* Look for static opCall
9622 * https://issues.dlang.org/show_bug.cgi?id=2702
9624 * e1 = typeof(e1).opCall(arguments)
9626 e2x
= typeDotIdExp(e2x
.loc
, e1x
.type
, Id
.call);
9627 e2x
= new CallExp(exp
.loc
, e2x
, exp
.e2
);
9629 e2x
= e2x
.expressionSemantic(sc
);
9630 e2x
= resolveProperties(sc
, e2x
);
9631 if (e2x
.op
== EXP
.error
)
9636 if (e2x
.checkValue() || e2x
.checkSharedAccess(sc
))
9640 else // https://issues.dlang.org/show_bug.cgi?id=11355
9642 AggregateDeclaration ad2
= isAggregate(e2x
.type
);
9643 if (ad2
&& ad2
.aliasthis
&& !isRecursiveAliasThis(exp
.att2
, exp
.e2
.type
))
9645 /* Rewrite (e1 op e2) as:
9646 * (e1 op e2.aliasthis)
9648 exp
.e2
= new DotIdExp(exp
.e2
.loc
, exp
.e2
, ad2
.aliasthis
.ident
);
9649 result
= exp
.expressionSemantic(sc
);
9654 else if (exp
.op
== EXP
.assign
)
9656 if (e1x
.op
== EXP
.index
&& (cast(IndexExp
)e1x
).e1
.type
.toBasetype().ty
== Taarray
)
9663 * ref __aakey = key;
9665 * (__aakey in __aatmp
9666 * ? __aatmp[__aakey].opAssign(__aaval)
9667 * : ConstructExp(__aatmp[__aakey], __aaval));
9669 // ensure we keep the expr modifiable
9670 Expression esetting
= (cast(IndexExp
)e1x
).markSettingAAElem();
9671 if (esetting
.op
== EXP
.error
)
9676 assert(esetting
.op
== EXP
.index
);
9677 IndexExp ie
= cast(IndexExp
) esetting
;
9678 Type t2
= e2x
.type
.toBasetype();
9680 Expression e0
= null;
9681 Expression ea
= extractSideEffect(sc
, "__aatmp", e0
, ie
.e1
);
9682 Expression ek
= extractSideEffect(sc
, "__aakey", e0
, ie
.e2
);
9683 Expression ev
= extractSideEffect(sc
, "__aaval", e0
, e2x
);
9685 AssignExp ae
= cast(AssignExp
)exp
.copy();
9686 ae
.e1
= new IndexExp(exp
.loc
, ea
, ek
);
9687 ae
.e1
= ae
.e1
.expressionSemantic(sc
);
9688 ae
.e1
= ae
.e1
.optimize(WANTvalue
);
9690 Expression e
= ae
.op_overload(sc
);
9693 Expression ey
= null;
9694 if (t2
.ty
== Tstruct
&& sd
== t2
.toDsymbol(sc
))
9698 else if (!ev
.implicitConvTo(ie
.type
) && sd
.ctor
)
9700 // Look for implicit constructor call
9701 // Rewrite as S().ctor(e2)
9702 ey
= new StructLiteralExp(exp
.loc
, sd
, null);
9703 ey
= new DotIdExp(exp
.loc
, ey
, Id
.ctor
);
9704 ey
= new CallExp(exp
.loc
, ey
, ev
);
9705 ey
= ey
.trySemantic(sc
);
9710 ex
= new IndexExp(exp
.loc
, ea
, ek
);
9711 ex
= ex
.expressionSemantic(sc
);
9712 ex
= ex
.modifiableLvalue(sc
, ex
); // allocate new slot
9713 ex
= ex
.optimize(WANTvalue
);
9715 ey
= new ConstructExp(exp
.loc
, ex
, ey
);
9716 ey
= ey
.expressionSemantic(sc
);
9717 if (ey
.op
== EXP
.error
)
9724 // https://issues.dlang.org/show_bug.cgi?id=14144
9725 // The whole expression should have the common type
9726 // of opAssign() return and assigned AA entry.
9727 // Even if there's no common type, expression should be typed as void.
9728 if (!typeMerge(sc
, EXP
.question
, ex
, ey
))
9730 ex
= new CastExp(ex
.loc
, ex
, Type
.tvoid
);
9731 ey
= new CastExp(ey
.loc
, ey
, Type
.tvoid
);
9733 e
= new CondExp(exp
.loc
, new InExp(exp
.loc
, ek
, ea
), ex
, ey
);
9735 e
= Expression
.combine(e0
, e
);
9736 e
= e
.expressionSemantic(sc
);
9743 Expression e
= exp
.op_overload(sc
);
9752 assert(exp
.op
== EXP
.blit
);
9754 if (e2x
.checkValue())
9760 else if (t1
.ty
== Tclass
)
9762 // Disallow assignment operator overloads for same type
9763 if (exp
.op
== EXP
.assign
&& !exp
.e2
.implicitConvTo(exp
.e1
.type
))
9765 Expression e
= exp
.op_overload(sc
);
9772 if (exp
.e2
.checkValue())
9775 else if (t1
.ty
== Tsarray
)
9777 // SliceExp cannot have static array type without context inference.
9778 assert(exp
.e1
.op
!= EXP
.slice
);
9779 Expression e1x
= exp
.e1
;
9780 Expression e2x
= exp
.e2
;
9782 /* C strings come through as static arrays. May need to adjust the size of the
9783 * string to match the size of e1.
9785 Type t2
= e2x
.type
.toBasetype();
9786 if (sc
.flags
& SCOPE
.Cfile
&& e2x
.isStringExp() && t2
.isTypeSArray())
9788 uinteger_t dim1
= t1
.isTypeSArray().dim
.toInteger();
9789 uinteger_t dim2
= t2
.isTypeSArray().dim
.toInteger();
9790 if (dim1
+ 1 == dim2 || dim2
< dim1
)
9792 auto tsa2
= t2
.isTypeSArray();
9793 auto newt
= tsa2
.next
.sarrayOf(dim1
).immutableOf();
9794 e2x
= castTo(e2x
, sc
, newt
);
9799 if (e2x
.implicitConvTo(e1x
.type
))
9801 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()))
9803 if (e1x
.checkPostblit(sc
, t1
))
9807 // e2 matches to t1 because of the implicit length match, so
9808 if (isUnaArrayOp(e2x
.op
) ||
isBinArrayOp(e2x
.op
))
9810 // convert e1 to e1[]
9811 // e.g. e1[] = a[] + b[];
9812 auto sle
= new SliceExp(e1x
.loc
, e1x
, null, null);
9814 e1x
= sle
.expressionSemantic(sc
);
9818 // convert e2 to t1 later
9819 // e.g. e1 = [1, 2, 3];
9824 if (e2x
.implicitConvTo(t1
.nextOf().arrayOf()) > MATCH
.nomatch
)
9826 uinteger_t dim1
= (cast(TypeSArray
)t1
).dim
.toInteger();
9827 uinteger_t dim2
= dim1
;
9828 if (auto ale
= e2x
.isArrayLiteralExp())
9830 dim2
= ale
.elements ? ale
.elements
.length
: 0;
9832 else if (auto se
= e2x
.isSliceExp())
9834 Type tx
= toStaticArrayType(se
);
9836 dim2
= (cast(TypeSArray
)tx
).dim
.toInteger();
9840 error(exp
.loc
, "mismatched array lengths, %d and %d", cast(int)dim1
, cast(int)dim2
);
9845 // May be block or element-wise assignment, so
9846 // convert e1 to e1[]
9847 if (exp
.op
!= EXP
.assign
)
9849 // If multidimensional static array, treat as one large array
9851 // Find the appropriate array type depending on the assignment, e.g.
9852 // int[3] = int => int[3]
9853 // int[3][2] = int => int[6]
9854 // int[3][2] = int[] => int[3][2]
9855 // int[3][2][4] + int => int[24]
9856 // int[3][2][4] + int[] => int[3][8]
9857 ulong dim
= t1
.isTypeSArray().dim
.toUInteger();
9858 auto type
= t1
.nextOf();
9860 for (TypeSArray tsa
; (tsa
= type
.isTypeSArray()) !is null; )
9862 import core
.checkedint
: mulu
;
9864 // Accumulate skipped dimensions
9865 bool overflow
= false;
9866 dim
= mulu(dim
, tsa
.dim
.toUInteger(), overflow
);
9867 if (overflow || dim
>= uint.max
)
9869 // dym exceeds maximum array size
9870 error(exp
.loc
, "static array `%s` size overflowed to %llu",
9871 e1x
.type
.toChars(), cast(ulong) dim
);
9875 // Move to the element type
9876 type
= tsa
.nextOf().toBasetype();
9878 // Rewrite ex1 as a static array if a matching type was found
9879 if (e2x
.implicitConvTo(type
) > MATCH
.nomatch
)
9881 e1x
.type
= type
.sarrayOf(dim
);
9886 auto sle
= new SliceExp(e1x
.loc
, e1x
, null, null);
9888 e1x
= sle
.expressionSemantic(sc
);
9890 if (e1x
.op
== EXP
.error
)
9891 return setResult(e1x
);
9892 if (e2x
.op
== EXP
.error
)
9893 return setResult(e2x
);
9897 t1
= e1x
.type
.toBasetype();
9899 /* Check the mutability of e1.
9901 if (auto ale
= exp
.e1
.isArrayLengthExp())
9903 // e1 is not an lvalue, but we let code generator handle it
9905 auto ale1x
= ale
.e1
.modifiableLvalue(sc
, exp
.e1
);
9906 if (ale1x
.op
== EXP
.error
)
9907 return setResult(ale1x
);
9910 Type tn
= ale
.e1
.type
.toBasetype().nextOf();
9911 checkDefCtor(ale
.loc
, tn
);
9913 Identifier hook
= global
.params
.tracegc ? Id
._d_arraysetlengthTTrace
: Id
._d_arraysetlengthT
;
9914 if (!verifyHookExist(exp
.loc
, *sc
, Id
._d_arraysetlengthTImpl
, "resizing arrays"))
9917 exp
.e2
= exp
.e2
.expressionSemantic(sc
);
9918 auto lc
= lastComma(exp
.e2
);
9919 lc
= lc
.optimize(WANTvalue
);
9920 // use slice expression when arr.length = 0 to avoid runtime call
9921 if(lc
.op
== EXP
.int64
&& lc
.toInteger() == 0)
9923 Expression se
= new SliceExp(ale
.loc
, ale
.e1
, lc
, lc
);
9924 Expression as
= new AssignExp(ale
.loc
, ale
.e1
, se
);
9925 as
= as
.expressionSemantic(sc
);
9926 auto res
= Expression
.combine(as
, exp
.e2
);
9927 res
.type
= ale
.type
;
9928 return setResult(res
);
9931 if (!sc
.needsCodegen()) // if compile time creature only
9933 exp
.type
= Type
.tsize_t
;
9934 return setResult(exp
);
9937 // Lower to object._d_arraysetlengthTImpl!(typeof(e1))._d_arraysetlengthT{,Trace}(e1, e2)
9938 Expression id
= new IdentifierExp(ale
.loc
, Id
.empty
);
9939 id
= new DotIdExp(ale
.loc
, id
, Id
.object
);
9940 auto tiargs
= new Objects();
9941 tiargs
.push(ale
.e1
.type
);
9942 id
= new DotTemplateInstanceExp(ale
.loc
, id
, Id
._d_arraysetlengthTImpl
, tiargs
);
9943 id
= new DotIdExp(ale
.loc
, id
, hook
);
9944 id
= id
.expressionSemantic(sc
);
9946 auto arguments
= new Expressions();
9947 arguments
.reserve(5);
9948 if (global
.params
.tracegc
)
9950 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ? sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
9951 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
9952 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
9953 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
9955 arguments
.push(ale
.e1
);
9956 arguments
.push(exp
.e2
);
9958 Expression ce
= new CallExp(ale
.loc
, id
, arguments
).expressionSemantic(sc
);
9959 auto res
= new LoweredAssignExp(exp
, ce
);
9960 // if (global.params.verbose)
9961 // message("lowered %s =>\n %s", exp.toChars(), res.toChars());
9962 res
.type
= Type
.tsize_t
;
9963 return setResult(res
);
9965 else if (auto se
= exp
.e1
.isSliceExp())
9967 Type tn
= se
.type
.nextOf();
9968 const fun
= sc
.func
;
9969 if (exp
.op
== EXP
.assign
&& !tn
.isMutable() &&
9970 // allow modifiation in module ctor, see
9971 // https://issues.dlang.org/show_bug.cgi?id=9884
9972 (!fun ||
(fun
&& !fun
.isStaticCtorDeclaration())))
9974 error(exp
.loc
, "slice `%s` is not mutable", se
.toChars());
9978 if (exp
.op
== EXP
.assign
&& !tn
.baseElemOf().isAssignable())
9980 error(exp
.loc
, "slice `%s` is not mutable, struct `%s` has immutable members",
9981 exp
.e1
.toChars(), tn
.baseElemOf().toChars());
9982 result
= ErrorExp
.get();
9986 // For conditional operator, both branches need conversion.
9987 while (se
.e1
.op
== EXP
.slice
)
9988 se
= cast(SliceExp
)se
.e1
;
9989 if (se
.e1
.op
== EXP
.question
&& se
.e1
.type
.toBasetype().ty
== Tsarray
)
9991 se
.e1
= se
.e1
.modifiableLvalue(sc
, exp
.e1
);
9992 if (se
.e1
.op
== EXP
.error
)
9993 return setResult(se
.e1
);
9998 if (t1
.ty
== Tsarray
&& exp
.op
== EXP
.assign
)
10000 Type tn
= exp
.e1
.type
.nextOf();
10001 if (tn
&& !tn
.baseElemOf().isAssignable())
10003 error(exp
.loc
, "array `%s` is not mutable, struct `%s` has immutable members",
10004 exp
.e1
.toChars(), tn
.baseElemOf().toChars());
10005 result
= ErrorExp
.get();
10010 Expression e1x
= exp
.e1
;
10012 // Try to do a decent error message with the expression
10013 // before it gets constant folded
10014 if (exp
.op
== EXP
.assign
)
10015 e1x
= e1x
.modifiableLvalue(sc
, e1old
);
10017 e1x
= e1x
.optimize(WANTvalue
, /*keepLvalue*/ true);
10019 if (e1x
.op
== EXP
.error
)
10027 /* Tweak e2 based on the type of e1.
10029 Expression e2x
= exp
.e2
;
10030 Type t2
= e2x
.type
.toBasetype();
10032 // If it is a array, get the element type. Note that it may be
10033 // multi-dimensional.
10035 while (telem
.ty
== Tarray
)
10036 telem
= telem
.nextOf();
10038 if (exp
.e1
.op
== EXP
.slice
&& t1
.nextOf() &&
10039 (telem
.ty
!= Tvoid || e2x
.op
== EXP
.null_
) &&
10040 e2x
.implicitConvTo(t1
.nextOf()))
10042 // Check for block assignment. If it is of type void[], void[][], etc,
10043 // '= null' is the only allowable block assignment (Bug 7493)
10044 exp
.memset
= MemorySet
.blockAssign
; // make it easy for back end to tell what this is
10045 e2x
= e2x
.implicitCastTo(sc
, t1
.nextOf());
10046 if (exp
.op
!= EXP
.blit
&& e2x
.isLvalue() && exp
.e1
.checkPostblit(sc
, t1
.nextOf()))
10049 else if (exp
.e1
.op
== EXP
.slice
&&
10050 (t2
.ty
== Tarray || t2
.ty
== Tsarray
) &&
10051 t2
.nextOf().implicitConvTo(t1
.nextOf()))
10053 // Check element-wise assignment.
10055 /* If assigned elements number is known at compile time,
10056 * check the mismatch.
10058 SliceExp se1
= cast(SliceExp
)exp
.e1
;
10059 TypeSArray tsa1
= cast(TypeSArray
)toStaticArrayType(se1
);
10060 TypeSArray tsa2
= null;
10061 if (auto ale
= e2x
.isArrayLiteralExp())
10062 tsa2
= cast(TypeSArray
)t2
.nextOf().sarrayOf(ale
.elements
.length
);
10063 else if (auto se
= e2x
.isSliceExp())
10064 tsa2
= cast(TypeSArray
)toStaticArrayType(se
);
10066 tsa2
= t2
.isTypeSArray();
10070 uinteger_t dim1
= tsa1
.dim
.toInteger();
10071 uinteger_t dim2
= tsa2
.dim
.toInteger();
10074 error(exp
.loc
, "mismatched array lengths %d and %d for assignment `%s`", cast(int)dim1
, cast(int)dim2
, exp
.toChars());
10079 if (exp
.op
!= EXP
.blit
&&
10080 (e2x
.op
== EXP
.slice
&& (cast(UnaExp
)e2x
).e1
.isLvalue() ||
10081 e2x
.op
== EXP
.cast_
&& (cast(UnaExp
)e2x
).e1
.isLvalue() ||
10082 e2x
.op
!= EXP
.slice
&& e2x
.isLvalue()))
10084 if (exp
.e1
.checkPostblit(sc
, t1
.nextOf()))
10090 if (global
.params
.warnings
!= DiagnosticReporting
.off
&& !global
.gag
&& exp
.op
== EXP
.assign
&&
10091 e2x
.op
!= EXP
.slice
&& e2x
.op
!= EXP
.assign
&&
10092 e2x
.op
!= EXP
.arrayLiteral
&& e2x
.op
!= EXP
.string_
&&
10093 !(e2x
.op
== EXP
.add || e2x
.op
== EXP
.min ||
10094 e2x
.op
== EXP
.mul || e2x
.op
== EXP
.div ||
10095 e2x
.op
== EXP
.mod || e2x
.op
== EXP
.xor ||
10096 e2x
.op
== EXP
.and || e2x
.op
== EXP
.or ||
10097 e2x
.op
== EXP
.pow ||
10098 e2x
.op
== EXP
.tilde || e2x
.op
== EXP
.negate
))
10100 const(char)* e1str
= exp
.e1
.toChars();
10101 const(char)* e2str
= e2x
.toChars();
10102 exp
.warning("explicit element-wise assignment `%s = (%s)[]` is better than `%s = %s`", e1str
, e2str
, e1str
, e2str
);
10106 Type t2n
= t2
.nextOf();
10107 Type t1n
= t1
.nextOf();
10109 if (t2n
.equivalent(t1n
) ||
10110 t1n
.isBaseOf(t2n
, &offset
) && offset
== 0)
10112 /* Allow copy of distinct qualifier elements.
10114 * char[] dst; const(char)[] src;
10117 * class C {} class D : C {}
10121 if (isArrayOpValid(e2x
))
10123 // Don't add CastExp to keep AST for array operations
10125 e2x
.type
= exp
.e1
.type
.constOf();
10128 e2x
= e2x
.castTo(sc
, exp
.e1
.type
.constOf());
10132 /* https://issues.dlang.org/show_bug.cgi?id=15778
10133 * A string literal has an array type of immutable
10134 * elements by default, and normally it cannot be convertible to
10135 * array type of mutable elements. But for element-wise assignment,
10136 * elements need to be const at best. So we should give a chance
10137 * to change code unit size for polysemous string literal.
10139 if (e2x
.op
== EXP
.string_
)
10140 e2x
= e2x
.implicitCastTo(sc
, exp
.e1
.type
.constOf());
10142 e2x
= e2x
.implicitCastTo(sc
, exp
.e1
.type
);
10144 if (t1n
.toBasetype
.ty
== Tvoid
&& t2n
.toBasetype
.ty
== Tvoid
)
10146 if (sc
.setUnsafe(false, exp
.loc
, "cannot copy `void[]` to `void[]` in `@safe` code"))
10154 if (global
.params
.warnings
!= DiagnosticReporting
.off
&& !global
.gag
&& exp
.op
== EXP
.assign
&&
10155 t1
.ty
== Tarray
&& t2
.ty
== Tsarray
&&
10156 e2x
.op
!= EXP
.slice
&&
10157 t2
.implicitConvTo(t1
))
10159 // Disallow ar[] = sa (Converted to ar[] = sa[])
10160 // Disallow da = sa (Converted to da = sa[])
10161 const(char)* e1str
= exp
.e1
.toChars();
10162 const(char)* e2str
= e2x
.toChars();
10163 const(char)* atypestr
= exp
.e1
.op
== EXP
.slice ?
"element-wise" : "slice";
10164 exp
.warning("explicit %s assignment `%s = (%s)[]` is better than `%s = %s`", atypestr
, e1str
, e2str
, e1str
, e2str
);
10167 if (exp
.op
== EXP
.blit
)
10168 e2x
= e2x
.castTo(sc
, exp
.e1
.type
);
10171 e2x
= e2x
.implicitCastTo(sc
, exp
.e1
.type
);
10173 // Fix Issue 13435: https://issues.dlang.org/show_bug.cgi?id=13435
10175 // If the implicit cast has failed and the assign expression is
10176 // the initialization of a struct member field
10177 if (e2x
.op
== EXP
.error
&& exp
.op
== EXP
.construct
&& t1
.ty
== Tstruct
)
10179 scope sd
= (cast(TypeStruct
)t1
).sym
;
10180 Dsymbol opAssign
= search_function(sd
, Id
.assign
);
10182 // and the struct defines an opAssign
10185 // offer more information about the cause of the problem
10186 errorSupplemental(exp
.loc
,
10187 "`%s` is the first assignment of `%s` therefore it represents its initialization",
10188 exp
.toChars(), exp
.e1
.toChars());
10189 errorSupplemental(exp
.loc
,
10190 "`opAssign` methods are not used for initialization, but for subsequent assignments");
10195 if (e2x
.op
== EXP
.error
)
10201 t2
= exp
.e2
.type
.toBasetype();
10203 /* Look for array operations
10205 if ((t2
.ty
== Tarray || t2
.ty
== Tsarray
) && isArrayOpValid(exp
.e2
))
10207 // Look for valid array operations
10208 if (exp
.memset
!= MemorySet
.blockAssign
&&
10209 exp
.e1
.op
== EXP
.slice
&&
10210 (isUnaArrayOp(exp
.e2
.op
) ||
isBinArrayOp(exp
.e2
.op
)))
10212 exp
.type
= exp
.e1
.type
;
10213 if (exp
.op
== EXP
.construct
) // https://issues.dlang.org/show_bug.cgi?id=10282
10214 // tweak mutability of e1 element
10215 exp
.e1
.type
= exp
.e1
.type
.nextOf().mutableOf().arrayOf();
10216 result
= arrayOp(exp
, sc
);
10220 // Drop invalid array operations in e2
10221 // d = a[] + b[], d = (a[] + b[])[0..2], etc
10222 if (checkNonAssignmentArrayOp(exp
.e2
, exp
.memset
!= MemorySet
.blockAssign
&& exp
.op
== EXP
.assign
))
10225 // Remains valid array assignments
10226 // d = d[], d = [1,2,3], etc
10229 /* Don't allow assignment to classes that were allocated on the stack with:
10230 * scope Class c = new Class();
10232 if (exp
.e1
.op
== EXP
.variable
&& exp
.op
== EXP
.assign
)
10234 VarExp ve
= cast(VarExp
)exp
.e1
;
10235 VarDeclaration vd
= ve
.var
.isVarDeclaration();
10236 if (vd
&& vd
.onstack
)
10238 assert(t1
.ty
== Tclass
);
10239 error(exp
.loc
, "cannot rebind scope variables");
10243 if (exp
.e1
.op
== EXP
.variable
&& (cast(VarExp
)exp
.e1
).var
.ident
== Id
.ctfe
)
10245 error(exp
.loc
, "cannot modify compiler-generated variable `__ctfe`");
10248 exp
.type
= exp
.e1
.type
;
10250 auto assignElem
= exp
.e2
;
10251 auto res
= exp
.op
== EXP
.assign ? exp
.reorderSettingAAElem(sc
) : exp
;
10252 /* https://issues.dlang.org/show_bug.cgi?id=22366
10254 * `reorderSettingAAElem` creates a tree of comma expressions, however,
10255 * `checkAssignExp` expects only AssignExps.
10257 if (res
== exp
) // no `AA[k] = v` rewrite was performed
10258 checkAssignEscape(sc
, res
, false, false);
10260 checkNewEscape(sc
, assignElem
, false); // assigning to AA puts it on heap
10262 if (auto ae
= res
.isConstructExp())
10264 Type t1b
= ae
.e1
.type
.toBasetype();
10265 if (t1b
.ty
!= Tsarray
&& t1b
.ty
!= Tarray
)
10266 return setResult(res
);
10268 // only non-trivial array constructions may need to be lowered (non-POD elements basically)
10269 Type t1e
= t1b
.nextOf();
10270 TypeStruct ts
= t1e
.baseElemOf().isTypeStruct();
10271 if (!ts ||
(!ts
.sym
.postblit
&& !ts
.sym
.hasCopyCtor
&& !ts
.sym
.dtor
))
10272 return setResult(res
);
10274 // don't lower ref-constructions etc.
10275 if (!(t1b
.ty
== Tsarray || ae
.e1
.isSliceExp
) ||
10276 (ae
.e1
.isVarExp
&& ae
.e1
.isVarExp
.var
.isVarDeclaration
.isReference
))
10277 return setResult(res
);
10279 // Construction from an equivalent other array?
10280 // Only lower with lvalue RHS elements; let the glue layer move rvalue elements.
10281 Type t2b
= ae
.e2
.type
.toBasetype();
10282 // skip over a (possibly implicit) cast of a static array RHS to a slice
10283 Expression rhs
= ae
.e2
;
10284 Type rhsType
= t2b
;
10285 if (t2b
.ty
== Tarray
)
10287 if (auto ce
= rhs
.isCastExp())
10289 auto ct
= ce
.e1
.type
.toBasetype();
10290 if (ct
.ty
== Tsarray
)
10298 if (!sc
.needsCodegen()) // interpreter can handle these
10299 return setResult(res
);
10301 const lowerToArrayCtor
=
10302 ( (rhsType
.ty
== Tarray
&& !rhs
.isArrayLiteralExp
) ||
10303 (rhsType
.ty
== Tsarray
&& rhs
.isLvalue
) ) &&
10304 t1e
.equivalent(t2b
.nextOf
);
10306 // Construction from a single element?
10307 // If the RHS is an rvalue, then we'll need to make a temporary for it (copied multiple times).
10308 const lowerToArraySetCtor
= !lowerToArrayCtor
&& t1e
.equivalent(t2b
);
10310 if (lowerToArrayCtor || lowerToArraySetCtor
)
10312 auto func
= lowerToArrayCtor ? Id
._d_arrayctor
: Id
._d_arraysetctor
;
10313 const other
= lowerToArrayCtor ?
"other array" : "value";
10314 if (!verifyHookExist(exp
.loc
, *sc
, func
, "construct array with " ~ other
, Id
.object
))
10317 // Lower to object._d_array{,set}ctor(e1, e2)
10318 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
10319 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
10320 id
= new DotIdExp(exp
.loc
, id
, func
);
10322 auto arguments
= new Expressions();
10323 arguments
.push(new CastExp(ae
.loc
, ae
.e1
, t1e
.arrayOf
).expressionSemantic(sc
));
10324 if (lowerToArrayCtor
)
10326 arguments
.push(new CastExp(ae
.loc
, rhs
, t2b
.nextOf
.arrayOf
).expressionSemantic(sc
));
10327 Expression ce
= new CallExp(exp
.loc
, id
, arguments
);
10328 res
= ce
.expressionSemantic(sc
);
10333 // promote an rvalue RHS element to a temporary, it's passed by ref to _d_arraysetctor
10334 if (!ae
.e2
.isLvalue
)
10336 auto vd
= copyToTemp(STC
.scope_
, "__setctor", ae
.e2
);
10337 e0
= new DeclarationExp(vd
.loc
, vd
).expressionSemantic(sc
);
10338 arguments
.push(new VarExp(vd
.loc
, vd
).expressionSemantic(sc
));
10341 arguments
.push(ae
.e2
);
10343 Expression ce
= new CallExp(exp
.loc
, id
, arguments
);
10344 res
= Expression
.combine(e0
, ce
).expressionSemantic(sc
);
10347 if (global
.params
.v
.verbose
)
10348 message("lowered %s =>\n %s", exp
.toChars(), res
.toChars());
10351 else if (auto ae
= res
.isAssignExp())
10352 res
= lowerArrayAssign(ae
);
10353 else if (auto ce
= res
.isCommaExp())
10355 if (auto ae1
= ce
.e1
.isAssignExp())
10356 ce
.e1
= lowerArrayAssign(ae1
, true);
10357 if (auto ae2
= ce
.e2
.isAssignExp())
10358 ce
.e2
= lowerArrayAssign(ae2
, true);
10361 return setResult(res
);
10364 /***************************************
10365 * Lower AssignExp to `_d_array{setassign,assign_l,assign_r}` if needed.
10368 * ae = the AssignExp to be lowered
10369 * fromCommaExp = indicates whether `ae` is part of a CommaExp or not,
10370 * so no unnecessary temporay variable is created.
10372 * a CommaExp contiaining call a to `_d_array{setassign,assign_l,assign_r}`
10373 * if needed or `ae` otherwise
10375 private Expression
lowerArrayAssign(AssignExp ae
, bool fromCommaExp
= false)
10377 Type t1b
= ae
.e1
.type
.toBasetype();
10378 if (t1b
.ty
!= Tsarray
&& t1b
.ty
!= Tarray
)
10381 const isArrayAssign
= (ae
.e1
.isSliceExp() || ae
.e1
.type
.ty
== Tsarray
) &&
10382 (ae
.e2
.type
.ty
== Tsarray || ae
.e2
.type
.ty
== Tarray
) &&
10383 (ae
.e1
.type
.nextOf() && ae
.e2
.type
.nextOf() && ae
.e1
.type
.nextOf
.mutableOf
.equals(ae
.e2
.type
.nextOf
.mutableOf()));
10385 const isArraySetAssign
= (ae
.e1
.isSliceExp() || ae
.e1
.type
.ty
== Tsarray
) &&
10386 (ae
.e1
.type
.nextOf() && ae
.e2
.type
.implicitConvTo(ae
.e1
.type
.nextOf()));
10388 if (!isArrayAssign
&& !isArraySetAssign
)
10391 const ts
= t1b
.nextOf().baseElemOf().isTypeStruct();
10392 if (!ts ||
(!ts
.sym
.postblit
&& !ts
.sym
.dtor
))
10396 Identifier func
= isArraySetAssign ? Id
._d_arraysetassign
:
10397 ae
.e2
.isLvalue() || ae
.e2
.isSliceExp() ? Id
._d_arrayassign_l
: Id
._d_arrayassign_r
;
10399 // Lower to `.object._d_array{setassign,assign_l,assign_r}(e1, e2)``
10400 Expression id
= new IdentifierExp(ae
.loc
, Id
.empty
);
10401 id
= new DotIdExp(ae
.loc
, id
, Id
.object
);
10402 id
= new DotIdExp(ae
.loc
, id
, func
);
10404 auto arguments
= new Expressions();
10405 arguments
.push(new CastExp(ae
.loc
, ae
.e1
, ae
.e1
.type
.nextOf
.arrayOf
)
10406 .expressionSemantic(sc
));
10408 Expression eValue2
, value2
= ae
.e2
;
10409 if (isArrayAssign
&& value2
.isLvalue())
10410 value2
= new CastExp(ae
.loc
, ae
.e2
, ae
.e2
.type
.nextOf
.arrayOf())
10411 .expressionSemantic(sc
);
10412 else if (!fromCommaExp
&&
10413 (isArrayAssign ||
(isArraySetAssign
&& !value2
.isLvalue())))
10415 // Rvalues from CommaExps were introduced in `visit(AssignExp)`
10416 // and are temporary variables themselves. Rvalues from trivial
10417 // SliceExps are simply passed by reference without any copying.
10419 // `__assigntmp` will be destroyed together with the array `ae.e1`.
10420 // When `ae.e2` is a variadic arg array, it is also `scope`, so
10421 // `__assigntmp` may also be scope.
10422 StorageClass
stc = STC
.nodtor
;
10424 stc |
= STC
.rvalue | STC
.scope_
;
10426 auto vd
= copyToTemp(stc, "__assigntmp", ae
.e2
);
10427 eValue2
= new DeclarationExp(vd
.loc
, vd
).expressionSemantic(sc
);
10428 value2
= new VarExp(vd
.loc
, vd
).expressionSemantic(sc
);
10430 arguments
.push(value2
);
10432 Expression ce
= new CallExp(ae
.loc
, id
, arguments
);
10433 res
= Expression
.combine(eValue2
, ce
).expressionSemantic(sc
);
10435 res
= Expression
.combine(res
, ae
.e1
).expressionSemantic(sc
);
10437 if (global
.params
.v
.verbose
)
10438 message("lowered %s =>\n %s", ae
.toChars(), res
.toChars());
10440 res
= new LoweredAssignExp(ae
, res
);
10441 res
.type
= ae
.type
;
10446 override void visit(PowAssignExp exp
)
10454 Expression e
= exp
.op_overload(sc
);
10461 if (exp
.e1
.checkReadModifyWrite(exp
.op
, exp
.e2
))
10464 assert(exp
.e1
.type
&& exp
.e2
.type
);
10465 if (exp
.e1
.op
== EXP
.slice || exp
.e1
.type
.ty
== Tarray || exp
.e1
.type
.ty
== Tsarray
)
10467 if (checkNonAssignmentArrayOp(exp
.e1
))
10471 if (exp
.e2
.implicitConvTo(exp
.e1
.type
.nextOf()))
10474 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
.nextOf());
10476 else if (Expression ex
= typeCombine(exp
, sc
))
10482 // Check element types are arithmetic
10483 Type tb1
= exp
.e1
.type
.nextOf().toBasetype();
10484 Type tb2
= exp
.e2
.type
.toBasetype();
10485 if (tb2
.ty
== Tarray || tb2
.ty
== Tsarray
)
10486 tb2
= tb2
.nextOf().toBasetype();
10487 if ((tb1
.isintegral() || tb1
.isfloating()) && (tb2
.isintegral() || tb2
.isfloating()))
10489 exp
.type
= exp
.e1
.type
;
10490 result
= arrayOp(exp
, sc
);
10496 exp
.e1
= exp
.e1
.modifiableLvalue(sc
, exp
.e1
);
10499 if ((exp
.e1
.type
.isintegral() || exp
.e1
.type
.isfloating()) && (exp
.e2
.type
.isintegral() || exp
.e2
.type
.isfloating()))
10501 Expression e0
= null;
10502 e
= exp
.reorderSettingAAElem(sc
);
10503 e
= Expression
.extractLast(e
, e0
);
10506 if (exp
.e1
.op
== EXP
.variable
)
10508 // Rewrite: e1 = e1 ^^ e2
10509 e
= new PowExp(exp
.loc
, exp
.e1
.syntaxCopy(), exp
.e2
);
10510 e
= new AssignExp(exp
.loc
, exp
.e1
, e
);
10514 // Rewrite: ref tmp = e1; tmp = tmp ^^ e2
10515 auto v
= copyToTemp(STC
.ref_
, "__powtmp", exp
.e1
);
10516 auto de = new DeclarationExp(exp
.e1
.loc
, v
);
10517 auto ve
= new VarExp(exp
.e1
.loc
, v
);
10518 e
= new PowExp(exp
.loc
, ve
, exp
.e2
);
10519 e
= new AssignExp(exp
.loc
, new VarExp(exp
.e1
.loc
, v
), e
);
10520 e
= new CommaExp(exp
.loc
, de, e
);
10522 e
= Expression
.combine(e0
, e
);
10523 e
= e
.expressionSemantic(sc
);
10527 result
= exp
.incompatibleTypes();
10530 override void visit(CatAssignExp exp
)
10538 //printf("CatAssignExp::semantic() %s\n", exp.toChars());
10539 Expression e
= exp
.op_overload(sc
);
10546 if (SliceExp se
= exp
.e1
.isSliceExp())
10548 if (se
.e1
.type
.toBasetype().ty
== Tsarray
)
10550 error(exp
.loc
, "cannot append to static array `%s`", se
.e1
.type
.toChars());
10555 exp
.e1
= exp
.e1
.modifiableLvalue(sc
, exp
.e1
);
10556 if (exp
.e1
.op
== EXP
.error
)
10561 if (exp
.e2
.op
== EXP
.error
)
10567 if (checkNonAssignmentArrayOp(exp
.e2
))
10570 Type tb1
= exp
.e1
.type
.toBasetype();
10571 Type tb1next
= tb1
.nextOf();
10572 Type tb2
= exp
.e2
.type
.toBasetype();
10575 * EXP.concatenateAssign: appending T[] to T[]
10576 * EXP.concatenateElemAssign: appending T to T[]
10577 * EXP.concatenateDcharAssign: appending dchar to T[]
10579 if ((tb1
.ty
== Tarray
) &&
10580 (tb2
.ty
== Tarray || tb2
.ty
== Tsarray
) &&
10581 (exp
.e2
.implicitConvTo(exp
.e1
.type
) ||
10582 (tb2
.nextOf().implicitConvTo(tb1next
) &&
10583 (tb2
.nextOf().size(Loc
.initial
) == tb1next
.size(Loc
.initial
)))))
10585 // EXP.concatenateAssign
10586 assert(exp
.op
== EXP
.concatenateAssign
);
10587 if (exp
.e1
.checkPostblit(sc
, tb1next
))
10590 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
);
10592 else if ((tb1
.ty
== Tarray
) && exp
.e2
.implicitConvTo(tb1next
))
10594 /* https://issues.dlang.org/show_bug.cgi?id=19782
10596 * If e2 is implicitly convertible to tb1next, the conversion
10597 * might be done through alias this, in which case, e2 needs to
10598 * be modified accordingly (e2 => e2.aliasthis).
10600 if (tb2
.ty
== Tstruct
&& (cast(TypeStruct
)tb2
).implicitConvToThroughAliasThis(tb1next
))
10602 if (tb2
.ty
== Tclass
&& (cast(TypeClass
)tb2
).implicitConvToThroughAliasThis(tb1next
))
10605 if (exp
.e2
.checkPostblit(sc
, tb2
))
10608 if (checkNewEscape(sc
, exp
.e2
, false))
10611 exp
= new CatElemAssignExp(exp
.loc
, exp
.type
, exp
.e1
, exp
.e2
.castTo(sc
, tb1next
));
10612 exp
.e2
= doCopyOrMove(sc
, exp
.e2
);
10614 else if (tb1
.ty
== Tarray
&&
10615 (tb1next
.ty
== Tchar || tb1next
.ty
== Twchar
) &&
10616 exp
.e2
.type
.ty
!= tb1next
.ty
&&
10617 exp
.e2
.implicitConvTo(Type
.tdchar
))
10619 // Append dchar to char[] or wchar[]
10620 exp
= new CatDcharAssignExp(exp
.loc
, exp
.type
, exp
.e1
, exp
.e2
.castTo(sc
, Type
.tdchar
));
10622 /* Do not allow appending wchar to char[] because if wchar happens
10623 * to be a surrogate pair, nothing good can result.
10628 // Try alias this on first operand
10629 static Expression
tryAliasThisForLhs(BinAssignExp exp
, Scope
* sc
)
10631 AggregateDeclaration ad1
= isAggregate(exp
.e1
.type
);
10632 if (!ad1 ||
!ad1
.aliasthis
)
10635 /* Rewrite (e1 op e2) as:
10636 * (e1.aliasthis op e2)
10638 if (isRecursiveAliasThis(exp
.att1
, exp
.e1
.type
))
10640 //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
10641 Expression e1
= new DotIdExp(exp
.loc
, exp
.e1
, ad1
.aliasthis
.ident
);
10642 BinExp be
= cast(BinExp
)exp
.copy();
10644 return be
.trySemantic(sc
);
10647 // Try alias this on second operand
10648 static Expression
tryAliasThisForRhs(BinAssignExp exp
, Scope
* sc
)
10650 AggregateDeclaration ad2
= isAggregate(exp
.e2
.type
);
10651 if (!ad2 ||
!ad2
.aliasthis
)
10653 /* Rewrite (e1 op e2) as:
10654 * (e1 op e2.aliasthis)
10656 if (isRecursiveAliasThis(exp
.att2
, exp
.e2
.type
))
10658 //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
10659 Expression e2
= new DotIdExp(exp
.loc
, exp
.e2
, ad2
.aliasthis
.ident
);
10660 BinExp be
= cast(BinExp
)exp
.copy();
10662 return be
.trySemantic(sc
);
10666 result
= tryAliasThisForLhs(exp
, sc
);
10670 result
= tryAliasThisForRhs(exp
, sc
);
10674 error(exp
.loc
, "cannot append type `%s` to type `%s`", tb2
.toChars(), tb1
.toChars());
10678 if (exp
.e2
.checkValue() || exp
.e2
.checkSharedAccess(sc
))
10681 exp
.type
= exp
.e1
.type
;
10682 auto assignElem
= exp
.e2
;
10683 auto res
= exp
.reorderSettingAAElem(sc
);
10684 if (res
!= exp
) // `AA[k] = v` rewrite was performed
10685 checkNewEscape(sc
, assignElem
, false);
10686 else if (exp
.op
== EXP
.concatenateElemAssign || exp
.op
== EXP
.concatenateDcharAssign
)
10687 checkAssignEscape(sc
, res
, false, false);
10691 if ((exp
.op
== EXP
.concatenateAssign || exp
.op
== EXP
.concatenateElemAssign
) &&
10694 // if aa ordering is triggered, `res` will be a CommaExp
10695 // and `.e2` will be the rewritten original expression.
10697 // `output` will point to the expression that the lowering will overwrite
10698 Expression
* output
;
10699 if (auto comma
= res
.isCommaExp())
10701 output
= &comma
.e2
;
10702 // manual cast because it could be either CatAssignExp or CatElemAssignExp
10703 exp
= cast(CatAssignExp
)comma
.e2
;
10708 exp
= cast(CatAssignExp
)result
;
10711 if (exp
.op
== EXP
.concatenateAssign
)
10713 Identifier hook
= global
.params
.tracegc ? Id
._d_arrayappendTTrace
: Id
._d_arrayappendT
;
10715 if (!verifyHookExist(exp
.loc
, *sc
, hook
, "appending array to arrays", Id
.object
))
10718 // Lower to object._d_arrayappendT{,Trace}({file, line, funcname}, e1, e2)
10719 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
10720 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
10721 id
= new DotIdExp(exp
.loc
, id
, hook
);
10723 auto arguments
= new Expressions();
10724 arguments
.reserve(5);
10725 if (global
.params
.tracegc
)
10727 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ? sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
10728 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
10729 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
10730 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
10733 arguments
.push(exp
.e1
);
10734 arguments
.push(exp
.e2
);
10735 Expression ce
= new CallExp(exp
.loc
, id
, arguments
);
10736 *output
= ce
.expressionSemantic(sc
);
10738 else if (exp
.op
== EXP
.concatenateElemAssign
)
10740 /* Do not lower concats to the indices array returned by
10741 *`static foreach`, as this array is only used at compile-time.
10743 if (auto ve
= exp
.e1
.isVarExp
)
10745 import core
.stdc
.ctype
: isdigit
;
10746 // The name of the indices array that static foreach loops uses.
10747 // See dmd.cond.lowerNonArrayAggregate
10748 enum varName
= "__res";
10749 const(char)[] id
= ve
.var
.ident
.toString
;
10750 if (ve
.var
.storage_class
& STC
.temp
&& id
.length
> varName
.length
&&
10751 id
[0 .. varName
.length
] == varName
&& id
[varName
.length
].isdigit
)
10755 Identifier hook
= global
.params
.tracegc ? Id
._d_arrayappendcTXTrace
: Id
._d_arrayappendcTX
;
10756 if (!verifyHookExist(exp
.loc
, *sc
, Id
._d_arrayappendcTXImpl
, "appending element to arrays", Id
.object
))
10759 // Lower to object._d_arrayappendcTXImpl!(typeof(e1))._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2
10760 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
10761 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
10762 auto tiargs
= new Objects();
10763 tiargs
.push(exp
.e1
.type
);
10764 id
= new DotTemplateInstanceExp(exp
.loc
, id
, Id
._d_arrayappendcTXImpl
, tiargs
);
10765 id
= new DotIdExp(exp
.loc
, id
, hook
);
10767 auto arguments
= new Expressions();
10768 arguments
.reserve(5);
10769 if (global
.params
.tracegc
)
10771 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ? sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
10772 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
10773 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
10774 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
10777 Expression eValue1
;
10778 Expression value1
= extractSideEffect(sc
, "__appendtmp", eValue1
, exp
.e1
);
10780 arguments
.push(value1
);
10781 arguments
.push(new IntegerExp(exp
.loc
, 1, Type
.tsize_t
));
10783 Expression ce
= new CallExp(exp
.loc
, id
, arguments
);
10785 Expression eValue2
;
10786 Expression value2
= exp
.e2
;
10787 if (!value2
.isVarExp() && !value2
.isConst())
10789 /* Before the template hook, this check was performed in e2ir.d
10790 * for expressions like `a ~= a[$-1]`. Here, $ will be modified
10791 * by calling `_d_arrayappendcT`, so we need to save `a[$-1]` in
10792 * a temporary variable.
10794 value2
= extractSideEffect(sc
, "__appendtmp", eValue2
, value2
, true);
10797 // `__appendtmp*` will be destroyed together with the array `exp.e1`.
10798 auto vd
= eValue2
.isDeclarationExp().declaration
.isVarDeclaration();
10799 vd
.storage_class |
= STC
.nodtor
;
10800 // Be more explicit that this "declaration" is local to the expression
10801 vd
.storage_class |
= STC
.exptemp
;
10804 auto ale
= new ArrayLengthExp(exp
.loc
, value1
);
10805 auto elem
= new IndexExp(exp
.loc
, value1
, new MinExp(exp
.loc
, ale
, IntegerExp
.literal
!1));
10806 auto ae
= new ConstructExp(exp
.loc
, elem
, value2
);
10808 auto e0
= Expression
.combine(ce
, ae
).expressionSemantic(sc
);
10809 e0
= Expression
.combine(e0
, value1
);
10810 e0
= Expression
.combine(eValue1
, e0
);
10812 e0
= Expression
.combine(eValue2
, e0
);
10814 *output
= e0
.expressionSemantic(sc
);
10820 override void visit(AddExp exp
)
10822 static if (LOGSEMANTIC
)
10824 printf("AddExp::semantic('%s')\n", exp
.toChars());
10832 if (Expression ex
= binSemanticProp(exp
, sc
))
10837 Expression e
= exp
.op_overload(sc
);
10844 /* ImportC: convert arrays to pointers, functions to pointers to functions
10846 exp
.e1
= exp
.e1
.arrayFuncConv(sc
);
10847 exp
.e2
= exp
.e2
.arrayFuncConv(sc
);
10849 Type tb1
= exp
.e1
.type
.toBasetype();
10850 Type tb2
= exp
.e2
.type
.toBasetype();
10853 if (tb1
.ty
== Tdelegate || tb1
.isPtrToFunction())
10855 err |
= exp
.e1
.checkArithmetic(exp
.op
) || exp
.e1
.checkSharedAccess(sc
);
10857 if (tb2
.ty
== Tdelegate || tb2
.isPtrToFunction())
10859 err |
= exp
.e2
.checkArithmetic(exp
.op
) || exp
.e2
.checkSharedAccess(sc
);
10864 if (tb1
.ty
== Tpointer
&& exp
.e2
.type
.isintegral() || tb2
.ty
== Tpointer
&& exp
.e1
.type
.isintegral())
10866 result
= scaleFactor(exp
, sc
);
10870 if (tb1
.ty
== Tpointer
&& tb2
.ty
== Tpointer
)
10872 result
= exp
.incompatibleTypes();
10876 if (Expression ex
= typeCombine(exp
, sc
))
10882 Type tb
= exp
.type
.toBasetype();
10883 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
10885 if (!isArrayOpValid(exp
))
10887 result
= arrayOpInvalidError(exp
);
10894 tb1
= exp
.e1
.type
.toBasetype();
10895 if (!target
.isVectorOpSupported(tb1
, exp
.op
, tb2
))
10897 result
= exp
.incompatibleTypes();
10900 if ((tb1
.isreal() && exp
.e2
.type
.isimaginary()) ||
(tb1
.isimaginary() && exp
.e2
.type
.isreal()))
10902 switch (exp
.type
.toBasetype().ty
)
10906 exp
.type
= Type
.tcomplex32
;
10911 exp
.type
= Type
.tcomplex64
;
10916 exp
.type
= Type
.tcomplex80
;
10926 override void visit(MinExp exp
)
10928 static if (LOGSEMANTIC
)
10930 printf("MinExp::semantic('%s')\n", exp
.toChars());
10938 if (Expression ex
= binSemanticProp(exp
, sc
))
10943 Expression e
= exp
.op_overload(sc
);
10950 /* ImportC: convert arrays to pointers, functions to pointers to functions
10952 exp
.e1
= exp
.e1
.arrayFuncConv(sc
);
10953 exp
.e2
= exp
.e2
.arrayFuncConv(sc
);
10955 Type t1
= exp
.e1
.type
.toBasetype();
10956 Type t2
= exp
.e2
.type
.toBasetype();
10959 if (t1
.ty
== Tdelegate || t1
.isPtrToFunction())
10961 err |
= exp
.e1
.checkArithmetic(exp
.op
) || exp
.e1
.checkSharedAccess(sc
);
10963 if (t2
.ty
== Tdelegate || t2
.isPtrToFunction())
10965 err |
= exp
.e2
.checkArithmetic(exp
.op
) || exp
.e2
.checkSharedAccess(sc
);
10970 if (t1
.ty
== Tpointer
)
10972 if (t2
.ty
== Tpointer
)
10974 // https://dlang.org/spec/expression.html#add_expressions
10975 // "If both operands are pointers, and the operator is -, the pointers are
10976 // subtracted and the result is divided by the size of the type pointed to
10977 // by the operands. It is an error if the pointers point to different types."
10978 Type p1
= t1
.nextOf();
10979 Type p2
= t2
.nextOf();
10981 if (!p1
.equivalent(p2
))
10983 // Deprecation to remain for at least a year, after which this should be
10984 // changed to an error
10985 // See https://github.com/dlang/dmd/pull/7332
10986 deprecation(exp
.loc
,
10987 "cannot subtract pointers to different types: `%s` and `%s`.",
10988 t1
.toChars(), t2
.toChars());
10991 // Need to divide the result by the stride
10992 // Replace (ptr - ptr) with (ptr - ptr) / stride
10995 // make sure pointer types are compatible
10996 if (Expression ex
= typeCombine(exp
, sc
))
11002 exp
.type
= Type
.tptrdiff_t
;
11003 stride
= t2
.nextOf().size();
11006 e
= new IntegerExp(exp
.loc
, 0, Type
.tptrdiff_t
);
11008 else if (stride
== cast(long)SIZE_INVALID
)
11009 e
= ErrorExp
.get();
11012 e
= new DivExp(exp
.loc
, exp
, new IntegerExp(Loc
.initial
, stride
, Type
.tptrdiff_t
));
11013 e
.type
= Type
.tptrdiff_t
;
11016 else if (t2
.isintegral())
11017 e
= scaleFactor(exp
, sc
);
11020 error(exp
.loc
, "can't subtract `%s` from pointer", t2
.toChars());
11021 e
= ErrorExp
.get();
11026 if (t2
.ty
== Tpointer
)
11028 exp
.type
= exp
.e2
.type
;
11029 error(exp
.loc
, "can't subtract pointer from `%s`", exp
.e1
.type
.toChars());
11033 if (Expression ex
= typeCombine(exp
, sc
))
11039 Type tb
= exp
.type
.toBasetype();
11040 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
11042 if (!isArrayOpValid(exp
))
11044 result
= arrayOpInvalidError(exp
);
11051 t1
= exp
.e1
.type
.toBasetype();
11052 t2
= exp
.e2
.type
.toBasetype();
11053 if (!target
.isVectorOpSupported(t1
, exp
.op
, t2
))
11055 result
= exp
.incompatibleTypes();
11058 if ((t1
.isreal() && t2
.isimaginary()) ||
(t1
.isimaginary() && t2
.isreal()))
11060 switch (exp
.type
.ty
)
11064 exp
.type
= Type
.tcomplex32
;
11069 exp
.type
= Type
.tcomplex64
;
11074 exp
.type
= Type
.tcomplex80
;
11086 * If the given expression is a `CatExp`, the function tries to lower it to
11087 * `_d_arraycatnTX`.
11090 * ee = the `CatExp` to lower
11092 * `_d_arraycatnTX(e1, e2, ..., en)` if `ee` is `e1 ~ e2 ~ ... en`
11095 private Expression
lowerToArrayCat(CatExp exp
)
11097 // String literals are concatenated by the compiler. No lowering is needed.
11098 if ((exp
.e1
.isStringExp() && (exp
.e2
.isIntegerExp() || exp
.e2
.isStringExp())) ||
11099 (exp
.e2
.isStringExp() && (exp
.e1
.isIntegerExp() || exp
.e1
.isStringExp())))
11102 bool useTraceGCHook
= global
.params
.tracegc
&& sc
.needsCodegen();
11104 Identifier hook
= useTraceGCHook ? Id
._d_arraycatnTXTrace
: Id
._d_arraycatnTX
;
11105 if (!verifyHookExist(exp
.loc
, *sc
, hook
, "concatenating arrays"))
11111 void handleCatArgument(Expressions
*arguments
, Expression e
)
11113 if (auto ce
= e
.isCatExp())
11115 Expression lowering
= ce
.lowering
;
11117 /* Skip `file`, `line`, and `funcname` if the hook of the parent
11118 * `CatExp` is `_d_arraycatnTXTrace`.
11120 if (auto callExp
= isRuntimeHook(lowering
, hook
))
11122 if (hook
== Id
._d_arraycatnTX
)
11123 arguments
.pushSlice((*callExp
.arguments
)[]);
11125 arguments
.pushSlice((*callExp
.arguments
)[3 .. $]);
11132 auto arguments
= new Expressions();
11133 if (useTraceGCHook
)
11135 auto funcname
= (sc
.callsc
&& sc
.callsc
.func
) ?
11136 sc
.callsc
.func
.toPrettyChars() : sc
.func
.toPrettyChars();
11137 arguments
.push(new StringExp(exp
.loc
, exp
.loc
.filename
.toDString()));
11138 arguments
.push(new IntegerExp(exp
.loc
, exp
.loc
.linnum
, Type
.tint32
));
11139 arguments
.push(new StringExp(exp
.loc
, funcname
.toDString()));
11142 handleCatArgument(arguments
, exp
.e1
);
11143 handleCatArgument(arguments
, exp
.e2
);
11145 Expression id
= new IdentifierExp(exp
.loc
, Id
.empty
);
11146 id
= new DotIdExp(exp
.loc
, id
, Id
.object
);
11148 auto tiargs
= new Objects();
11149 tiargs
.push(exp
.type
);
11150 id
= new DotTemplateInstanceExp(exp
.loc
, id
, hook
, tiargs
);
11151 id
= new CallExp(exp
.loc
, id
, arguments
);
11152 return id
.expressionSemantic(sc
);
11155 void trySetCatExpLowering(Expression exp
)
11157 /* `_d_arraycatnTX` canot be used with `-betterC`, but `CatExp`s may be
11158 * used with `-betterC`, but only during CTFE.
11160 if (!global
.params
.useGC
)
11163 if (auto ce
= exp
.isCatExp())
11164 ce
.lowering
= lowerToArrayCat(ce
);
11167 override void visit(CatExp exp
)
11169 // https://dlang.org/spec/expression.html#cat_expressions
11170 //printf("CatExp.semantic() %s\n", toChars());
11177 if (Expression ex
= binSemanticProp(exp
, sc
))
11182 Expression e
= exp
.op_overload(sc
);
11189 Type tb1
= exp
.e1
.type
.toBasetype();
11190 Type tb2
= exp
.e2
.type
.toBasetype();
11192 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
11193 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
11197 Type tb1next
= tb1
.nextOf();
11198 Type tb2next
= tb2
.nextOf();
11200 // Check for: array ~ array
11201 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
)))
11203 /* https://issues.dlang.org/show_bug.cgi?id=9248
11204 * Here to avoid the case of:
11205 * void*[] a = [cast(void*)1];
11206 * void*[] b = [cast(void*)2];
11209 * a ~ [cast(void*)b];
11212 /* https://issues.dlang.org/show_bug.cgi?id=14682
11213 * Also to avoid the case of:
11217 * a ~ cast(int[])[];
11222 // Check for: array ~ element
11223 if ((tb1
.ty
== Tsarray || tb1
.ty
== Tarray
) && tb2
.ty
!= Tvoid
)
11225 if (exp
.e1
.op
== EXP
.arrayLiteral
)
11227 exp
.e2
= doCopyOrMove(sc
, exp
.e2
);
11228 // https://issues.dlang.org/show_bug.cgi?id=14686
11229 // Postblit call appears in AST, and this is
11230 // finally translated to an ArrayLiteralExp in below optimize().
11232 else if (exp
.e1
.op
== EXP
.string_
)
11234 // No postblit call exists on character (integer) value.
11238 if (exp
.e2
.checkPostblit(sc
, tb2
))
11240 // Postblit call will be done in runtime helper function
11243 if (exp
.e1
.op
== EXP
.arrayLiteral
&& exp
.e1
.implicitConvTo(tb2
.arrayOf()))
11245 exp
.e1
= exp
.e1
.implicitCastTo(sc
, tb2
.arrayOf());
11246 exp
.type
= tb2
.arrayOf();
11249 if (exp
.e2
.implicitConvTo(tb1next
) >= MATCH
.convert
)
11251 exp
.e2
= exp
.e2
.implicitCastTo(sc
, tb1next
);
11252 exp
.type
= tb1next
.arrayOf();
11254 if (checkNewEscape(sc
, exp
.e2
, false))
11256 result
= exp
.optimize(WANTvalue
);
11257 trySetCatExpLowering(result
);
11261 // Check for: element ~ array
11262 if ((tb2
.ty
== Tsarray || tb2
.ty
== Tarray
) && tb1
.ty
!= Tvoid
)
11264 if (exp
.e2
.op
== EXP
.arrayLiteral
)
11266 exp
.e1
= doCopyOrMove(sc
, exp
.e1
);
11268 else if (exp
.e2
.op
== EXP
.string_
)
11273 if (exp
.e1
.checkPostblit(sc
, tb1
))
11277 if (exp
.e2
.op
== EXP
.arrayLiteral
&& exp
.e2
.implicitConvTo(tb1
.arrayOf()))
11279 exp
.e2
= exp
.e2
.implicitCastTo(sc
, tb1
.arrayOf());
11280 exp
.type
= tb1
.arrayOf();
11283 if (exp
.e1
.implicitConvTo(tb2next
) >= MATCH
.convert
)
11285 exp
.e1
= exp
.e1
.implicitCastTo(sc
, tb2next
);
11286 exp
.type
= tb2next
.arrayOf();
11288 if (checkNewEscape(sc
, exp
.e1
, false))
11290 result
= exp
.optimize(WANTvalue
);
11291 trySetCatExpLowering(result
);
11297 if ((tb1
.ty
== Tsarray || tb1
.ty
== Tarray
) && (tb2
.ty
== Tsarray || tb2
.ty
== Tarray
) && (tb1next
.mod || tb2next
.mod
) && (tb1next
.mod
!= tb2next
.mod
))
11299 Type t1
= tb1next
.mutableOf().constOf().arrayOf();
11300 Type t2
= tb2next
.mutableOf().constOf().arrayOf();
11301 if (exp
.e1
.op
== EXP
.string_
&& !(cast(StringExp
)exp
.e1
).committed
)
11304 exp
.e1
= exp
.e1
.castTo(sc
, t1
);
11305 if (exp
.e2
.op
== EXP
.string_
&& !(cast(StringExp
)exp
.e2
).committed
)
11308 exp
.e2
= exp
.e2
.castTo(sc
, t2
);
11311 if (Expression ex
= typeCombine(exp
, sc
))
11314 trySetCatExpLowering(result
);
11317 exp
.type
= exp
.type
.toHeadMutable();
11319 Type tb
= exp
.type
.toBasetype();
11320 if (tb
.ty
== Tsarray
)
11321 exp
.type
= tb
.nextOf().arrayOf();
11322 if (exp
.type
.ty
== Tarray
&& tb1next
&& tb2next
&& tb1next
.mod
!= tb2next
.mod
)
11324 exp
.type
= exp
.type
.nextOf().toHeadMutable().arrayOf();
11326 if (Type tbn
= tb
.nextOf())
11328 if (exp
.checkPostblit(sc
, tbn
))
11331 Type t1
= exp
.e1
.type
.toBasetype();
11332 Type t2
= exp
.e2
.type
.toBasetype();
11333 if ((t1
.ty
== Tarray || t1
.ty
== Tsarray
) &&
11334 (t2
.ty
== Tarray || t2
.ty
== Tsarray
))
11336 // Normalize to ArrayLiteralExp or StringExp as far as possible
11337 e
= exp
.optimize(WANTvalue
);
11341 //printf("(%s) ~ (%s)\n", e1.toChars(), e2.toChars());
11342 result
= exp
.incompatibleTypes();
11347 trySetCatExpLowering(result
);
11350 override void visit(MulExp exp
)
11354 printf("MulExp::semantic() %s\n", exp
.toChars());
11362 if (Expression ex
= binSemanticProp(exp
, sc
))
11367 Expression e
= exp
.op_overload(sc
);
11374 if (Expression ex
= typeCombine(exp
, sc
))
11380 Type tb
= exp
.type
.toBasetype();
11381 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
11383 if (!isArrayOpValid(exp
))
11385 result
= arrayOpInvalidError(exp
);
11392 if (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
))
11395 if (exp
.type
.isfloating())
11397 Type t1
= exp
.e1
.type
;
11398 Type t2
= exp
.e2
.type
;
11404 else if (t2
.isreal())
11408 else if (t1
.isimaginary())
11410 if (t2
.isimaginary())
11412 switch (t1
.toBasetype().ty
)
11415 exp
.type
= Type
.tfloat32
;
11419 exp
.type
= Type
.tfloat64
;
11423 exp
.type
= Type
.tfloat80
;
11431 exp
.e1
.type
= exp
.type
;
11432 exp
.e2
.type
= exp
.type
;
11433 e
= new NegExp(exp
.loc
, exp
);
11434 e
= e
.expressionSemantic(sc
);
11439 exp
.type
= t2
; // t2 is complex
11441 else if (t2
.isimaginary())
11443 exp
.type
= t1
; // t1 is complex
11446 else if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
11448 result
= exp
.incompatibleTypes();
11454 override void visit(DivExp exp
)
11462 if (Expression ex
= binSemanticProp(exp
, sc
))
11467 Expression e
= exp
.op_overload(sc
);
11474 if (Expression ex
= typeCombine(exp
, sc
))
11480 Type tb
= exp
.type
.toBasetype();
11481 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
11483 if (!isArrayOpValid(exp
))
11485 result
= arrayOpInvalidError(exp
);
11492 if (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
))
11495 if (exp
.type
.isfloating())
11497 Type t1
= exp
.e1
.type
;
11498 Type t2
= exp
.e2
.type
;
11503 if (t2
.isimaginary())
11507 e
= new NegExp(exp
.loc
, exp
);
11508 e
= e
.expressionSemantic(sc
);
11513 else if (t2
.isreal())
11517 else if (t1
.isimaginary())
11519 if (t2
.isimaginary())
11521 switch (t1
.toBasetype().ty
)
11524 exp
.type
= Type
.tfloat32
;
11528 exp
.type
= Type
.tfloat64
;
11532 exp
.type
= Type
.tfloat80
;
11540 exp
.type
= t2
; // t2 is complex
11542 else if (t2
.isimaginary())
11544 exp
.type
= t1
; // t1 is complex
11547 else if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
11549 result
= exp
.incompatibleTypes();
11555 override void visit(ModExp exp
)
11563 if (Expression ex
= binSemanticProp(exp
, sc
))
11568 Expression e
= exp
.op_overload(sc
);
11575 if (Expression ex
= typeCombine(exp
, sc
))
11581 Type tb
= exp
.type
.toBasetype();
11582 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
11584 if (!isArrayOpValid(exp
))
11586 result
= arrayOpInvalidError(exp
);
11592 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
11594 result
= exp
.incompatibleTypes();
11598 if (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
))
11601 if (exp
.type
.isfloating())
11603 exp
.type
= exp
.e1
.type
;
11604 if (exp
.e2
.type
.iscomplex())
11606 error(exp
.loc
, "cannot perform modulo complex arithmetic");
11613 override void visit(PowExp exp
)
11621 //printf("PowExp::semantic() %s\n", toChars());
11622 if (Expression ex
= binSemanticProp(exp
, sc
))
11627 Expression e
= exp
.op_overload(sc
);
11634 if (Expression ex
= typeCombine(exp
, sc
))
11640 Type tb
= exp
.type
.toBasetype();
11641 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
11643 if (!isArrayOpValid(exp
))
11645 result
= arrayOpInvalidError(exp
);
11652 if (exp
.checkArithmeticBin() || exp
.checkSharedAccessBin(sc
))
11655 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
11657 result
= exp
.incompatibleTypes();
11661 // First, attempt to fold the expression.
11662 e
= exp
.optimize(WANTvalue
);
11663 if (e
.op
!= EXP
.pow
)
11665 e
= e
.expressionSemantic(sc
);
11670 Module mmath
= Module
.loadStdMath();
11673 error(e
.loc
, "`%s` requires `std.math` for `^^` operators", e
.toChars());
11676 e
= new ScopeExp(exp
.loc
, mmath
);
11678 if (exp
.e2
.op
== EXP
.float64
&& exp
.e2
.toReal() == CTFloat
.half
)
11680 // Replace e1 ^^ 0.5 with .std.math.sqrt(e1)
11681 e
= new CallExp(exp
.loc
, new DotIdExp(exp
.loc
, e
, Id
._sqrt
), exp
.e1
);
11685 // Replace e1 ^^ e2 with .std.math.pow(e1, e2)
11686 e
= new CallExp(exp
.loc
, new DotIdExp(exp
.loc
, e
, Id
._pow
), exp
.e1
, exp
.e2
);
11688 e
= e
.expressionSemantic(sc
);
11693 override void visit(ShlExp exp
)
11695 //printf("ShlExp::semantic(), type = %p\n", type);
11702 if (Expression ex
= binSemanticProp(exp
, sc
))
11707 Expression e
= exp
.op_overload(sc
);
11714 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
11717 if (!target
.isVectorOpSupported(exp
.e1
.type
.toBasetype(), exp
.op
, exp
.e2
.type
.toBasetype()))
11719 result
= exp
.incompatibleTypes();
11722 exp
.e1
= integralPromotions(exp
.e1
, sc
);
11723 if (exp
.e2
.type
.toBasetype().ty
!= Tvector
)
11724 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tshiftcnt
);
11726 exp
.type
= exp
.e1
.type
;
11730 override void visit(ShrExp exp
)
11738 if (Expression ex
= binSemanticProp(exp
, sc
))
11743 Expression e
= exp
.op_overload(sc
);
11750 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
11753 if (!target
.isVectorOpSupported(exp
.e1
.type
.toBasetype(), exp
.op
, exp
.e2
.type
.toBasetype()))
11755 result
= exp
.incompatibleTypes();
11758 exp
.e1
= integralPromotions(exp
.e1
, sc
);
11759 if (exp
.e2
.type
.toBasetype().ty
!= Tvector
)
11760 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tshiftcnt
);
11762 exp
.type
= exp
.e1
.type
;
11766 override void visit(UshrExp exp
)
11774 if (Expression ex
= binSemanticProp(exp
, sc
))
11779 Expression e
= exp
.op_overload(sc
);
11786 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
11789 if (!target
.isVectorOpSupported(exp
.e1
.type
.toBasetype(), exp
.op
, exp
.e2
.type
.toBasetype()))
11791 result
= exp
.incompatibleTypes();
11794 exp
.e1
= integralPromotions(exp
.e1
, sc
);
11795 if (exp
.e2
.type
.toBasetype().ty
!= Tvector
)
11796 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tshiftcnt
);
11798 exp
.type
= exp
.e1
.type
;
11802 override void visit(AndExp exp
)
11810 if (Expression ex
= binSemanticProp(exp
, sc
))
11815 Expression e
= exp
.op_overload(sc
);
11822 if (exp
.e1
.type
.toBasetype().ty
== Tbool
&& exp
.e2
.type
.toBasetype().ty
== Tbool
)
11824 exp
.type
= exp
.e1
.type
;
11829 if (Expression ex
= typeCombine(exp
, sc
))
11835 Type tb
= exp
.type
.toBasetype();
11836 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
11838 if (!isArrayOpValid(exp
))
11840 result
= arrayOpInvalidError(exp
);
11846 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
11848 result
= exp
.incompatibleTypes();
11851 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
11857 override void visit(OrExp exp
)
11865 if (Expression ex
= binSemanticProp(exp
, sc
))
11870 Expression e
= exp
.op_overload(sc
);
11877 if (exp
.e1
.type
.toBasetype().ty
== Tbool
&& exp
.e2
.type
.toBasetype().ty
== Tbool
)
11879 exp
.type
= exp
.e1
.type
;
11884 if (Expression ex
= typeCombine(exp
, sc
))
11890 Type tb
= exp
.type
.toBasetype();
11891 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
11893 if (!isArrayOpValid(exp
))
11895 result
= arrayOpInvalidError(exp
);
11901 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
11903 result
= exp
.incompatibleTypes();
11906 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
11912 override void visit(XorExp exp
)
11920 if (Expression ex
= binSemanticProp(exp
, sc
))
11925 Expression e
= exp
.op_overload(sc
);
11932 if (exp
.e1
.type
.toBasetype().ty
== Tbool
&& exp
.e2
.type
.toBasetype().ty
== Tbool
)
11934 exp
.type
= exp
.e1
.type
;
11939 if (Expression ex
= typeCombine(exp
, sc
))
11945 Type tb
= exp
.type
.toBasetype();
11946 if (tb
.ty
== Tarray || tb
.ty
== Tsarray
)
11948 if (!isArrayOpValid(exp
))
11950 result
= arrayOpInvalidError(exp
);
11956 if (!target
.isVectorOpSupported(tb
, exp
.op
, exp
.e2
.type
.toBasetype()))
11958 result
= exp
.incompatibleTypes();
11961 if (exp
.checkIntegralBin() || exp
.checkSharedAccessBin(sc
))
11967 override void visit(LogicalExp exp
)
11969 static if (LOGSEMANTIC
)
11971 printf("LogicalExp::semantic() %s\n", exp
.toChars());
11980 exp
.setNoderefOperands();
11982 Expression e1x
= exp
.e1
.expressionSemantic(sc
);
11984 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
11985 if (e1x
.op
== EXP
.type
)
11986 e1x
= resolveAliasThis(sc
, e1x
);
11988 e1x
= resolveProperties(sc
, e1x
);
11989 e1x
= e1x
.toBoolean(sc
);
11991 if (sc
.flags
& SCOPE
.condition
)
11993 /* If in static if, don't evaluate e2 if we don't have to.
11995 e1x
= e1x
.optimize(WANTvalue
);
11996 if (e1x
.toBool().hasValue(exp
.op
== EXP
.orOr
))
11998 if (sc
.flags
& SCOPE
.Cfile
)
11999 result
= new IntegerExp(exp
.op
== EXP
.orOr
);
12001 result
= IntegerExp
.createBool(exp
.op
== EXP
.orOr
);
12006 CtorFlow ctorflow
= sc
.ctorflow
.clone();
12007 Expression e2x
= exp
.e2
.expressionSemantic(sc
);
12008 sc
.merge(exp
.loc
, ctorflow
);
12009 ctorflow
.freeFieldinit();
12011 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
12012 if (e2x
.op
== EXP
.type
)
12013 e2x
= resolveAliasThis(sc
, e2x
);
12015 e2x
= resolveProperties(sc
, e2x
);
12017 auto f1
= checkNonAssignmentArrayOp(e1x
);
12018 auto f2
= checkNonAssignmentArrayOp(e2x
);
12022 // Unless the right operand is 'void', the expression is converted to 'bool'.
12023 if (e2x
.type
.ty
!= Tvoid
)
12024 e2x
= e2x
.toBoolean(sc
);
12026 if (e2x
.op
== EXP
.type || e2x
.op
== EXP
.scope_
)
12028 error(exp
.loc
, "`%s` is not an expression", exp
.e2
.toChars());
12031 if (e1x
.op
== EXP
.error || e1x
.type
.ty
== Tnoreturn
)
12036 if (e2x
.op
== EXP
.error
)
12042 // The result type is 'bool', unless the right operand has type 'void'.
12043 if (e2x
.type
.ty
== Tvoid
)
12044 exp
.type
= Type
.tvoid
;
12046 exp
.type
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? Type
.tint32
: Type
.tbool
;
12054 override void visit(CmpExp exp
)
12056 static if (LOGSEMANTIC
)
12058 printf("CmpExp::semantic('%s')\n", exp
.toChars());
12066 exp
.setNoderefOperands();
12068 if (Expression ex
= binSemanticProp(exp
, sc
))
12073 Type t1
= exp
.e1
.type
.toBasetype();
12074 Type t2
= exp
.e2
.type
.toBasetype();
12075 if (t1
.ty
== Tclass
&& exp
.e2
.op
== EXP
.null_ || t2
.ty
== Tclass
&& exp
.e1
.op
== EXP
.null_
)
12077 error(exp
.loc
, "do not use `null` when comparing class types");
12082 EXP cmpop
= exp
.op
;
12083 if (auto e
= exp
.op_overload(sc
, &cmpop
))
12085 if (!e
.type
.isscalar() && e
.type
.equals(exp
.e1
.type
))
12087 error(exp
.loc
, "recursive `opCmp` expansion");
12090 if (e
.op
== EXP
.call)
12093 if (t1
.ty
== Tclass
&& t2
.ty
== Tclass
)
12095 // Lower to object.__cmp(e1, e2)
12096 Expression cl
= new IdentifierExp(exp
.loc
, Id
.empty
);
12097 cl
= new DotIdExp(exp
.loc
, cl
, Id
.object
);
12098 cl
= new DotIdExp(exp
.loc
, cl
, Id
.__cmp
);
12099 cl
= cl
.expressionSemantic(sc
);
12101 auto arguments
= new Expressions();
12102 // Check if op_overload found a better match by calling e2.opCmp(e1)
12103 // If the operands were swapped, then the result must be reversed
12104 // e1.opCmp(e2) == -e2.opCmp(e1)
12105 // cmpop takes care of this
12106 if (exp
.op
== cmpop
)
12108 arguments
.push(exp
.e1
);
12109 arguments
.push(exp
.e2
);
12113 // Use better match found by op_overload
12114 arguments
.push(exp
.e2
);
12115 arguments
.push(exp
.e1
);
12118 cl
= new CallExp(exp
.loc
, cl
, arguments
);
12119 cl
= new CmpExp(cmpop
, exp
.loc
, cl
, new IntegerExp(0));
12120 result
= cl
.expressionSemantic(sc
);
12124 e
= new CmpExp(cmpop
, exp
.loc
, e
, IntegerExp
.literal
!0);
12125 e
= e
.expressionSemantic(sc
);
12132 if (Expression ex
= typeCombine(exp
, sc
))
12138 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
12139 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
12143 exp
.type
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? Type
.tint32
: Type
.tbool
;
12145 // Special handling for array comparisons
12146 Expression arrayLowering
= null;
12147 t1
= exp
.e1
.type
.toBasetype();
12148 t2
= exp
.e2
.type
.toBasetype();
12149 if ((t1
.ty
== Tarray || t1
.ty
== Tsarray || t1
.ty
== Tpointer
) && (t2
.ty
== Tarray || t2
.ty
== Tsarray || t2
.ty
== Tpointer
))
12151 Type t1next
= t1
.nextOf();
12152 Type t2next
= t2
.nextOf();
12153 if (t1next
.implicitConvTo(t2next
) < MATCH
.constant
&& t2next
.implicitConvTo(t1next
) < MATCH
.constant
&& (t1next
.ty
!= Tvoid
&& t2next
.ty
!= Tvoid
))
12155 error(exp
.loc
, "array comparison type mismatch, `%s` vs `%s`", t1next
.toChars(), t2next
.toChars());
12159 if ((t1
.ty
== Tarray || t1
.ty
== Tsarray
) &&
12160 (t2
.ty
== Tarray || t2
.ty
== Tsarray
))
12162 if (!verifyHookExist(exp
.loc
, *sc
, Id
.__cmp
, "comparing arrays"))
12165 // Lower to object.__cmp(e1, e2)
12166 Expression al
= new IdentifierExp(exp
.loc
, Id
.empty
);
12167 al
= new DotIdExp(exp
.loc
, al
, Id
.object
);
12168 al
= new DotIdExp(exp
.loc
, al
, Id
.__cmp
);
12169 al
= al
.expressionSemantic(sc
);
12171 auto arguments
= new Expressions(2);
12172 (*arguments
)[0] = exp
.e1
;
12173 (*arguments
)[1] = exp
.e2
;
12175 al
= new CallExp(exp
.loc
, al
, arguments
);
12176 al
= new CmpExp(exp
.op
, exp
.loc
, al
, IntegerExp
.literal
!0);
12178 arrayLowering
= al
;
12181 else if (t1
.ty
== Tstruct || t2
.ty
== Tstruct ||
(t1
.ty
== Tclass
&& t2
.ty
== Tclass
))
12183 if (t2
.ty
== Tstruct
)
12184 error(exp
.loc
, "need member function `opCmp()` for %s `%s` to compare", t2
.toDsymbol(sc
).kind(), t2
.toChars());
12186 error(exp
.loc
, "need member function `opCmp()` for %s `%s` to compare", t1
.toDsymbol(sc
).kind(), t1
.toChars());
12189 else if (t1
.iscomplex() || t2
.iscomplex())
12191 error(exp
.loc
, "compare not defined for complex operands");
12194 else if (t1
.ty
== Taarray || t2
.ty
== Taarray
)
12196 error(exp
.loc
, "`%s` is not defined for associative arrays", EXPtoString(exp
.op
).ptr
);
12199 else if (!target
.isVectorOpSupported(t1
, exp
.op
, t2
))
12201 result
= exp
.incompatibleTypes();
12206 bool r1
= exp
.e1
.checkValue() || exp
.e1
.checkSharedAccess(sc
);
12207 bool r2
= exp
.e2
.checkValue() || exp
.e2
.checkSharedAccess(sc
);
12212 //printf("CmpExp: %s, type = %s\n", e.toChars(), e.type.toChars());
12215 arrayLowering
= arrayLowering
.expressionSemantic(sc
);
12216 result
= arrayLowering
;
12220 if (auto tv
= t1
.isTypeVector())
12221 exp
.type
= tv
.toBooleanVector();
12227 override void visit(InExp exp
)
12235 if (Expression ex
= binSemanticProp(exp
, sc
))
12240 Expression e
= exp
.op_overload(sc
);
12247 Type t2b
= exp
.e2
.type
.toBasetype();
12252 TypeAArray ta
= cast(TypeAArray
)t2b
;
12254 // Special handling for array keys
12255 if (!arrayTypeCompatibleWithoutCasting(exp
.e1
.type
, ta
.index
))
12257 // Convert key to type of key
12258 exp
.e1
= exp
.e1
.implicitCastTo(sc
, ta
.index
);
12261 semanticTypeInfo(sc
, ta
.index
);
12263 // Return type is pointer to value
12264 exp
.type
= ta
.nextOf().pointerTo();
12271 case Tarray
, Tsarray
:
12272 result
= exp
.incompatibleTypes();
12273 errorSupplemental(exp
.loc
, "`in` is only allowed on associative arrays");
12274 const(char)* slice
= (t2b
.ty
== Tsarray
) ?
"[]" : "";
12275 errorSupplemental(exp
.loc
, "perhaps use `std.algorithm.find(%s, %s%s)` instead",
12276 exp
.e1
.toChars(), exp
.e2
.toChars(), slice
);
12280 result
= exp
.incompatibleTypes();
12286 override void visit(RemoveExp e
)
12288 if (Expression ex
= binSemantic(e
, sc
))
12296 override void visit(EqualExp exp
)
12298 //printf("EqualExp::semantic('%s')\n", exp.toChars());
12305 exp
.setNoderefOperands();
12307 if (auto e
= binSemanticProp(exp
, sc
))
12312 if (exp
.e1
.op
== EXP
.type || exp
.e2
.op
== EXP
.type
)
12314 /* https://issues.dlang.org/show_bug.cgi?id=12520
12315 * empty tuples are represented as types so special cases are added
12316 * so that they can be compared for equality with tuples of values.
12318 static auto extractTypeTupAndExpTup(Expression e
)
12320 static struct Result
{ bool ttEmpty
; bool te
; }
12321 auto tt
= e
.op
== EXP
.type ? e
.isTypeExp().type
.isTypeTuple() : null;
12322 return Result(tt
&& (!tt
.arguments ||
!tt
.arguments
.length
), e
.isTupleExp() !is null);
12324 auto tups1
= extractTypeTupAndExpTup(exp
.e1
);
12325 auto tups2
= extractTypeTupAndExpTup(exp
.e2
);
12326 // AliasSeq!() == AliasSeq!(<at least a value>)
12327 if (tups1
.ttEmpty
&& tups2
.te
)
12329 result
= IntegerExp
.createBool(exp
.op
!= EXP
.equal
);
12332 // AliasSeq!(<at least a value>) == AliasSeq!()
12333 else if (tups1
.te
&& tups2
.ttEmpty
)
12335 result
= IntegerExp
.createBool(exp
.op
!= EXP
.equal
);
12338 // AliasSeq!() == AliasSeq!()
12339 else if (tups1
.ttEmpty
&& tups2
.ttEmpty
)
12341 result
= IntegerExp
.createBool(exp
.op
== EXP
.equal
);
12344 // otherwise, two types are really not comparable
12345 result
= exp
.incompatibleTypes();
12350 auto t1
= exp
.e1
.type
;
12351 auto t2
= exp
.e2
.type
;
12352 if (t1
.ty
== Tenum
&& t2
.ty
== Tenum
&& !t1
.equivalent(t2
))
12353 error(exp
.loc
, "comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`",
12354 t1
.toChars(), t2
.toChars());
12357 /* Before checking for operator overloading, check to see if we're
12358 * comparing the addresses of two statics. If so, we can just see
12359 * if they are the same symbol.
12361 if (exp
.e1
.op
== EXP
.address
&& exp
.e2
.op
== EXP
.address
)
12363 AddrExp ae1
= cast(AddrExp
)exp
.e1
;
12364 AddrExp ae2
= cast(AddrExp
)exp
.e2
;
12365 if (ae1
.e1
.op
== EXP
.variable
&& ae2
.e1
.op
== EXP
.variable
)
12367 VarExp ve1
= cast(VarExp
)ae1
.e1
;
12368 VarExp ve2
= cast(VarExp
)ae2
.e1
;
12369 if (ve1
.var
== ve2
.var
)
12371 // They are the same, result is 'true' for ==, 'false' for !=
12372 result
= IntegerExp
.createBool(exp
.op
== EXP
.equal
);
12378 Type t1
= exp
.e1
.type
.toBasetype();
12379 Type t2
= exp
.e2
.type
.toBasetype();
12381 // Indicates whether the comparison of the 2 specified array types
12382 // requires an object.__equals() lowering.
12383 static bool needsDirectEq(Type t1
, Type t2
, Scope
* sc
)
12385 Type t1n
= t1
.nextOf().toBasetype();
12386 Type t2n
= t2
.nextOf().toBasetype();
12387 if ((t1n
.ty
.isSomeChar
&& t2n
.ty
.isSomeChar
) ||
12388 (t1n
.ty
== Tvoid || t2n
.ty
== Tvoid
))
12392 if (t1n
.constOf() != t2n
.constOf())
12396 while (t
.toBasetype().nextOf())
12397 t
= t
.nextOf().toBasetype();
12398 if (auto ts
= t
.isTypeStruct())
12400 // semanticTypeInfo() makes sure hasIdentityEquals has been computed
12401 if (global
.params
.useTypeInfo
&& Type
.dtypeinfo
)
12402 semanticTypeInfo(sc
, ts
);
12404 return ts
.sym
.hasIdentityEquals
; // has custom opEquals
12410 if (auto e
= exp
.op_overload(sc
))
12417 const isArrayComparison
= (t1
.ty
== Tarray || t1
.ty
== Tsarray
) &&
12418 (t2
.ty
== Tarray || t2
.ty
== Tsarray
);
12419 const needsArrayLowering
= isArrayComparison
&& needsDirectEq(t1
, t2
, sc
);
12421 if (!needsArrayLowering
)
12423 // https://issues.dlang.org/show_bug.cgi?id=23783
12424 if (exp
.e1
.checkSharedAccess(sc
) || exp
.e2
.checkSharedAccess(sc
))
12426 if (auto e
= typeCombine(exp
, sc
))
12433 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
12434 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
12438 exp
.type
= (sc
&& sc
.flags
& SCOPE
.Cfile
) ? Type
.tint32
: Type
.tbool
;
12440 if (!isArrayComparison
)
12442 if (exp
.e1
.type
!= exp
.e2
.type
&& exp
.e1
.type
.isfloating() && exp
.e2
.type
.isfloating())
12444 // Cast both to complex
12445 exp
.e1
= exp
.e1
.castTo(sc
, Type
.tcomplex80
);
12446 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tcomplex80
);
12450 // lower some array comparisons to object.__equals(e1, e2)
12451 if (needsArrayLowering ||
(t1
.ty
== Tarray
&& t2
.ty
== Tarray
))
12453 //printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars());
12455 // https://issues.dlang.org/show_bug.cgi?id=22390
12456 // Equality comparison between array of noreturns simply lowers to length equality comparison
12457 if (t1
.nextOf
.isTypeNoreturn() && t2
.nextOf
.isTypeNoreturn())
12459 Expression exp_l1
= new DotIdExp(exp
.e1
.loc
, exp
.e1
, Id
.length
);
12460 Expression exp_l2
= new DotIdExp(exp
.e2
.loc
, exp
.e2
, Id
.length
);
12461 auto e
= new EqualExp(EXP
.equal
, exp
.loc
, exp_l1
, exp_l2
);
12462 result
= e
.expressionSemantic(sc
);
12466 if (!verifyHookExist(exp
.loc
, *sc
, Id
.__equals
, "equal checks on arrays"))
12469 Expression __equals
= new IdentifierExp(exp
.loc
, Id
.empty
);
12470 Identifier id
= Identifier
.idPool("__equals");
12471 __equals
= new DotIdExp(exp
.loc
, __equals
, Id
.object
);
12472 __equals
= new DotIdExp(exp
.loc
, __equals
, id
);
12474 /* https://issues.dlang.org/show_bug.cgi?id=23674
12476 * Optimize before creating the call expression to the
12477 * druntime hook as the optimizer may output errors
12478 * that will get swallowed otherwise.
12480 exp
.e1
= exp
.e1
.optimize(WANTvalue
);
12481 exp
.e2
= exp
.e2
.optimize(WANTvalue
);
12483 auto arguments
= new Expressions(2);
12484 (*arguments
)[0] = exp
.e1
;
12485 (*arguments
)[1] = exp
.e2
;
12487 __equals
= new CallExp(exp
.loc
, __equals
, arguments
);
12488 if (exp
.op
== EXP
.notEqual
)
12490 __equals
= new NotExp(exp
.loc
, __equals
);
12492 __equals
= __equals
.trySemantic(sc
); // for better error message
12495 error(exp
.loc
, "incompatible types for array comparison: `%s` and `%s`",
12496 exp
.e1
.type
.toChars(), exp
.e2
.type
.toChars());
12497 __equals
= ErrorExp
.get();
12504 if (exp
.e1
.type
.toBasetype().ty
== Taarray
)
12505 semanticTypeInfo(sc
, exp
.e1
.type
.toBasetype());
12508 if (!target
.isVectorOpSupported(t1
, exp
.op
, t2
))
12510 result
= exp
.incompatibleTypes();
12514 if (auto tv
= t1
.isTypeVector())
12515 exp
.type
= tv
.toBooleanVector();
12520 override void visit(IdentityExp exp
)
12528 exp
.setNoderefOperands();
12530 if (auto e
= binSemanticProp(exp
, sc
))
12536 if (auto e
= typeCombine(exp
, sc
))
12542 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
12543 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
12547 if (exp
.e1
.op
== EXP
.type || exp
.e2
.op
== EXP
.type
)
12549 result
= exp
.incompatibleTypes();
12553 exp
.type
= Type
.tbool
;
12555 if (exp
.e1
.type
!= exp
.e2
.type
&& exp
.e1
.type
.isfloating() && exp
.e2
.type
.isfloating())
12557 // Cast both to complex
12558 exp
.e1
= exp
.e1
.castTo(sc
, Type
.tcomplex80
);
12559 exp
.e2
= exp
.e2
.castTo(sc
, Type
.tcomplex80
);
12562 auto tb1
= exp
.e1
.type
.toBasetype();
12563 auto tb2
= exp
.e2
.type
.toBasetype();
12564 if (!target
.isVectorOpSupported(tb1
, exp
.op
, tb2
))
12566 result
= exp
.incompatibleTypes();
12570 if (exp
.e1
.op
== EXP
.call)
12571 exp
.e1
= (cast(CallExp
)exp
.e1
).addDtorHook(sc
);
12572 if (exp
.e2
.op
== EXP
.call)
12573 exp
.e2
= (cast(CallExp
)exp
.e2
).addDtorHook(sc
);
12575 if (exp
.e1
.type
.toBasetype().ty
== Tsarray ||
12576 exp
.e2
.type
.toBasetype().ty
== Tsarray
)
12577 deprecation(exp
.loc
, "identity comparison of static arrays "
12578 ~ "implicitly coerces them to slices, "
12579 ~ "which are compared by reference");
12584 override void visit(CondExp exp
)
12586 static if (LOGSEMANTIC
)
12588 printf("CondExp::semantic('%s')\n", exp
.toChars());
12596 if (auto die
= exp
.econd
.isDotIdExp())
12597 die
.noderef
= true;
12599 Expression ec
= exp
.econd
.expressionSemantic(sc
);
12600 ec
= resolveProperties(sc
, ec
);
12601 ec
= ec
.toBoolean(sc
);
12603 CtorFlow ctorflow_root
= sc
.ctorflow
.clone();
12604 Expression e1x
= exp
.e1
.expressionSemantic(sc
).arrayFuncConv(sc
);
12605 e1x
= resolveProperties(sc
, e1x
);
12607 CtorFlow ctorflow1
= sc
.ctorflow
;
12608 sc
.ctorflow
= ctorflow_root
;
12609 Expression e2x
= exp
.e2
.expressionSemantic(sc
).arrayFuncConv(sc
);
12610 e2x
= resolveProperties(sc
, e2x
);
12612 sc
.merge(exp
.loc
, ctorflow1
);
12613 ctorflow1
.freeFieldinit();
12615 if (ec
.op
== EXP
.error
)
12620 if (ec
.type
== Type
.terror
)
12624 if (e1x
.op
== EXP
.error
)
12629 if (e1x
.type
== Type
.terror
)
12633 if (e2x
.op
== EXP
.error
)
12638 if (e2x
.type
== Type
.terror
)
12642 auto f0
= checkNonAssignmentArrayOp(exp
.econd
);
12643 auto f1
= checkNonAssignmentArrayOp(exp
.e1
);
12644 auto f2
= checkNonAssignmentArrayOp(exp
.e2
);
12645 if (f0 || f1 || f2
)
12648 Type t1
= exp
.e1
.type
;
12649 Type t2
= exp
.e2
.type
;
12651 // https://issues.dlang.org/show_bug.cgi?id=23767
12652 // `cast(void*) 0` should be treated as `null` so the ternary expression
12653 // gets the pointer type of the other branch
12654 if (sc
.flags
& SCOPE
.Cfile
)
12656 static void rewriteCNull(ref Expression e
, ref Type t
)
12658 if (!t
.isTypePointer())
12660 if (auto ie
= e
.optimize(WANTvalue
).isIntegerExp())
12662 if (ie
.getInteger() == 0)
12664 e
= new NullExp(e
.loc
, Type
.tnull
);
12669 rewriteCNull(exp
.e1
, t1
);
12670 rewriteCNull(exp
.e2
, t2
);
12673 if (t1
.ty
== Tnoreturn
)
12676 exp
.e1
= specialNoreturnCast(exp
.e1
, exp
.type
);
12678 else if (t2
.ty
== Tnoreturn
)
12681 exp
.e2
= specialNoreturnCast(exp
.e2
, exp
.type
);
12683 // If either operand is void the result is void, we have to cast both
12684 // the expression to void so that we explicitly discard the expression
12686 // https://issues.dlang.org/show_bug.cgi?id=16598
12687 else if (t1
.ty
== Tvoid || t2
.ty
== Tvoid
)
12689 exp
.type
= Type
.tvoid
;
12690 exp
.e1
= exp
.e1
.castTo(sc
, exp
.type
);
12691 exp
.e2
= exp
.e2
.castTo(sc
, exp
.type
);
12697 if (Expression ex
= typeCombine(exp
, sc
))
12703 switch (exp
.e1
.type
.toBasetype().ty
)
12708 exp
.e2
= exp
.e2
.castTo(sc
, exp
.e1
.type
);
12713 switch (exp
.e2
.type
.toBasetype().ty
)
12718 exp
.e1
= exp
.e1
.castTo(sc
, exp
.e2
.type
);
12723 if (exp
.type
.toBasetype().ty
== Tarray
)
12725 exp
.e1
= exp
.e1
.castTo(sc
, exp
.type
);
12726 exp
.e2
= exp
.e2
.castTo(sc
, exp
.type
);
12729 exp
.type
= exp
.type
.merge2();
12732 printf("res: %s\n", exp
.type
.toChars());
12733 printf("e1 : %s\n", exp
.e1
.type
.toChars());
12734 printf("e2 : %s\n", exp
.e2
.type
.toChars());
12737 /* https://issues.dlang.org/show_bug.cgi?id=14696
12738 * If either e1 or e2 contain temporaries which need dtor,
12739 * make them conditional.
12741 * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2)
12743 * (auto __cond = cond) ? (... __tmp1) : (... __tmp2)
12744 * and replace edtors of __tmp1 and __tmp2 with:
12745 * __tmp1.edtor --> __cond && __tmp1.dtor()
12746 * __tmp2.edtor --> __cond || __tmp2.dtor()
12753 override void visit(GenericExp exp
)
12755 static if (LOGSEMANTIC
)
12757 printf("GenericExp::semantic('%s')\n", exp
.toChars());
12759 // C11 6.5.1.1 Generic Selection
12761 auto ec
= exp
.cntlExp
.expressionSemantic(sc
).arrayFuncConv(sc
);
12762 bool errors
= ec
.isErrorExp() !is null;
12765 auto types
= (*exp
.types
)[];
12766 foreach (i
, ref t
; types
)
12769 continue; // `default:` case
12770 t
= t
.typeSemantic(ec
.loc
, sc
);
12771 if (t
.isTypeError())
12777 /* C11 6.5.1-2 duplicate check
12779 /* C11 distinguishes int, long, and long long. But D doesn't, so depending on the
12780 * C target, a long may have the same type as `int` in the D type system.
12781 * So, skip checks when this may be the case. Later pick the first match
12784 (t
.ty
== Tint32 || t
.ty
== Tuns32
) && target
.c
.longsize
== 4 ||
12785 (t
.ty
== Tint64 || t
.ty
== Tuns64
) && target
.c
.longsize
== 8 ||
12786 (t
.ty
== Tfloat64 || t
.ty
== Timaginary64 || t
.ty
== Tcomplex64
) && target
.c
.long_doublesize
== 8
12790 foreach (t2
; types
[0 .. i
])
12792 if (t2
&& t2
.equals(t
))
12794 error(ec
.loc
, "generic association type `%s` can only appear once", t
.toChars());
12801 auto exps
= (*exp
.exps
)[];
12802 foreach (ref e
; exps
)
12804 e
= e
.expressionSemantic(sc
);
12805 if (e
.isErrorExp())
12812 enum size_t None
= ~0;
12813 size_t imatch
= None
;
12814 size_t idefault
= None
;
12815 foreach (const i
, t
; types
)
12819 /* if tc is compatible with t, it's a match
12820 * C11 6.2.7 defines a compatible type as being the same type, including qualifiers
12824 assert(imatch
== None
);
12826 break; // pick first match
12830 idefault
= i
; // multiple defaults are not allowed, and are caught by cparse
12833 if (imatch
== None
)
12835 if (imatch
== None
)
12837 error(exp
.loc
, "no compatible generic association type for controlling expression type `%s`", tc
.toChars());
12841 result
= exps
[imatch
];
12844 override void visit(FileInitExp e
)
12846 //printf("FileInitExp::semantic()\n");
12847 e
.type
= Type
.tstring
;
12851 override void visit(LineInitExp e
)
12853 e
.type
= Type
.tint32
;
12857 override void visit(ModuleInitExp e
)
12859 //printf("ModuleInitExp::semantic()\n");
12860 e
.type
= Type
.tstring
;
12864 override void visit(FuncInitExp e
)
12866 //printf("FuncInitExp::semantic()\n");
12867 e
.type
= Type
.tstring
;
12870 result
= e
.resolveLoc(Loc
.initial
, sc
);
12876 override void visit(PrettyFuncInitExp e
)
12878 //printf("PrettyFuncInitExp::semantic()\n");
12879 e
.type
= Type
.tstring
;
12882 result
= e
.resolveLoc(Loc
.initial
, sc
);
12890 /**********************************
12891 * Try to run semantic routines.
12892 * If they fail, return NULL.
12894 Expression
trySemantic(Expression exp
, Scope
* sc
)
12896 //printf("+trySemantic(%s)\n", exp.toChars());
12897 uint errors
= global
.startGagging();
12898 Expression e
= expressionSemantic(exp
, sc
);
12899 if (global
.endGagging(errors
))
12903 //printf("-trySemantic(%s)\n", exp.toChars());
12907 /**************************
12908 * Helper function for easy error propagation.
12909 * If error occurs, returns ErrorExp. Otherwise returns NULL.
12911 Expression
unaSemantic(UnaExp e
, Scope
* sc
)
12913 static if (LOGSEMANTIC
)
12915 printf("UnaExp::semantic('%s')\n", e
.toChars());
12917 Expression e1x
= e
.e1
.expressionSemantic(sc
);
12918 if (e1x
.op
== EXP
.error
)
12924 /**************************
12925 * Helper function for easy error propagation.
12926 * If error occurs, returns ErrorExp. Otherwise returns NULL.
12928 Expression
binSemantic(BinExp e
, Scope
* sc
)
12930 static if (LOGSEMANTIC
)
12932 printf("BinExp::semantic('%s')\n", e
.toChars());
12934 Expression e1x
= e
.e1
.expressionSemantic(sc
);
12935 Expression e2x
= e
.e2
.expressionSemantic(sc
);
12937 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
12938 if (e1x
.op
== EXP
.type
)
12939 e1x
= resolveAliasThis(sc
, e1x
);
12940 if (e2x
.op
== EXP
.type
)
12941 e2x
= resolveAliasThis(sc
, e2x
);
12943 if (e1x
.op
== EXP
.error
)
12945 if (e2x
.op
== EXP
.error
)
12952 Expression
binSemanticProp(BinExp e
, Scope
* sc
)
12954 if (Expression ex
= binSemantic(e
, sc
))
12956 Expression e1x
= resolveProperties(sc
, e
.e1
);
12957 Expression e2x
= resolveProperties(sc
, e
.e2
);
12958 if (e1x
.op
== EXP
.error
)
12960 if (e2x
.op
== EXP
.error
)
12967 // entrypoint for semantic ExpressionSemanticVisitor
12968 extern (C
++) Expression
expressionSemantic(Expression e
, Scope
* sc
)
12970 scope v
= new ExpressionSemanticVisitor(sc
);
12975 private Expression
dotIdSemanticPropX(DotIdExp exp
, Scope
* sc
)
12977 //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars());
12978 if (Expression ex
= unaSemantic(exp
, sc
))
12981 if (!(sc
.flags
& SCOPE
.Cfile
) && exp
.ident
== Id
._mangleof
)
12985 // return mangleof as an Expression
12986 static Expression
dotMangleof(const ref Loc loc
, Scope
* sc
, Dsymbol
ds)
12989 if (auto f
= ds.isFuncDeclaration())
12991 if (f
.checkForwardRef(loc
))
12992 return ErrorExp
.get();
12994 if (f
.purityInprocess || f
.safetyInprocess || f
.nothrowInprocess || f
.nogcInprocess
)
12996 error(loc
, "%s `%s` cannot retrieve its `.mangleof` while inferring attributes", f
.kind
, f
.toPrettyChars
);
12997 return ErrorExp
.get();
13001 mangleToBuffer(ds, buf
);
13002 Expression e
= new StringExp(loc
, buf
.extractSlice());
13003 return e
.expressionSemantic(sc
);
13009 case EXP
.scope_
: return dotMangleof(exp
.loc
, sc
, exp
.e1
.isScopeExp().sds
);
13010 case EXP
.variable
: return dotMangleof(exp
.loc
, sc
, exp
.e1
.isVarExp().var
);
13011 case EXP
.dotVariable
: return dotMangleof(exp
.loc
, sc
, exp
.e1
.isDotVarExp().var
);
13012 case EXP
.overloadSet
: return dotMangleof(exp
.loc
, sc
, exp
.e1
.isOverExp().vars
);
13013 case EXP
.template_
:
13015 TemplateExp te
= exp
.e1
.isTemplateExp();
13016 return dotMangleof(exp
.loc
, sc
, ds = te
.fd ? te
.fd
.isDsymbol() : te
.td
);
13024 if (exp
.e1
.isVarExp() && exp
.e1
.type
.toBasetype().isTypeSArray() && exp
.ident
== Id
.length
)
13026 // bypass checkPurity
13027 return exp
.e1
.type
.dotExp(sc
, exp
.e1
, exp
.ident
, cast(DotExpFlag
) (exp
.noderef
* DotExpFlag
.noDeref
));
13030 if (!exp
.e1
.isDotExp())
13032 exp
.e1
= resolvePropertiesX(sc
, exp
.e1
);
13035 if (auto te
= exp
.e1
.isTupleExp())
13037 if (exp
.ident
== Id
.offsetof
)
13039 /* 'distribute' the .offsetof to each of the tuple elements.
13041 auto exps
= new Expressions(te
.exps
.length
);
13042 foreach (i
, e
; (*te
.exps
)[])
13044 (*exps
)[i
] = new DotIdExp(e
.loc
, e
, Id
.offsetof
);
13046 // Don't evaluate te.e0 in runtime
13047 Expression e
= new TupleExp(exp
.loc
, null, exps
);
13048 e
= e
.expressionSemantic(sc
);
13051 if (exp
.ident
== Id
.length
)
13053 // Don't evaluate te.e0 in runtime
13054 return new IntegerExp(exp
.loc
, te
.exps
.length
, Type
.tsize_t
);
13058 // https://issues.dlang.org/show_bug.cgi?id=14416
13059 // Template has no built-in properties except for 'stringof'.
13060 if ((exp
.e1
.isDotTemplateExp() || exp
.e1
.isTemplateExp()) && exp
.ident
!= Id
.stringof
)
13062 error(exp
.loc
, "template `%s` does not have property `%s`", exp
.e1
.toChars(), exp
.ident
.toChars());
13063 return ErrorExp
.get();
13067 error(exp
.loc
, "expression `%s` does not have property `%s`", exp
.e1
.toChars(), exp
.ident
.toChars());
13068 return ErrorExp
.get();
13074 /******************************
13075 * Resolve properties, i.e. `e1.ident`, without seeing UFCS.
13077 * exp = expression to resolve
13079 * gag = do not emit error messages, just return `null`
13081 * resolved expression, null if error
13083 Expression
dotIdSemanticProp(DotIdExp exp
, Scope
* sc
, bool gag
)
13085 //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars());
13087 //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
13089 const cfile
= (sc
.flags
& SCOPE
.Cfile
) != 0;
13091 /* Special case: rewrite this.id and super.id
13092 * to be classtype.id and baseclasstype.id
13093 * if we have no this pointer.
13095 if ((exp
.e1
.isThisExp() || exp
.e1
.isSuperExp()) && !hasThis(sc
))
13097 if (AggregateDeclaration ad
= sc
.getStructClassScope())
13099 if (exp
.e1
.isThisExp())
13101 exp
.e1
= new TypeExp(exp
.e1
.loc
, ad
.type
);
13105 if (auto cd
= ad
.isClassDeclaration())
13108 exp
.e1
= new TypeExp(exp
.e1
.loc
, cd
.baseClass
.type
);
13115 Expression e
= dotIdSemanticPropX(exp
, sc
);
13122 if (auto de = exp
.e1
.isDotExp())
13133 Type t1b
= exp
.e1
.type
.toBasetype();
13135 if (auto ie
= eright
.isScopeExp()) // also used for template alias's
13137 auto flags
= SearchLocalsOnly
;
13138 /* Disable access to another module's private imports.
13139 * The check for 'is sds our current module' is because
13140 * the current module should have access to its own imports.
13142 if (ie
.sds
.isModule() && ie
.sds
!= sc
._module
)
13143 flags |
= IgnorePrivateImports
;
13144 if (sc
.flags
& SCOPE
.ignoresymbolvisibility
)
13145 flags |
= IgnoreSymbolVisibility
;
13146 Dsymbol s
= ie
.sds
.search(exp
.loc
, exp
.ident
, flags
);
13147 /* Check for visibility before resolving aliases because public
13148 * aliases to private symbols are public.
13150 if (s
&& !(sc
.flags
& SCOPE
.ignoresymbolvisibility
) && !symbolIsVisible(sc
._module
, s
))
13156 auto p
= s
.isPackage();
13157 if (p
&& checkAccess(sc
, p
))
13164 // if 's' is a tuple variable, the tuple is returned.
13167 exp
.checkDeprecated(sc
, s
);
13168 exp
.checkDisabled(sc
, s
);
13170 if (auto em
= s
.isEnumMember())
13172 return em
.getVarExp(exp
.loc
, sc
);
13174 if (auto v
= s
.isVarDeclaration())
13176 //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars());
13178 !v
.type
.deco
&& v
.inuse
)
13181 error(exp
.loc
, "circular reference to %s `%s`", v
.kind(), v
.toPrettyChars());
13183 error(exp
.loc
, "forward reference to %s `%s`", v
.kind(), v
.toPrettyChars());
13184 return ErrorExp
.get();
13186 if (v
.type
.isTypeError())
13187 return ErrorExp
.get();
13189 if ((v
.storage_class
& STC
.manifest
) && v
._init
&& !exp
.wantsym
)
13191 /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2().
13192 * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably
13193 * be reverted. `wantsym` is the hack to work around the problem.
13197 error(exp
.loc
, "circular initialization of %s `%s`", v
.kind(), v
.toPrettyChars());
13198 return ErrorExp
.get();
13200 auto e
= v
.expandInitializer(exp
.loc
);
13202 e
= e
.expressionSemantic(sc
);
13211 eleft
= new ThisExp(exp
.loc
);
13212 e
= new DotVarExp(exp
.loc
, eleft
, v
);
13213 e
= e
.expressionSemantic(sc
);
13217 e
= new VarExp(exp
.loc
, v
);
13220 e
= new CommaExp(exp
.loc
, eleft
, e
);
13225 return e
.expressionSemantic(sc
);
13228 if (auto f
= s
.isFuncDeclaration())
13230 //printf("it's a function\n");
13231 if (!f
.functionSemantic())
13232 return ErrorExp
.get();
13237 eleft
= new ThisExp(exp
.loc
);
13238 e
= new DotVarExp(exp
.loc
, eleft
, f
, true);
13239 e
= e
.expressionSemantic(sc
);
13243 e
= new VarExp(exp
.loc
, f
, true);
13246 e
= new CommaExp(exp
.loc
, eleft
, e
);
13252 if (auto td
= s
.isTemplateDeclaration())
13256 e
= new DotTemplateExp(exp
.loc
, eleft
, td
);
13258 e
= new TemplateExp(exp
.loc
, td
);
13259 e
= e
.expressionSemantic(sc
);
13262 if (OverDeclaration od
= s
.isOverDeclaration())
13264 Expression e
= new VarExp(exp
.loc
, od
, true);
13267 e
= new CommaExp(exp
.loc
, eleft
, e
);
13268 e
.type
= Type
.tvoid
; // ambiguous type?
13270 return e
.expressionSemantic(sc
);
13272 if (auto o
= s
.isOverloadSet())
13274 //printf("'%s' is an overload set\n", o.toChars());
13275 return new OverExp(exp
.loc
, o
);
13278 if (auto t
= s
.getType())
13280 return (new TypeExp(exp
.loc
, t
)).expressionSemantic(sc
);
13283 if (auto tup
= s
.isTupleDeclaration())
13287 Expression e
= new DotVarExp(exp
.loc
, eleft
, tup
);
13288 e
= e
.expressionSemantic(sc
);
13291 Expression e
= new TupleExp(exp
.loc
, tup
);
13292 e
= e
.expressionSemantic(sc
);
13296 if (auto sds
= s
.isScopeDsymbol())
13298 //printf("it's a ScopeDsymbol %s\n", ident.toChars());
13299 Expression e
= new ScopeExp(exp
.loc
, sds
);
13300 e
= e
.expressionSemantic(sc
);
13302 e
= new DotExp(exp
.loc
, eleft
, e
);
13306 if (auto imp
= s
.isImport())
13308 Expression se
= new ScopeExp(exp
.loc
, imp
.pkg
);
13309 return se
.expressionSemantic(sc
);
13312 if (auto attr
= s
.isAttribDeclaration())
13314 if (auto sm
= ie
.sds
.search(exp
.loc
, exp
.ident
, flags
))
13316 auto es
= new DsymbolExp(exp
.loc
, sm
);
13321 // BUG: handle other cases like in IdentifierExp::semantic()
13324 printf("s = %p '%s', kind = '%s'\n", s
, s
.toChars(), s
.kind());
13328 else if (exp
.ident
== Id
.stringof
)
13330 Expression e
= new StringExp(exp
.loc
, ie
.toString());
13331 e
= e
.expressionSemantic(sc
);
13334 if (ie
.sds
.isPackage() || ie
.sds
.isImport() || ie
.sds
.isModule())
13340 s
= ie
.sds
.search_correct(exp
.ident
);
13341 if (s
&& symbolIsVisible(sc
, s
))
13344 error(exp
.loc
, "undefined identifier `%s` in %s `%s`, perhaps add `static import %s;`", exp
.ident
.toChars(), ie
.sds
.kind(), ie
.sds
.toPrettyChars(), s
.toPrettyChars());
13346 error(exp
.loc
, "undefined identifier `%s` in %s `%s`, did you mean %s `%s`?", exp
.ident
.toChars(), ie
.sds
.kind(), ie
.sds
.toPrettyChars(), s
.kind(), s
.toChars());
13349 error(exp
.loc
, "undefined identifier `%s` in %s `%s`", exp
.ident
.toChars(), ie
.sds
.kind(), ie
.sds
.toPrettyChars());
13350 return ErrorExp
.get();
13352 else if (t1b
.ty
== Tpointer
&& exp
.e1
.type
.ty
!= Tenum
&&
13354 exp
.ident
== Id
.__sizeof ||
13355 exp
.ident
== Id
.__xalignof ||
13357 (exp
.ident
== Id
._mangleof ||
13358 exp
.ident
== Id
.offsetof ||
13359 exp
.ident
== Id
._init ||
13360 exp
.ident
== Id
.stringof
)
13363 Type t1bn
= t1b
.nextOf();
13366 if (AggregateDeclaration ad
= isAggregate(t1bn
))
13368 if (!ad
.members
) // https://issues.dlang.org/show_bug.cgi?id=11312
13378 if (gag
&& t1bn
.ty
== Tvoid
)
13380 Expression e
= new PtrExp(exp
.loc
, exp
.e1
);
13381 e
= e
.expressionSemantic(sc
);
13382 const newFlag
= cast(DotExpFlag
) (gag
* DotExpFlag
.gag | exp
.noderef
* DotExpFlag
.noDeref
);
13383 return e
.type
.dotExp(sc
, e
, exp
.ident
, newFlag
);
13385 else if (exp
.ident
== Id
.__xalignof
&&
13386 exp
.e1
.isVarExp() &&
13387 exp
.e1
.isVarExp().var
.isVarDeclaration() &&
13388 !exp
.e1
.isVarExp().var
.isVarDeclaration().alignment
.isUnknown())
13390 // For `x.alignof` get the alignment of the variable, not the alignment of its type
13391 const explicitAlignment
= exp
.e1
.isVarExp().var
.isVarDeclaration().alignment
;
13392 const naturalAlignment
= exp
.e1
.type
.alignsize();
13393 const actualAlignment
= explicitAlignment
.isDefault() ? naturalAlignment
: explicitAlignment
.get();
13394 Expression e
= new IntegerExp(exp
.loc
, actualAlignment
, Type
.tsize_t
);
13397 else if ((exp
.ident
== Id
.max || exp
.ident
== Id
.min
) &&
13398 exp
.e1
.isVarExp() &&
13399 exp
.e1
.isVarExp().var
.isBitFieldDeclaration())
13401 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
13402 auto bf
= exp
.e1
.isVarExp().var
.isBitFieldDeclaration();
13403 return new IntegerExp(exp
.loc
, bf
.getMinMax(exp
.ident
), bf
.type
);
13405 else if ((exp
.ident
== Id
.max || exp
.ident
== Id
.min
) &&
13406 exp
.e1
.isDotVarExp() &&
13407 exp
.e1
.isDotVarExp().var
.isBitFieldDeclaration())
13409 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
13410 auto bf
= exp
.e1
.isDotVarExp().var
.isBitFieldDeclaration();
13411 return new IntegerExp(exp
.loc
, bf
.getMinMax(exp
.ident
), bf
.type
);
13415 if (exp
.e1
.isTypeExp() || exp
.e1
.isTemplateExp())
13418 const flag
= cast(DotExpFlag
) (exp
.noderef
* DotExpFlag
.noDeref | gag
* DotExpFlag
.gag
);
13420 Expression e
= exp
.e1
.type
.dotExp(sc
, exp
.e1
, exp
.ident
, flag
);
13423 e
= e
.expressionSemantic(sc
);
13430 * Resolve `e1.ident!tiargs` without seeing UFCS.
13432 * exp = the `DotTemplateInstanceExp` to resolve
13433 * sc = the semantic scope
13434 * gag = stop "not a property" error and return `null`.
13436 * `null` if error or not found, or the resolved expression.
13438 Expression
dotTemplateSemanticProp(DotTemplateInstanceExp exp
, Scope
* sc
, bool gag
)
13440 static if (LOGSEMANTIC
)
13442 printf("DotTemplateInstanceExpY::semantic('%s')\n", exp
.toChars());
13445 static Expression
errorExp()
13447 return ErrorExp
.get();
13450 Expression e1
= exp
.e1
;
13452 if (exp
.ti
.tempdecl
&& exp
.ti
.tempdecl
.parent
&& exp
.ti
.tempdecl
.parent
.isTemplateMixin())
13454 // if 'ti.tempdecl' happens to be found in a mixin template don't lose that info
13455 // and do the symbol search in that context (Issue: 19476)
13456 auto tm
= cast(TemplateMixin
)exp
.ti
.tempdecl
.parent
;
13457 e1
= new DotExp(exp
.e1
.loc
, exp
.e1
, new ScopeExp(tm
.loc
, tm
));
13460 auto die
= new DotIdExp(exp
.loc
, e1
, exp
.ti
.name
);
13462 Expression e
= die
.dotIdSemanticPropX(sc
);
13465 exp
.e1
= die
.e1
; // take back
13466 Type t1b
= exp
.e1
.type
.toBasetype();
13467 if (t1b
.ty
== Tarray || t1b
.ty
== Tsarray || t1b
.ty
== Taarray || t1b
.ty
== Tnull ||
(t1b
.isTypeBasic() && t1b
.ty
!= Tvoid
))
13469 /* No built-in type has templatized properties, so do shortcut.
13470 * It is necessary in: 1024.max!"a < b"
13475 e
= die
.dotIdSemanticProp(sc
, gag
);
13479 isDotOpDispatch(e
))
13481 /* opDispatch!tiargs would be a function template that needs IFTI,
13482 * so it's not a template
13490 if (e
.op
== EXP
.error
)
13492 if (DotVarExp dve
= e
.isDotVarExp())
13494 if (FuncDeclaration fd
= dve
.var
.isFuncDeclaration())
13496 if (TemplateDeclaration td
= fd
.findTemplateDeclRoot())
13498 e
= new DotTemplateExp(dve
.loc
, dve
.e1
, td
);
13499 e
= e
.expressionSemantic(sc
);
13502 else if (OverDeclaration od
= dve
.var
.isOverDeclaration())
13504 exp
.e1
= dve
.e1
; // pull semantic() result
13506 if (!exp
.findTempDecl(sc
))
13508 if (exp
.ti
.needsTypeInference(sc
))
13510 exp
.ti
.dsymbolSemantic(sc
);
13511 if (!exp
.ti
.inst || exp
.ti
.errors
) // if template failed to expand
13514 if (Declaration v
= exp
.ti
.toAlias().isDeclaration())
13516 if (v
.type
&& !v
.type
.deco
)
13517 v
.type
= v
.type
.typeSemantic(v
.loc
, sc
);
13518 return new DotVarExp(exp
.loc
, exp
.e1
, v
)
13519 .expressionSemantic(sc
);
13521 return new DotExp(exp
.loc
, exp
.e1
, new ScopeExp(exp
.loc
, exp
.ti
))
13522 .expressionSemantic(sc
);
13525 else if (e
.op
== EXP
.variable
)
13527 VarExp ve
= cast(VarExp
)e
;
13528 if (FuncDeclaration fd
= ve
.var
.isFuncDeclaration())
13530 if (TemplateDeclaration td
= fd
.findTemplateDeclRoot())
13532 e
= new TemplateExp(ve
.loc
, td
)
13533 .expressionSemantic(sc
);
13536 else if (OverDeclaration od
= ve
.var
.isOverDeclaration())
13538 exp
.ti
.tempdecl
= od
;
13539 return new ScopeExp(exp
.loc
, exp
.ti
)
13540 .expressionSemantic(sc
);
13544 if (DotTemplateExp dte
= e
.isDotTemplateExp())
13546 exp
.e1
= dte
.e1
; // pull semantic() result
13548 exp
.ti
.tempdecl
= dte
.td
;
13549 if (!exp
.ti
.semanticTiargs(sc
))
13551 if (exp
.ti
.needsTypeInference(sc
))
13553 exp
.ti
.dsymbolSemantic(sc
);
13554 if (!exp
.ti
.inst || exp
.ti
.errors
) // if template failed to expand
13557 if (Declaration v
= exp
.ti
.toAlias().isDeclaration())
13559 return new DotVarExp(exp
.loc
, exp
.e1
, v
)
13560 .expressionSemantic(sc
);
13562 return new DotExp(exp
.loc
, exp
.e1
, new ScopeExp(exp
.loc
, exp
.ti
))
13563 .expressionSemantic(sc
);
13565 else if (e
.op
== EXP
.template_
)
13567 exp
.ti
.tempdecl
= (cast(TemplateExp
)e
).td
;
13568 return new ScopeExp(exp
.loc
, exp
.ti
)
13569 .expressionSemantic(sc
);
13571 else if (DotExp
de = e
.isDotExp())
13573 if (de.e2
.op
== EXP
.overloadSet
)
13575 if (!exp
.findTempDecl(sc
) ||
!exp
.ti
.semanticTiargs(sc
))
13579 if (exp
.ti
.needsTypeInference(sc
))
13581 exp
.ti
.dsymbolSemantic(sc
);
13582 if (!exp
.ti
.inst || exp
.ti
.errors
) // if template failed to expand
13585 if (Declaration v
= exp
.ti
.toAlias().isDeclaration())
13587 if (v
.type
&& !v
.type
.deco
)
13588 v
.type
= v
.type
.typeSemantic(v
.loc
, sc
);
13589 return new DotVarExp(exp
.loc
, exp
.e1
, v
)
13590 .expressionSemantic(sc
);
13592 return new DotExp(exp
.loc
, exp
.e1
, new ScopeExp(exp
.loc
, exp
.ti
))
13593 .expressionSemantic(sc
);
13596 else if (OverExp oe
= e
.isOverExp())
13598 exp
.ti
.tempdecl
= oe
.vars
;
13599 return new ScopeExp(exp
.loc
, exp
.ti
)
13600 .expressionSemantic(sc
);
13604 error(exp
.loc
, "`%s` isn't a template", e
.toChars());
13608 /***************************************
13609 * If expression is shared, check that we can access it.
13610 * Give error message if not.
13613 * e = expression to check
13615 * returnRef = Whether this expression is for a `return` statement
13616 * off a `ref` function, in which case a single level
13617 * of dereference is allowed (e.g. `shared(int)*`).
13621 bool checkSharedAccess(Expression e
, Scope
* sc
, bool returnRef
= false)
13623 if (global
.params
.noSharedAccess
!= FeatureState
.enabled ||
13626 sc
.flags
& SCOPE
.ctfe
)
13631 //printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef);
13633 bool check(Expression e
, bool allowRef
)
13635 bool sharedError(Expression e
)
13637 // https://dlang.org/phobos/core_atomic.html
13638 error(e
.loc
, "direct access to shared `%s` is not allowed, see `core.atomic`", e
.toChars());
13642 // Error by default
13643 bool visit(Expression e
)
13645 // https://issues.dlang.org/show_bug.cgi?id=23639
13646 // Should be able to cast(shared)
13647 if (!e
.isCastExp() && e
.type
.isShared())
13648 return sharedError(e
);
13652 bool visitNew(NewExp e
)
13655 check(e
.thisexp
, false);
13659 bool visitVar(VarExp e
)
13661 // https://issues.dlang.org/show_bug.cgi?id=20908
13662 // direct access to init symbols is ok as they
13663 // cannot be modified.
13664 if (e
.var
.isSymbolDeclaration())
13667 // https://issues.dlang.org/show_bug.cgi?id=22626
13668 // Synchronized functions don't need to use core.atomic
13669 // when accessing `this`.
13670 if (sc
.func
&& sc
.func
.isSynchronized())
13672 if (e
.var
.isThisDeclaration())
13675 return sharedError(e
);
13677 else if (!allowRef
&& e
.var
.type
.isShared())
13678 return sharedError(e
);
13683 bool visitAddr(AddrExp e
)
13685 return check(e
.e1
, true);
13688 bool visitPtr(PtrExp e
)
13690 if (!allowRef
&& e
.type
.isShared())
13691 return sharedError(e
);
13693 if (e
.e1
.type
.isShared())
13694 return sharedError(e
);
13696 return check(e
.e1
, false);
13699 bool visitDotVar(DotVarExp e
)
13701 //printf("dotvarexp = %s\n", e.toChars());
13702 if (e
.type
.isShared())
13704 if (e
.e1
.isThisExp())
13706 // https://issues.dlang.org/show_bug.cgi?id=22626
13707 if (sc
.func
&& sc
.func
.isSynchronized())
13710 // https://issues.dlang.org/show_bug.cgi?id=23790
13711 if (e
.e1
.type
.isTypeStruct())
13715 auto fd
= e
.var
.isFuncDeclaration();
13716 const sharedFunc
= fd
&& fd
.type
.isShared
;
13717 if (!allowRef
&& !sharedFunc
)
13718 return sharedError(e
);
13720 // Allow using `DotVarExp` within value types
13721 if (e
.e1
.type
.isTypeSArray() || e
.e1
.type
.isTypeStruct())
13722 return check(e
.e1
, allowRef
);
13724 // If we end up with a single `VarExp`, it might be a `ref` param
13725 // `shared ref T` param == `shared(T)*`.
13726 if (auto ve
= e
.e1
.isVarExp())
13728 return check(e
.e1
, allowRef
&& (ve
.var
.storage_class
& STC
.ref_
));
13731 return sharedError(e
);
13734 return check(e
.e1
, false);
13737 bool visitIndex(IndexExp e
)
13739 if (!allowRef
&& e
.type
.isShared())
13740 return sharedError(e
);
13742 if (e
.e1
.type
.isShared())
13743 return sharedError(e
);
13745 return check(e
.e1
, false);
13748 bool visitComma(CommaExp e
)
13750 // Cannot be `return ref` since we can't use the return,
13751 // but it's better to show that error than an unrelated `shared` one
13752 return check(e
.e2
, true);
13757 default: return visit(e
);
13759 // Those have no indirections / can be ignored
13762 case EXP
.complex80
:
13764 case EXP
.null_
: return false;
13766 case EXP
.variable
: return visitVar(e
.isVarExp());
13767 case EXP
.new_
: return visitNew(e
.isNewExp());
13768 case EXP
.address
: return visitAddr(e
.isAddrExp());
13769 case EXP
.star
: return visitPtr(e
.isPtrExp());
13770 case EXP
.dotVariable
: return visitDotVar(e
.isDotVarExp());
13771 case EXP
.index
: return visitIndex(e
.isIndexExp());
13775 return check(e
, returnRef
);
13780 /****************************************************
13781 * Determine if `exp`, which gets its address taken, can do so safely.
13784 * exp = expression having its address taken
13785 * v = the variable getting its address taken
13787 * `true` if ok, `false` for error
13789 bool checkAddressVar(Scope
* sc
, Expression exp
, VarDeclaration v
)
13791 //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars());
13795 if (!v
.canTakeAddressOf())
13797 error(exp
.loc
, "cannot take address of `%s`", exp
.toChars());
13800 if (sc
.func
&& !sc
.intypeof
&& !v
.isDataseg())
13802 if (global
.params
.useDIP1000
!= FeatureState
.enabled
&&
13803 !(v
.storage_class
& STC
.temp
) &&
13804 sc
.setUnsafe(false, exp
.loc
, "cannot take address of local `%s` in `@safe` function `%s`", v
, sc
.func
))
13812 /**************************************
13813 * This check ensures that the object in `exp` can have its address taken, or
13814 * issue a diagnostic error.
13816 * e = expression to check
13819 * true if the expression is addressable
13821 bool checkAddressable(Expression e
, Scope
* sc
)
13828 case EXP
.dotVariable
:
13829 // https://issues.dlang.org/show_bug.cgi?id=22749
13830 // Error about taking address of any bit-field, regardless of
13831 // whether SCOPE.Cfile is set.
13832 if (auto bf
= ex
.isDotVarExp().var
.isBitFieldDeclaration())
13834 error(e
.loc
, "cannot take address of bit-field `%s`", bf
.toChars());
13837 goto case EXP
.cast_
;
13840 ex
= ex
.isBinExp().e1
;
13846 ex
= ex
.isUnaExp().e1
;
13850 if (sc
.flags
& SCOPE
.Cfile
)
13852 // C11 6.5.3.2: A variable that has its address taken cannot be
13853 // stored in a register.
13854 // C11 6.3.2.1: An array that has its address computed with `[]`
13855 // or cast to an lvalue pointer cannot be stored in a register.
13856 if (ex
.isVarExp().var
.storage_class
& STC
.register
)
13858 if (e
.isIndexExp())
13859 error(e
.loc
, "cannot index through register variable `%s`", ex
.toChars());
13861 error(e
.loc
, "cannot take address of register variable `%s`", ex
.toChars());
13876 /*******************************
13877 * Checks the attributes of a function.
13878 * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`)
13879 * and usage of `deprecated` and `@disabled`-ed symbols are checked.
13882 * exp = expression to check attributes for
13883 * sc = scope of the function
13884 * f = function to be checked
13885 * Returns: `true` if error occur.
13887 private bool checkFunctionAttributes(Expression exp
, Scope
* sc
, FuncDeclaration f
)
13891 bool error
= checkDisabled(sc
, f
);
13892 error |
= checkDeprecated(sc
, f
);
13893 error |
= checkPurity(sc
, f
);
13894 error |
= checkSafety(sc
, f
);
13895 error |
= checkNogc(sc
, f
);
13900 /*******************************
13901 * Helper function for `getRightThis()`.
13902 * Gets `this` of the next outer aggregate.
13904 * loc = location to use for error messages
13906 * s = the parent symbol of the existing `this`
13907 * ad = struct or class we need the correct `this` for
13908 * e1 = existing `this`
13909 * t = type of the existing `this`
13910 * var = the specific member of ad we're accessing
13911 * flag = if true, return `null` instead of throwing an error
13913 * Expression representing the `this` for the var
13915 Expression
getThisSkipNestedFuncs(const ref Loc loc
, Scope
* sc
, Dsymbol s
, AggregateDeclaration ad
, Expression e1
, Type t
, Dsymbol var
, bool flag
= false)
13918 while (s
&& s
.isFuncDeclaration())
13920 FuncDeclaration f
= s
.isFuncDeclaration();
13924 e1
= new VarExp(loc
, f
.vthis
);
13925 if (f
.hasDualContext())
13929 e1
= e1
.expressionSemantic(sc
);
13930 e1
= new PtrExp(loc
, e1
);
13931 uint i
= f
.followInstantiationContext(ad
);
13932 e1
= new IndexExp(loc
, e1
, new IntegerExp(i
));
13933 s
= f
.toParentP(ad
);
13941 error(e1
.loc
, "need `this` of type `%s` to access member `%s` from static function `%s`", ad
.toChars(), var
.toChars(), f
.toChars());
13942 e1
= ErrorExp
.get();
13947 if (n
> 1 || e1
.op
== EXP
.index
)
13948 e1
= e1
.expressionSemantic(sc
);
13949 if (s
&& e1
.type
.equivalent(Type
.tvoidptr
))
13951 if (auto sad
= s
.isAggregateDeclaration())
13953 Type ta
= sad
.handleType();
13954 if (ta
.ty
== Tstruct
)
13955 ta
= ta
.pointerTo();
13959 e1
.type
= e1
.type
.addMod(t
.mod
);
13963 /*******************************
13964 * Make a dual-context container for use as a `this` argument.
13966 * loc = location to use for error messages
13967 * sc = current scope
13968 * fd = target function that will take the `this` argument
13970 * Temporary closure variable.
13972 * The function `fd` is added to the nested references of the
13973 * newly created variable such that a closure is made for the variable when
13974 * the address of `fd` is taken.
13976 VarDeclaration
makeThis2Argument(const ref Loc loc
, Scope
* sc
, FuncDeclaration fd
)
13978 Type tthis2
= Type
.tvoidptr
.sarrayOf(2);
13979 VarDeclaration vthis2
= new VarDeclaration(loc
, tthis2
, Identifier
.generateId("__this"), null);
13980 vthis2
.storage_class |
= STC
.temp
;
13981 vthis2
.dsymbolSemantic(sc
);
13982 vthis2
.parent
= sc
.parent
;
13983 // make it a closure var
13985 sc
.func
.closureVars
.push(vthis2
);
13986 // add `fd` to the nested refs
13987 vthis2
.nestedrefs
.push(fd
);
13991 /*******************************
13992 * Make sure that the runtime hook `id` exists.
13994 * loc = location to use for error messages
13995 * sc = current scope
13996 * id = the hook identifier
13997 * description = what the hook does
13998 * module_ = what module the hook is located in
14000 * a `bool` indicating if the hook is present.
14002 bool verifyHookExist(const ref Loc loc
, ref Scope sc
, Identifier id
, string description
, Identifier module_
= Id
.object
)
14004 auto rootSymbol
= sc
.search(loc
, Id
.empty
, null);
14005 if (auto moduleSymbol
= rootSymbol
.search(loc
, module_
))
14006 if (moduleSymbol
.search(loc
, id
))
14008 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
);
14012 /***************************************
14013 * Fit elements[] to the corresponding types of the `sd`'s fields.
14016 * sd = the struct declaration
14017 * loc = location to use for error messages
14019 * elements = explicit arguments used to construct object
14020 * stype = the constructed object type.
14022 * false if any errors occur,
14023 * otherwise true and elements[] are rewritten for the output.
14025 private bool fit(StructDeclaration sd
, const ref Loc loc
, Scope
* sc
, Expressions
* elements
, Type stype
)
14030 const nfields
= sd
.nonHiddenFields();
14032 for (size_t i
= 0; i
< elements
.length
; i
++)
14034 Expression e
= (*elements
)[i
];
14038 e
= resolveProperties(sc
, e
);
14041 if (i
< sd
.fields
.length
&& e
.op
== EXP
.null_
)
14043 // CTFE sometimes creates null as hidden pointer; we'll allow this.
14046 .error(loc
, "more initializers than fields (%llu) of `%s`", cast(ulong)nfields
, sd
.toChars());
14049 VarDeclaration v
= sd
.fields
[i
];
14050 if (v
.offset
< offset
)
14052 .error(loc
, "overlapping initialization for `%s`", v
.toChars());
14053 if (!sd
.isUnionDeclaration())
14055 enum errorMsg
= "`struct` initializers that contain anonymous unions" ~
14056 " must initialize only the first member of a `union`. All subsequent" ~
14057 " non-overlapping fields are default initialized";
14058 .errorSupplemental(loc
, errorMsg
);
14062 const vsize
= v
.type
.size();
14063 if (vsize
== SIZE_INVALID
)
14065 offset
= cast(uint)(v
.offset
+ vsize
);
14069 t
= t
.addMod(stype
.mod
);
14071 Type tb
= t
.toBasetype();
14073 const hasPointers
= tb
.hasPointers();
14076 if ((!stype
.alignment
.isDefault() && stype
.alignment
.get() < target
.ptrsize ||
14077 (v
.offset
& (target
.ptrsize
- 1))) &&
14078 (sc
.setUnsafe(false, loc
,
14079 "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd
, v
)))
14085 /* Look for case of initializing a static array with a too-short
14086 * string literal, such as:
14087 * char[5] foo = "abc";
14088 * Allow this by doing an explicit cast, which will lengthen the string
14091 if (e
.op
== EXP
.string_
&& tb
.ty
== Tsarray
)
14093 StringExp se
= cast(StringExp
)e
;
14094 Type typeb
= se
.type
.toBasetype();
14095 TY tynto
= tb
.nextOf().ty
;
14096 if (!se
.committed
&&
14097 (typeb
.ty
== Tarray || typeb
.ty
== Tsarray
) && tynto
.isSomeChar
&&
14098 se
.numberOfCodeUnits(tynto
) < (cast(TypeSArray
)tb
).dim
.toInteger())
14100 e
= se
.castTo(sc
, t
);
14105 while (!e
.implicitConvTo(t
) && tb
.ty
== Tsarray
)
14107 /* Static array initialization, as in:
14111 tb
= t
.toBasetype();
14113 if (!e
.implicitConvTo(t
))
14114 t
= origType
; // restore type for better diagnostic
14116 e
= e
.implicitCastTo(sc
, t
);
14118 if (e
.op
== EXP
.error
)
14121 (*elements
)[i
] = doCopyOrMove(sc
, e
);
14128 * Returns `em` as a VariableExp
14130 * em = the EnumMember to wrap
14131 * loc = location of use of em
14132 * sc = scope of use of em
14134 * VarExp referenceing `em` or ErrorExp if `em` if disabled/deprecated
14136 Expression
getVarExp(EnumMember em
, const ref Loc loc
, Scope
* sc
)
14138 dsymbolSemantic(em
, sc
);
14140 return ErrorExp
.get();
14141 em
.checkDisabled(loc
, sc
);
14143 if (em
.depdecl
&& !em
.depdecl
._scope
)
14144 em
.depdecl
._scope
= sc
;
14145 em
.checkDeprecated(loc
, sc
);
14148 return ErrorExp
.get();
14149 Expression e
= new VarExp(loc
, em
);
14150 e
= e
.expressionSemantic(sc
);
14151 if (!(sc
.flags
& SCOPE
.Cfile
) && em
.isCsymbol())
14153 /* C11 types them as int. But if in D file,
14154 * type qualified names as the enum
14156 e
.type
= em
.parent
.isEnumDeclaration().type
;
14163 /*****************************
14164 * Try to treat `exp` as a boolean,
14166 * exp = the expression
14167 * sc = scope to evalute `exp` in
14169 * Modified expression on success, ErrorExp on error
14171 Expression
toBoolean(Expression exp
, Scope
* sc
)
14176 error(exp
.loc
, "`delete` does not give a boolean result");
14177 return ErrorExp
.get();
14180 auto ce
= exp
.isCommaExp();
14181 auto ex2
= ce
.e2
.toBoolean(sc
);
14182 if (ex2
.op
== EXP
.error
)
14185 ce
.type
= ce
.e2
.type
;
14189 case EXP
.construct
:
14191 case EXP
.loweredAssignExp
:
14192 if (sc
.flags
& SCOPE
.Cfile
)
14196 // are usually mistakes.
14197 error(exp
.loc
, "assignment cannot be used as a condition, perhaps `==` was meant?");
14198 return ErrorExp
.get();
14203 auto le
= exp
.isLogicalExp();
14204 auto ex2
= le
.e2
.toBoolean(sc
);
14205 if (ex2
.op
== EXP
.error
)
14211 auto ce
= exp
.isCondExp();
14212 auto ex1
= ce
.e1
.toBoolean(sc
);
14213 auto ex2
= ce
.e2
.toBoolean(sc
);
14214 if (ex1
.op
== EXP
.error
)
14216 if (ex2
.op
== EXP
.error
)
14224 // Default is 'yes' - do nothing
14225 Expression e
= arrayFuncConv(exp
, sc
);
14227 Type tb
= t
.toBasetype();
14232 // Structs can be converted to bool using opCast(bool)()
14233 if (auto ts
= tb
.isTypeStruct())
14235 AggregateDeclaration ad
= ts
.sym
;
14236 /* Don't really need to check for opCast first, but by doing so we
14237 * get better error messages if it isn't there.
14239 if (Dsymbol fd
= search_function(ad
, Id
._cast
))
14241 e
= new CastExp(exp
.loc
, e
, Type
.tbool
);
14242 e
= e
.expressionSemantic(sc
);
14246 // Forward to aliasthis.
14247 if (ad
.aliasthis
&& !isRecursiveAliasThis(att
, tb
))
14249 e
= resolveAliasThis(sc
, e
);
14251 tb
= e
.type
.toBasetype();
14258 if (!t
.isBoolean())
14260 if (tb
!= Type
.terror
)
14261 error(exp
.loc
, "expression `%s` of type `%s` does not have a boolean value",
14262 exp
.toChars(), t
.toChars());
14263 return ErrorExp
.get();