d: Merge upstream dmd, druntime 4c18eed967, phobos d945686a4.
[official-gcc.git] / gcc / d / dmd / expressionsem.d
blob0bdcda9fe6ea67443b0e135c42faffe02d5c9b73
1 /**
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;
18 import dmd.access;
19 import dmd.aggregate;
20 import dmd.aliasthis;
21 import dmd.arrayop;
22 import dmd.arraytypes;
23 import dmd.attrib;
24 import dmd.astcodegen;
25 import dmd.astenums;
26 import dmd.canthrow;
27 import dmd.chkformat;
28 import dmd.ctorflow;
29 import dmd.dscope;
30 import dmd.dsymbol;
31 import dmd.declaration;
32 import dmd.dclass;
33 import dmd.dcast;
34 import dmd.delegatize;
35 import dmd.denum;
36 import dmd.dimport;
37 import dmd.dinterpret;
38 import dmd.dmangle;
39 import dmd.dmodule;
40 import dmd.dstruct;
41 import dmd.dsymbolsem;
42 import dmd.dtemplate;
43 import dmd.errors;
44 import dmd.escape;
45 import dmd.expression;
46 import dmd.file_manager;
47 import dmd.func;
48 import dmd.globals;
49 import dmd.hdrgen;
50 import dmd.id;
51 import dmd.identifier;
52 import dmd.imphint;
53 import dmd.importc;
54 import dmd.init;
55 import dmd.initsem;
56 import dmd.inline;
57 import dmd.intrange;
58 import dmd.location;
59 import dmd.mtype;
60 import dmd.mustuse;
61 import dmd.nspace;
62 import dmd.opover;
63 import dmd.optimize;
64 import dmd.parse;
65 import dmd.printast;
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;
72 import dmd.root.utf;
73 import dmd.semantic2;
74 import dmd.semantic3;
75 import dmd.sideeffect;
76 import dmd.safe;
77 import dmd.target;
78 import dmd.tokens;
79 import dmd.traits;
80 import dmd.typesem;
81 import dmd.typinf;
82 import dmd.utils;
83 import dmd.visitor;
85 enum LOGSEMANTIC = false;
87 /********************************************************
88 * Perform semantic analysis and CTFE on expressions to produce
89 * a string.
90 * Params:
91 * buf = append generated string to buffer
92 * sc = context
93 * exps = array of Expressions
94 * Returns:
95 * true on error
97 bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps)
99 if (!exps)
100 return false;
102 foreach (ex; *exps)
104 if (!ex)
105 continue;
106 auto sc2 = sc.startCTFE();
107 sc2.tinst = null;
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);
111 sc2.endCTFE();
113 // allowed to contain types as well as expressions
114 auto e4 = ctfeInterpretForPragmaMsg(e3);
115 if (!e4 || e4.op == EXP.error)
116 return true;
118 // expand tuple
119 if (auto te = e4.isTupleExp())
121 if (expressionsToString(buf, sc, te.exps))
122 return true;
123 continue;
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;
129 if (ty.isSomeChar)
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());
137 else
138 buf.writestring(e4.toString());
140 return false;
144 /***********************************************************
145 * Resolve `exp` as a compile-time known string.
146 * Params:
147 * sc = scope
148 * exp = Expression which expected as a string
149 * s = What the string is expected for, will be used in error diagnostic.
150 * Returns:
151 * String literal, or `null` if error happens.
153 StringExp semanticString(Scope *sc, Expression exp, const char* s)
155 sc = sc.startCTFE();
156 exp = exp.expressionSemantic(sc);
157 exp = resolveProperties(sc, exp);
158 sc = sc.endCTFE();
160 if (exp.op == EXP.error)
161 return null;
163 auto e = exp;
164 if (exp.type.isString())
166 e = e.ctfeInterpret();
167 if (e.op == EXP.error)
168 return null;
171 auto se = e.toStringExp();
172 if (!se)
174 error(exp.loc, "`string` expected for %s, not `(%s)` of type `%s`",
175 s, exp.toChars(), exp.type.toChars());
176 return null;
178 return se;
181 private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue)
183 Expression e0;
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
191 * Rewrite:
192 * e1.opIndex( ... use of $ ... )
193 * e1.opSlice( ... use of $ ... )
194 * as:
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
202 ue.e1 = e1;
203 return e0;
206 /**************************************
207 * Runs semantic on ae.arguments. Declares temporary variables
208 * if '$' was used.
210 Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0)
212 assert(!ae.lengthVar);
213 *pe0 = null;
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)
219 if (i == 0)
220 *pe0 = extractOpDollarSideEffect(sc, ae);
222 if (e.op == EXP.interval && !(slice && slice.isTemplateDeclaration()))
224 Lfallback:
225 if (ae.arguments.length == 1)
226 return null;
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;
235 sc = sc.push(sym);
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);
249 sc = sc.pop();
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);
256 tiargs.push(edim);
258 auto fargs = new Expressions(2);
259 (*fargs)[0] = ie.lwr;
260 (*fargs)[1] = ie.upr;
262 uint xerrors = global.startGagging();
263 sc = sc.push();
264 FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, ArgumentList(fargs), FuncResolveFlag.quiet);
265 sc = sc.pop();
266 global.endGagging(xerrors);
267 if (!fslice)
268 goto Lfallback;
270 e = new DotTemplateInstanceExp(ae.loc, ae.e1, slice.ident, tiargs);
271 e = new CallExp(ae.loc, e, fargs);
272 e = e.expressionSemantic(sc);
275 if (!e.type)
277 error(ae.loc, "`%s` has no value", e.toChars());
278 e = ErrorExp.get();
280 if (e.op == EXP.error)
281 return e;
283 (*ae.arguments)[i] = e;
285 return ae;
288 /**************************************
289 * Runs semantic on se.lwr and se.upr. Declares a temporary variable
290 * if '$' was used.
291 * Returns:
292 * ae, or ErrorExp if errors occurred
294 Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* pe0)
296 //assert(!ae.lengthVar);
297 if (!ie)
298 return ae;
300 VarDeclaration lengthVar = ae.lengthVar;
301 bool errors = false;
303 // create scope for '$'
304 auto sym = new ArrayScopeSymbol(sc, ae);
305 sym.parent = sc.scopesym;
306 sc = sc.push(sym);
308 Expression sem(Expression e)
310 e = e.expressionSemantic(sc);
311 e = resolveProperties(sc, e);
312 if (!e.type)
314 error(ae.loc, "`%s` has no value", e.toChars());
315 errors = true;
317 return e;
320 ie.lwr = sem(ie.lwr);
321 ie.upr = sem(ie.upr);
323 if (ie.lwr.isErrorExp() || ie.upr.isErrorExp())
324 errors = true;
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);
334 sc = sc.pop();
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)
345 bool err = false;
346 foreach (ref e; exps)
348 if (e is null) continue;
349 auto e2 = e.expressionSemantic(sc);
350 if (e2.op == EXP.error)
351 err = true;
352 if (preserveErrors || e2.op != EXP.error)
353 e = e2;
355 return err;
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`.
364 Params:
365 exp = expression that is checked
367 Returns:
368 An `assert(0)` expression if `exp` contains a `noreturn`
369 variable access, `exp` otherwise.
372 Expression checkNoreturnVarAccess(Expression exp)
374 assert(exp.type);
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;
386 return result;
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());
395 Loc loc = ue.loc;
397 // TODO: merge with Scope.search.searchScopes()
398 Dsymbol searchScopes(int flags)
400 Dsymbol s = null;
401 for (Scope* scx = sc; scx; scx = scx.enclosing)
403 if (!scx.scopesym)
404 continue;
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);
408 if (s)
410 // overload set contains only module scope symbols.
411 if (s.isOverloadSet())
412 break;
413 // selective/renamed imports also be picked up
414 if (AliasDeclaration ad = s.isAliasDeclaration())
416 if (ad._import)
417 break;
419 // See only module scope symbols for UFCS target.
420 Dsymbol p = s.toParent2();
421 if (p && p.isModule())
422 break;
424 s = null;
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))
428 break;
430 return s;
433 int flags = 0;
434 Dsymbol s;
436 if (sc.flags & SCOPE.ignoresymbolvisibility)
437 flags |= IgnoreSymbolVisibility;
439 // First look in local scopes
440 s = searchScopes(flags | SearchLocalsOnly);
441 if (!s)
443 // Second look in imported modules
444 s = searchScopes(flags | SearchImportsOnly);
447 if (!s)
448 return ue.e1.type.getProperty(sc, loc, ident, 0, ue.e1);
450 FuncDeclaration f = s.isFuncDeclaration();
451 if (f)
453 TemplateDeclaration td = getFuncTemplateDecl(f);
454 if (td)
456 if (td.overroot)
457 td = td.overroot;
458 s = td;
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);
478 else
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;
493 return false;
497 /******************************
498 * Pull out callable entity with UFCS.
500 private Expression resolveUFCS(Scope* sc, CallExp ce)
502 Loc loc = ce.loc;
503 Expression eleft;
504 Expression e;
506 if (auto die = ce.e1.isDotIdExp())
508 Identifier ident = die.ident;
510 Expression ex = die.dotIdSemanticPropX(sc);
511 if (ex != die)
513 ce.e1 = ex;
514 return null;
516 eleft = die.e1;
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)
529 /* Transform:
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);
557 else
559 if (Expression ey = die.dotIdSemanticProp(sc, 1))
561 if (ey.op == EXP.error)
562 return ey;
563 ce.e1 = ey;
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))
574 return e;
576 if (arrayExpressionSemantic(originalArguments.peekSlice(), sc))
577 return ErrorExp.get();
579 /* fall down to UFCS */
581 else
582 return null;
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.
593 * struct A
595 * string[string] a;
596 * alias a this;
599 * void fun()
601 * A s;
602 * s.remove("foo");
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)
612 // check alias this
613 Expression alias_e = resolveAliasThis(sc, die.e1, 1);
614 if (alias_e && alias_e != die.e1)
616 die.e1 = alias_e;
617 CallExp ce2 = ce.syntaxCopy();
618 ce2.e1 = die;
619 e = ce2.isCallExp().trySemantic(sc);
620 if (e)
621 return e;
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))
632 ce.e1 = ey;
633 return null;
635 eleft = dti.e1;
636 e = searchUFCS(sc, dti, dti.ti.name);
638 else
639 return null;
641 // Rewrite
642 ce.e1 = e;
643 if (!ce.arguments)
644 ce.arguments = new Expressions();
645 ce.arguments.shift(eleft);
646 if (!ce.names)
647 ce.names = new Identifiers();
648 ce.names.shift(null);
649 ce.isUfcsRewrite = true;
650 return null;
653 int expandAliasThisTuples(Expressions* exps, size_t starti = 0)
655 if (!exps || exps.length == 0)
656 return -1;
658 for (size_t u = starti; u < exps.length; u++)
660 Expression exp = (*exps)[u];
661 if (TupleDeclaration td = exp.isAliasThisTuple)
663 exps.remove(u);
664 size_t i;
665 td.foreachVar((s)
667 auto d = s.isDeclaration();
668 auto e = new DotVarExp(exp.loc, exp, d);
669 assert(d.type);
670 e.type = d.type;
671 exps.insert(u + i, e);
672 ++i;
674 version (none)
676 printf("expansion ->\n");
677 foreach (e; exps)
679 printf("\texps[%d] e = %s %s\n", i, EXPtoString(e.op), e.toChars());
682 return cast(int)u;
685 return -1;
688 /******************************
689 * Pull out property with UFCS.
691 private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2 = null)
693 Loc loc = e1.loc;
694 Expression eleft;
695 Expression e;
697 if (auto die = e1.isDotIdExp())
699 eleft = die.e1;
700 e = searchUFCS(sc, die, die.ident);
702 else if (auto dti = e1.isDotTemplateInstanceExp())
704 eleft = dti.e1;
705 e = searchUFCS(sc, dti, dti.ti.name);
707 else
708 return null;
710 if (e is null)
711 return null;
713 // Rewrite
714 if (e2)
716 // run semantic without gagging
717 e2 = e2.expressionSemantic(sc);
719 /* f(e1) = e2
721 Expression ex = e.copy();
722 auto a1 = new Expressions(1);
723 (*a1)[0] = eleft;
724 ex = new CallExp(loc, ex, a1);
725 auto e1PassSemantic = ex.trySemantic(sc);
727 /* f(e1, e2)
729 auto a2 = new Expressions(2);
730 (*a2)[0] = eleft;
731 (*a2)[1] = e2;
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);
746 else if (ex && !e)
748 ex = new AssignExp(loc, ex, e2);
749 return ex.expressionSemantic(sc);
751 else
753 // strict setter prints errors if fails
754 e = e.expressionSemantic(sc);
756 return e;
758 else
760 /* f(e1)
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);
771 return e;
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)
784 assert(os);
785 foreach (s; os.a)
787 auto fd = s.isFuncDeclaration();
788 auto td = s.isTemplateDeclaration();
789 if (fd)
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);
802 return e1;
805 Expression handleTemplateDecl(TemplateDeclaration td)
807 assert(td);
808 if (td.onemember)
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);
818 return e1;
821 Expression handleFuncDecl(FuncDeclaration fd)
823 assert(fd);
824 if (fd.type.isTypeFunction().isproperty)
825 return resolveProperties(sc, e1);
826 return 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())
838 if (dti.ti.tempdecl)
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())
846 Dsymbol s = se.sds;
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());
861 return e1;
864 /****************************************
865 * Turn symbol `s` into the expression it represents.
867 * Params:
868 * s = symbol to resolve
869 * loc = location of use of `s`
870 * sc = context
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.
874 * Returns:
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());
884 Lagain:
885 Expression e;
887 //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars());
888 //printf("s = '%s', s.kind = '%s'\n", s.toChars(), s.kind());
889 Dsymbol olds = s;
890 Declaration d = s.isDeclaration();
891 if (d && (d.storage_class & STC.templateparameter))
893 s = s.toAlias();
895 else
897 // functions are checked after overloading
898 // templates are checked after matching constraints
899 if (!s.isFuncDeclaration() && !s.isTemplateDeclaration())
901 s.checkDeprecated(loc, sc);
902 if (d)
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.
908 s = s.toAlias();
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);
914 if (d)
915 d.checkDisabled(loc, sc);
918 if (auto sd = s.isDeclaration())
920 if (sd.isSystem())
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());
929 else
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)
961 if (v.inuse)
963 error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
964 return ErrorExp.get();
966 e = v.expandInitializer(loc);
967 v.inuse++;
968 e = e.expressionSemantic(sc);
969 v.inuse--;
970 return e;
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
975 if (v.isThis())
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);
984 else
985 e = new VarExp(loc, v);
986 e = e.expressionSemantic(sc);
987 return e;
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())
997 f = f.toAliasFunc();
998 if (!f.functionSemantic())
999 return ErrorExp.get();
1001 if (!hasOverloads && f.checkForwardRef(loc))
1002 return ErrorExp.get();
1004 auto fd = s.isFuncDeclaration();
1005 fd.type = f.type;
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;
1012 return e;
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())
1022 if (!imp.pkg)
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);
1055 else
1056 e = new TupleExp(loc, tup);
1057 e = e.expressionSemantic(sc);
1058 return e;
1061 if (TemplateInstance ti = s.isTemplateInstance())
1063 ti.dsymbolSemantic(sc);
1064 if (!ti.inst || ti.errors)
1065 return ErrorExp.get();
1066 s = ti.toAlias();
1067 if (!s.isTemplateInstance())
1068 goto Lagain;
1069 e = new ScopeExp(loc, ti);
1070 e = e.expressionSemantic(sc);
1071 return e;
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);
1082 else
1083 e = new TemplateExp(loc, td);
1084 e = e.expressionSemantic(sc);
1085 return e;
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.
1096 * Params:
1097 * loc = location to use for error messages
1098 * sc = context
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
1103 * Returns:
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'.
1116 return e1;
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)
1141 return e1;
1142 goto L1;
1147 /* If e1 is not the 'this' pointer for ad
1149 if (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
1176 // class type.
1177 e1 = getThisSkipNestedFuncs(loc, sc, tcd.toParentP(ad), ad, e1, t, var);
1178 if (e1.op == EXP.error)
1179 return e1;
1180 goto L1;
1183 /* Can't find a path from e1 to ad
1185 if (flag)
1186 return null;
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();
1191 return e1;
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:
1202 * struct X
1204 * void gun() {}
1206 * struct A
1208 * void fun() {}
1209 * void sun()
1211 * fun();
1212 * X.gun(); // error
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
1221 * `this` as `gun`.
1223 * Returns:
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();
1237 if (!thisAd)
1238 return false;
1240 auto requiredAd = calledFunc.isMemberLocal();
1241 if (!requiredAd)
1242 return false;
1244 if (thisAd == requiredAd)
1245 return true;
1247 // if outerfunc is the member of a nested aggregate, then let
1248 // getRightThis take care of this.
1249 if (thisAd.isNested())
1250 return true;
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();
1255 if (!cd)
1256 return false;
1258 if (cd.isBaseOf2(thisAd.isClassDeclaration()))
1259 return true;
1261 return false;
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);
1270 Loc loc = e1.loc;
1272 OverloadSet os;
1273 Dsymbol s;
1274 Objects* tiargs;
1275 Type tthis;
1276 if (auto de = e1.isDotExp())
1278 if (auto oe = de.e2.isOverExp())
1280 tiargs = null;
1281 tthis = de.e1.type;
1282 os = oe.vars;
1283 goto Los;
1286 else if (e1.isOverExp())
1288 tiargs = null;
1289 tthis = null;
1290 os = e1.isOverExp().vars;
1291 Los:
1292 assert(os);
1293 FuncDeclaration fd = null;
1294 if (e2)
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();
1302 a.push(e2);
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))
1308 if (f.errors)
1309 return ErrorExp.get();
1310 fd = f;
1311 assert(fd.type.ty == Tfunction);
1314 if (fd)
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))
1325 if (f.errors)
1326 return ErrorExp.get();
1327 fd = f;
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();
1337 if (fd)
1339 Expression e = new CallExp(loc, e1);
1340 if (e2)
1342 e = new AssignExp(loc, e, e2);
1343 if (saveAtts)
1345 (cast(BinExp)e).att1 = saveAtts.att1;
1346 (cast(BinExp)e).att2 = saveAtts.att2;
1349 return e.expressionSemantic(sc);
1352 if (e2)
1353 goto Leprop;
1355 else if (auto dti = e1.isDotTemplateInstanceExp())
1357 if (!dti.findTempDecl(sc))
1358 goto Leprop;
1359 if (!dti.ti.semanticTiargs(sc))
1360 goto Leprop;
1361 tiargs = dti.ti.tiargs;
1362 tthis = dti.e1.type;
1363 if ((os = dti.ti.tempdecl.isOverloadSet()) !is null)
1364 goto Los;
1365 if ((s = dti.ti.tempdecl) !is null)
1366 goto Lfd;
1368 else if (auto dte = e1.isDotTemplateExp())
1370 s = dte.td;
1371 tiargs = null;
1372 tthis = dte.e1.type;
1373 goto Lfd;
1375 else if (auto se = e1.isScopeExp())
1377 s = se.sds;
1378 TemplateInstance ti = s.isTemplateInstance();
1379 if (ti && !ti.semanticRun && ti.tempdecl)
1381 //assert(ti.needsTypeInference(sc));
1382 if (!ti.semanticTiargs(sc))
1383 goto Leprop;
1384 tiargs = ti.tiargs;
1385 tthis = null;
1386 if ((os = ti.tempdecl.isOverloadSet()) !is null)
1387 goto Los;
1388 if ((s = ti.tempdecl) !is null)
1389 goto Lfd;
1392 else if (auto te = e1.isTemplateExp())
1394 s = te.td;
1395 tiargs = null;
1396 tthis = null;
1397 goto Lfd;
1399 else if (e1.isDotVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isDotVarExp().var.isOverDeclaration()))
1401 DotVarExp dve = e1.isDotVarExp();
1402 s = dve.var;
1403 tiargs = null;
1404 tthis = dve.e1.type;
1405 goto Lfd;
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;
1414 tiargs = null;
1415 tthis = null;
1416 Lfd:
1417 assert(s);
1418 if (e2)
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();
1426 a.push(e2);
1428 FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(a), FuncResolveFlag.quiet);
1429 if (fd && fd.type)
1431 if (fd.errors)
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);
1440 if (fd && fd.type)
1442 if (fd.errors)
1443 return ErrorExp.get();
1444 TypeFunction tf = fd.type.isTypeFunction();
1445 if (!e2 || tf.isref)
1447 Expression e = new CallExp(loc, e1);
1448 if (e2)
1450 e = new AssignExp(loc, e, e2);
1451 if (saveAtts)
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);
1468 if (e2)
1469 goto Leprop;
1471 if (auto ve = e1.isVarExp())
1473 if (auto v = ve.var.isVarDeclaration())
1475 if (ve.checkPurity(sc, v))
1476 return ErrorExp.get();
1479 if (e2)
1480 return null;
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();
1507 if (!e1.type)
1509 error(loc, "cannot resolve type for %s", e1.toChars());
1510 e1 = ErrorExp.get();
1512 return e1;
1514 Leprop:
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();
1525 return e;
1528 /****************************************
1529 * The common type is determined by applying ?: to each pair.
1530 * Output:
1531 * exps[] properties resolved, implicitly cast to common type, rewritten in place
1532 * Returns:
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);
1547 Type t0 = null;
1548 Expression e0 = null;
1549 bool foundType;
1551 for (size_t i = 0; i < exps.length; i++)
1553 Expression e = exps[i];
1554 if (!e)
1555 continue;
1557 e = resolveProperties(sc, e);
1558 if (!e.type)
1560 error(e.loc, "`%s` has no value", e.toChars());
1561 t0 = Type.terror;
1562 continue;
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"
1568 t0 = Type.terror;
1569 continue;
1571 if (e.type.ty == Tvoid)
1573 // void expressions do not concur to the determination of the common
1574 // type.
1575 continue;
1577 if (checkNonAssignmentArrayOp(e))
1579 t0 = Type.terror;
1580 continue;
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;
1591 condexp.e1 = e0;
1592 condexp.e2 = e;
1593 condexp.loc = e.loc;
1594 Expression ex = condexp.expressionSemantic(sc);
1595 if (ex.op == EXP.error)
1596 e = ex;
1597 else
1599 // Convert to common type
1600 exps[i] = condexp.e1.castTo(sc, condexp.type);
1601 e = condexp.e2.castTo(sc, condexp.type);
1604 e0 = e;
1605 t0 = e.type;
1606 if (e.op != EXP.error)
1607 exps[i] = e;
1610 // [] is typed as void[]
1611 if (!t0)
1612 return Type.tvoid;
1614 // It's an error, don't do the cast
1615 if (t0.ty == Terror)
1616 return null;
1618 for (size_t i = 0; i < exps.length; i++)
1620 Expression e = exps[i];
1621 if (!e)
1622 continue;
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.
1632 return null;
1634 exps[i] = e;
1636 return t0;
1639 private Expression opAssignToOp(const ref Loc loc, EXP op, Expression e1, Expression e2) @safe
1641 Expression e;
1642 switch (op)
1644 case EXP.addAssign:
1645 e = new AddExp(loc, e1, e2);
1646 break;
1648 case EXP.minAssign:
1649 e = new MinExp(loc, e1, e2);
1650 break;
1652 case EXP.mulAssign:
1653 e = new MulExp(loc, e1, e2);
1654 break;
1656 case EXP.divAssign:
1657 e = new DivExp(loc, e1, e2);
1658 break;
1660 case EXP.modAssign:
1661 e = new ModExp(loc, e1, e2);
1662 break;
1664 case EXP.andAssign:
1665 e = new AndExp(loc, e1, e2);
1666 break;
1668 case EXP.orAssign:
1669 e = new OrExp(loc, e1, e2);
1670 break;
1672 case EXP.xorAssign:
1673 e = new XorExp(loc, e1, e2);
1674 break;
1676 case EXP.leftShiftAssign:
1677 e = new ShlExp(loc, e1, e2);
1678 break;
1680 case EXP.rightShiftAssign:
1681 e = new ShrExp(loc, e1, e2);
1682 break;
1684 case EXP.unsignedRightShiftAssign:
1685 e = new UshrExp(loc, e1, e2);
1686 break;
1688 default:
1689 assert(0);
1691 return e;
1694 /*********************
1695 * Rewrite:
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);
1706 return e;
1708 else
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);
1717 return e;
1721 /****************************************
1722 * Preprocess arguments to function.
1724 * Tuples in argumentList get expanded, properties resolved, rewritten in place
1726 * Params:
1727 * sc = scope
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
1731 * Returns:
1732 * `true` when a semantic error occurred
1734 private bool preFunctionParameters(Scope* sc, ArgumentList argumentList, const bool reportErrors = true)
1736 Expressions* exps = argumentList.arguments;
1737 bool err = false;
1738 if (exps)
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)
1754 if (reportErrors)
1756 error(arg.loc, "cannot pass type `%s` as a function argument", arg.toChars());
1757 arg = ErrorExp.get();
1759 err = true;
1762 else if (arg.type.toBasetype().ty == Tfunction)
1764 if (reportErrors)
1766 error(arg.loc, "cannot pass function `%s` as a function argument", arg.toChars());
1767 arg = ErrorExp.get();
1769 err = true;
1771 else if (checkNonAssignmentArrayOp(arg))
1773 arg = ErrorExp.get();
1774 err = true;
1776 (*exps)[i] = arg;
1779 return err;
1782 /********************************************
1783 * Issue an error if default construction is disabled for type t.
1784 * Default construction is required for arrays and 'out' parameters.
1785 * Returns:
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);
1796 return true;
1799 return false;
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
1810 * Params:
1811 * loc = location of function call
1812 * sc = context
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
1820 * Returns:
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() : "");
1829 assert(arguments);
1830 assert(fd || tf.next);
1831 const size_t nparams = tf.parameterList.length;
1832 const olderrors = global.errors;
1833 bool err = false;
1834 Expression eprefix = null;
1835 *peprefix = null;
1837 if (argumentList.names)
1839 const(char)* msg = null;
1840 auto resolvedArgs = tf.resolveNamedArgs(argumentList, &msg);
1841 if (!resolvedArgs)
1843 // while errors are usually already caught by `tf.callMatch`,
1844 // this can happen when calling `typeof(freefunc)`
1845 if (msg)
1846 error(loc, "%s", msg);
1847 return true;
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());
1859 return true;
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)
1881 if (sc._module)
1882 sc._module.hasAlwaysInlines = true;
1883 if (sc.func)
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
1894 * of the arguments.
1896 MOD wildmatch = (tthis && !isCtorCall) ? tthis.Type.deduceWild(tf, false) : 0;
1898 bool done = false;
1899 foreach (const i; 0 .. n)
1901 Expression arg = (i < nargs) ? (*arguments)[i] : null;
1903 if (i < nparams)
1905 bool errorArgs()
1907 error(loc, "expected %llu function arguments, not %llu", cast(ulong)nparams, cast(ulong)nargs);
1908 return true;
1911 Parameter p = tf.parameterList[i];
1913 if (!arg)
1915 if (!p.defaultArg)
1917 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams)
1918 goto L2;
1919 return errorArgs();
1921 arg = p.defaultArg;
1922 if (!arg.type)
1923 arg = arg.expressionSemantic(sc);
1924 arg = inlineCopy(arg, sc);
1925 // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
1926 arg = arg.resolveLoc(loc, sc);
1927 if (i >= nargs)
1929 arguments.push(arg);
1930 nargs++;
1932 else
1933 (*arguments)[i] = arg;
1935 else
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());
1949 MATCH m;
1950 if ((m = arg.implicitConvTo(p.type)) > MATCH.nomatch)
1952 if (p.type.nextOf() && arg.implicitConvTo(p.type.nextOf()) >= m)
1953 goto L2;
1954 else if (nargs != nparams)
1955 return errorArgs();
1956 goto L1;
1960 Type tb = p.type.toBasetype();
1961 switch (tb.ty)
1963 case Tsarray:
1964 case Tarray:
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
1970 * is now optimized.
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);
1987 else
1988 a = a.implicitCastTo(sc, tbn);
1989 a = a.addDtorHook(sc);
1990 (*elements)[u] = a;
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);
1998 arg.type = p.type;
2000 break;
2002 case Tclass:
2004 /* Set arg to be:
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);
2011 break;
2013 default:
2014 if (!arg)
2016 error(loc, "not enough arguments");
2017 return true;
2019 break;
2021 arg = arg.expressionSemantic(sc);
2022 //printf("\targ = '%s'\n", arg.toChars());
2023 arguments.setDim(i + 1);
2024 (*arguments)[i] = arg;
2025 nargs = i + 1;
2026 done = true;
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);
2039 if (done)
2040 break;
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);
2050 return true;
2053 if (fd)
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; }
2060 * struct S {
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!
2067 * void test() {
2068 * int a;
2069 * auto s = foo(a);
2070 * s.baz!a() = 1; // bad!
2074 bool checkEnclosingWild(Dsymbol s)
2076 bool checkWild(Dsymbol s)
2078 if (!s)
2079 return false;
2080 if (auto ad = s.isAggregateDeclaration())
2082 if (ad.isNested())
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);
2093 return false;
2096 Dsymbol ctx0 = s.toParent2();
2097 Dsymbol ctx1 = s.toParentLocal();
2098 if (checkWild(ctx0))
2099 return true;
2100 if (ctx0 != ctx1)
2101 return checkWild(ctx1);
2102 return false;
2104 if ((fd.isThis() || fd.isNested()) && checkEnclosingWild(fd))
2105 return true;
2107 else if (tf.isWild())
2108 return errorInout(wildmatch);
2111 Expression firstArg = null;
2112 final switch (returnParamDest(tf, tthis))
2114 case ReturnParamDest.returnVal:
2115 break;
2116 case ReturnParamDest.firstArg:
2117 firstArg = nargs > 0 ? (*arguments)[0] : null;
2118 break;
2119 case ReturnParamDest.this_:
2120 firstArg = ethis;
2121 break;
2124 assert(nargs >= nparams);
2125 foreach (const i, arg; (*arguments)[0 .. nargs])
2127 assert(arg);
2128 if (i < nparams)
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)
2138 : p.type;
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 &&
2168 !arg.isLvalue() &&
2169 targ.isCopyable())
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_)
2185 Type t = arg.type;
2186 if (!t.isMutable() || !t.isAssignable()) // check blit assignable
2188 error(arg.loc, "cannot modify struct `%s` with immutable members", arg.toChars());
2189 err = true;
2191 else
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.
2244 Expression a = arg;
2245 if (auto ce = a.isCastExp())
2246 a = ce.e1;
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)
2280 --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());
2291 else
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)
2303 case Tfloat32:
2304 arg = arg.castTo(sc, Type.tfloat64);
2305 break;
2307 case Timaginary32:
2308 arg = arg.castTo(sc, Type.timaginary64);
2309 break;
2311 default:
2312 break;
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);
2321 err = true;
2323 if (arg.type.ty == Tsarray)
2325 error(arg.loc, "cannot pass static arrays to `%s` vararg functions", p);
2326 err = true;
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");
2335 err = true;
2337 if (arg.type.needsCopyOrPostblit())
2339 error(arg.loc, "cannot pass types with postblits or copy constructors as variadic arguments");
2340 err = true;
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);
2351 else
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());
2364 err = true;
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);
2392 else
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))
2421 lastthrow = i;
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)
2428 firstdtor = i;
2429 lastdtor = i;
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
2470 if (isLazy)
2471 continue;
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
2476 * this arg.
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
2498 if (needsDtor)
2499 tmp.isArgDtorVar = true; // mark it so that the backend passes it by ref to the function being called
2501 else
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
2506 if (!needsDtor)
2508 if (tmp.edtor)
2510 assert(i == lastPrefix);
2511 tmp.edtor = null;
2514 else
2516 // edtor => (__gate || edtor)
2517 assert(tmp.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));
2529 // arg => __pfx/y
2530 arg = new VarExp(loc, tmp);
2531 arg = arg.expressionSemantic(sc);
2532 if (isRef)
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_) ||
2568 tf.islive)
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);
2581 (*args)[i] = arg;
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;
2591 if (isCtorCall)
2593 //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd.toChars(), fd.type.toChars(),
2594 // wildmatch, tf.isWild(), fd.isReturnIsolated());
2595 if (!tthis)
2597 assert(sc.intypeof || global.errors);
2598 tthis = fd.isThis().type.addMod(fd.type.mod);
2600 if (tf.isWild() && !fd.isReturnIsolated())
2602 if (wildmatch)
2603 tret = tret.substWildTo(wildmatch);
2604 int offset;
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);
2610 err = true;
2613 tret = tthis;
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);
2623 *prettype = tret;
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))
2632 * Params:
2633 * sym = the symbol to be checked
2635 * Returns:
2636 * the symbol which `sym` represents (or `null` if it doesn't represent a `Package`)
2638 Package resolveIsPackage(Dsymbol sym)
2640 Package pkg;
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`",
2646 imp.toChars());
2647 assert(0);
2649 pkg = imp.pkg;
2651 else if (auto mod = sym.isModule())
2652 pkg = mod.isPackageFile ? mod.pkg : sym.isPackage();
2653 else
2654 pkg = sym.isPackage();
2655 if (pkg)
2656 pkg.resolvePKGunknown();
2657 return pkg;
2661 private extern (C++) final class ExpressionSemanticVisitor : Visitor
2663 alias visit = Visitor.visit;
2665 Scope* sc;
2666 Expression result;
2668 this(Scope* sc) scope @safe
2670 this.sc = sc;
2673 private void setError()
2675 result = ErrorExp.get();
2678 private void needThisError(Loc loc, FuncDeclaration f)
2680 auto t = f.isThis();
2681 assert(t);
2682 .error(loc, "calling non-static function `%s` requires an instance of type `%s`", f.toChars(), t.toChars());
2683 setError();
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());
2696 if (e.type)
2697 e.type = e.type.typeSemantic(e.loc, sc);
2698 else
2699 e.type = Type.tvoid;
2700 result = e;
2703 override void visit(IntegerExp e)
2705 assert(e.type);
2706 if (e.type.ty == Terror)
2707 return setError();
2709 assert(e.type.deco);
2710 e.setInteger(e.getInteger());
2711 result = e;
2714 override void visit(RealExp e)
2716 if (!e.type)
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);
2723 if (t.ty == Terror)
2724 return setError();
2726 Type tf;
2727 switch (e.type.ty)
2729 case Timaginary32: tf = Type.tfloat32; break;
2730 case Timaginary64: tf = Type.tfloat64; break;
2731 case Timaginary80: tf = Type.tfloat80; break;
2732 default:
2733 assert(0);
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);
2744 return;
2746 else
2747 e.type = e.type.typeSemantic(e.loc, sc);
2748 result = e;
2751 override void visit(ComplexExp e)
2753 if (!e.type)
2754 e.type = Type.tcomplex80;
2755 else
2756 e.type = e.type.typeSemantic(e.loc, sc);
2757 result = e;
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
2768 result = exp;
2769 return;
2772 Dsymbol scopesym;
2773 Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym);
2774 if (s)
2776 if (s.errors)
2777 return setError();
2779 Expression e;
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
2789 Scope* scwith = sc;
2790 while (scwith.scopesym != scopesym)
2792 scwith = scwith.enclosing;
2793 assert(scwith);
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)
2799 Dsymbol s2;
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());
2803 return setError();
2806 s = s.toAlias();
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);
2815 else
2817 if (withsym)
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);
2825 else
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);
2832 return;
2835 /* If f is really a function template,
2836 * then replace f with the function template declaration.
2838 FuncDeclaration f = s.isFuncDeclaration();
2839 if (f)
2841 TemplateDeclaration td = getFuncTemplateDecl(f);
2842 if (td)
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);
2848 result = e;
2849 return;
2853 if (global.params.fixAliasThis)
2855 ExpressionDsymbol expDsym = scopesym.isExpressionDsymbol();
2856 if (expDsym)
2858 //printf("expDsym = %s\n", expDsym.exp.toChars());
2859 result = expDsym.exp.expressionSemantic(sc);
2860 return;
2863 // Haven't done overload resolution yet, so pass 1
2864 e = symbolToExp(s, exp.loc, sc, true);
2866 result = e;
2867 return;
2870 if (!global.params.fixAliasThis && hasThis(sc))
2872 for (AggregateDeclaration ad = sc.getStructClassScope(); ad;)
2874 if (ad.aliasthis)
2876 Expression e;
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);
2881 if (e)
2883 result = e;
2884 return;
2888 auto cd = ad.isClassDeclaration();
2889 if (cd && cd.baseClass && cd.baseClass != ClassDeclaration.object)
2891 ad = cd.baseClass;
2892 continue;
2894 break;
2898 if (exp.ident == Id.ctfe)
2900 if (sc.flags & SCOPE.ctfe)
2902 error(exp.loc, "variable `__ctfe` cannot be read at compile time");
2903 return setError();
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);
2912 result = e;
2913 return;
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
2921 // above wins.
2922 // https://issues.dlang.org/show_bug.cgi?id=6400
2923 for (Scope* sc2 = sc; sc2; sc2 = sc2.enclosing)
2925 if (!sc2.scopesym)
2926 continue;
2928 if (auto ss = sc2.scopesym.isWithScopeSymbol())
2930 if (ss.withstate.wthis)
2932 Expression e;
2933 e = new VarExp(exp.loc, ss.withstate.wthis);
2934 e = new DotIdExp(exp.loc, e, exp.ident);
2935 e = e.trySemantic(sc);
2936 if (e)
2938 result = e;
2939 return;
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)
2947 Expression e;
2948 e = new TypeExp(exp.loc, t);
2949 e = new DotIdExp(exp.loc, e, exp.ident);
2950 e = e.trySemantic(sc);
2951 if (e)
2953 result = e;
2954 return;
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 `$`");
2971 else
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");
2988 if (e.type)
2990 result = e;
2991 return;
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)
3005 if (!s)
3007 error(e.loc, "`%s` is not in a class or struct scope", e.toChars());
3008 return setError();
3010 ClassDeclaration cd = s.isClassDeclaration();
3011 if (cd)
3013 e.type = cd.type;
3014 result = e;
3015 return;
3017 StructDeclaration sd = s.isStructDeclaration();
3018 if (sd)
3020 e.type = sd.type;
3021 result = e;
3022 return;
3026 if (!fd)
3028 error(e.loc, "`this` is only defined in non-static member functions, not `%s`", sc.parent.toChars());
3029 return setError();
3032 assert(fd.vthis);
3033 e.var = fd.vthis;
3034 assert(e.var.parent);
3035 ad = fd.isMemberLocal();
3036 if (!ad)
3037 ad = fd.isMember2();
3038 assert(ad);
3039 e.type = ad.type.addMod(e.var.type.mod);
3041 if (e.var.checkNestedReference(sc, e.loc))
3042 return setError();
3044 result = e;
3047 override void visit(SuperExp e)
3049 static if (LOGSEMANTIC)
3051 printf("SuperExp::semantic('%s')\n", e.toChars());
3053 if (e.type)
3055 result = e;
3056 return;
3059 FuncDeclaration fd = hasThis(sc);
3060 ClassDeclaration cd;
3061 Dsymbol s;
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)
3071 if (!s)
3073 error(e.loc, "`%s` is not in a class scope", e.toChars());
3074 return setError();
3076 cd = s.isClassDeclaration();
3077 if (cd)
3079 cd = cd.baseClass;
3080 if (!cd)
3082 error(e.loc, "class `%s` has no `super`", s.toChars());
3083 return setError();
3085 e.type = cd.type;
3086 result = e;
3087 return;
3091 if (!fd)
3092 goto Lerr;
3094 e.var = fd.vthis;
3095 assert(e.var && e.var.parent);
3097 s = fd.toParentDecl();
3098 if (s.isTemplateDeclaration()) // allow inside template constraint
3099 s = s.toParent();
3100 assert(s);
3101 cd = s.isClassDeclaration();
3102 //printf("parent is %s %s\n", fd.toParent().kind(), fd.toParent().toChars());
3103 if (!cd)
3104 goto Lerr;
3105 if (!cd.baseClass)
3107 error(e.loc, "no base class for `%s`", cd.toChars());
3108 e.type = cd.type.addMod(e.var.type.mod);
3110 else
3112 e.type = cd.baseClass.type;
3113 e.type = e.type.castMod(e.var.type.mod);
3116 if (e.var.checkNestedReference(sc, e.loc))
3117 return setError();
3119 result = e;
3120 return;
3122 Lerr:
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
3134 if (e.type)
3136 result = e;
3137 return;
3139 e.type = Type.tnull;
3140 result = e;
3143 override void visit(StringExp e)
3145 static if (LOGSEMANTIC)
3147 printf("StringExp::semantic() %s\n", e.toChars());
3149 if (e.type)
3151 result = e;
3152 return;
3155 OutBuffer buffer;
3156 size_t newlen = 0;
3157 size_t u;
3158 dchar c;
3160 switch (e.postfix)
3162 case 'd':
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);
3168 return setError();
3170 else
3172 buffer.write4(c);
3173 newlen++;
3176 buffer.write4(0);
3177 e.setData(buffer.extractData(), newlen, 4);
3178 if (sc && sc.flags & SCOPE.Cfile)
3179 e.type = Type.tuns32.sarrayOf(e.len + 1);
3180 else
3181 e.type = Type.tdchar.immutableOf().arrayOf();
3182 e.committed = true;
3183 break;
3185 case 'w':
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);
3191 return setError();
3193 else
3195 buffer.writeUTF16(c);
3196 newlen++;
3197 if (c >= 0x10000)
3198 newlen++;
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);
3205 else
3206 e.type = Type.twchar.immutableOf().arrayOf();
3207 e.committed = true;
3208 break;
3210 case 'c':
3211 e.committed = true;
3212 goto default;
3214 default:
3215 if (sc && sc.flags & SCOPE.Cfile)
3216 e.type = Type.tchar.sarrayOf(e.len + 1);
3217 else
3218 e.type = Type.tchar.immutableOf().arrayOf();
3219 break;
3221 e.type = e.type.typeSemantic(e.loc, sc);
3222 //type = type.immutableOf();
3223 //printf("type = %s\n", type.toChars());
3225 result = e;
3228 override void visit(TupleExp exp)
3230 static if (LOGSEMANTIC)
3232 printf("+TupleExp::semantic(%s)\n", exp.toChars());
3234 if (exp.type)
3236 result = exp;
3237 return;
3240 if (exp.e0)
3241 exp.e0 = exp.e0.expressionSemantic(sc);
3243 // Run semantic() on each argument
3244 bool err = false;
3245 for (size_t i = 0; i < exp.exps.length; i++)
3247 Expression e = (*exp.exps)[i];
3248 e = e.expressionSemantic(sc);
3249 if (!e.type)
3251 error(exp.loc, "`%s` has no value", e.toChars());
3252 err = true;
3254 else if (e.op == EXP.error)
3255 err = true;
3256 else
3257 (*exp.exps)[i] = e;
3259 if (err)
3260 return setError();
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());
3267 result = exp;
3270 override void visit(ArrayLiteralExp e)
3272 static if (LOGSEMANTIC)
3274 printf("ArrayLiteralExp::semantic('%s')\n", e.toChars());
3276 if (e.type)
3278 result = e;
3279 return;
3282 /* Perhaps an empty array literal [ ] should be rewritten as null?
3285 if (e.basis)
3286 e.basis = e.basis.expressionSemantic(sc);
3287 if (arrayExpressionSemantic(e.elements.peekSlice(), sc) || (e.basis && e.basis.op == EXP.error))
3288 return setError();
3290 expandTuples(e.elements);
3292 if (e.basis)
3293 e.elements.push(e.basis);
3294 Type t0 = arrayExpressionToCommonType(sc, *e.elements);
3295 if (e.basis)
3296 e.basis = e.elements.pop();
3297 if (t0 is null)
3298 return setError();
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());
3308 return setError();
3311 if (global.params.useTypeInfo && Type.dtypeinfo)
3312 semanticTypeInfo(sc, e.type);
3314 result = e;
3317 override void visit(AssocArrayLiteralExp e)
3319 static if (LOGSEMANTIC)
3321 printf("AssocArrayLiteralExp::semantic('%s')\n", e.toChars());
3323 if (e.type)
3325 result = e;
3326 return;
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)
3333 return setError();
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);
3341 return setError();
3344 Type tkey = arrayExpressionToCommonType(sc, *e.keys);
3345 Type tvalue = arrayExpressionToCommonType(sc, *e.values);
3346 if (tkey is null || tvalue is null)
3347 return setError();
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))
3355 return setError();
3357 result = e;
3360 override void visit(StructLiteralExp e)
3362 static if (LOGSEMANTIC)
3364 printf("StructLiteralExp::semantic('%s')\n", e.toChars());
3366 if (e.type)
3368 result = e;
3369 return;
3372 e.sd.size(e.loc);
3373 if (e.sd.sizeok != Sizeok.done)
3374 return setError();
3376 // run semantic() on each element
3377 if (arrayExpressionSemantic(e.elements.peekSlice(), sc))
3378 return setError();
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))
3385 return setError();
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();
3396 return setError();
3399 if (checkFrameAccess(e.loc, sc, e.sd, e.elements.length))
3400 return setError();
3402 e.type = e.stype ? e.stype : e.sd.type;
3403 result = e;
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);
3415 if (!e)
3417 error(cle.loc, "cannot convert initializer `%s` to expression", init.toChars());
3418 return setError();
3420 result = e;
3421 return;
3424 override void visit(TypeExp exp)
3426 if (exp.type.ty == Terror)
3427 return setError();
3429 //printf("TypeExp::semantic(%s)\n", exp.type.toChars());
3430 Expression e;
3431 Type t;
3432 Dsymbol s;
3434 dmd.typesem.resolve(exp.type, exp.loc, sc, e, t, s, true);
3435 if (e)
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);
3450 else if (t)
3452 //printf("t = %d %s\n", t.ty, t.toChars());
3453 exp.type = t.typeSemantic(exp.loc, sc);
3454 e = exp;
3456 else if (s)
3458 //printf("s = %s %s\n", s.kind(), s.toChars());
3459 e = symbolToExp(s, exp.loc, sc, true);
3461 else
3462 assert(0);
3464 exp.type.checkComplexTransition(exp.loc, sc);
3466 result = e;
3469 override void visit(ScopeExp exp)
3471 static if (LOGSEMANTIC)
3473 printf("+ScopeExp::semantic(%p '%s')\n", exp, exp.toChars());
3475 if (exp.type)
3477 result = exp;
3478 return;
3481 ScopeDsymbol sds2 = exp.sds;
3482 TemplateInstance ti = sds2.isTemplateInstance();
3483 while (ti)
3485 WithScopeSymbol withsym;
3486 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc))
3487 return setError();
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);
3493 return;
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);
3506 return;
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);
3517 return;
3520 // ti is an instance which requires IFTI.
3521 exp.sds = ti;
3522 exp.type = Type.tvoid;
3523 result = exp;
3524 return;
3526 ti.dsymbolSemantic(sc);
3527 if (!ti.inst || ti.errors)
3528 return setError();
3530 Dsymbol s = ti.toAlias();
3531 if (s == ti)
3533 exp.sds = ti;
3534 exp.type = Type.tvoid;
3535 result = exp;
3536 return;
3538 sds2 = s.isScopeDsymbol();
3539 if (sds2)
3541 ti = sds2.isTemplateInstance();
3542 //printf("+ sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
3543 continue;
3546 if (auto v = s.isVarDeclaration())
3548 if (!v.type)
3550 error(exp.loc, "forward reference of %s `%s`", v.kind(), v.toChars());
3551 return setError();
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.
3562 * template foo(T) {
3563 * enum bool foo = foo; // recursive definition check (v.inuse)
3565 * template bar(T) {
3566 * enum bool bar = bar!T; // recursive instantiation check (ti.inuse)
3569 if (ti.inuse)
3571 error(exp.loc, "recursive expansion of %s `%s`", ti.kind(), ti.toPrettyChars());
3572 return setError();
3574 v.checkDeprecated(exp.loc, sc);
3575 auto e = v.expandInitializer(exp.loc);
3576 ti.inuse++;
3577 e = e.expressionSemantic(sc);
3578 ti.inuse--;
3579 result = e;
3580 return;
3584 //printf("s = %s, '%s'\n", s.kind(), s.toChars());
3585 auto e = symbolToExp(s, exp.loc, sc, true);
3586 //printf("-1ScopeExp::semantic()\n");
3587 result = e;
3588 return;
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);
3599 return;
3602 if (auto td = sds2.isTemplateDeclaration())
3604 result = (new TemplateExp(exp.loc, td)).expressionSemantic(sc);
3605 return;
3608 exp.sds = sds2;
3609 exp.type = Type.tvoid;
3610 //printf("-2ScopeExp::semantic() %s\n", toChars());
3611 result = exp;
3615 * Sets the `lowering` field of a `NewExp` to a call to `_d_newitemT` unless
3616 * compiling with `-betterC` or within `__traits(compiles)`.
3618 * Params:
3619 * ne = the `NewExp` to lower
3621 private void tryLowerToNewItem(NewExp ne)
3623 if (!global.params.useGC || !sc.needsCodegen())
3624 return;
3626 auto hook = global.params.tracegc ? Id._d_newitemTTrace : Id._d_newitemT;
3627 if (!verifyHookExist(ne.loc, *sc, hook, "new struct"))
3628 return;
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_);
3642 tiargs.push(t);
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());
3664 if (exp.thisexp)
3665 printf("\tthisexp = %s\n", exp.thisexp.toChars());
3666 printf("\tnewtype: %s\n", exp.newtype.toChars());
3668 if (exp.type) // if semantic() already run
3670 result = exp;
3671 return;
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
3680 // not a tuple.
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);
3691 else
3693 edim = ts.dim;
3694 exp.newtype = ts.next;
3698 ClassDeclaration cdthis = null;
3699 if (exp.thisexp)
3701 exp.thisexp = exp.thisexp.expressionSemantic(sc);
3702 if (exp.thisexp.op == EXP.error)
3703 return setError();
3705 cdthis = exp.thisexp.type.isClassHandle();
3706 if (!cdthis)
3708 error(exp.loc, "`this` for nested class must be a class type, not `%s`", exp.thisexp.type.toChars());
3709 return setError();
3712 sc = sc.push(cdthis);
3713 exp.type = exp.newtype.typeSemantic(exp.loc, sc);
3714 sc = sc.pop();
3716 else
3718 exp.type = exp.newtype.typeSemantic(exp.loc, sc);
3720 if (exp.type.ty == Terror)
3721 return setError();
3723 if (edim)
3725 if (exp.type.toBasetype().ty == Ttuple)
3727 // --> new T[edim]
3728 exp.type = new TypeSArray(exp.type, edim);
3729 exp.type = exp.type.typeSemantic(exp.loc, sc);
3730 if (exp.type.ty == Terror)
3731 return setError();
3733 else
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))
3747 return setError();
3749 if (preFunctionParameters(sc, exp.argumentList))
3751 return setError();
3754 if (exp.thisexp && tb.ty != Tclass)
3756 error(exp.loc, "`.new` is only for allocating nested classes, not `%s`", tb.toChars());
3757 return setError();
3760 const size_t nargs = exp.arguments ? exp.arguments.length : 0;
3761 Expression newprefix = null;
3763 if (auto tc = tb.isTypeClass())
3765 auto cd = tc.sym;
3766 if (cd.errors)
3767 return setError();
3768 cd.size(exp.loc);
3769 if (cd.sizeok != Sizeok.done)
3770 return setError();
3771 if (!cd.ctor)
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());
3776 return setError();
3779 if (cd.isInterfaceDeclaration())
3781 error(exp.loc, "cannot create instance of interface `%s`", cd.toChars());
3782 return setError();
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());
3798 return setError();
3800 // checkDeprecated() is already done in newtype.typeSemantic().
3802 if (cd.isNested())
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())
3812 if (!cdthis)
3814 void noReferenceToOuterClass()
3816 if (cd.isAnonymous)
3817 error(exp.loc, "cannot construct anonymous nested class because no implicit `this` reference to outer class is available");
3818 else
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());
3821 return setError();
3824 if (!sc.hasThis)
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())
3831 if (!sp)
3832 return noReferenceToOuterClass();
3833 ClassDeclaration cdp = sp.isClassDeclaration();
3834 if (!cdp)
3835 continue;
3836 if (cdp == cdn || cdn.isBaseOf(cdp, null))
3837 break;
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)
3844 return setError();
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());
3852 return setError();
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());
3858 return setError();
3861 else if (exp.thisexp)
3863 error(exp.loc, "`.new` is only for allocating nested classes");
3864 return setError();
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());
3873 return setError();
3876 else
3877 assert(0);
3879 else if (exp.thisexp)
3881 error(exp.loc, "`.new` is only for allocating nested classes");
3882 return setError();
3885 if (cd.vthis2)
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());
3895 return setError();
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());
3904 return setError();
3907 if (cd.ctor)
3909 FuncDeclaration f = resolveFuncCall(exp.loc, sc, cd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard);
3910 if (!f || f.errors)
3911 return setError();
3913 checkFunctionAttributes(exp, sc, f);
3914 checkAccess(cd, exp.loc, sc, f);
3916 TypeFunction tf = f.type.isTypeFunction();
3917 if (!exp.arguments)
3918 exp.arguments = new Expressions();
3919 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix))
3920 return setError();
3922 exp.member = f.isCtorDeclaration();
3923 assert(exp.member);
3925 else
3927 if (nargs)
3929 error(exp.loc, "no constructor for `%s`", cd.toChars());
3930 return setError();
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)
3942 continue;
3943 v.inuse++;
3944 v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret);
3945 import dmd.semantic2 : lowerStaticAAs;
3946 lowerStaticAAs(v, sc);
3947 v.inuse--;
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())
3957 assert(cd.ctor);
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);
3967 Expression idVal;
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);
3979 return;
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"))
3989 return setError();
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`
3996 tiargs.push(t);
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())
4014 auto sd = ts.sym;
4015 sd.size(exp.loc);
4016 if (sd.sizeok != Sizeok.done)
4017 return setError();
4018 if (!sd.ctor)
4019 sd.ctor = sd.searchCtor();
4020 if (sd.noDefaultCtor && !nargs)
4022 error(exp.loc, "default construction is disabled for type `%s`", sd.type.toChars());
4023 return setError();
4025 // checkDeprecated() is already done in newtype.typeSemantic().
4027 if (sd.disableNew)
4029 error(exp.loc, "cannot allocate `struct %s` with `new` because it is annotated with `@disable new()`",
4030 originalNewtype.toChars());
4031 return setError();
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);
4041 if (!f || f.errors)
4042 return setError();
4044 checkFunctionAttributes(exp, sc, f);
4045 checkAccess(sd, exp.loc, sc, f);
4047 TypeFunction tf = f.type.isTypeFunction();
4048 if (!exp.arguments)
4049 exp.arguments = new Expressions();
4050 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix))
4051 return setError();
4053 exp.member = f.isCtorDeclaration();
4054 assert(exp.member);
4056 if (checkFrameAccess(exp.loc, sc, sd, sd.fields.length))
4057 return setError();
4059 else
4061 if (exp.names)
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
4068 if (!exp.arguments)
4069 return setError();
4071 else if (!exp.arguments)
4073 exp.arguments = new Expressions();
4076 if (!sd.fit(exp.loc, sc, exp.arguments, tb))
4077 return setError();
4079 if (!sd.fill(exp.loc, *exp.arguments, false))
4080 return setError();
4082 if (checkFrameAccess(exp.loc, sc, sd, exp.arguments ? exp.arguments.length : 0))
4083 return setError();
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))
4090 return setError();
4094 exp.type = exp.type.pointerTo();
4095 tryLowerToNewItem(exp);
4097 else if (tb.ty == Tarray)
4099 if (!nargs)
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");
4104 return setError();
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());
4113 return setError();
4115 for (size_t i = 0; i < nargs; i++)
4117 if (tb.ty != Tarray)
4119 error(exp.loc, "too many arguments for array");
4120 return setError();
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());
4127 return setError();
4130 arg = resolveProperties(sc, arg);
4131 arg = arg.implicitCastTo(sc, Type.tsize_t);
4132 if (arg.op == EXP.error)
4133 return setError();
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());
4139 return setError();
4141 (*exp.arguments)[i] = arg;
4142 tb = tb.isTypeDArray().next.toBasetype();
4145 else if (tb.isscalar())
4147 if (!nargs)
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());
4155 return setError();
4157 Expression e = (*exp.arguments)[0];
4158 e = e.implicitCastTo(sc, tb);
4159 (*exp.arguments)[0] = e;
4161 else
4163 error(exp.loc, "more than one argument for construction of `%s`", exp.type.toChars());
4164 return setError();
4167 exp.type = exp.type.pointerTo();
4168 tryLowerToNewItem(exp);
4170 else if (tb.ty == Taarray)
4172 // e.g. `new Alias(args)`
4173 if (nargs)
4175 error(exp.loc, "`new` cannot take arguments for an associative array");
4176 return setError();
4179 else
4181 error(exp.loc, "cannot create a `%s` with `new`", exp.type.toChars());
4182 return setError();
4185 //printf("NewExp: '%s'\n", toChars());
4186 //printf("NewExp:type '%s'\n", type.toChars());
4187 semanticTypeInfo(sc, exp.type);
4189 if (newprefix)
4191 result = Expression.combine(newprefix, exp);
4192 return;
4194 result = 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);
4210 sc = sc.pop();
4212 if (!e.cd.errors && sc.intypeof && !sc.parent.inNonRoot())
4214 ScopeDsymbol sds = sc.tinst ? cast(ScopeDsymbol)sc.tinst : sc._module;
4215 if (!sds.members)
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);
4233 if (!e.type)
4234 e.type = e.var.type.pointerTo();
4236 if (auto v = e.var.isVarDeclaration())
4238 if (v.checkNestedReference(sc, e.loc))
4239 return setError();
4241 else if (auto f = e.var.isFuncDeclaration())
4243 if (f.checkNestedReference(sc, e.loc))
4244 return setError();
4247 result = e;
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();
4260 if (fd)
4262 //printf("L%d fd = %s\n", __LINE__, f.toChars());
4263 if (!fd.functionSemantic())
4264 return setError();
4267 if (!e.type)
4268 e.type = e.var.type;
4269 if (e.type && !e.type.deco)
4271 auto decl = e.var.isDeclaration();
4272 if (decl)
4273 decl.inuse++;
4274 e.type = e.type.typeSemantic(e.loc, sc);
4275 if (decl)
4276 decl.inuse--;
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);
4285 if (vd)
4287 if (vd.checkNestedReference(sc, e.loc))
4288 return setError();
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);
4295 else if (fd)
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))
4301 return setError();
4303 else if (auto od = e.var.isOverDeclaration())
4305 e.type = Type.tvoid; // ambiguous type?
4308 result = e;
4311 override void visit(FuncExp exp)
4313 static if (LOGSEMANTIC)
4315 printf("FuncExp::semantic(%s)\n", exp.toChars());
4316 if (exp.fd.treq)
4317 printf(" treq = %s\n", exp.fd.treq.toChars());
4320 if (exp.type)
4322 result = exp;
4323 return;
4326 Expression e = exp;
4327 uint olderrors;
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)
4338 //if (fd.treq)
4339 // fd.treq = fd.treq.dsymbolSemantic(loc, sc);
4341 exp.genIdent(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();
4349 if (tfv)
4351 TypeFunction tfl = cast(TypeFunction)exp.fd.type;
4352 tfl.next = tfv.nextOf();
4356 //printf("td = %p, treq = %p\n", td, fd.treq);
4357 if (exp.td)
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
4365 FuncExp fe;
4366 if (exp.matchType(exp.fd.treq, sc, &fe, sc.eSink) > MATCH.nomatch)
4367 e = fe;
4368 else
4369 e = ErrorExp.get();
4371 goto Ldone;
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;
4386 e = ErrorExp.get();
4387 goto Ldone;
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
4396 // the error
4397 if (exp.fd.type.isTypeError())
4399 e = ErrorExp.get();
4400 goto Ldone;
4402 exp.type = new TypeDelegate(exp.fd.type.isTypeFunction());
4403 exp.type = exp.type.typeSemantic(exp.loc, sc);
4405 exp.fd.tok = TOK.delegate_;
4407 else
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++;
4430 Ldone:
4431 sc = sc.pop();
4432 result = e;
4436 * Perform semantic analysis on function literals
4438 * Test the following construct:
4439 * ---
4440 * (x, y, z) { return x + y + z; }(42, 84, 1992);
4441 * ---
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)
4451 return checkarg;
4454 exp.genIdent(sc);
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];
4465 if (p.defaultArg)
4466 dim = arguments.length;
4469 if ((tfl.parameterList.varargs == VarArg.none && arguments.length > dim) ||
4470 arguments.length < dim)
4472 OutBuffer buf;
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),
4477 buf.peekChars());
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)
4493 if (u == dim)
4494 break;
4496 if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident)
4498 Expression e = (*arguments)[u];
4499 tiargs.push(e.type);
4500 break;
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());
4517 if (exp.type)
4519 result = exp;
4520 return; // semantic() already run
4523 Objects* tiargs = null; // initial list of template arguments
4524 Expression ethis = null;
4525 Type tthis = null;
4526 Expression e1org = exp.e1;
4528 if (auto ce = exp.e1.isCommaExp())
4530 /* Rewrite (a,b)(args) as (a,(b(args)))
4532 exp.e1 = ce.e2;
4533 ce.e2 = exp;
4534 result = ce.expressionSemantic(sc);
4535 return;
4537 if (DelegateExp de = exp.e1.isDelegateExp())
4539 exp.e1 = new DotVarExp(de.loc, de.e1, de.func, de.hasOverloads);
4540 visit(exp);
4541 return;
4543 if (FuncExp fe = exp.e1.isFuncExp())
4545 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
4546 preFunctionParameters(sc, exp.argumentList))
4547 return setError();
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)
4553 result = exp.e1;
4554 return;
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);
4564 return;
4568 if (Expression ex = resolveUFCS(sc, exp))
4570 result = ex;
4571 return;
4574 /* This recognizes:
4575 * foo!(tiargs)(funcargs)
4577 if (ScopeExp se = exp.e1.isScopeExp())
4579 TemplateInstance ti = se.sds.isTemplateInstance();
4580 if (ti)
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))
4587 return setError();
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);
4592 goto Ldotti;
4594 if (ti.needsTypeInference(sc, 1))
4596 /* Go with partial explicit specialization
4598 tiargs = ti.tiargs;
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);
4604 else
4605 exp.e1 = new OverExp(exp.loc, ti.tempdecl.isOverloadSet());
4607 else
4609 Expression e1x = exp.e1.expressionSemantic(sc);
4610 if (e1x.op == EXP.error)
4612 result = e1x;
4613 return;
4615 exp.e1 = e1x;
4620 /* This recognizes:
4621 * expr.foo!(tiargs)(funcargs)
4623 Ldotti:
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))
4632 return setError();
4633 if (ti.needsTypeInference(sc, 1))
4635 /* Go with partial explicit specialization
4637 tiargs = ti.tiargs;
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);
4645 else
4646 exp.e1 = new DotExp(exp.loc, se.e1, new OverExp(exp.loc, ti.tempdecl.isOverloadSet()));
4648 else
4650 Expression e1x = exp.e1.expressionSemantic(sc);
4651 if (e1x.op == EXP.error)
4653 result = e1x;
4654 return;
4656 exp.e1 = e1x;
4661 Type att = null;
4662 Lagain:
4663 //printf("Lagain: %s\n", toChars());
4664 exp.f = null;
4665 if (exp.e1.op == EXP.this_ || exp.e1.op == EXP.super_)
4667 // semantic() run later for these
4669 else
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)
4680 goto Ldotti;
4683 else
4685 __gshared int nest;
4686 if (++nest > global.recursionLimit)
4688 error(exp.loc, "recursive evaluation of `%s`", exp.toChars());
4689 --nest;
4690 return setError();
4692 Expression ex = unaSemantic(exp, sc);
4693 --nest;
4694 if (ex)
4696 result = ex;
4697 return;
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))
4717 return setError();
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)
4730 ethis = de.e1;
4731 tthis = de.e1.type;
4732 exp.e1 = de.e2;
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().
4751 if (numArgs == 1)
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);
4760 (*decls)[0] = s;
4761 s = new LinkDeclaration(s.loc, LINK.c, decls);
4762 result = new DeclarationExp(exp.loc, s);
4763 result = result.expressionSemantic(sc);
4765 else
4767 error(arg.loc, "identifier or `(` expected");
4768 result = ErrorExp.get();
4770 return;
4772 error(exp.loc, "identifier or `(` expected before `)`");
4773 result = ErrorExp.get();
4774 return;
4778 Type t1 = exp.e1.type ? exp.e1.type.toBasetype() : null;
4780 if (exp.e1.op == EXP.error)
4782 result = exp.e1;
4783 return;
4785 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
4786 preFunctionParameters(sc, exp.argumentList))
4787 return setError();
4789 // Check for call operator overload
4790 if (t1)
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)
4797 return setError();
4798 if (!sd.ctor)
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
4806 constructor.
4808 if (sd.ctor)
4810 auto ctor = sd.ctor.isCtorDeclaration();
4811 if (ctor && ctor.isCpCtor && ctor.isGenerated())
4812 sd.ctor = null;
4815 // First look for constructor
4816 if (exp.e1.op == EXP.type && sd.ctor)
4818 if (!sd.noDefaultCtor && !(exp.arguments && exp.arguments.length))
4819 goto Lx;
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())
4829 goto Lx;
4831 auto sle = new StructLiteralExp(exp.loc, sd, null, exp.e1.type);
4832 if (!sd.fill(exp.loc, *sle.elements, true))
4833 return setError();
4834 if (checkFrameAccess(exp.loc, sc, sd, sle.elements.length))
4835 return setError();
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;
4846 Expression e = sle;
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));
4859 else
4860 assert(0);
4861 e = new CallExp(exp.loc, e, exp.arguments);
4862 e = e.expressionSemantic(sc);
4863 result = e;
4864 return;
4866 // No constructor, look for overload of opCall
4867 if (search_function(sd, Id.call))
4868 goto L1;
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);
4875 goto Lagain;
4877 error(exp.loc, "%s `%s` does not overload ()", sd.kind(), sd.toChars());
4878 return setError();
4881 /* It's a struct literal
4884 Expressions* resolvedArgs = exp.arguments;
4885 if (exp.names)
4887 resolvedArgs = resolveStructLiteralNamedArgs(sd, exp.e1.type, sc, exp.loc,
4888 (*exp.names)[],
4889 (size_t i, Type t) => (*exp.arguments)[i],
4890 i => (*exp.arguments)[i].loc
4892 if (!resolvedArgs)
4894 result = ErrorExp.get();
4895 return;
4899 Expression e = new StructLiteralExp(exp.loc, sd, resolvedArgs, exp.e1.type);
4900 e = e.expressionSemantic(sc);
4901 result = e;
4902 return;
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);
4911 result = e;
4912 return;
4914 else if (exp.e1.op == EXP.type && t1.isscalar())
4916 Expression e;
4918 // Make sure to use the enum type itself rather than its
4919 // base type
4920 // https://issues.dlang.org/show_bug.cgi?id=16346
4921 if (exp.e1.type.ty == Tenum)
4923 t1 = exp.e1.type;
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);
4936 else
4938 error(exp.loc, "more than one argument for construction of `%s`", t1.toChars());
4939 return setError();
4941 e = e.expressionSemantic(sc);
4942 result = e;
4943 return;
4947 FuncDeclaration resolveOverloadSet(Loc loc, Scope* sc,
4948 OverloadSet os, Objects* tiargs, Type tthis, ArgumentList argumentList)
4950 FuncDeclaration f = null;
4951 foreach (s; os.a)
4953 if (tiargs && s.isFuncDeclaration())
4954 continue;
4955 if (auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, argumentList, FuncResolveFlag.quiet))
4957 if (f2.errors)
4958 return null;
4959 if (f)
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.
4970 else
4971 ScopeDsymbol.multiplyDefined(loc, f, f2); // issue error
4973 else
4974 f = f2;
4977 if (!f)
4979 .error(loc, "no overload matches for `%s`", exp.toChars());
4980 errorSupplemental(loc, "Candidates are:");
4981 foreach (s; os.a)
4983 overloadApply(s, (ds){
4984 if (auto fd = ds.isFuncDeclaration())
4985 .errorSupplemental(ds.loc, "%s%s", fd.toChars(),
4986 fd.type.toTypeFunction().parameterList.parametersTypeToChars());
4987 else
4988 .errorSupplemental(ds.loc, "%s", ds.toChars());
4989 return 0;
4993 else if (f.errors)
4994 f = null;
4995 return f;
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
5004 DotVarExp dve;
5005 DotTemplateExp dte;
5006 Dsymbol s;
5007 if (exp.e1.op == EXP.dotVariable)
5009 dve = cast(DotVarExp)exp.e1;
5010 dte = null;
5011 s = dve.var;
5012 tiargs = null;
5014 else
5016 dve = null;
5017 dte = cast(DotTemplateExp)exp.e1;
5018 s = dte.td;
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)
5024 return setError();
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;
5031 auto ad2 = b.sym;
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);
5035 assert(vi >= 0);
5036 exp.f = ad2.vtbl[vi].isFuncDeclaration();
5037 assert(exp.f);
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)
5045 result = ue.e1;
5046 return;
5048 ethis = ue.e1;
5049 tthis = ue.e1.type;
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))
5053 return setError();
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());
5063 return setError();
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);
5080 return setError();
5083 if (!exp.f.needThis())
5085 exp.e1 = Expression.combine(ue.e1, new VarExp(exp.loc, exp.f, false));
5087 else
5089 if (ue1old.checkRightThis(sc))
5090 return setError();
5091 if (exp.e1.op == EXP.dotVariable)
5093 dve.var = exp.f;
5094 exp.e1.type = exp.f.type;
5096 else
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)
5101 return setError();
5102 ue = cast(UnaExp)exp.e1;
5104 version (none)
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;
5128 if (ad != cd)
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();
5141 exp.e1 = e;
5143 t1 = exp.e1.type;
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_;
5151 if (isSuper)
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");
5157 return setError();
5159 if (!cd.baseClass.ctor)
5161 error(exp.loc, "no super class constructor for `%s`", cd.baseClass.toChars());
5162 return setError();
5165 else
5167 // `this` call expression must be inside a
5168 // constructor
5169 if (!ad || !sc.func.isCtorDeclaration())
5171 error(exp.loc, "constructor call must be in a constructor");
5172 return setError();
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);
5200 else
5201 exp.f = resolveFuncCall(exp.loc, sc, ctor, null, tthis, exp.argumentList, FuncResolveFlag.standard);
5203 if (!exp.f || exp.f.errors)
5204 return setError();
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)
5213 return setError();
5214 t1 = exp.e1.type;
5216 // BUG: this should really be done by checking the static
5217 // call graph
5218 if (exp.f == sc.func)
5220 error(exp.loc, "cyclic constructor call");
5221 return setError();
5224 else if (auto oe = exp.e1.isOverExp())
5226 exp.f = resolveOverloadSet(exp.loc, sc, oe.vars, tiargs, tthis, exp.argumentList);
5227 if (!exp.f)
5228 return setError();
5229 if (ethis)
5230 exp.e1 = new DotVarExp(exp.loc, ethis, exp.f, false);
5231 else
5232 exp.e1 = new VarExp(exp.loc, exp.f, false);
5233 goto Lagain;
5235 else if (!t1)
5237 error(exp.loc, "function expected before `()`, not `%s`", exp.e1.toChars());
5238 return setError();
5240 else if (t1.ty == Terror)
5242 return setError();
5244 else if (t1.ty != Tfunction)
5246 TypeFunction tf;
5247 const(char)* p;
5248 Dsymbol s;
5249 exp.f = null;
5250 if (auto fe = exp.e1.isFuncExp())
5252 // function literal that direct called is always inferred.
5253 assert(fe.fd);
5254 exp.f = fe.fd;
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;
5263 p = "delegate";
5265 else if (auto tfx = t1.isPtrToFunction())
5267 tf = tfx;
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);
5274 if (!exp.f)
5275 return setError();
5276 if (exp.f.needThis())
5278 dve.var = exp.f;
5279 dve.type = exp.f.type;
5280 dve.hasOverloads = false;
5281 goto Lagain;
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);
5286 return;
5288 else if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.isOverDeclaration())
5290 s = (cast(VarExp)exp.e1).var;
5291 goto L2;
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)
5300 return setError();
5301 if (exp.f.needThis())
5303 if (hasThis(sc))
5305 // Supply an implicit 'this', as in
5306 // this.ident
5307 exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), exp.f, false);
5308 goto Lagain;
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);
5316 goto Lagain;
5318 else
5320 error(exp.loc, "function expected before `()`, not `%s` of type `%s`", exp.e1.toChars(), exp.e1.type.toChars());
5321 return setError();
5324 const(char)* failMessage;
5325 if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc))
5327 OutBuffer buf;
5328 buf.writeByte('(');
5329 argExpTypesToCBuffer(buf, exp.arguments);
5330 buf.writeByte(')');
5331 if (tthis)
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());
5337 if (failMessage)
5338 errorSupplemental(exp.loc, "%s", failMessage);
5339 return setError();
5341 // Purity and safety check should run after testing arguments matching
5342 if (exp.f)
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))
5348 return setError();
5350 else if (sc.func && sc.intypeof != 1 && !(sc.flags & (SCOPE.ctfe | SCOPE.debug_)))
5352 bool err = false;
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());
5357 err = true;
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());
5363 err = true;
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());
5370 err = true;
5372 if (err)
5373 return setError();
5376 if (t1.ty == Tpointer)
5378 Expression e = new PtrExp(exp.loc, exp.e1);
5379 e.type = tf;
5380 exp.e1 = e;
5382 t1 = tf;
5384 else if (VarExp ve = exp.e1.isVarExp())
5386 // Do overload resolution
5387 exp.f = ve.var.isFuncDeclaration();
5388 assert(exp.f);
5389 tiargs = null;
5391 if (exp.f.overnext)
5392 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.overloadOnly);
5393 else
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))
5400 OutBuffer buf;
5401 buf.writeByte('(');
5402 argExpTypesToCBuffer(buf, exp.arguments);
5403 buf.writeByte(')');
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());
5415 if (failMessage)
5416 errorSupplemental(exp.loc, "%s", failMessage);
5417 exp.f = null;
5420 if (!exp.f || exp.f.errors)
5421 return setError();
5423 if (exp.f.needThis())
5425 // Change the ancestor lambdas to delegate before hasThis(sc) call.
5426 if (exp.f.checkNestedReference(sc, exp.loc))
5427 return setError();
5429 auto memberFunc = hasThis(sc);
5430 if (memberFunc && haveSameThis(memberFunc, exp.f))
5432 // Supply an implicit 'this', as in
5433 // this.ident
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.
5437 goto Lagain;
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
5447 if (exp.f.overnext)
5448 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.standard);
5450 if (!exp.f || exp.f.errors)
5451 return setError();
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))
5462 return setError();
5464 ethis = null;
5465 tthis = null;
5467 if (ve.hasOverloads)
5469 exp.e1 = new VarExp(ve.loc, exp.f, false);
5470 exp.e1.type = exp.f.type;
5472 t1 = exp.f.type;
5474 assert(t1.ty == Tfunction);
5476 Expression argprefix;
5477 if (!exp.arguments)
5478 exp.arguments = new Expressions();
5479 if (functionParameters(exp.loc, sc, cast(TypeFunction)t1, ethis, tthis, exp.argumentList, exp.f, &exp.type, &argprefix))
5480 return setError();
5482 if (!exp.type)
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());
5487 return setError();
5490 if (exp.f && exp.f.tintro)
5492 Type t = exp.type;
5493 int offset = 0;
5494 TypeFunction tf = cast(TypeFunction)exp.f.tintro;
5495 if (tf.next.isBaseOf(t, &offset) && offset)
5497 exp.type = tf.next;
5498 result = Expression.combine(argprefix, exp.castTo(sc, t));
5499 return;
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);
5511 if (isSuper)
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)
5520 Loc loc = exp.loc;
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());
5558 return setError();
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)
5570 if (e.type)
5572 result = e;
5573 return;
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
5584 * wrapper.
5586 Dsymbol s = e.declaration;
5588 while (1)
5590 AttribDeclaration ad = s.isAttribDeclaration();
5591 if (ad)
5593 if (ad.decl && ad.decl.length == 1)
5595 s = (*ad.decl)[0];
5596 continue;
5599 break;
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.
5605 if (s.ident)
5607 VarDeclaration v = s.isVarDeclaration();
5608 if (v)
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
5619 v.inuse++;
5620 v.type = v.type.typeSemantic(v.loc, sc2);
5621 v.inuse--;
5622 sc2.pop();
5624 else
5626 /* Do semantic() on initializer first so this will be illegal:
5627 * int a = a;
5629 e.declaration.dsymbolSemantic(sc);
5630 s.parent = sc.parent;
5634 if (!sc.insert(s))
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());
5640 return setError();
5643 if (v && (sc.flags & SCOPE.Cfile))
5645 /* Do semantic() on initializer last so this will be legal:
5646 * int a = a;
5648 e.declaration.dsymbolSemantic(sc);
5649 s.parent = sc.parent;
5652 if (sc.func)
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
5669 if (!s.localNum)
5671 error(e.loc, "more than 65535 symbols with name `%s` generated", s.ident.toChars());
5672 return setError();
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)
5694 Dsymbol s2;
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))
5702 if (sc.func.fes)
5704 deprecation(e.loc, "%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
5706 else
5708 error(e.loc, "%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
5709 return setError();
5717 if (!s.isVarDeclaration())
5719 Scope* sc2 = sc;
5720 if (sc2.stc & (STC.pure_ | STC.nothrow_ | STC.nogc))
5721 sc2 = sc.push();
5722 sc2.stc &= ~(STC.pure_ | STC.nothrow_ | STC.nogc);
5723 e.declaration.dsymbolSemantic(sc2);
5724 if (sc2 != sc)
5725 sc2.pop();
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;
5739 result = e;
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);
5753 if (ta)
5755 dmd.typesem.resolve(ta, exp.loc, sc, ea, ta, sa, true);
5758 if (ea)
5760 if (auto sym = getDsymbol(ea))
5761 ea = symbolToExp(sym, exp.loc, sc, false);
5762 else
5763 ea = ea.expressionSemantic(sc);
5764 ea = resolveProperties(sc, ea);
5765 ta = ea.type;
5766 if (ea.op == EXP.type)
5767 ea = null;
5770 if (!ta)
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() : ""));
5774 return setError();
5777 ta.checkComplexTransition(exp.loc, sc);
5779 Expression e;
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");
5786 e = ErrorExp.get();
5788 else if (!Type.typeinfoclass)
5790 error(exp.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
5791 e = ErrorExp.get();
5793 else
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)
5804 e = ErrorExp.get();
5806 else
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)
5818 genObjCode = false;
5821 e.type = getTypeInfoType(exp.loc, ta, sc, genObjCode);
5822 semanticTypeInfo(sc, ta);
5824 if (ea)
5826 e = new CommaExp(exp.loc, ea, e); // execute ea
5827 e = e.expressionSemantic(sc);
5830 result = e;
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;
5845 result = e;
5848 override void visit(IsExp e)
5850 /* is(targ id tok tspec)
5851 * is(targ id : tok2)
5852 * is(targ id == tok2)
5854 Type tded = null;
5856 void yes()
5858 //printf("yes\n");
5859 if (!e.id)
5861 result = IntegerExp.createBool(true);
5862 return;
5865 Dsymbol s;
5866 Tuple tup = isTuple(tded);
5867 if (tup)
5868 s = new TupleDeclaration(e.loc, e.id, &tup.objects);
5869 else
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);
5888 void no()
5890 result = IntegerExp.createBool(false);
5891 //printf("no\n");
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");
5901 return setError();
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);
5910 if (sym is null)
5911 return no();
5912 Package p = resolveIsPackage(sym);
5913 if (p is null)
5914 return no();
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.
5916 return no();
5917 else if(e.tok2 == TOK.module_ && !(p.isModule() || p.isPackageMod()))
5918 return no();
5919 tded = e.targ;
5920 return yes();
5924 Scope* sc2 = sc.copy(); // keep sc.flags
5925 sc2.tinst = null;
5926 sc2.minst = null;
5927 sc2.flags |= SCOPE.fullinst;
5928 Type t = e.targ.trySemantic(e.loc, sc2);
5929 sc2.pop();
5930 if (!t) // errors, so condition is false
5931 return no();
5932 e.targ = t;
5935 if (e.tok2 != TOK.reserved)
5937 switch (e.tok2)
5939 case TOK.struct_:
5940 if (e.targ.ty != Tstruct)
5941 return no();
5942 if ((cast(TypeStruct)e.targ).sym.isUnionDeclaration())
5943 return no();
5944 tded = e.targ;
5945 break;
5947 case TOK.union_:
5948 if (e.targ.ty != Tstruct)
5949 return no();
5950 if (!(cast(TypeStruct)e.targ).sym.isUnionDeclaration())
5951 return no();
5952 tded = e.targ;
5953 break;
5955 case TOK.class_:
5956 if (e.targ.ty != Tclass)
5957 return no();
5958 if ((cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
5959 return no();
5960 tded = e.targ;
5961 break;
5963 case TOK.interface_:
5964 if (e.targ.ty != Tclass)
5965 return no();
5966 if (!(cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
5967 return no();
5968 tded = e.targ;
5969 break;
5971 case TOK.const_:
5972 if (!e.targ.isConst())
5973 return no();
5974 tded = e.targ;
5975 break;
5977 case TOK.immutable_:
5978 if (!e.targ.isImmutable())
5979 return no();
5980 tded = e.targ;
5981 break;
5983 case TOK.shared_:
5984 if (!e.targ.isShared())
5985 return no();
5986 tded = e.targ;
5987 break;
5989 case TOK.inout_:
5990 if (!e.targ.isWild())
5991 return no();
5992 tded = e.targ;
5993 break;
5995 case TOK.super_:
5996 // If class or interface, get the base class and interfaces
5997 if (e.targ.ty != Tclass)
5998 return no();
5999 else
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);
6013 break;
6015 case TOK.enum_:
6016 if (e.targ.ty != Tenum)
6017 return no();
6018 if (e.id)
6019 tded = (cast(TypeEnum)e.targ).sym.getMemtype(e.loc);
6020 else
6021 tded = e.targ;
6023 if (tded.ty == Terror)
6024 return setError();
6025 break;
6027 case TOK.delegate_:
6028 if (e.targ.ty != Tdelegate)
6029 return no();
6030 tded = (cast(TypeDelegate)e.targ).next; // the underlying function type
6031 break;
6033 case TOK.function_:
6034 if (e.targ.ty != Tfunction)
6035 return no();
6036 goto case;
6037 case TOK.parameters:
6039 if (auto tf = e.targ.isFunction_Delegate_PtrToFunction())
6040 tded = tf;
6041 else
6042 return no();
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)
6054 return setError();
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);
6058 break;
6060 case TOK.return_:
6061 /* Get the 'return type' for the function,
6062 * delegate, or pointer to function.
6064 if (auto tf = e.targ.isFunction_Delegate_PtrToFunction())
6065 tded = tf.next;
6066 else
6067 return no();
6068 break;
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);
6077 if (!tded)
6078 return no();
6079 // not valid for a parameter
6080 break;
6082 case TOK.vector:
6083 if (e.targ.ty != Tvector)
6084 return no();
6085 tded = (cast(TypeVector)e.targ).basetype;
6086 break;
6088 default:
6089 assert(0);
6092 // https://issues.dlang.org/show_bug.cgi?id=18753
6093 if (tded)
6094 return yes();
6095 return no();
6097 else if (e.tspec && !e.id && !(e.parameters && e.parameters.length))
6099 /* Evaluate to true if targ matches tspec
6100 * is(targ == tspec)
6101 * is(targ : 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))
6117 return yes();
6118 else
6119 return no();
6121 else if (preventAliasThis && e.targ.ty == Tclass)
6123 if ((cast(TypeClass) e.targ).implicitConvToWithoutAliasThis(e.tspec))
6124 return yes();
6125 else
6126 return no();
6128 else if (e.targ.implicitConvTo(e.tspec))
6129 return yes();
6130 else
6131 return no();
6133 else /* == */
6135 if (e.targ.equals(e.tspec))
6136 return yes();
6137 else
6138 return no();
6141 else if (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);
6156 dedtypes.zero();
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))
6162 return no();
6164 else
6166 tded = cast(Type)dedtypes[0];
6167 if (!tded)
6168 tded = e.targ;
6169 Objects tiargs = Objects(1);
6170 tiargs[0] = e.targ;
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)
6181 return no();
6182 s.dsymbolSemantic(sc);
6183 if (!sc.insert(s))
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);
6193 return yes();
6196 else if (e.id)
6198 /* Declare id as an alias for type targ. Evaluate to true
6199 * is(targ id)
6201 tded = e.targ;
6203 return yes();
6206 override void visit(BinAssignExp exp)
6208 if (exp.type)
6210 result = exp;
6211 return;
6214 Expression e = exp.op_overload(sc);
6215 if (e)
6217 result = e;
6218 return;
6221 if (exp.e1.op == EXP.arrayLength)
6223 // arr.length op= e2;
6224 e = rewriteOpAssign(exp);
6225 e = e.expressionSemantic(sc);
6226 result = e;
6227 return;
6229 if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
6231 if (checkNonAssignmentArrayOp(exp.e1))
6232 return setError();
6234 if (exp.e1.op == EXP.slice)
6235 (cast(SliceExp)exp.e1).arrayop = true;
6237 // T[] op= ...
6238 if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
6240 // T[] op= T
6241 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
6243 else if (Expression ex = typeCombine(exp, sc))
6245 result = ex;
6246 return;
6248 exp.type = exp.e1.type;
6249 result = arrayOp(exp, sc);
6250 return;
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());
6263 return setError();
6266 if (exp.e1.checkScalar() ||
6267 exp.e1.checkReadModifyWrite(exp.op, exp.e2) ||
6268 exp.e1.checkSharedAccess(sc))
6269 return setError();
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())
6278 return setError();
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);
6283 return;
6286 if (Expression ex = typeCombine(exp, sc))
6288 result = ex;
6289 return;
6292 if (arith && (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)))
6293 return setError();
6294 if ((bitwise || shift) && (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)))
6295 return setError();
6297 if (shift)
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();
6306 return;
6309 if (exp.e1.op == EXP.error || exp.e2.op == EXP.error)
6310 return setError();
6312 e = exp.checkOpAssignTypes(sc);
6313 if (e.op == EXP.error)
6315 result = e;
6316 return;
6319 assert(e.op == EXP.assign || e == exp);
6320 result = (cast(BinExp)e).reorderSettingAAElem(sc);
6323 private Expression compileIt(MixinExp exp)
6325 OutBuffer buf;
6326 if (expressionsToString(buf, sc, exp.exps))
6327 return null;
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;
6336 p.nextToken();
6337 //printf("p.loc.linnum = %d\n", p.loc.linnum);
6339 Expression e = p.parseExpression();
6340 if (global.errors != errors)
6341 return null;
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`",
6348 str.ptr);
6349 return null;
6351 return e;
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);
6365 if (!e)
6366 return setError();
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");
6378 if (!se)
6379 return setError();
6380 se = se.toUTF8(sc);
6382 auto namez = se.toStringz();
6383 if (!global.filePath)
6385 error(e.loc, "need `-J` switch to import text file `%s`", namez.ptr);
6386 return setError();
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());
6397 return setError();
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]);
6405 return setError();
6408 if (FileName.refersToParentDir(namez))
6410 error(e.loc, "path refers to parent (`..`) directory: `%s`", se.toChars());
6411 return setError();
6414 auto resolvedNamez = FileName.searchPath(global.filePath, namez, false);
6415 if (!resolvedNamez)
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);
6426 return setError();
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(")");
6452 ob.writenl();
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);
6465 else
6467 error(e.loc, "cannot read file `%s`", resolvedNamez.ptr);
6468 return setError();
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;
6490 if (generateMsg)
6491 // no message - use assert expression as msg
6493 if (!verifyHookExist(exp.loc, *sc, Id._d_assert_fail, "generating assert messages"))
6494 return setError();
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
6508 Params:
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)
6523 die.noderef = true;
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)
6549 return op;
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())
6565 return left;
6567 // Sanity check that `op` can be converted to boolean
6568 // But don't raise errors for assignments enclosed in another expression
6569 if (op is exp.e1)
6570 op.toBoolean(sc);
6573 // Tuples with side-effects already receive a temporary during semantic
6574 if (op.type.isTypeTuple())
6576 auto te = op.isTupleExp();
6577 assert(te);
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);
6594 return op;
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))
6601 exp.e1 = e1;
6604 Expressions* es;
6605 Objects* tiargs;
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 ||
6626 op == EXP.in_ ||
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:
6638 // a.opEquals(b)
6639 // https://issues.dlang.org/show_bug.cgi?id=20100
6640 if (args.length == 1)
6642 auto dv = callExp.e1.isDotVarExp();
6643 assert(dv);
6645 // runtime args
6646 (*es)[1] = maybePromoteToTmp(dv.e1);
6647 (*es)[2] = maybePromoteToTmp((*args)[0]);
6649 else
6651 // runtime args
6652 (*es)[1] = maybePromoteToTmp((*args)[0]);
6653 (*es)[2] = maybePromoteToTmp((*args)[1]);
6656 else
6658 auto binExp = cast(EqualExp) exp.e1;
6660 // runtime args
6661 (*es)[1] = maybePromoteToTmp(binExp.e1);
6662 (*es)[2] = maybePromoteToTmp(binExp.e2);
6665 // template args
6666 Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : EXPtoString(exp.e1.op));
6667 comp = comp.expressionSemantic(sc);
6668 (*es)[0] = comp;
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())
6686 ne = ne2;
6687 else
6689 (*es)[0] = new StringExp(loc, neg ? "!" : "");
6690 (*es)[1] = maybePromoteToTmp(ne.e1);
6691 break;
6695 else
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!");
6709 goto LSkip;
6712 else
6714 OutBuffer buf;
6715 buf.printf("`%s` failed", exp.toChars());
6716 exp.msg = new StringExp(Loc.initial, buf.extractSlice());
6717 goto LSkip;
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);
6725 exp.msg = ec;
6728 LSkip:
6729 if (Expression ex = unaSemantic(exp, sc))
6731 result = ex;
6732 return;
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)
6742 result = exp.e1;
6743 return;
6746 if (exp.msg)
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)
6757 result = exp.msg;
6758 return;
6761 auto f1 = checkNonAssignmentArrayOp(exp.e1);
6762 auto f2 = exp.msg && checkNonAssignmentArrayOp(exp.msg);
6763 if (f1 || f2)
6764 return setError();
6766 if (exp.e1.toBool().hasValue(false))
6768 /* This is an `assert(0)` which means halt program execution
6770 FuncDeclaration fd = sc.parent.isFuncDeclaration();
6771 if (fd)
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);
6779 result = e;
6780 return;
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;
6788 else
6789 exp.type = Type.tvoid;
6791 result = !temporariesPrefix
6792 ? exp
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))
6801 result = te;
6802 else
6803 setError();
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);
6821 return;
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
6830 Expression e;
6831 Type t;
6832 Dsymbol s;
6833 dmd.typesem.resolve(exp.e1.type, exp.e1.loc, sc, e, t, s, true);
6834 if (e)
6836 error(exp.e1.loc, "argument to `_Alignof` must be a type");
6837 return setError();
6839 else if (t)
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);
6847 else if (s)
6849 error(exp.e1.loc, "argument to `_Alignof` must be a type");
6850 return setError();
6852 else
6853 assert(0);
6854 return;
6857 if (exp.ident != Id.__sizeof)
6859 result = fieldLookup(exp.e1, sc, exp.ident, exp.arrow);
6860 return;
6864 Expression e = exp.dotIdSemanticProp(sc, 1);
6866 if (e && isDotOpDispatch(e))
6868 auto ode = 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 */
6874 else
6876 result = e;
6877 return;
6880 if (!e) // if failed to find the property
6882 /* If ident is not a valid property, rewrite:
6883 * e1.ident
6884 * as:
6885 * .ident(e1)
6887 e = resolveUFCSProperties(sc, exp);
6889 result = e;
6892 override void visit(DotTemplateExp e)
6894 if (e.type)
6896 result = e;
6897 return;
6899 if (Expression ex = unaSemantic(e, sc))
6901 result = ex;
6902 return;
6904 // 'void' like TemplateExp
6905 e.type = Type.tvoid;
6906 result = e;
6909 override void visit(DotVarExp exp)
6911 static if (LOGSEMANTIC)
6913 printf("DotVarExp::semantic('%s')\n", exp.toChars());
6915 if (exp.type)
6917 result = exp;
6918 return;
6921 exp.var = exp.var.toAlias().isDeclaration();
6923 exp.e1 = exp.e1.expressionSemantic(sc);
6925 if (auto tup = exp.var.isTupleDeclaration())
6927 /* Replace:
6928 * e1.tuple(a, b, c)
6929 * with:
6930 * tuple(e1.a, e1.b, e1.c)
6932 Expression e0;
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];
6940 Expression e;
6941 Declaration var;
6942 switch (o.dyncast()) with (DYNCAST)
6944 case expression:
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
6952 var = ve.var;
6953 break;
6954 case dsymbol:
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);
6961 else
6962 var = d;
6963 break;
6964 case type:
6965 e = new TypeExp(exp.loc, cast(Type)o);
6966 break;
6967 default:
6968 error(exp.loc, "`%s` is not an expression", o.toChars());
6969 return setError();
6971 if (var)
6972 e = new DotVarExp(exp.loc, ev, var);
6973 exps.push(e);
6976 Expression e = new TupleExp(exp.loc, e0, exps);
6977 e = e.expressionSemantic(sc);
6978 result = e;
6979 return;
6981 else if (auto ad = exp.var.isAliasDeclaration())
6983 if (auto t = ad.getType())
6985 result = new TypeExp(exp.loc, t).expressionSemantic(sc);
6986 return;
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())
6998 return setError();
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())
7006 // (e1, fd)
7007 auto e = symbolToExp(fd, exp.loc, sc, false);
7008 result = Expression.combine(exp.e1, e);
7009 return;
7012 exp.type = fd.type;
7013 assert(exp.type);
7015 else if (OverDeclaration od = exp.var.isOverDeclaration())
7017 exp.type = Type.tvoid; // ambiguous type?
7019 else
7021 exp.type = exp.var.type;
7022 if (!exp.type && global.errors) // var is goofed up, just return error.
7023 return setError();
7024 assert(exp.type);
7026 if (t1.ty == Tpointer)
7027 t1 = t1.nextOf();
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))
7042 exp.e1 = e1x;
7043 else
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);
7049 result = e;
7050 return;
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);
7058 if (e)
7060 result = e;
7061 return;
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
7068 // (e1, v)
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);
7073 result = e;
7074 return;
7077 //printf("-DotVarExp::semantic('%s')\n", toChars());
7078 result = exp;
7081 override void visit(DotTemplateInstanceExp exp)
7083 static if (LOGSEMANTIC)
7085 printf("DotTemplateInstanceExp::semantic('%s')\n", exp.toChars());
7087 if (exp.type)
7089 result = exp;
7090 return;
7092 // Indicate we need to resolve by UFCS.
7093 Expression e = exp.dotTemplateSemanticProp(sc, DotExpFlag.gag);
7094 if (!e)
7095 e = resolveUFCSProperties(sc, exp);
7096 if (e is exp)
7097 e.type = Type.tvoid; // Unresolved type, because it needs inference
7098 result = e;
7101 override void visit(DelegateExp e)
7103 static if (LOGSEMANTIC)
7105 printf("DelegateExp::semantic('%s')\n", e.toChars());
7107 if (e.type)
7109 result = e;
7110 return;
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();
7120 if (f.needThis())
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());
7133 return setError();
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);
7143 result = e;
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());
7156 return setError();
7159 VarDeclaration vthis2 = makeThis2Argument(e.loc, sc, f);
7160 e.vthis2 = vthis2;
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());
7173 if (exp.type)
7175 result = exp;
7176 return;
7179 if (auto e = unaSemantic(exp, sc))
7181 result = e;
7182 return;
7185 exp.type = exp.sym.getType().addMod(exp.e1.type.mod);
7186 result = exp;
7189 override void visit(AddrExp exp)
7191 static if (LOGSEMANTIC)
7193 printf("AddrExp::semantic('%s')\n", exp.toChars());
7195 if (exp.type)
7197 result = exp;
7198 return;
7201 if (Expression ex = unaSemantic(exp, sc))
7203 result = ex;
7204 return;
7207 if (sc.flags & SCOPE.Cfile)
7209 /* Special handling for &"string"/&(T[]){0, 1}
7210 * since C regards string/array literals as lvalues
7212 auto e = exp.e1;
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();
7220 result = e;
7221 return;
7223 else
7225 // `toLvalue` call further below is upon exp.e1, omitting & from the error message
7226 exp.toLvalue(sc, null);
7227 return setError();
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
7242 return setError();
7244 Dsymbol s = ti.toAlias();
7245 FuncDeclaration f = s.isFuncDeclaration();
7246 if (f)
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();
7256 if (ti)
7258 //assert(ti.needsTypeInference(sc));
7259 ti.dsymbolSemantic(sc);
7260 if (!ti.inst || ti.errors) // if template failed to expand
7261 return setError();
7263 Dsymbol s = ti.toAlias();
7264 FuncDeclaration f = s.isFuncDeclaration();
7265 if (f)
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
7279 * actual symbol.
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
7295 * memory.
7297 if (1)
7299 if (sc.setUnsafe(false, exp.loc,
7300 "cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve, sc.func))
7302 setError();
7303 return;
7306 VarExp ve2 = callExp.e1.isVarExp();
7307 ve2.delegateWasExtracted = true;
7308 ve2.var.storage_class |= STC.scope_;
7309 result = ve2;
7310 return;
7316 exp.e1 = exp.e1.toLvalue(sc, null);
7317 if (exp.e1.op == EXP.error)
7319 result = exp.e1;
7320 return;
7322 if (checkNonAssignmentArrayOp(exp.e1))
7323 return setError();
7325 if (!exp.e1.type)
7327 error(exp.loc, "cannot take address of `%s`", exp.e1.toChars());
7328 return setError();
7330 if (!checkAddressable(exp, sc))
7331 return setError();
7333 bool hasOverloads;
7334 if (auto f = isFuncAddress(exp, &hasOverloads))
7336 if (!hasOverloads && f.checkForwardRef(exp.loc))
7337 return setError();
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());
7350 else
7351 error(exp.loc, "forward reference to type `%s` of expression `%s`", exp.e1.type.toChars(), exp.e1.toChars());
7352 return setError();
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();
7363 if (f)
7365 f = f.toAliasFunc(); // FIXME, should see overloads
7366 // https://issues.dlang.org/show_bug.cgi?id=1983
7367 if (!dve.hasOverloads)
7368 f.tookAddressOf++;
7370 Expression e;
7371 if (f.needThis())
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);
7376 result = e;
7377 return;
7380 // Look for misaligned pointer in @safe mode
7381 if (checkUnsafeAccess(sc, dve, !exp.type.isMutable(), true))
7382 return setError();
7384 else if (exp.e1.op == EXP.variable)
7386 VarExp ve = cast(VarExp)exp.e1;
7387 VarDeclaration v = ve.var.isVarDeclaration();
7388 if (v)
7390 if (!checkAddressVar(sc, exp.e1, v))
7391 return setError();
7393 ve.checkPurity(sc, v);
7395 FuncDeclaration f = ve.var.isFuncDeclaration();
7396 if (f)
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.
7411 f.tookAddressOf++;
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);
7424 result = e;
7425 return;
7428 Expression e = new DelegateExp(exp.loc, exp.e1, f, ve.hasOverloads);
7429 e = e.expressionSemantic(sc);
7430 result = e;
7431 return;
7433 if (f.needThis())
7435 auto memberFunc = hasThis(sc);
7436 if (memberFunc && haveSameThis(memberFunc, f))
7438 /* Should probably supply 'this' after overload resolution,
7439 * not before.
7441 Expression ethis = new ThisExp(exp.loc);
7442 Expression e = new DelegateExp(exp.loc, ethis, f, ve.hasOverloads);
7443 e = e.expressionSemantic(sc);
7444 result = e;
7445 return;
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`",
7451 f, sc.func);
7456 else if (exp.e1.op == EXP.index)
7458 /* For:
7459 * int[3] a;
7460 * &a[i]
7461 * check 'a' the same as for a regular variable
7463 if (VarDeclaration v = expToVariable(exp.e1))
7465 exp.e1.checkPurity(sc, v);
7468 else if (wasCond)
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
7481 ce.e1.type = null;
7482 ce.e1 = ce.e1.expressionSemantic(sc);
7483 ce.e2.type = null;
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());
7495 if (exp.type)
7497 result = exp;
7498 return;
7501 Expression e = exp.op_overload(sc);
7502 if (e)
7504 result = e;
7505 return;
7508 exp.e1 = exp.e1.arrayFuncConv(sc);
7510 Type tb = exp.e1.type.toBasetype();
7511 switch (tb.ty)
7513 case Tpointer:
7514 exp.type = (cast(TypePointer)tb).next;
7515 break;
7517 case Tsarray:
7518 case Tarray:
7519 if (isNonAssignmentArrayOp(exp.e1))
7520 goto default;
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());
7524 break;
7526 case Terror:
7527 return setError();
7529 case Tnull:
7530 exp.type = Type.tnoreturn; // typeof(*null) is bottom type
7531 break;
7533 default:
7534 error(exp.loc, "can only `*` a pointer, not a `%s`", exp.e1.type.toChars());
7535 goto case Terror;
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
7542 result = exp;
7543 return;
7546 if (exp.checkValue())
7547 return setError();
7549 result = exp;
7552 override void visit(NegExp exp)
7554 static if (LOGSEMANTIC)
7556 printf("NegExp::semantic('%s')\n", exp.toChars());
7558 if (exp.type)
7560 result = exp;
7561 return;
7564 Expression e = exp.op_overload(sc);
7565 if (e)
7567 result = e;
7568 return;
7571 fix16997(sc, exp);
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);
7579 return;
7581 result = exp;
7582 return;
7584 if (!target.isVectorOpSupported(tb, exp.op))
7586 result = exp.incompatibleTypes();
7587 return;
7589 if (exp.e1.checkNoBool())
7590 return setError();
7591 if (exp.e1.checkArithmetic(exp.op) ||
7592 exp.e1.checkSharedAccess(sc))
7593 return setError();
7595 result = exp;
7598 override void visit(UAddExp exp)
7600 static if (LOGSEMANTIC)
7602 printf("UAddExp::semantic('%s')\n", exp.toChars());
7604 assert(!exp.type);
7606 Expression e = exp.op_overload(sc);
7607 if (e)
7609 result = e;
7610 return;
7613 fix16997(sc, exp);
7614 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op))
7616 result = exp.incompatibleTypes();
7617 return;
7619 if (exp.e1.checkNoBool())
7620 return setError();
7621 if (exp.e1.checkArithmetic(exp.op))
7622 return setError();
7623 if (exp.e1.checkSharedAccess(sc))
7624 return setError();
7626 result = exp.e1;
7629 override void visit(ComExp exp)
7631 if (exp.type)
7633 result = exp;
7634 return;
7637 Expression e = exp.op_overload(sc);
7638 if (e)
7640 result = e;
7641 return;
7644 fix16997(sc, exp);
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);
7652 return;
7654 result = exp;
7655 return;
7657 if (!target.isVectorOpSupported(tb, exp.op))
7659 result = exp.incompatibleTypes();
7660 return;
7662 if (exp.e1.checkNoBool())
7663 return setError();
7664 if (exp.e1.checkIntegral() ||
7665 exp.e1.checkSharedAccess(sc))
7666 return setError();
7668 result = exp;
7671 override void visit(NotExp e)
7673 if (e.type)
7675 result = e;
7676 return;
7679 e.setNoderefOperand();
7681 // Note there is no operator overload
7682 if (Expression ex = unaSemantic(e, sc))
7684 result = ex;
7685 return;
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)
7696 result = e.e1;
7697 return;
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))
7707 return setError();
7709 e.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
7710 result = e;
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
7719 if (!exp.isRAII)
7721 error(exp.loc, "the `delete` keyword is obsolete");
7722 errorSupplemental(exp.loc, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead");
7723 return setError();
7726 Expression e = exp;
7728 if (Expression ex = unaSemantic(exp, sc))
7730 result = ex;
7731 return;
7733 exp.e1 = resolveProperties(sc, exp.e1);
7734 exp.e1 = exp.e1.modifiableLvalue(sc, null);
7735 if (exp.e1.op == EXP.error)
7737 result = exp.e1;
7738 return;
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());
7749 return setError();
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());
7758 return setError();
7761 bool err = false;
7762 if (cd.dtor)
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);
7769 if (err)
7770 return setError();
7772 result = e;
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);
7782 if (exp.type)
7784 result = exp;
7785 return;
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.
7800 Loc loc = exp.loc;
7801 Type t;
7802 Expression e;
7803 Dsymbol s;
7804 exp.to.resolve(loc, sc, e, t, s);
7805 if (e !is null)
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);
7816 assert(result);
7817 result = result.expressionSemantic(sc);
7818 return;
7822 if (exp.to)
7824 exp.to = exp.to.typeSemantic(exp.loc, sc);
7825 if (exp.to == Type.terror)
7826 return setError();
7828 if (!exp.to.hasPointers())
7829 exp.setNoderefOperand();
7831 // When e1 is a template lambda, this cast may instantiate it with
7832 // the type 'to'.
7833 exp.e1 = inferType(exp.e1, exp.to);
7836 if (auto e = unaSemantic(exp, sc))
7838 result = e;
7839 return;
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)
7852 result = e1x;
7853 return;
7855 if (e1x.checkType())
7856 return setError();
7857 exp.e1 = e1x;
7859 if (!exp.e1.type)
7861 error(exp.loc, "cannot cast `%s`", exp.e1.toChars());
7862 return setError();
7865 // https://issues.dlang.org/show_bug.cgi?id=19954
7866 if (exp.e1.type.ty == Ttuple)
7868 if (exp.to)
7870 if (TypeTuple tt = exp.to.isTypeTuple())
7872 if (exp.e1.type.implicitConvTo(tt))
7874 result = exp.e1.castTo(sc, tt);
7875 return;
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)
7894 return setError();
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());
7900 return setError();
7903 // cast(void) is used to mark e1 as unused, so it is safe
7904 if (exp.to.ty == Tvoid)
7906 exp.type = exp.to;
7907 result = exp;
7908 return;
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);
7916 return;
7920 Type t1b = exp.e1.type.toBasetype();
7921 Type tob = exp.to.toBasetype();
7923 if (allowImplicitConstruction && tob.ty == Tstruct && !tob.equals(t1b))
7925 /* Look to replace:
7926 * cast(S)t
7927 * with:
7928 * S(t)
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);
7935 if (e)
7937 result = e;
7938 return;
7942 if (!t1b.equals(tob) && (t1b.ty == Tarray || t1b.ty == Tsarray))
7944 if (checkNonAssignmentArrayOp(exp.e1))
7945 return setError();
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);
7953 return;
7956 Expression ex = exp.e1.castTo(sc, exp.to);
7957 if (ex.op == EXP.error)
7959 result = ex;
7960 return;
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))
7968 return setError();
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))
7981 if (ad.aliasthis)
7983 Expression e = resolveAliasThis(sc, exp.e1);
7984 e = new CastExp(exp.loc, e, exp.to);
7985 result = e.expressionSemantic(sc);
7986 return;
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)
8001 return setError();
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"))
8007 return setError();
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();
8020 tiargs.push(tFrom);
8021 tiargs.push(tTo);
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);
8029 return;
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);
8045 ex.type = exp.to;
8048 result = ex;
8051 override void visit(VectorExp exp)
8053 static if (LOGSEMANTIC)
8055 printf("VectorExp::semantic('%s')\n", exp.toChars());
8057 if (exp.type)
8059 result = exp;
8060 return;
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)
8067 result = exp.e1;
8068 return;
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)
8080 return false;
8082 error(exp.loc, "constant expression expected, not `%s`", elem.toChars());
8083 return true;
8086 exp.e1 = exp.e1.optimize(WANTvalue);
8087 bool res;
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)
8097 checkElem(exp.e1);
8099 result = res ? ErrorExp.get() : exp;
8102 override void visit(VectorArrayExp e)
8104 static if (LOGSEMANTIC)
8106 printf("VectorArrayExp::semantic('%s')\n", e.toChars());
8108 if (!e.type)
8110 unaSemantic(e, sc);
8111 e.e1 = resolveProperties(sc, e.e1);
8113 if (e.e1.op == EXP.error)
8115 result = e.e1;
8116 return;
8118 assert(e.e1.type.ty == Tvector);
8119 e.type = e.e1.type.isTypeVector().basetype;
8121 result = e;
8124 override void visit(SliceExp exp)
8126 static if (LOGSEMANTIC)
8128 printf("SliceExp::semantic('%s')\n", exp.toChars());
8130 if (exp.type)
8132 result = exp;
8133 return;
8136 // operator overloading should be handled in ArrayExp already.
8137 if (Expression ex = unaSemantic(exp, sc))
8139 result = ex;
8140 return;
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());
8148 return setError();
8150 Expression e = new TypeExp(exp.loc, exp.e1.type.arrayOf());
8151 result = e.expressionSemantic(sc);
8152 return;
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)
8163 e = e.copy();
8164 e.type = t1b.nextOf().arrayOf();
8166 result = e;
8167 return;
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)
8175 result = se;
8176 return;
8179 if (isArrayOpOperand(exp.e1))
8181 // Convert (a[]+b[])[] to a[]+b[]
8182 result = exp.e1;
8183 return;
8186 if (exp.e1.op == EXP.error)
8188 result = exp.e1;
8189 return;
8191 if (exp.e1.type.ty == Terror)
8192 return setError();
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());
8200 return setError();
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);
8209 if (s)
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)[]`",
8216 exp.e1.toChars(),
8217 s.ident.toChars(),
8218 exp.e1.toChars()
8225 return setError();
8227 if (sc.setUnsafe(false, exp.loc, "pointer slicing not allowed in safe functions"))
8228 return setError();
8230 else if (t1b.ty == Tarray)
8233 else if (t1b.ty == Tsarray)
8236 else if (t1b.ty == Ttuple)
8238 if (!exp.lwr && !exp.upr)
8240 result = exp.e1;
8241 return;
8243 if (!exp.lwr || !exp.upr)
8245 error(exp.loc, "need upper and lower bound to slice a sequence");
8246 return setError();
8249 else if (t1b.ty == Tvector && exp.e1.isLvalue())
8251 // Convert e1 to corresponding static array
8252 TypeVector tv1 = cast(TypeVector)t1b;
8253 t1b = tv1.basetype;
8254 t1b = t1b.castMod(tv1.mod);
8255 exp.e1.type = t1b;
8257 else
8259 error(exp.loc, "`%s` cannot be sliced with `[]`", t1b.ty == Tvoid ? exp.e1.toChars() : t1b.toChars());
8260 return setError();
8263 /* Run semantic on lwr and upr.
8265 Scope* scx = sc;
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;
8271 sc = sc.push(sym);
8273 if (exp.lwr)
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)
8280 sc = sc.endCTFE();
8281 exp.lwr = exp.lwr.implicitCastTo(sc, Type.tsize_t);
8283 if (exp.upr)
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)
8290 sc = sc.endCTFE();
8291 exp.upr = exp.upr.implicitCastTo(sc, Type.tsize_t);
8293 if (sc != scx)
8294 sc = sc.pop();
8295 if (exp.lwr && exp.lwr.type == Type.terror || exp.upr && exp.upr.type == Type.terror)
8296 return setError();
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();
8305 TupleExp te;
8306 TypeTuple tup;
8307 size_t length;
8308 if (exp.e1.op == EXP.tuple) // slicing an expression tuple
8310 te = cast(TupleExp)exp.e1;
8311 tup = null;
8312 length = te.exps.length;
8314 else if (exp.e1.op == EXP.type) // slicing a type tuple
8316 te = null;
8317 tup = cast(TypeTuple)t1b;
8318 length = Parameter.dim(tup.arguments);
8320 else
8321 assert(0);
8323 if (i2 < i1 || length < i2)
8325 error(exp.loc, "string slice `[%llu .. %llu]` is out of bounds", i1, i2);
8326 return setError();
8329 size_t j1 = cast(size_t)i1;
8330 size_t j2 = cast(size_t)i2;
8331 Expression e;
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);
8341 else
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);
8348 args.push(arg);
8350 e = new TypeExp(exp.e1.loc, new TypeTuple(args));
8352 e = e.expressionSemantic(sc);
8353 result = e;
8354 return;
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;
8400 else
8401 assert(0);
8403 exp.lowerIsLessThanUpper = (lwrRange.imax <= uprRange.imin);
8405 //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", exp.upperIsInBounds, exp.lowerIsLessThanUpper);
8408 result = exp;
8411 override void visit(ArrayLengthExp e)
8413 static if (LOGSEMANTIC)
8415 printf("ArrayLengthExp::semantic('%s')\n", e.toChars());
8417 if (e.type)
8419 result = e;
8420 return;
8423 if (Expression ex = unaSemantic(e, sc))
8425 result = ex;
8426 return;
8428 e.e1 = resolveProperties(sc, e.e1);
8430 e.type = Type.tsize_t;
8431 result = e;
8434 override void visit(ArrayExp exp)
8436 static if (LOGSEMANTIC)
8438 printf("ArrayExp::semantic('%s')\n", exp.toChars());
8440 assert(!exp.type);
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);
8449 return;
8453 result = exp.carraySemantic(sc); // C semantics
8454 if (result)
8455 return;
8457 Expression e = exp.op_overload(sc);
8458 if (e)
8460 result = e;
8461 return;
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());
8470 else
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());
8481 if (exp.type)
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)
8489 result = exp.e2;
8490 return;
8492 if (exp.e2.op == EXP.type)
8494 result = exp.e2;
8495 return;
8497 if (auto te = exp.e2.isTemplateExp())
8499 Expression e = new DotTemplateExp(exp.loc, exp.e1, te.td);
8500 result = e.expressionSemantic(sc);
8501 return;
8503 if (!exp.type)
8504 exp.type = exp.e2.type;
8505 result = exp;
8508 override void visit(CommaExp e)
8510 //printf("Semantic.CommaExp() %s\n", e.toChars());
8511 if (e.type)
8513 result = e;
8514 return;
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))
8526 result = ex;
8527 return;
8529 e.e1 = e.e1.addDtorHook(sc);
8531 if (checkNonAssignmentArrayOp(e.e1))
8532 return setError();
8534 // Comma expressions trigger this conversion
8535 e.e2 = e.e2.arrayFuncConv(sc);
8537 e.type = e.e2.type;
8538 result = e;
8540 if (sc.flags & SCOPE.Cfile)
8541 return;
8543 if (e.type is Type.tvoid)
8545 checkMustUse(e.e1, sc);
8546 discardValue(e.e1);
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());
8558 if (e.type)
8560 result = e;
8561 return;
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)
8574 result = le;
8575 return;
8577 if (ue.op == EXP.error)
8579 result = ue;
8580 return;
8583 e.lwr = le;
8584 e.upr = ue;
8586 e.type = Type.tvoid;
8587 result = e;
8590 override void visit(DelegatePtrExp e)
8592 static if (LOGSEMANTIC)
8594 printf("DelegatePtrExp::semantic('%s')\n", e.toChars());
8596 if (!e.type)
8598 unaSemantic(e, sc);
8599 e.e1 = resolveProperties(sc, e.e1);
8601 if (e.e1.op == EXP.error)
8603 result = e.e1;
8604 return;
8606 e.type = Type.tvoidptr;
8608 result = e;
8611 override void visit(DelegateFuncptrExp e)
8613 static if (LOGSEMANTIC)
8615 printf("DelegateFuncptrExp::semantic('%s')\n", e.toChars());
8617 if (!e.type)
8619 unaSemantic(e, sc);
8620 e.e1 = resolveProperties(sc, e.e1);
8621 if (e.e1.op == EXP.error)
8623 result = e.e1;
8624 return;
8626 e.type = e.e1.type.nextOf().pointerTo();
8628 result = e;
8631 override void visit(IndexExp exp)
8633 static if (LOGSEMANTIC)
8635 printf("IndexExp::semantic('%s')\n", exp.toChars());
8637 if (exp.type)
8639 result = exp;
8640 return;
8643 // operator overloading should be handled in ArrayExp already.
8644 if (!exp.e1.type)
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);
8651 Type nt;
8652 if (exp.e2.op == EXP.type)
8653 nt = new TypeAArray(exp.e1.type, exp.e2.type);
8654 else
8655 nt = new TypeSArray(exp.e1.type, exp.e2);
8656 Expression e = new TypeExp(exp.loc, nt);
8657 result = e.expressionSemantic(sc);
8658 return;
8660 if (exp.e1.op == EXP.error)
8662 result = exp.e1;
8663 return;
8665 if (exp.e1.type.ty == Terror)
8666 return setError();
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
8675 t1b = tv1.basetype;
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))
8682 return setError();
8685 /* Run semantic on e2
8687 Scope* scx = sc;
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;
8693 sc = sc.push(sym);
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)
8700 sc = sc.endCTFE();
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
8707 if (sc != scx)
8708 sc = sc.pop();
8709 if (exp.e2.type == Type.terror)
8710 return setError();
8712 if (checkNonAssignmentArrayOp(exp.e1))
8713 return setError();
8715 switch (t1b.ty)
8717 case Tpointer:
8718 if (t1b.isPtrToFunction())
8720 error(exp.loc, "cannot index function pointer `%s`", exp.e1.toChars());
8721 return setError();
8723 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8724 if (exp.e2.type == Type.terror)
8725 return setError();
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))
8732 return setError();
8734 exp.type = (cast(TypeNext)t1b).next;
8735 break;
8737 case Tarray:
8738 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8739 if (exp.e2.type == Type.terror)
8740 return setError();
8741 exp.type = (cast(TypeNext)t1b).next;
8742 break;
8744 case Tsarray:
8746 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8747 if (exp.e2.type == Type.terror)
8748 return setError();
8749 exp.type = t1b.nextOf();
8750 break;
8752 case Taarray:
8754 TypeAArray taa = cast(TypeAArray)t1b;
8755 /* We can skip the implicit conversion if they differ only by
8756 * constness
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)
8764 return setError();
8767 semanticTypeInfo(sc, taa);
8768 checkNewEscape(sc, exp.e2, false);
8770 exp.type = taa.next;
8771 break;
8773 case Ttuple:
8775 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8776 if (exp.e2.type == Type.terror)
8777 return setError();
8779 exp.e2 = exp.e2.ctfeInterpret();
8780 uinteger_t index = exp.e2.toUInteger();
8782 TupleExp te;
8783 TypeTuple tup;
8784 size_t length;
8785 if (exp.e1.op == EXP.tuple)
8787 te = cast(TupleExp)exp.e1;
8788 tup = null;
8789 length = te.exps.length;
8791 else if (exp.e1.op == EXP.type)
8793 te = null;
8794 tup = cast(TypeTuple)t1b;
8795 length = Parameter.dim(tup.arguments);
8797 else
8798 assert(0);
8800 if (length <= index)
8802 error(exp.loc, "array index `[%llu]` is outside array bounds `[0 .. %llu]`", index, cast(ulong)length);
8803 return setError();
8805 Expression e;
8806 if (exp.e1.op == EXP.tuple)
8808 e = (*te.exps)[cast(size_t)index];
8809 e = Expression.combine(te.e0, e);
8811 else
8812 e = new TypeExp(exp.e1.loc, Parameter.getNth(tup.arguments, cast(size_t)index).type);
8813 result = e;
8814 return;
8816 default:
8817 error(exp.loc, "`%s` must be an array or pointer type, not `%s`", exp.e1.toChars(), exp.e1.type.toChars());
8818 return setError();
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();
8833 if (length)
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);
8849 return;
8855 result = exp;
8858 override void visit(PostExp exp)
8860 static if (LOGSEMANTIC)
8862 printf("PostExp::semantic('%s')\n", exp.toChars());
8864 if (exp.type)
8866 result = exp;
8867 return;
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);
8877 return;
8881 if (Expression ex = binSemantic(exp, sc))
8883 result = ex;
8884 return;
8886 Expression e1x = resolveProperties(sc, exp.e1);
8887 if (e1x.op == EXP.error)
8889 result = e1x;
8890 return;
8892 exp.e1 = e1x;
8894 Expression e = exp.op_overload(sc);
8895 if (e)
8897 result = e;
8898 return;
8901 if (exp.e1.checkReadModifyWrite(exp.op))
8902 return setError();
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);
8908 return setError();
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)
8923 // ref v = e1;
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);
8929 /* Rewrite as:
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
8941 if (de)
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);
8946 result = e;
8947 return;
8950 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
8951 exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
8953 e = exp;
8954 if (exp.e1.checkScalar() ||
8955 exp.e1.checkSharedAccess(sc))
8956 return setError();
8957 if (exp.e1.checkNoBool())
8958 return setError();
8960 if (exp.e1.type.ty == Tpointer)
8961 e = scaleFactor(exp, sc);
8962 else
8963 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
8964 e.type = exp.e1.type;
8965 result = e;
8968 override void visit(PreExp exp)
8970 Expression e = exp.op_overload(sc);
8971 // printf("PreExp::semantic('%s')\n", toChars());
8972 if (e)
8974 result = e;
8975 return;
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);
8981 else
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
8989 * Params:
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
8995 * Returns:
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;
9007 if (sd.isNested())
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();
9015 sle.type = t;
9016 return sle;
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);
9034 result = e;
9037 if (exp.type)
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)
9052 Expression e0;
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())
9064 Expression res;
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
9081 while (true)
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);
9092 if (!ad)
9093 break;
9094 if (search_function(ad, Id.indexass))
9096 // Deal with $
9097 res = resolveOpDollar(sc, ae, &e0);
9098 if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
9099 goto Lfallback;
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);
9106 exp.e2 = 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);
9117 else
9118 res = res.expressionSemantic(sc);
9119 if (res)
9120 return setResult(Expression.combine(e0, res));
9123 Lfallback:
9124 if (maybeSlice && search_function(ad, Id.sliceass))
9126 // Deal with $
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);
9135 exp.e2 = res;
9137 /* Rewrite (a[i..j] = e2) as:
9138 * a.opSliceAssign(e2, i, j)
9140 auto a = new Expressions();
9141 a.push(exp.e2);
9142 if (ie)
9144 a.push(ie.lwr);
9145 a.push(ie.upr);
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);
9161 if (ae.e1)
9162 continue;
9164 break;
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
9176 * Could mean:
9177 * .f(e, value)
9178 * or:
9179 * .f(e) = value
9181 if (auto dti = e1x.isDotTemplateInstanceExp())
9183 Expression e = dti.dotTemplateSemanticProp(sc, DotExpFlag.gag);
9184 if (!e)
9186 return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
9189 e1x = e;
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.
9209 auto ode = e;
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 */
9216 else
9217 return setResult(e);
9219 if (!e)
9220 return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
9221 e1x = e;
9223 else
9225 if (auto se = e1x.isSliceExp())
9226 se.arrayop = true;
9228 e1x = e1x.expressionSemantic(sc);
9231 /* We have f = value.
9232 * Could mean:
9233 * f(value)
9234 * or:
9235 * f() = value
9237 if (Expression e = resolvePropertiesX(sc, e1x, exp.e2, exp))
9238 return setResult(e);
9240 if (e1x.checkRightThis(sc))
9242 return setError();
9244 exp.e1 = e1x;
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))
9267 return setError();
9269 auto etmp = checkNoreturnVarAccess(e2x);
9270 if (etmp != e2x)
9271 return setResult(etmp);
9273 exp.e2 = e2x;
9276 /* Rewrite tuple assignment as a tuple of assignments.
9279 Expression e2x = exp.e2;
9281 Ltupleassign:
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);
9291 return setError();
9293 if (dim == 0)
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);
9299 else
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);
9318 if (!td)
9319 goto Lnomatch;
9321 assert(exp.e1.type.ty == Ttuple);
9322 TypeTuple tt = cast(TypeTuple)exp.e1.type;
9324 Expression e0;
9325 Expression ev = extractSideEffect(sc, "__tup", e0, e2x);
9327 auto iexps = new Expressions();
9328 iexps.push(ev);
9329 for (size_t u = 0; u < iexps.length; u++)
9331 Lexpand:
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)
9345 break;
9346 goto Lexpand;
9348 goto Lnomatch;
9351 e2x = new TupleExp(e2x.loc, e0, iexps);
9352 e2x = e2x.expressionSemantic(sc);
9353 if (e2x.op == EXP.error)
9355 result = e2x;
9356 return;
9358 // Do not need to overwrite this.e2
9359 goto Ltupleassign;
9361 Lnomatch:
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());
9371 auto t = exp.type;
9372 exp = new ConstructExp(exp.loc, exp.e1, exp.e2);
9373 exp.type = t;
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)
9382 result = e1x;
9383 return;
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,
9407 // do nothing
9409 else if (t1.ty == Tstruct)
9411 auto e1x = exp.e1;
9412 auto e2x = exp.e2;
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)
9420 sd.size(exp.loc);
9421 if (sd.sizeok != Sizeok.done)
9422 return setError();
9423 if (!sd.ctor)
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
9444 * initializer
9446 Expression einit = getInitExp(sd, exp.loc, sc, t1);
9447 if (einit.op == EXP.error)
9449 result = einit;
9450 return;
9453 auto ae = new BlitExp(exp.loc, exp.e1, einit);
9454 ae.type = e1x.type;
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();
9461 dvx.e1 = e1x;
9462 auto cx = cast(CallExp)ce.copy();
9463 cx.e1 = dvx;
9464 if (checkConstructorEscape(sc, cx, false))
9465 return setError();
9467 Expression e0;
9468 Expression.extractLast(e2x, e0);
9470 auto e = Expression.combine(e0, ae, cx);
9471 e = e.expressionSemantic(sc);
9472 result = e;
9473 return;
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)
9483 /* Rewrite as:
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);
9491 return;
9493 if (sd.postblit || sd.hasCopyCtor)
9495 /* We have a copy constructor for this
9498 if (e2x.isLvalue())
9500 if (sd.hasCopyCtor)
9502 /* Rewrite as:
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;
9508 Expression e;
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);
9516 return;
9518 else
9520 if (!e2x.type.implicitConvTo(e1x.type))
9522 error(exp.loc, "conversion error from `%s` to `%s`",
9523 e2x.type.toChars(), e1x.type.toChars());
9524 return setError();
9527 /* Rewrite as:
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);
9541 return;
9544 else
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);
9565 return;
9569 else if (!e2x.implicitConvTo(t1))
9571 sd.size(exp.loc);
9572 if (sd.sizeok != Sizeok.done)
9573 return setError();
9574 if (!sd.ctor)
9575 sd.ctor = sd.searchCtor();
9577 if (sd.ctor)
9579 /* Look for implicit constructor call
9580 * Rewrite as:
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?");
9604 return setError();
9608 Expression einit = new BlitExp(exp.loc, e1x, getInitExp(sd, exp.loc, sc, t1));
9609 einit.type = e1x.type;
9611 Expression e;
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);
9616 result = e;
9617 return;
9619 if (search_function(sd, Id.call))
9621 /* Look for static opCall
9622 * https://issues.dlang.org/show_bug.cgi?id=2702
9623 * Rewrite as:
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)
9633 result = e2x;
9634 return;
9636 if (e2x.checkValue() || e2x.checkSharedAccess(sc))
9637 return setError();
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);
9650 return;
9654 else if (exp.op == EXP.assign)
9656 if (e1x.op == EXP.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray)
9659 * Rewrite:
9660 * aa[key] = e2;
9661 * as:
9662 * ref __aatmp = aa;
9663 * ref __aakey = key;
9664 * ref __aaval = e2;
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)
9673 result = esetting;
9674 return;
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);
9689 ae.e2 = ev;
9690 Expression e = ae.op_overload(sc);
9691 if (e)
9693 Expression ey = null;
9694 if (t2.ty == Tstruct && sd == t2.toDsymbol(sc))
9696 ey = ev;
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);
9707 if (ey)
9709 Expression ex;
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)
9719 result = ey;
9720 return;
9722 ex = e;
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);
9737 result = e;
9738 return;
9741 else
9743 Expression e = exp.op_overload(sc);
9744 if (e)
9746 result = e;
9747 return;
9751 else
9752 assert(exp.op == EXP.blit);
9754 if (e2x.checkValue())
9755 return setError();
9757 exp.e1 = e1x;
9758 exp.e2 = e2x;
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);
9766 if (e)
9768 result = e;
9769 return;
9772 if (exp.e2.checkValue())
9773 return setError();
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);
9795 exp.e2 = e2x;
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))
9804 return setError();
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);
9813 sle.arrayop = true;
9814 e1x = sle.expressionSemantic(sc);
9816 else
9818 // convert e2 to t1 later
9819 // e.g. e1 = [1, 2, 3];
9822 else
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);
9835 if (tx)
9836 dim2 = (cast(TypeSArray)tx).dim.toInteger();
9838 if (dim1 != dim2)
9840 error(exp.loc, "mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2);
9841 return setError();
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);
9872 return setError();
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);
9882 break;
9886 auto sle = new SliceExp(e1x.loc, e1x, null, null);
9887 sle.arrayop = true;
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);
9895 exp.e1 = e1x;
9896 exp.e2 = 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);
9908 ale.e1 = 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"))
9915 return setError();
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());
9975 return setError();
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();
9983 return;
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);
9996 else
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();
10006 return;
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)
10021 result = e1x;
10022 return;
10024 exp.e1 = e1x;
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.
10034 Type telem = t1;
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()))
10047 return setError();
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);
10065 else
10066 tsa2 = t2.isTypeSArray();
10068 if (tsa1 && tsa2)
10070 uinteger_t dim1 = tsa1.dim.toInteger();
10071 uinteger_t dim2 = tsa2.dim.toInteger();
10072 if (dim1 != dim2)
10074 error(exp.loc, "mismatched array lengths %d and %d for assignment `%s`", cast(int)dim1, cast(int)dim2, exp.toChars());
10075 return setError();
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()))
10085 return setError();
10088 version (none)
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();
10108 int offset;
10109 if (t2n.equivalent(t1n) ||
10110 t1n.isBaseOf(t2n, &offset) && offset == 0)
10112 /* Allow copy of distinct qualifier elements.
10113 * eg.
10114 * char[] dst; const(char)[] src;
10115 * dst[] = src;
10117 * class C {} class D : C {}
10118 * C[2] ca; D[] da;
10119 * ca[] = da;
10121 if (isArrayOpValid(e2x))
10123 // Don't add CastExp to keep AST for array operations
10124 e2x = e2x.copy();
10125 e2x.type = exp.e1.type.constOf();
10127 else
10128 e2x = e2x.castTo(sc, exp.e1.type.constOf());
10130 else
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());
10141 else
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"))
10147 return setError();
10150 else
10152 version (none)
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);
10169 else
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
10183 if (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)
10197 result = e2x;
10198 return;
10200 exp.e2 = e2x;
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);
10217 return;
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))
10223 return setError();
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;
10249 assert(exp.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);
10259 else
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)
10292 rhs = ce.e1;
10293 rhsType = ct;
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))
10315 return setError();
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);
10330 else
10332 Expression e0;
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));
10340 else
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.
10367 * Params:
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.
10371 * Returns:
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)
10379 return ae;
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)
10389 return ae;
10391 const ts = t1b.nextOf().baseElemOf().isTypeStruct();
10392 if (!ts || (!ts.sym.postblit && !ts.sym.dtor))
10393 return ae;
10395 Expression res;
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;
10423 if (isArrayAssign)
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);
10434 if (isArrayAssign)
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;
10443 return res;
10446 override void visit(PowAssignExp exp)
10448 if (exp.type)
10450 result = exp;
10451 return;
10454 Expression e = exp.op_overload(sc);
10455 if (e)
10457 result = e;
10458 return;
10461 if (exp.e1.checkReadModifyWrite(exp.op, exp.e2))
10462 return setError();
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))
10468 return setError();
10470 // T[] ^^= ...
10471 if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
10473 // T[] ^^= T
10474 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
10476 else if (Expression ex = typeCombine(exp, sc))
10478 result = ex;
10479 return;
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);
10491 return;
10494 else
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);
10504 assert(e == exp);
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);
10512 else
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);
10524 result = e;
10525 return;
10527 result = exp.incompatibleTypes();
10530 override void visit(CatAssignExp exp)
10532 if (exp.type)
10534 result = exp;
10535 return;
10538 //printf("CatAssignExp::semantic() %s\n", exp.toChars());
10539 Expression e = exp.op_overload(sc);
10540 if (e)
10542 result = e;
10543 return;
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());
10551 return setError();
10555 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
10556 if (exp.e1.op == EXP.error)
10558 result = exp.e1;
10559 return;
10561 if (exp.e2.op == EXP.error)
10563 result = exp.e2;
10564 return;
10567 if (checkNonAssignmentArrayOp(exp.e2))
10568 return setError();
10570 Type tb1 = exp.e1.type.toBasetype();
10571 Type tb1next = tb1.nextOf();
10572 Type tb2 = exp.e2.type.toBasetype();
10574 /* Possibilities:
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))
10588 return setError();
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))
10601 goto Laliasthis;
10602 if (tb2.ty == Tclass && (cast(TypeClass)tb2).implicitConvToThroughAliasThis(tb1next))
10603 goto Laliasthis;
10604 // Append element
10605 if (exp.e2.checkPostblit(sc, tb2))
10606 return setError();
10608 if (checkNewEscape(sc, exp.e2, false))
10609 return setError();
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.
10626 else
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)
10633 return null;
10635 /* Rewrite (e1 op e2) as:
10636 * (e1.aliasthis op e2)
10638 if (isRecursiveAliasThis(exp.att1, exp.e1.type))
10639 return null;
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();
10643 be.e1 = e1;
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)
10652 return null;
10653 /* Rewrite (e1 op e2) as:
10654 * (e1 op e2.aliasthis)
10656 if (isRecursiveAliasThis(exp.att2, exp.e2.type))
10657 return null;
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();
10661 be.e2 = e2;
10662 return be.trySemantic(sc);
10665 Laliasthis:
10666 result = tryAliasThisForLhs(exp, sc);
10667 if (result)
10668 return;
10670 result = tryAliasThisForRhs(exp, sc);
10671 if (result)
10672 return;
10674 error(exp.loc, "cannot append type `%s` to type `%s`", tb2.toChars(), tb1.toChars());
10675 return setError();
10678 if (exp.e2.checkValue() || exp.e2.checkSharedAccess(sc))
10679 return setError();
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);
10689 result = res;
10691 if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) &&
10692 sc.needsCodegen())
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;
10705 else
10707 output = &result;
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))
10716 return setError();
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)
10752 return;
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))
10757 return setError();
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);
10795 exp.e2 = value2;
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());
10826 if (exp.type)
10828 result = exp;
10829 return;
10832 if (Expression ex = binSemanticProp(exp, sc))
10834 result = ex;
10835 return;
10837 Expression e = exp.op_overload(sc);
10838 if (e)
10840 result = e;
10841 return;
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();
10852 bool err = false;
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);
10861 if (err)
10862 return setError();
10864 if (tb1.ty == Tpointer && exp.e2.type.isintegral() || tb2.ty == Tpointer && exp.e1.type.isintegral())
10866 result = scaleFactor(exp, sc);
10867 return;
10870 if (tb1.ty == Tpointer && tb2.ty == Tpointer)
10872 result = exp.incompatibleTypes();
10873 return;
10876 if (Expression ex = typeCombine(exp, sc))
10878 result = ex;
10879 return;
10882 Type tb = exp.type.toBasetype();
10883 if (tb.ty == Tarray || tb.ty == Tsarray)
10885 if (!isArrayOpValid(exp))
10887 result = arrayOpInvalidError(exp);
10888 return;
10890 result = exp;
10891 return;
10894 tb1 = exp.e1.type.toBasetype();
10895 if (!target.isVectorOpSupported(tb1, exp.op, tb2))
10897 result = exp.incompatibleTypes();
10898 return;
10900 if ((tb1.isreal() && exp.e2.type.isimaginary()) || (tb1.isimaginary() && exp.e2.type.isreal()))
10902 switch (exp.type.toBasetype().ty)
10904 case Tfloat32:
10905 case Timaginary32:
10906 exp.type = Type.tcomplex32;
10907 break;
10909 case Tfloat64:
10910 case Timaginary64:
10911 exp.type = Type.tcomplex64;
10912 break;
10914 case Tfloat80:
10915 case Timaginary80:
10916 exp.type = Type.tcomplex80;
10917 break;
10919 default:
10920 assert(0);
10923 result = exp;
10926 override void visit(MinExp exp)
10928 static if (LOGSEMANTIC)
10930 printf("MinExp::semantic('%s')\n", exp.toChars());
10932 if (exp.type)
10934 result = exp;
10935 return;
10938 if (Expression ex = binSemanticProp(exp, sc))
10940 result = ex;
10941 return;
10943 Expression e = exp.op_overload(sc);
10944 if (e)
10946 result = e;
10947 return;
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();
10958 bool err = false;
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);
10967 if (err)
10968 return setError();
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
10993 long stride;
10995 // make sure pointer types are compatible
10996 if (Expression ex = typeCombine(exp, sc))
10998 result = ex;
10999 return;
11002 exp.type = Type.tptrdiff_t;
11003 stride = t2.nextOf().size();
11004 if (stride == 0)
11006 e = new IntegerExp(exp.loc, 0, Type.tptrdiff_t);
11008 else if (stride == cast(long)SIZE_INVALID)
11009 e = ErrorExp.get();
11010 else
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);
11018 else
11020 error(exp.loc, "can't subtract `%s` from pointer", t2.toChars());
11021 e = ErrorExp.get();
11023 result = e;
11024 return;
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());
11030 return setError();
11033 if (Expression ex = typeCombine(exp, sc))
11035 result = ex;
11036 return;
11039 Type tb = exp.type.toBasetype();
11040 if (tb.ty == Tarray || tb.ty == Tsarray)
11042 if (!isArrayOpValid(exp))
11044 result = arrayOpInvalidError(exp);
11045 return;
11047 result = exp;
11048 return;
11051 t1 = exp.e1.type.toBasetype();
11052 t2 = exp.e2.type.toBasetype();
11053 if (!target.isVectorOpSupported(t1, exp.op, t2))
11055 result = exp.incompatibleTypes();
11056 return;
11058 if ((t1.isreal() && t2.isimaginary()) || (t1.isimaginary() && t2.isreal()))
11060 switch (exp.type.ty)
11062 case Tfloat32:
11063 case Timaginary32:
11064 exp.type = Type.tcomplex32;
11065 break;
11067 case Tfloat64:
11068 case Timaginary64:
11069 exp.type = Type.tcomplex64;
11070 break;
11072 case Tfloat80:
11073 case Timaginary80:
11074 exp.type = Type.tcomplex80;
11075 break;
11077 default:
11078 assert(0);
11081 result = exp;
11082 return;
11086 * If the given expression is a `CatExp`, the function tries to lower it to
11087 * `_d_arraycatnTX`.
11089 * Params:
11090 * ee = the `CatExp` to lower
11091 * Returns:
11092 * `_d_arraycatnTX(e1, e2, ..., en)` if `ee` is `e1 ~ e2 ~ ... en`
11093 * `ee` otherwise
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())))
11100 return exp;
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"))
11107 setError();
11108 return result;
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)[]);
11124 else
11125 arguments.pushSlice((*callExp.arguments)[3 .. $]);
11128 else
11129 arguments.push(e);
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)
11161 return;
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());
11171 if (exp.type)
11173 result = exp;
11174 return;
11177 if (Expression ex = binSemanticProp(exp, sc))
11179 result = ex;
11180 return;
11182 Expression e = exp.op_overload(sc);
11183 if (e)
11185 result = e;
11186 return;
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);
11194 if (f1 || f2)
11195 return setError();
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];
11207 * a ~ b;
11208 * becoming:
11209 * a ~ [cast(void*)b];
11212 /* https://issues.dlang.org/show_bug.cgi?id=14682
11213 * Also to avoid the case of:
11214 * int[][] a;
11215 * a ~ [];
11216 * becoming:
11217 * a ~ cast(int[])[];
11219 goto Lpeer;
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.
11236 else
11238 if (exp.e2.checkPostblit(sc, tb2))
11239 return setError();
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();
11247 goto L2elem;
11249 if (exp.e2.implicitConvTo(tb1next) >= MATCH.convert)
11251 exp.e2 = exp.e2.implicitCastTo(sc, tb1next);
11252 exp.type = tb1next.arrayOf();
11253 L2elem:
11254 if (checkNewEscape(sc, exp.e2, false))
11255 return setError();
11256 result = exp.optimize(WANTvalue);
11257 trySetCatExpLowering(result);
11258 return;
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_)
11271 else
11273 if (exp.e1.checkPostblit(sc, tb1))
11274 return setError();
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();
11281 goto L1elem;
11283 if (exp.e1.implicitConvTo(tb2next) >= MATCH.convert)
11285 exp.e1 = exp.e1.implicitCastTo(sc, tb2next);
11286 exp.type = tb2next.arrayOf();
11287 L1elem:
11288 if (checkNewEscape(sc, exp.e1, false))
11289 return setError();
11290 result = exp.optimize(WANTvalue);
11291 trySetCatExpLowering(result);
11292 return;
11296 Lpeer:
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)
11302 exp.e1.type = t1;
11303 else
11304 exp.e1 = exp.e1.castTo(sc, t1);
11305 if (exp.e2.op == EXP.string_ && !(cast(StringExp)exp.e2).committed)
11306 exp.e2.type = t2;
11307 else
11308 exp.e2 = exp.e2.castTo(sc, t2);
11311 if (Expression ex = typeCombine(exp, sc))
11313 result = ex;
11314 trySetCatExpLowering(result);
11315 return;
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))
11329 return setError();
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);
11339 else
11341 //printf("(%s) ~ (%s)\n", e1.toChars(), e2.toChars());
11342 result = exp.incompatibleTypes();
11343 return;
11346 result = e;
11347 trySetCatExpLowering(result);
11350 override void visit(MulExp exp)
11352 version (none)
11354 printf("MulExp::semantic() %s\n", exp.toChars());
11356 if (exp.type)
11358 result = exp;
11359 return;
11362 if (Expression ex = binSemanticProp(exp, sc))
11364 result = ex;
11365 return;
11367 Expression e = exp.op_overload(sc);
11368 if (e)
11370 result = e;
11371 return;
11374 if (Expression ex = typeCombine(exp, sc))
11376 result = ex;
11377 return;
11380 Type tb = exp.type.toBasetype();
11381 if (tb.ty == Tarray || tb.ty == Tsarray)
11383 if (!isArrayOpValid(exp))
11385 result = arrayOpInvalidError(exp);
11386 return;
11388 result = exp;
11389 return;
11392 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
11393 return setError();
11395 if (exp.type.isfloating())
11397 Type t1 = exp.e1.type;
11398 Type t2 = exp.e2.type;
11400 if (t1.isreal())
11402 exp.type = t2;
11404 else if (t2.isreal())
11406 exp.type = t1;
11408 else if (t1.isimaginary())
11410 if (t2.isimaginary())
11412 switch (t1.toBasetype().ty)
11414 case Timaginary32:
11415 exp.type = Type.tfloat32;
11416 break;
11418 case Timaginary64:
11419 exp.type = Type.tfloat64;
11420 break;
11422 case Timaginary80:
11423 exp.type = Type.tfloat80;
11424 break;
11426 default:
11427 assert(0);
11430 // iy * iv = -yv
11431 exp.e1.type = exp.type;
11432 exp.e2.type = exp.type;
11433 e = new NegExp(exp.loc, exp);
11434 e = e.expressionSemantic(sc);
11435 result = e;
11436 return;
11438 else
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();
11449 return;
11451 result = exp;
11454 override void visit(DivExp exp)
11456 if (exp.type)
11458 result = exp;
11459 return;
11462 if (Expression ex = binSemanticProp(exp, sc))
11464 result = ex;
11465 return;
11467 Expression e = exp.op_overload(sc);
11468 if (e)
11470 result = e;
11471 return;
11474 if (Expression ex = typeCombine(exp, sc))
11476 result = ex;
11477 return;
11480 Type tb = exp.type.toBasetype();
11481 if (tb.ty == Tarray || tb.ty == Tsarray)
11483 if (!isArrayOpValid(exp))
11485 result = arrayOpInvalidError(exp);
11486 return;
11488 result = exp;
11489 return;
11492 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
11493 return setError();
11495 if (exp.type.isfloating())
11497 Type t1 = exp.e1.type;
11498 Type t2 = exp.e2.type;
11500 if (t1.isreal())
11502 exp.type = t2;
11503 if (t2.isimaginary())
11505 // x/iv = i(-x/v)
11506 exp.e2.type = t1;
11507 e = new NegExp(exp.loc, exp);
11508 e = e.expressionSemantic(sc);
11509 result = e;
11510 return;
11513 else if (t2.isreal())
11515 exp.type = t1;
11517 else if (t1.isimaginary())
11519 if (t2.isimaginary())
11521 switch (t1.toBasetype().ty)
11523 case Timaginary32:
11524 exp.type = Type.tfloat32;
11525 break;
11527 case Timaginary64:
11528 exp.type = Type.tfloat64;
11529 break;
11531 case Timaginary80:
11532 exp.type = Type.tfloat80;
11533 break;
11535 default:
11536 assert(0);
11539 else
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();
11550 return;
11552 result = exp;
11555 override void visit(ModExp exp)
11557 if (exp.type)
11559 result = exp;
11560 return;
11563 if (Expression ex = binSemanticProp(exp, sc))
11565 result = ex;
11566 return;
11568 Expression e = exp.op_overload(sc);
11569 if (e)
11571 result = e;
11572 return;
11575 if (Expression ex = typeCombine(exp, sc))
11577 result = ex;
11578 return;
11581 Type tb = exp.type.toBasetype();
11582 if (tb.ty == Tarray || tb.ty == Tsarray)
11584 if (!isArrayOpValid(exp))
11586 result = arrayOpInvalidError(exp);
11587 return;
11589 result = exp;
11590 return;
11592 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11594 result = exp.incompatibleTypes();
11595 return;
11598 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
11599 return setError();
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");
11607 return setError();
11610 result = exp;
11613 override void visit(PowExp exp)
11615 if (exp.type)
11617 result = exp;
11618 return;
11621 //printf("PowExp::semantic() %s\n", toChars());
11622 if (Expression ex = binSemanticProp(exp, sc))
11624 result = ex;
11625 return;
11627 Expression e = exp.op_overload(sc);
11628 if (e)
11630 result = e;
11631 return;
11634 if (Expression ex = typeCombine(exp, sc))
11636 result = ex;
11637 return;
11640 Type tb = exp.type.toBasetype();
11641 if (tb.ty == Tarray || tb.ty == Tsarray)
11643 if (!isArrayOpValid(exp))
11645 result = arrayOpInvalidError(exp);
11646 return;
11648 result = exp;
11649 return;
11652 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
11653 return setError();
11655 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11657 result = exp.incompatibleTypes();
11658 return;
11661 // First, attempt to fold the expression.
11662 e = exp.optimize(WANTvalue);
11663 if (e.op != EXP.pow)
11665 e = e.expressionSemantic(sc);
11666 result = e;
11667 return;
11670 Module mmath = Module.loadStdMath();
11671 if (!mmath)
11673 error(e.loc, "`%s` requires `std.math` for `^^` operators", e.toChars());
11674 return setError();
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);
11683 else
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);
11689 result = e;
11690 return;
11693 override void visit(ShlExp exp)
11695 //printf("ShlExp::semantic(), type = %p\n", type);
11696 if (exp.type)
11698 result = exp;
11699 return;
11702 if (Expression ex = binSemanticProp(exp, sc))
11704 result = ex;
11705 return;
11707 Expression e = exp.op_overload(sc);
11708 if (e)
11710 result = e;
11711 return;
11714 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11715 return setError();
11717 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
11719 result = exp.incompatibleTypes();
11720 return;
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;
11727 result = exp;
11730 override void visit(ShrExp exp)
11732 if (exp.type)
11734 result = exp;
11735 return;
11738 if (Expression ex = binSemanticProp(exp, sc))
11740 result = ex;
11741 return;
11743 Expression e = exp.op_overload(sc);
11744 if (e)
11746 result = e;
11747 return;
11750 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11751 return setError();
11753 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
11755 result = exp.incompatibleTypes();
11756 return;
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;
11763 result = exp;
11766 override void visit(UshrExp exp)
11768 if (exp.type)
11770 result = exp;
11771 return;
11774 if (Expression ex = binSemanticProp(exp, sc))
11776 result = ex;
11777 return;
11779 Expression e = exp.op_overload(sc);
11780 if (e)
11782 result = e;
11783 return;
11786 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11787 return setError();
11789 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
11791 result = exp.incompatibleTypes();
11792 return;
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;
11799 result = exp;
11802 override void visit(AndExp exp)
11804 if (exp.type)
11806 result = exp;
11807 return;
11810 if (Expression ex = binSemanticProp(exp, sc))
11812 result = ex;
11813 return;
11815 Expression e = exp.op_overload(sc);
11816 if (e)
11818 result = e;
11819 return;
11822 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
11824 exp.type = exp.e1.type;
11825 result = exp;
11826 return;
11829 if (Expression ex = typeCombine(exp, sc))
11831 result = ex;
11832 return;
11835 Type tb = exp.type.toBasetype();
11836 if (tb.ty == Tarray || tb.ty == Tsarray)
11838 if (!isArrayOpValid(exp))
11840 result = arrayOpInvalidError(exp);
11841 return;
11843 result = exp;
11844 return;
11846 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11848 result = exp.incompatibleTypes();
11849 return;
11851 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11852 return setError();
11854 result = exp;
11857 override void visit(OrExp exp)
11859 if (exp.type)
11861 result = exp;
11862 return;
11865 if (Expression ex = binSemanticProp(exp, sc))
11867 result = ex;
11868 return;
11870 Expression e = exp.op_overload(sc);
11871 if (e)
11873 result = e;
11874 return;
11877 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
11879 exp.type = exp.e1.type;
11880 result = exp;
11881 return;
11884 if (Expression ex = typeCombine(exp, sc))
11886 result = ex;
11887 return;
11890 Type tb = exp.type.toBasetype();
11891 if (tb.ty == Tarray || tb.ty == Tsarray)
11893 if (!isArrayOpValid(exp))
11895 result = arrayOpInvalidError(exp);
11896 return;
11898 result = exp;
11899 return;
11901 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11903 result = exp.incompatibleTypes();
11904 return;
11906 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11907 return setError();
11909 result = exp;
11912 override void visit(XorExp exp)
11914 if (exp.type)
11916 result = exp;
11917 return;
11920 if (Expression ex = binSemanticProp(exp, sc))
11922 result = ex;
11923 return;
11925 Expression e = exp.op_overload(sc);
11926 if (e)
11928 result = e;
11929 return;
11932 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
11934 exp.type = exp.e1.type;
11935 result = exp;
11936 return;
11939 if (Expression ex = typeCombine(exp, sc))
11941 result = ex;
11942 return;
11945 Type tb = exp.type.toBasetype();
11946 if (tb.ty == Tarray || tb.ty == Tsarray)
11948 if (!isArrayOpValid(exp))
11950 result = arrayOpInvalidError(exp);
11951 return;
11953 result = exp;
11954 return;
11956 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11958 result = exp.incompatibleTypes();
11959 return;
11961 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11962 return setError();
11964 result = exp;
11967 override void visit(LogicalExp exp)
11969 static if (LOGSEMANTIC)
11971 printf("LogicalExp::semantic() %s\n", exp.toChars());
11974 if (exp.type)
11976 result = exp;
11977 return;
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);
12000 else
12001 result = IntegerExp.createBool(exp.op == EXP.orOr);
12002 return;
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);
12019 if (f1 || f2)
12020 return setError();
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());
12029 return setError();
12031 if (e1x.op == EXP.error || e1x.type.ty == Tnoreturn)
12033 result = e1x;
12034 return;
12036 if (e2x.op == EXP.error)
12038 result = e2x;
12039 return;
12042 // The result type is 'bool', unless the right operand has type 'void'.
12043 if (e2x.type.ty == Tvoid)
12044 exp.type = Type.tvoid;
12045 else
12046 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
12048 exp.e1 = e1x;
12049 exp.e2 = e2x;
12050 result = exp;
12054 override void visit(CmpExp exp)
12056 static if (LOGSEMANTIC)
12058 printf("CmpExp::semantic('%s')\n", exp.toChars());
12060 if (exp.type)
12062 result = exp;
12063 return;
12066 exp.setNoderefOperands();
12068 if (Expression ex = binSemanticProp(exp, sc))
12070 result = ex;
12071 return;
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");
12078 return setError();
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");
12088 return setError();
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);
12111 else
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);
12121 return;
12124 e = new CmpExp(cmpop, exp.loc, e, IntegerExp.literal!0);
12125 e = e.expressionSemantic(sc);
12127 result = e;
12128 return;
12132 if (Expression ex = typeCombine(exp, sc))
12134 result = ex;
12135 return;
12138 auto f1 = checkNonAssignmentArrayOp(exp.e1);
12139 auto f2 = checkNonAssignmentArrayOp(exp.e2);
12140 if (f1 || f2)
12141 return setError();
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());
12156 return setError();
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"))
12163 return setError();
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());
12185 else
12186 error(exp.loc, "need member function `opCmp()` for %s `%s` to compare", t1.toDsymbol(sc).kind(), t1.toChars());
12187 return setError();
12189 else if (t1.iscomplex() || t2.iscomplex())
12191 error(exp.loc, "compare not defined for complex operands");
12192 return setError();
12194 else if (t1.ty == Taarray || t2.ty == Taarray)
12196 error(exp.loc, "`%s` is not defined for associative arrays", EXPtoString(exp.op).ptr);
12197 return setError();
12199 else if (!target.isVectorOpSupported(t1, exp.op, t2))
12201 result = exp.incompatibleTypes();
12202 return;
12204 else
12206 bool r1 = exp.e1.checkValue() || exp.e1.checkSharedAccess(sc);
12207 bool r2 = exp.e2.checkValue() || exp.e2.checkSharedAccess(sc);
12208 if (r1 || r2)
12209 return setError();
12212 //printf("CmpExp: %s, type = %s\n", e.toChars(), e.type.toChars());
12213 if (arrayLowering)
12215 arrayLowering = arrayLowering.expressionSemantic(sc);
12216 result = arrayLowering;
12217 return;
12220 if (auto tv = t1.isTypeVector())
12221 exp.type = tv.toBooleanVector();
12223 result = exp;
12224 return;
12227 override void visit(InExp exp)
12229 if (exp.type)
12231 result = exp;
12232 return;
12235 if (Expression ex = binSemanticProp(exp, sc))
12237 result = ex;
12238 return;
12240 Expression e = exp.op_overload(sc);
12241 if (e)
12243 result = e;
12244 return;
12247 Type t2b = exp.e2.type.toBasetype();
12248 switch (t2b.ty)
12250 case Taarray:
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();
12265 break;
12268 case Terror:
12269 return setError();
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);
12277 return;
12279 default:
12280 result = exp.incompatibleTypes();
12281 return;
12283 result = exp;
12286 override void visit(RemoveExp e)
12288 if (Expression ex = binSemantic(e, sc))
12290 result = ex;
12291 return;
12293 result = e;
12296 override void visit(EqualExp exp)
12298 //printf("EqualExp::semantic('%s')\n", exp.toChars());
12299 if (exp.type)
12301 result = exp;
12302 return;
12305 exp.setNoderefOperands();
12307 if (auto e = binSemanticProp(exp, sc))
12309 result = e;
12310 return;
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);
12330 return;
12332 // AliasSeq!(<at least a value>) == AliasSeq!()
12333 else if (tups1.te && tups2.ttEmpty)
12335 result = IntegerExp.createBool(exp.op != EXP.equal);
12336 return;
12338 // AliasSeq!() == AliasSeq!()
12339 else if (tups1.ttEmpty && tups2.ttEmpty)
12341 result = IntegerExp.createBool(exp.op == EXP.equal);
12342 return;
12344 // otherwise, two types are really not comparable
12345 result = exp.incompatibleTypes();
12346 return;
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);
12373 return;
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))
12390 return false;
12392 if (t1n.constOf() != t2n.constOf())
12393 return true;
12395 Type t = t1n;
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
12407 return false;
12410 if (auto e = exp.op_overload(sc))
12412 result = e;
12413 return;
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))
12425 return setError();
12426 if (auto e = typeCombine(exp, sc))
12428 result = e;
12429 return;
12433 auto f1 = checkNonAssignmentArrayOp(exp.e1);
12434 auto f2 = checkNonAssignmentArrayOp(exp.e2);
12435 if (f1 || f2)
12436 return setError();
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);
12463 return;
12466 if (!verifyHookExist(exp.loc, *sc, Id.__equals, "equal checks on arrays"))
12467 return setError();
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
12493 if (!__equals)
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();
12500 result = __equals;
12501 return;
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();
12511 return;
12514 if (auto tv = t1.isTypeVector())
12515 exp.type = tv.toBooleanVector();
12517 result = exp;
12520 override void visit(IdentityExp exp)
12522 if (exp.type)
12524 result = exp;
12525 return;
12528 exp.setNoderefOperands();
12530 if (auto e = binSemanticProp(exp, sc))
12532 result = e;
12533 return;
12536 if (auto e = typeCombine(exp, sc))
12538 result = e;
12539 return;
12542 auto f1 = checkNonAssignmentArrayOp(exp.e1);
12543 auto f2 = checkNonAssignmentArrayOp(exp.e2);
12544 if (f1 || f2)
12545 return setError();
12547 if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
12549 result = exp.incompatibleTypes();
12550 return;
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();
12567 return;
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");
12581 result = exp;
12584 override void visit(CondExp exp)
12586 static if (LOGSEMANTIC)
12588 printf("CondExp::semantic('%s')\n", exp.toChars());
12590 if (exp.type)
12592 result = exp;
12593 return;
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)
12617 result = ec;
12618 return;
12620 if (ec.type == Type.terror)
12621 return setError();
12622 exp.econd = ec;
12624 if (e1x.op == EXP.error)
12626 result = e1x;
12627 return;
12629 if (e1x.type == Type.terror)
12630 return setError();
12631 exp.e1 = e1x;
12633 if (e2x.op == EXP.error)
12635 result = e2x;
12636 return;
12638 if (e2x.type == Type.terror)
12639 return setError();
12640 exp.e2 = e2x;
12642 auto f0 = checkNonAssignmentArrayOp(exp.econd);
12643 auto f1 = checkNonAssignmentArrayOp(exp.e1);
12644 auto f2 = checkNonAssignmentArrayOp(exp.e2);
12645 if (f0 || f1 || f2)
12646 return setError();
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())
12659 return;
12660 if (auto ie = e.optimize(WANTvalue).isIntegerExp())
12662 if (ie.getInteger() == 0)
12664 e = new NullExp(e.loc, Type.tnull);
12665 t = Type.tnull;
12669 rewriteCNull(exp.e1, t1);
12670 rewriteCNull(exp.e2, t2);
12673 if (t1.ty == Tnoreturn)
12675 exp.type = t2;
12676 exp.e1 = specialNoreturnCast(exp.e1, exp.type);
12678 else if (t2.ty == Tnoreturn)
12680 exp.type = t1;
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
12685 // value if any
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);
12693 else if (t1 == t2)
12694 exp.type = t1;
12695 else
12697 if (Expression ex = typeCombine(exp, sc))
12699 result = ex;
12700 return;
12703 switch (exp.e1.type.toBasetype().ty)
12705 case Tcomplex32:
12706 case Tcomplex64:
12707 case Tcomplex80:
12708 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
12709 break;
12710 default:
12711 break;
12713 switch (exp.e2.type.toBasetype().ty)
12715 case Tcomplex32:
12716 case Tcomplex64:
12717 case Tcomplex80:
12718 exp.e1 = exp.e1.castTo(sc, exp.e2.type);
12719 break;
12720 default:
12721 break;
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();
12730 version (none)
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.
12740 * Rewrite:
12741 * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2)
12742 * to:
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()
12748 exp.hookDtors(sc);
12750 result = exp;
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;
12763 auto tc = ec.type;
12765 auto types = (*exp.types)[];
12766 foreach (i, ref t; types)
12768 if (!t)
12769 continue; // `default:` case
12770 t = t.typeSemantic(ec.loc, sc);
12771 if (t.isTypeError())
12773 errors = true;
12774 continue;
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
12783 if (
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
12788 continue;
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());
12795 errors = true;
12796 break;
12801 auto exps = (*exp.exps)[];
12802 foreach (ref e; exps)
12804 e = e.expressionSemantic(sc);
12805 if (e.isErrorExp())
12806 errors = true;
12809 if (errors)
12810 return setError();
12812 enum size_t None = ~0;
12813 size_t imatch = None;
12814 size_t idefault = None;
12815 foreach (const i, t; types)
12817 if (t)
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
12822 if (tc.equals(t))
12824 assert(imatch == None);
12825 imatch = i;
12826 break; // pick first match
12829 else
12830 idefault = i; // multiple defaults are not allowed, and are caught by cparse
12833 if (imatch == None)
12834 imatch = idefault;
12835 if (imatch == None)
12837 error(exp.loc, "no compatible generic association type for controlling expression type `%s`", tc.toChars());
12838 return setError();
12841 result = exps[imatch];
12844 override void visit(FileInitExp e)
12846 //printf("FileInitExp::semantic()\n");
12847 e.type = Type.tstring;
12848 result = e;
12851 override void visit(LineInitExp e)
12853 e.type = Type.tint32;
12854 result = e;
12857 override void visit(ModuleInitExp e)
12859 //printf("ModuleInitExp::semantic()\n");
12860 e.type = Type.tstring;
12861 result = e;
12864 override void visit(FuncInitExp e)
12866 //printf("FuncInitExp::semantic()\n");
12867 e.type = Type.tstring;
12868 if (sc.func)
12870 result = e.resolveLoc(Loc.initial, sc);
12871 return;
12873 result = e;
12876 override void visit(PrettyFuncInitExp e)
12878 //printf("PrettyFuncInitExp::semantic()\n");
12879 e.type = Type.tstring;
12880 if (sc.func)
12882 result = e.resolveLoc(Loc.initial, sc);
12883 return;
12886 result = e;
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))
12901 e = null;
12903 //printf("-trySemantic(%s)\n", exp.toChars());
12904 return e;
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)
12919 return e1x;
12920 e.e1 = e1x;
12921 return null;
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)
12944 return e1x;
12945 if (e2x.op == EXP.error)
12946 return e2x;
12947 e.e1 = e1x;
12948 e.e2 = e2x;
12949 return null;
12952 Expression binSemanticProp(BinExp e, Scope* sc)
12954 if (Expression ex = binSemantic(e, sc))
12955 return ex;
12956 Expression e1x = resolveProperties(sc, e.e1);
12957 Expression e2x = resolveProperties(sc, e.e2);
12958 if (e1x.op == EXP.error)
12959 return e1x;
12960 if (e2x.op == EXP.error)
12961 return e2x;
12962 e.e1 = e1x;
12963 e.e2 = e2x;
12964 return null;
12967 // entrypoint for semantic ExpressionSemanticVisitor
12968 extern (C++) Expression expressionSemantic(Expression e, Scope* sc)
12970 scope v = new ExpressionSemanticVisitor(sc);
12971 e.accept(v);
12972 return v.result;
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))
12979 return ex;
12981 if (!(sc.flags & SCOPE.Cfile) && exp.ident == Id._mangleof)
12983 // symbol.mangleof
12985 // return mangleof as an Expression
12986 static Expression dotMangleof(const ref Loc loc, Scope* sc, Dsymbol ds)
12988 assert(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();
13000 OutBuffer buf;
13001 mangleToBuffer(ds, buf);
13002 Expression e = new StringExp(loc, buf.extractSlice());
13003 return e.expressionSemantic(sc);
13006 Dsymbol ds;
13007 switch (exp.e1.op)
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);
13019 default:
13020 break;
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);
13049 return e;
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();
13065 if (!exp.e1.type)
13067 error(exp.loc, "expression `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
13068 return ErrorExp.get();
13071 return exp;
13074 /******************************
13075 * Resolve properties, i.e. `e1.ident`, without seeing UFCS.
13076 * Params:
13077 * exp = expression to resolve
13078 * sc = context
13079 * gag = do not emit error messages, just return `null`
13080 * Returns:
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);
13103 else
13105 if (auto cd = ad.isClassDeclaration())
13107 if (cd.baseClass)
13108 exp.e1 = new TypeExp(exp.e1.loc, cd.baseClass.type);
13115 Expression e = dotIdSemanticPropX(exp, sc);
13116 if (e != exp)
13117 return e;
13120 Expression eleft;
13121 Expression eright;
13122 if (auto de = exp.e1.isDotExp())
13124 eleft = de.e1;
13125 eright = de.e2;
13127 else
13129 eleft = null;
13130 eright = exp.e1;
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))
13152 s = null;
13154 if (s)
13156 auto p = s.isPackage();
13157 if (p && checkAccess(sc, p))
13159 s = null;
13162 if (s)
13164 // if 's' is a tuple variable, the tuple is returned.
13165 s = s.toAlias();
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());
13177 if (!v.type ||
13178 !v.type.deco && v.inuse)
13180 if (v.inuse)
13181 error(exp.loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
13182 else
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.
13195 if (v.inuse)
13197 error(exp.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
13198 return ErrorExp.get();
13200 auto e = v.expandInitializer(exp.loc);
13201 v.inuse++;
13202 e = e.expressionSemantic(sc);
13203 v.inuse--;
13204 return e;
13207 Expression e;
13208 if (v.needThis())
13210 if (!eleft)
13211 eleft = new ThisExp(exp.loc);
13212 e = new DotVarExp(exp.loc, eleft, v);
13213 e = e.expressionSemantic(sc);
13215 else
13217 e = new VarExp(exp.loc, v);
13218 if (eleft)
13220 e = new CommaExp(exp.loc, eleft, e);
13221 e.type = v.type;
13224 e = e.deref();
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();
13233 Expression e;
13234 if (f.needThis())
13236 if (!eleft)
13237 eleft = new ThisExp(exp.loc);
13238 e = new DotVarExp(exp.loc, eleft, f, true);
13239 e = e.expressionSemantic(sc);
13241 else
13243 e = new VarExp(exp.loc, f, true);
13244 if (eleft)
13246 e = new CommaExp(exp.loc, eleft, e);
13247 e.type = f.type;
13250 return e;
13252 if (auto td = s.isTemplateDeclaration())
13254 Expression e;
13255 if (eleft)
13256 e = new DotTemplateExp(exp.loc, eleft, td);
13257 else
13258 e = new TemplateExp(exp.loc, td);
13259 e = e.expressionSemantic(sc);
13260 return e;
13262 if (OverDeclaration od = s.isOverDeclaration())
13264 Expression e = new VarExp(exp.loc, od, true);
13265 if (eleft)
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())
13285 if (eleft)
13287 Expression e = new DotVarExp(exp.loc, eleft, tup);
13288 e = e.expressionSemantic(sc);
13289 return e;
13291 Expression e = new TupleExp(exp.loc, tup);
13292 e = e.expressionSemantic(sc);
13293 return e;
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);
13301 if (eleft)
13302 e = new DotExp(exp.loc, eleft, e);
13303 return 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);
13317 return es;
13321 // BUG: handle other cases like in IdentifierExp::semantic()
13322 debug
13324 printf("s = %p '%s', kind = '%s'\n", s, s.toChars(), s.kind());
13326 assert(0);
13328 else if (exp.ident == Id.stringof)
13330 Expression e = new StringExp(exp.loc, ie.toString());
13331 e = e.expressionSemantic(sc);
13332 return e;
13334 if (ie.sds.isPackage() || ie.sds.isImport() || ie.sds.isModule())
13336 gag = false;
13338 if (gag)
13339 return null;
13340 s = ie.sds.search_correct(exp.ident);
13341 if (s && symbolIsVisible(sc, s))
13343 if (s.isPackage())
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());
13345 else
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());
13348 else
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 ||
13356 !cfile &&
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();
13364 if (gag)
13366 if (AggregateDeclaration ad = isAggregate(t1bn))
13368 if (!ad.members) // https://issues.dlang.org/show_bug.cgi?id=11312
13369 return null;
13373 /* Rewrite:
13374 * p.ident
13375 * as:
13376 * (*p).ident
13378 if (gag && t1bn.ty == Tvoid)
13379 return null;
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);
13395 return e;
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);
13413 else
13415 if (exp.e1.isTypeExp() || exp.e1.isTemplateExp())
13416 gag = false;
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);
13421 if (e)
13423 e = e.expressionSemantic(sc);
13425 return e;
13430 * Resolve `e1.ident!tiargs` without seeing UFCS.
13431 * Params:
13432 * exp = the `DotTemplateInstanceExp` to resolve
13433 * sc = the semantic scope
13434 * gag = stop "not a property" error and return `null`.
13435 * Returns:
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);
13463 if (e == die)
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"
13472 if (gag)
13473 return null;
13475 e = die.dotIdSemanticProp(sc, gag);
13476 if (gag)
13478 if (!e ||
13479 isDotOpDispatch(e))
13481 /* opDispatch!tiargs would be a function template that needs IFTI,
13482 * so it's not a template
13484 return null;
13488 assert(e);
13490 if (e.op == EXP.error)
13491 return e;
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))
13507 goto Lerr;
13508 if (exp.ti.needsTypeInference(sc))
13509 return exp;
13510 exp.ti.dsymbolSemantic(sc);
13511 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
13512 return errorExp();
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))
13550 return errorExp();
13551 if (exp.ti.needsTypeInference(sc))
13552 return exp;
13553 exp.ti.dsymbolSemantic(sc);
13554 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
13555 return errorExp();
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))
13577 return errorExp();
13579 if (exp.ti.needsTypeInference(sc))
13580 return exp;
13581 exp.ti.dsymbolSemantic(sc);
13582 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
13583 return errorExp();
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);
13603 Lerr:
13604 error(exp.loc, "`%s` isn't a template", e.toChars());
13605 return errorExp();
13608 /***************************************
13609 * If expression is shared, check that we can access it.
13610 * Give error message if not.
13612 * Params:
13613 * e = expression to check
13614 * sc = context
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)*`).
13618 * Returns:
13619 * true on error
13621 bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
13623 if (global.params.noSharedAccess != FeatureState.enabled ||
13624 !sc ||
13625 sc.intypeof ||
13626 sc.flags & SCOPE.ctfe)
13628 return false;
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());
13639 return true;
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);
13649 return false;
13652 bool visitNew(NewExp e)
13654 if (e.thisexp)
13655 check(e.thisexp, false);
13656 return 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())
13665 return false;
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())
13673 return false;
13674 else
13675 return sharedError(e);
13677 else if (!allowRef && e.var.type.isShared())
13678 return sharedError(e);
13680 return false;
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())
13708 return false;
13710 // https://issues.dlang.org/show_bug.cgi?id=23790
13711 if (e.e1.type.isTypeStruct())
13712 return false;
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);
13755 switch (e.op)
13757 default: return visit(e);
13759 // Those have no indirections / can be ignored
13760 case EXP.call:
13761 case EXP.error:
13762 case EXP.complex80:
13763 case EXP.int64:
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.
13782 * Params:
13783 * sc = context
13784 * exp = expression having its address taken
13785 * v = the variable getting its address taken
13786 * Returns:
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());
13792 if (v is null)
13793 return true;
13795 if (!v.canTakeAddressOf())
13797 error(exp.loc, "cannot take address of `%s`", exp.toChars());
13798 return false;
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))
13806 return false;
13809 return true;
13812 /**************************************
13813 * This check ensures that the object in `exp` can have its address taken, or
13814 * issue a diagnostic error.
13815 * Params:
13816 * e = expression to check
13817 * sc = context
13818 * Returns:
13819 * true if the expression is addressable
13821 bool checkAddressable(Expression e, Scope* sc)
13823 Expression ex = e;
13824 while (true)
13826 switch (ex.op)
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());
13835 return false;
13837 goto case EXP.cast_;
13839 case EXP.index:
13840 ex = ex.isBinExp().e1;
13841 continue;
13843 case EXP.address:
13844 case EXP.array:
13845 case EXP.cast_:
13846 ex = ex.isUnaExp().e1;
13847 continue;
13849 case EXP.variable:
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());
13860 else
13861 error(e.loc, "cannot take address of register variable `%s`", ex.toChars());
13862 return false;
13865 break;
13867 default:
13868 break;
13870 break;
13872 return true;
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.
13881 * Params:
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)
13889 with(exp)
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);
13896 return error;
13900 /*******************************
13901 * Helper function for `getRightThis()`.
13902 * Gets `this` of the next outer aggregate.
13903 * Params:
13904 * loc = location to use for error messages
13905 * sc = context
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
13912 * Returns:
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)
13917 int n = 0;
13918 while (s && s.isFuncDeclaration())
13920 FuncDeclaration f = s.isFuncDeclaration();
13921 if (f.vthis)
13923 n++;
13924 e1 = new VarExp(loc, f.vthis);
13925 if (f.hasDualContext())
13927 // (*__this)[i]
13928 if (n > 1)
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);
13934 continue;
13937 else
13939 if (flag)
13940 return null;
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();
13943 return e1;
13945 s = s.toParent2();
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();
13956 e1.type = ta;
13959 e1.type = e1.type.addMod(t.mod);
13960 return e1;
13963 /*******************************
13964 * Make a dual-context container for use as a `this` argument.
13965 * Params:
13966 * loc = location to use for error messages
13967 * sc = current scope
13968 * fd = target function that will take the `this` argument
13969 * Returns:
13970 * Temporary closure variable.
13971 * Note:
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
13984 assert(sc.func);
13985 sc.func.closureVars.push(vthis2);
13986 // add `fd` to the nested refs
13987 vthis2.nestedrefs.push(fd);
13988 return vthis2;
13991 /*******************************
13992 * Make sure that the runtime hook `id` exists.
13993 * Params:
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
13999 * Returns:
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))
14007 return true;
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);
14009 return false;
14012 /***************************************
14013 * Fit elements[] to the corresponding types of the `sd`'s fields.
14015 * Params:
14016 * sd = the struct declaration
14017 * loc = location to use for error messages
14018 * sc = context
14019 * elements = explicit arguments used to construct object
14020 * stype = the constructed object type.
14021 * Returns:
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)
14027 if (!elements)
14028 return true;
14030 const nfields = sd.nonHiddenFields();
14031 size_t offset = 0;
14032 for (size_t i = 0; i < elements.length; i++)
14034 Expression e = (*elements)[i];
14035 if (!e)
14036 continue;
14038 e = resolveProperties(sc, e);
14039 if (i >= nfields)
14041 if (i < sd.fields.length && e.op == EXP.null_)
14043 // CTFE sometimes creates null as hidden pointer; we'll allow this.
14044 continue;
14046 .error(loc, "more initializers than fields (%llu) of `%s`", cast(ulong)nfields, sd.toChars());
14047 return false;
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);
14060 return false;
14062 const vsize = v.type.size();
14063 if (vsize == SIZE_INVALID)
14064 return false;
14065 offset = cast(uint)(v.offset + vsize);
14067 Type t = v.type;
14068 if (stype)
14069 t = t.addMod(stype.mod);
14070 Type origType = t;
14071 Type tb = t.toBasetype();
14073 const hasPointers = tb.hasPointers();
14074 if (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)))
14081 return false;
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
14089 * literal.
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);
14101 goto L1;
14105 while (!e.implicitConvTo(t) && tb.ty == Tsarray)
14107 /* Static array initialization, as in:
14108 * T[3][5] = e;
14110 t = tb.nextOf();
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)
14119 return false;
14121 (*elements)[i] = doCopyOrMove(sc, e);
14123 return true;
14128 * Returns `em` as a VariableExp
14129 * Params:
14130 * em = the EnumMember to wrap
14131 * loc = location of use of em
14132 * sc = scope of use of em
14133 * Returns:
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);
14139 if (em.errors)
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);
14147 if (em.errors)
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;
14157 assert(e.type);
14159 return e;
14163 /*****************************
14164 * Try to treat `exp` as a boolean,
14165 * Params:
14166 * exp = the expression
14167 * sc = scope to evalute `exp` in
14168 * Returns:
14169 * Modified expression on success, ErrorExp on error
14171 Expression toBoolean(Expression exp, Scope* sc)
14173 switch(exp.op)
14175 case EXP.delete_:
14176 error(exp.loc, "`delete` does not give a boolean result");
14177 return ErrorExp.get();
14179 case EXP.comma:
14180 auto ce = exp.isCommaExp();
14181 auto ex2 = ce.e2.toBoolean(sc);
14182 if (ex2.op == EXP.error)
14183 return ex2;
14184 ce.e2 = ex2;
14185 ce.type = ce.e2.type;
14186 return ce;
14188 case EXP.assign:
14189 case EXP.construct:
14190 case EXP.blit:
14191 case EXP.loweredAssignExp:
14192 if (sc.flags & SCOPE.Cfile)
14193 return exp;
14194 // Things like:
14195 // if (a = b) ...
14196 // are usually mistakes.
14197 error(exp.loc, "assignment cannot be used as a condition, perhaps `==` was meant?");
14198 return ErrorExp.get();
14200 //LogicalExp
14201 case EXP.andAnd:
14202 case EXP.orOr:
14203 auto le = exp.isLogicalExp();
14204 auto ex2 = le.e2.toBoolean(sc);
14205 if (ex2.op == EXP.error)
14206 return ex2;
14207 le.e2 = ex2;
14208 return le;
14210 case EXP.question:
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)
14215 return ex1;
14216 if (ex2.op == EXP.error)
14217 return ex2;
14218 ce.e1 = ex1;
14219 ce.e2 = ex2;
14220 return ce;
14223 default:
14224 // Default is 'yes' - do nothing
14225 Expression e = arrayFuncConv(exp, sc);
14226 Type t = e.type;
14227 Type tb = t.toBasetype();
14228 Type att = null;
14230 while (1)
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);
14243 return e;
14246 // Forward to aliasthis.
14247 if (ad.aliasthis && !isRecursiveAliasThis(att, tb))
14249 e = resolveAliasThis(sc, e);
14250 t = e.type;
14251 tb = e.type.toBasetype();
14252 continue;
14255 break;
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();
14265 return e;