d: Merge upstream dmd, druntime 26f049fb26, phobos 330d6a4fd.
[official-gcc.git] / gcc / d / dmd / expressionsem.d
blob25f755bdf0ed0eef92388856e4747509bc2943e5
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 exp.error("`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 ae.error("multi-dimensional slicing requires template `opSlice`");
228 return ErrorExp.get();
230 //printf("[%d] e = %s\n", i, e.toChars());
232 // Create scope for '$' variable for this dimension
233 auto sym = new ArrayScopeSymbol(sc, ae);
234 sym.parent = sc.scopesym;
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 ae.error("`%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 ae.error("`%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 * Pull out callable entity with UFCS.
488 private Expression resolveUFCS(Scope* sc, CallExp ce)
490 Loc loc = ce.loc;
491 Expression eleft;
492 Expression e;
494 if (auto die = ce.e1.isDotIdExp())
496 Identifier ident = die.ident;
498 Expression ex = die.dotIdSemanticPropX(sc);
499 if (ex != die)
501 ce.e1 = ex;
502 return null;
504 eleft = die.e1;
506 Type t = eleft.type.toBasetype();
507 if (t.ty == Tarray || t.ty == Tsarray || t.ty == Tnull || (t.isTypeBasic() && t.ty != Tvoid))
509 /* Built-in types and arrays have no callable properties, so do shortcut.
510 * It is necessary in: e.init()
513 else if (t.ty == Taarray)
515 if (ident == Id.remove)
517 /* Transform:
518 * aa.remove(arg) into delete aa[arg]
520 if (!ce.arguments || ce.arguments.length != 1)
522 ce.error("expected key as argument to `aa.remove()`");
523 return ErrorExp.get();
525 if (!eleft.type.isMutable())
527 ce.error("cannot remove key from `%s` associative array `%s`", MODtoChars(t.mod), eleft.toChars());
528 return ErrorExp.get();
530 Expression key = (*ce.arguments)[0];
531 key = key.expressionSemantic(sc);
532 key = resolveProperties(sc, key);
534 TypeAArray taa = t.isTypeAArray();
535 key = key.implicitCastTo(sc, taa.index);
537 if (key.checkValue() || key.checkSharedAccess(sc))
538 return ErrorExp.get();
540 semanticTypeInfo(sc, taa.index);
542 return new RemoveExp(loc, eleft, key);
545 else
547 if (Expression ey = die.dotIdSemanticProp(sc, 1))
549 if (ey.op == EXP.error)
550 return ey;
551 ce.e1 = ey;
552 if (isDotOpDispatch(ey))
554 // even opDispatch and UFCS must have valid arguments,
555 // so now that we've seen indication of a problem,
556 // check them for issues.
557 Expressions* originalArguments = Expression.arraySyntaxCopy(ce.arguments);
559 uint errors = global.startGagging();
560 e = ce.expressionSemantic(sc);
561 if (!global.endGagging(errors))
562 return e;
564 if (arrayExpressionSemantic(originalArguments.peekSlice(), sc))
565 return ErrorExp.get();
567 /* fall down to UFCS */
569 else
570 return null;
574 /* https://issues.dlang.org/show_bug.cgi?id=13953
576 * If a struct has an alias this to an associative array
577 * and remove is used on a struct instance, we have to
578 * check first if there is a remove function that can be called
579 * on the struct. If not we must check the alias this.
581 * struct A
583 * string[string] a;
584 * alias a this;
587 * void fun()
589 * A s;
590 * s.remove("foo");
593 const errors = global.startGagging();
594 e = searchUFCS(sc, die, ident);
595 // if there were any errors and the identifier was remove
596 if (global.endGagging(errors))
598 if (ident == Id.remove)
600 // check alias this
601 Expression alias_e = resolveAliasThis(sc, die.e1, 1);
602 if (alias_e && alias_e != die.e1)
604 die.e1 = alias_e;
605 CallExp ce2 = ce.syntaxCopy();
606 ce2.e1 = die;
607 e = ce2.isCallExp().trySemantic(sc);
608 if (e)
609 return e;
612 // if alias this did not work out, print the initial errors
613 searchUFCS(sc, die, ident);
616 else if (auto dti = ce.e1.isDotTemplateInstanceExp())
618 if (Expression ey = dti.dotTemplateSemanticProp(sc, DotExpFlag.gag))
620 ce.e1 = ey;
621 return null;
623 eleft = dti.e1;
624 e = searchUFCS(sc, dti, dti.ti.name);
626 else
627 return null;
629 // Rewrite
630 ce.e1 = e;
631 if (!ce.arguments)
632 ce.arguments = new Expressions();
633 ce.arguments.shift(eleft);
634 if (!ce.names)
635 ce.names = new Identifiers();
636 ce.names.shift(null);
637 ce.isUfcsRewrite = true;
638 return null;
641 /******************************
642 * Pull out property with UFCS.
644 private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2 = null)
646 Loc loc = e1.loc;
647 Expression eleft;
648 Expression e;
650 if (auto die = e1.isDotIdExp())
652 eleft = die.e1;
653 e = searchUFCS(sc, die, die.ident);
655 else if (auto dti = e1.isDotTemplateInstanceExp())
657 eleft = dti.e1;
658 e = searchUFCS(sc, dti, dti.ti.name);
660 else
661 return null;
663 if (e is null)
664 return null;
666 // Rewrite
667 if (e2)
669 // run semantic without gagging
670 e2 = e2.expressionSemantic(sc);
672 /* f(e1) = e2
674 Expression ex = e.copy();
675 auto a1 = new Expressions(1);
676 (*a1)[0] = eleft;
677 ex = new CallExp(loc, ex, a1);
678 auto e1PassSemantic = ex.trySemantic(sc);
680 /* f(e1, e2)
682 auto a2 = new Expressions(2);
683 (*a2)[0] = eleft;
684 (*a2)[1] = e2;
685 e = new CallExp(loc, e, a2);
686 e = e.trySemantic(sc);
687 if (!e1PassSemantic && !e)
689 /* https://issues.dlang.org/show_bug.cgi?id=20448
691 * If both versions have failed to pass semantic,
692 * f(e1) = e2 gets priority in error printing
693 * because f might be a templated function that
694 * failed to instantiate and we have to print
695 * the instantiation errors.
697 return e1.expressionSemantic(sc);
699 else if (ex && !e)
701 ex = new AssignExp(loc, ex, e2);
702 return ex.expressionSemantic(sc);
704 else
706 // strict setter prints errors if fails
707 e = e.expressionSemantic(sc);
709 return e;
711 else
713 /* f(e1)
715 auto arguments = new Expressions(1);
716 (*arguments)[0] = eleft;
717 e = new CallExp(loc, e, arguments);
719 // https://issues.dlang.org/show_bug.cgi?id=24017
720 if (sc.flags & SCOPE.debug_)
721 e.isCallExp().inDebugStatement = true;
723 e = e.expressionSemantic(sc);
724 return e;
728 /******************************
729 * If e1 is a property function (template), resolve it.
731 Expression resolvePropertiesOnly(Scope* sc, Expression e1)
733 //printf("e1 = %s %s\n", Token.toChars(e1.op), e1.toChars());
735 Expression handleOverloadSet(OverloadSet os)
737 assert(os);
738 foreach (s; os.a)
740 auto fd = s.isFuncDeclaration();
741 auto td = s.isTemplateDeclaration();
742 if (fd)
744 if (fd.type.isTypeFunction().isproperty)
745 return resolveProperties(sc, e1);
747 else if (td && td.onemember && (fd = td.onemember.isFuncDeclaration()) !is null)
749 if (fd.type.isTypeFunction().isproperty ||
750 (fd.storage_class2 & STC.property) ||
751 (td._scope.stc & STC.property))
752 return resolveProperties(sc, e1);
755 return e1;
758 Expression handleTemplateDecl(TemplateDeclaration td)
760 assert(td);
761 if (td.onemember)
763 if (auto fd = td.onemember.isFuncDeclaration())
765 if (fd.type.isTypeFunction().isproperty ||
766 (fd.storage_class2 & STC.property) ||
767 (td._scope.stc & STC.property))
768 return resolveProperties(sc, e1);
771 return e1;
774 Expression handleFuncDecl(FuncDeclaration fd)
776 assert(fd);
777 if (fd.type.isTypeFunction().isproperty)
778 return resolveProperties(sc, e1);
779 return e1;
782 if (auto de = e1.isDotExp())
784 if (auto os = de.e2.isOverExp())
785 return handleOverloadSet(os.vars);
787 else if (auto oe = e1.isOverExp())
788 return handleOverloadSet(oe.vars);
789 else if (auto dti = e1.isDotTemplateInstanceExp())
791 if (dti.ti.tempdecl)
792 if (auto td = dti.ti.tempdecl.isTemplateDeclaration())
793 return handleTemplateDecl(td);
795 else if (auto dte = e1.isDotTemplateExp())
796 return handleTemplateDecl(dte.td);
797 else if (auto se = e1.isScopeExp())
799 Dsymbol s = se.sds;
800 TemplateInstance ti = s.isTemplateInstance();
801 if (ti && !ti.semanticRun && ti.tempdecl)
802 if (auto td = ti.tempdecl.isTemplateDeclaration())
803 return handleTemplateDecl(td);
805 else if (auto et = e1.isTemplateExp())
806 return handleTemplateDecl(et.td);
807 else if (e1.isDotVarExp() && e1.type.isTypeFunction())
809 DotVarExp dve = e1.isDotVarExp();
810 return handleFuncDecl(dve.var.isFuncDeclaration());
812 else if (e1.isVarExp() && e1.type && e1.type.isTypeFunction() && (sc.intypeof || !e1.isVarExp().var.needThis()))
813 return handleFuncDecl(e1.isVarExp().var.isFuncDeclaration());
814 return e1;
817 /****************************************
818 * Turn symbol `s` into the expression it represents.
820 * Params:
821 * s = symbol to resolve
822 * loc = location of use of `s`
823 * sc = context
824 * hasOverloads = applies if `s` represents a function.
825 * true means it's overloaded and will be resolved later,
826 * false means it's the exact function symbol.
827 * Returns:
828 * `s` turned into an expression, `ErrorExp` if an error occurred
830 Expression symbolToExp(Dsymbol s, const ref Loc loc, Scope *sc, bool hasOverloads)
832 static if (LOGSEMANTIC)
834 printf("DsymbolExp::resolve(%s %s)\n", s.kind(), s.toChars());
837 Lagain:
838 Expression e;
840 //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars());
841 //printf("s = '%s', s.kind = '%s'\n", s.toChars(), s.kind());
842 Dsymbol olds = s;
843 Declaration d = s.isDeclaration();
844 if (d && (d.storage_class & STC.templateparameter))
846 s = s.toAlias();
848 else
850 // functions are checked after overloading
851 // templates are checked after matching constraints
852 if (!s.isFuncDeclaration() && !s.isTemplateDeclaration())
854 s.checkDeprecated(loc, sc);
855 if (d)
856 d.checkDisabled(loc, sc);
859 // https://issues.dlang.org/show_bug.cgi?id=12023
860 // if 's' is a tuple variable, the tuple is returned.
861 s = s.toAlias();
863 //printf("s = '%s', s.kind = '%s', s.needThis() = %p\n", s.toChars(), s.kind(), s.needThis());
864 if (s != olds && !s.isFuncDeclaration() && !s.isTemplateDeclaration())
866 s.checkDeprecated(loc, sc);
867 if (d)
868 d.checkDisabled(loc, sc);
871 if (auto sd = s.isDeclaration())
873 if (sd.isSystem())
875 if (sc.setUnsafePreview(global.params.systemVariables, false, loc,
876 "cannot access `@system` variable `%s` in @safe code", sd))
878 return ErrorExp.get();
884 if (auto em = s.isEnumMember())
886 return em.getVarExp(loc, sc);
888 if (auto v = s.isVarDeclaration())
890 //printf("Identifier '%s' is a variable, type '%s'\n", s.toChars(), v.type.toChars());
891 if (sc.intypeof == 1 && !v.inuse)
892 v.dsymbolSemantic(sc);
893 if (!v.type || // during variable type inference
894 !v.type.deco && v.inuse) // during variable type semantic
896 if (v.inuse) // variable type depends on the variable itself
897 error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
898 else // variable type cannot be determined
899 error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
900 return ErrorExp.get();
902 if (v.type.ty == Terror)
903 return ErrorExp.get();
905 if ((v.storage_class & STC.manifest) && v._init)
907 if (v.inuse)
909 error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
910 return ErrorExp.get();
912 e = v.expandInitializer(loc);
913 v.inuse++;
914 e = e.expressionSemantic(sc);
915 v.inuse--;
916 return e;
919 // We need to run semantics to correctly set 'STC.field' if it is a member variable
920 // that could be forward referenced. This is needed for 'v.needThis()' to work
921 if (v.isThis())
922 v.dsymbolSemantic(sc);
924 // Change the ancestor lambdas to delegate before hasThis(sc) call.
925 if (v.checkNestedReference(sc, loc))
926 return ErrorExp.get();
928 if (v.needThis() && hasThis(sc))
929 e = new DotVarExp(loc, new ThisExp(loc), v);
930 else
931 e = new VarExp(loc, v);
932 e = e.expressionSemantic(sc);
933 return e;
935 if (auto fld = s.isFuncLiteralDeclaration())
937 //printf("'%s' is a function literal\n", fld.toChars());
938 e = new FuncExp(loc, fld);
939 return e.expressionSemantic(sc);
941 if (auto f = s.isFuncDeclaration())
943 f = f.toAliasFunc();
944 if (!f.functionSemantic())
945 return ErrorExp.get();
947 if (!hasOverloads && f.checkForwardRef(loc))
948 return ErrorExp.get();
950 auto fd = s.isFuncDeclaration();
951 fd.type = f.type;
952 return new VarExp(loc, fd, hasOverloads);
954 if (OverDeclaration od = s.isOverDeclaration())
956 e = new VarExp(loc, od, true);
957 e.type = Type.tvoid;
958 return e;
960 if (OverloadSet o = s.isOverloadSet())
962 //printf("'%s' is an overload set\n", o.toChars());
963 return new OverExp(loc, o);
966 if (Import imp = s.isImport())
968 if (!imp.pkg)
970 .error(loc, "forward reference of import `%s`", imp.toChars());
971 return ErrorExp.get();
973 auto ie = new ScopeExp(loc, imp.pkg);
974 return ie.expressionSemantic(sc);
976 if (Package pkg = s.isPackage())
978 auto ie = new ScopeExp(loc, pkg);
979 return ie.expressionSemantic(sc);
981 if (Module mod = s.isModule())
983 auto ie = new ScopeExp(loc, mod);
984 return ie.expressionSemantic(sc);
986 if (Nspace ns = s.isNspace())
988 auto ie = new ScopeExp(loc, ns);
989 return ie.expressionSemantic(sc);
992 if (Type t = s.getType())
994 return (new TypeExp(loc, t)).expressionSemantic(sc);
997 if (TupleDeclaration tup = s.isTupleDeclaration())
999 if (tup.needThis() && hasThis(sc))
1000 e = new DotVarExp(loc, new ThisExp(loc), tup);
1001 else
1002 e = new TupleExp(loc, tup);
1003 e = e.expressionSemantic(sc);
1004 return e;
1007 if (TemplateInstance ti = s.isTemplateInstance())
1009 ti.dsymbolSemantic(sc);
1010 if (!ti.inst || ti.errors)
1011 return ErrorExp.get();
1012 s = ti.toAlias();
1013 if (!s.isTemplateInstance())
1014 goto Lagain;
1015 e = new ScopeExp(loc, ti);
1016 e = e.expressionSemantic(sc);
1017 return e;
1019 if (TemplateDeclaration td = s.isTemplateDeclaration())
1021 Dsymbol p = td.toParentLocal();
1022 FuncDeclaration fdthis = hasThis(sc);
1023 AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null;
1024 if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0)
1026 e = new DotTemplateExp(loc, new ThisExp(loc), td);
1028 else
1029 e = new TemplateExp(loc, td);
1030 e = e.expressionSemantic(sc);
1031 return e;
1034 .error(loc, "%s `%s` is not a variable", s.kind(), s.toChars());
1035 return ErrorExp.get();
1038 /*************************************************************
1039 * Given var, get the
1040 * right `this` pointer if var is in an outer class, but our
1041 * existing `this` pointer is in an inner class.
1042 * Params:
1043 * loc = location to use for error messages
1044 * sc = context
1045 * ad = struct or class we need the correct `this` for
1046 * e1 = existing `this`
1047 * var = the specific member of ad we're accessing
1048 * flag = if true, return `null` instead of throwing an error
1049 * Returns:
1050 * Expression representing the `this` for the var
1052 private Expression getRightThis(const ref Loc loc, Scope* sc, AggregateDeclaration ad, Expression e1, Dsymbol var, int flag = 0)
1054 //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars());
1056 Type t = e1.type.toBasetype();
1057 //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars());
1059 if (e1.op == EXP.objcClassReference)
1061 // We already have an Objective-C class reference, just use that as 'this'.
1062 return e1;
1064 else if (ad && ad.isClassDeclaration && ad.isClassDeclaration.classKind == ClassKind.objc &&
1065 var.isFuncDeclaration && var.isFuncDeclaration.isStatic &&
1066 var.isFuncDeclaration.objc.selector)
1068 return new ObjcClassReferenceExp(e1.loc, ad.isClassDeclaration());
1071 /* Access of a member which is a template parameter in dual-scope scenario
1072 * class A { inc(alias m)() { ++m; } } // `m` needs `this` of `B`
1073 * class B {int m; inc() { new A().inc!m(); } }
1075 if (e1.op == EXP.this_)
1077 FuncDeclaration f = hasThis(sc);
1078 if (f && f.hasDualContext())
1080 if (f.followInstantiationContext(ad))
1082 e1 = new VarExp(loc, f.vthis);
1083 e1 = new PtrExp(loc, e1);
1084 e1 = new IndexExp(loc, e1, IntegerExp.literal!1);
1085 e1 = getThisSkipNestedFuncs(loc, sc, f.toParent2(), ad, e1, t, var);
1086 if (e1.op == EXP.error)
1087 return e1;
1088 goto L1;
1093 /* If e1 is not the 'this' pointer for ad
1095 if (ad &&
1096 !(t.isTypePointer() && t.nextOf().isTypeStruct() && t.nextOf().isTypeStruct().sym == ad) &&
1097 !(t.isTypeStruct() && t.isTypeStruct().sym == ad))
1099 ClassDeclaration cd = ad.isClassDeclaration();
1100 ClassDeclaration tcd = t.isClassHandle();
1102 /* e1 is the right this if ad is a base class of e1
1104 if (!cd || !tcd || !(tcd == cd || cd.isBaseOf(tcd, null)))
1106 /* Only classes can be inner classes with an 'outer'
1107 * member pointing to the enclosing class instance
1109 if (tcd && tcd.isNested())
1111 /* e1 is the 'this' pointer for an inner class: tcd.
1112 * Rewrite it as the 'this' pointer for the outer class.
1114 auto vthis = tcd.followInstantiationContext(ad) ? tcd.vthis2 : tcd.vthis;
1115 e1 = new DotVarExp(loc, e1, vthis);
1116 e1.type = vthis.type;
1117 e1.type = e1.type.addMod(t.mod);
1118 // Do not call ensureStaticLinkTo()
1119 //e1 = e1.semantic(sc);
1121 // Skip up over nested functions, and get the enclosing
1122 // class type.
1123 e1 = getThisSkipNestedFuncs(loc, sc, tcd.toParentP(ad), ad, e1, t, var);
1124 if (e1.op == EXP.error)
1125 return e1;
1126 goto L1;
1129 /* Can't find a path from e1 to ad
1131 if (flag)
1132 return null;
1133 e1.error("`this` for `%s` needs to be type `%s` not type `%s`", var.toChars(), ad.toChars(), t.toChars());
1134 return ErrorExp.get();
1137 return e1;
1141 * Check whether `outerFunc` and `calledFunc` have the same `this`.
1142 * If `calledFunc` is the member of a base class of the class that contains
1143 * `outerFunc` we consider that they have the same this.
1145 * This function is used to test whether `this` needs to be prepended to
1146 * a function call or function symbol. For example:
1148 * struct X
1150 * void gun() {}
1152 * struct A
1154 * void fun() {}
1155 * void sun()
1157 * fun();
1158 * X.gun(); // error
1162 * When `fun` is called, `outerfunc` = `sun` and `calledFunc = `fun`.
1163 * `sun` is a member of `A` and `fun` is also a member of `A`, therefore
1164 * `this` can be prepended to `fun`. When `gun` is called (it will result
1165 * in an error, but that is not relevant here), which is a member of `X`,
1166 * no `this` is needed because the outer function does not have the same
1167 * `this` as `gun`.
1169 * Returns:
1170 * `true` if outerFunc and calledFunc may use the same `this` pointer.
1171 * `false` otherwise.
1173 private bool haveSameThis(FuncDeclaration outerFunc, FuncDeclaration calledFunc)
1175 // https://issues.dlang.org/show_bug.cgi?id=24013
1176 // traits(getOverloads) inserts an alias to select the overload.
1177 // When searching for the right this we need to use the aliased
1178 // overload/function, not the alias.
1179 outerFunc = outerFunc.toAliasFunc();
1180 calledFunc = calledFunc.toAliasFunc();
1182 auto thisAd = outerFunc.isMemberLocal();
1183 if (!thisAd)
1184 return false;
1186 auto requiredAd = calledFunc.isMemberLocal();
1187 if (!requiredAd)
1188 return false;
1190 if (thisAd == requiredAd)
1191 return true;
1193 // outerfunc is the member of a base class that contains calledFunc,
1194 // then we consider that they have the same this.
1195 auto cd = requiredAd.isClassDeclaration();
1196 if (!cd)
1197 return false;
1199 if (cd.isBaseOf2(thisAd.isClassDeclaration()))
1200 return true;
1202 // if outerfunc is the member of a nested aggregate, then let
1203 // getRightThis take care of this.
1204 if (thisAd.isNested())
1205 return true;
1207 return false;
1210 /***************************************
1211 * Pull out any properties.
1213 private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null, BinExp saveAtts = null)
1215 //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null);
1216 Loc loc = e1.loc;
1218 OverloadSet os;
1219 Dsymbol s;
1220 Objects* tiargs;
1221 Type tthis;
1222 if (auto de = e1.isDotExp())
1224 if (auto oe = de.e2.isOverExp())
1226 tiargs = null;
1227 tthis = de.e1.type;
1228 os = oe.vars;
1229 goto Los;
1232 else if (e1.isOverExp())
1234 tiargs = null;
1235 tthis = null;
1236 os = e1.isOverExp().vars;
1237 Los:
1238 assert(os);
1239 FuncDeclaration fd = null;
1240 if (e2)
1242 e2 = e2.expressionSemantic(sc);
1243 if (e2.op == EXP.error)
1244 return ErrorExp.get();
1245 e2 = resolveProperties(sc, e2);
1247 Expressions* a = new Expressions();
1248 a.push(e2);
1250 for (size_t i = 0; i < os.a.length; i++)
1252 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(a), FuncResolveFlag.quiet))
1254 if (f.errors)
1255 return ErrorExp.get();
1256 fd = f;
1257 assert(fd.type.ty == Tfunction);
1260 if (fd)
1262 Expression e = new CallExp(loc, e1, e2);
1263 return e.expressionSemantic(sc);
1267 for (size_t i = 0; i < os.a.length; i++)
1269 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet))
1271 if (f.errors)
1272 return ErrorExp.get();
1273 fd = f;
1274 assert(fd.type.ty == Tfunction);
1275 auto tf = fd.type.isTypeFunction();
1276 if (!tf.isref && e2)
1278 error(loc, "%s is not an lvalue", e1.toChars());
1279 return ErrorExp.get();
1283 if (fd)
1285 Expression e = new CallExp(loc, e1);
1286 if (e2)
1288 e = new AssignExp(loc, e, e2);
1289 if (saveAtts)
1291 (cast(BinExp)e).att1 = saveAtts.att1;
1292 (cast(BinExp)e).att2 = saveAtts.att2;
1295 return e.expressionSemantic(sc);
1298 if (e2)
1299 goto Leprop;
1301 else if (auto dti = e1.isDotTemplateInstanceExp())
1303 if (!dti.findTempDecl(sc))
1304 goto Leprop;
1305 if (!dti.ti.semanticTiargs(sc))
1306 goto Leprop;
1307 tiargs = dti.ti.tiargs;
1308 tthis = dti.e1.type;
1309 if ((os = dti.ti.tempdecl.isOverloadSet()) !is null)
1310 goto Los;
1311 if ((s = dti.ti.tempdecl) !is null)
1312 goto Lfd;
1314 else if (auto dte = e1.isDotTemplateExp())
1316 s = dte.td;
1317 tiargs = null;
1318 tthis = dte.e1.type;
1319 goto Lfd;
1321 else if (auto se = e1.isScopeExp())
1323 s = se.sds;
1324 TemplateInstance ti = s.isTemplateInstance();
1325 if (ti && !ti.semanticRun && ti.tempdecl)
1327 //assert(ti.needsTypeInference(sc));
1328 if (!ti.semanticTiargs(sc))
1329 goto Leprop;
1330 tiargs = ti.tiargs;
1331 tthis = null;
1332 if ((os = ti.tempdecl.isOverloadSet()) !is null)
1333 goto Los;
1334 if ((s = ti.tempdecl) !is null)
1335 goto Lfd;
1338 else if (auto te = e1.isTemplateExp())
1340 s = te.td;
1341 tiargs = null;
1342 tthis = null;
1343 goto Lfd;
1345 else if (e1.isDotVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isDotVarExp().var.isOverDeclaration()))
1347 DotVarExp dve = e1.isDotVarExp();
1348 s = dve.var;
1349 tiargs = null;
1350 tthis = dve.e1.type;
1351 goto Lfd;
1353 else if (sc && sc.flags & SCOPE.Cfile && e1.isVarExp() && !e2)
1355 // ImportC: do not implicitly call function if no ( ) are present
1357 else if (e1.isVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isVarExp().var.isOverDeclaration()))
1359 s = e1.isVarExp().var;
1360 tiargs = null;
1361 tthis = null;
1362 Lfd:
1363 assert(s);
1364 if (e2)
1366 e2 = e2.expressionSemantic(sc);
1367 if (e2.op == EXP.error)
1368 return ErrorExp.get();
1369 e2 = resolveProperties(sc, e2);
1371 Expressions* a = new Expressions();
1372 a.push(e2);
1374 FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(a), FuncResolveFlag.quiet);
1375 if (fd && fd.type)
1377 if (fd.errors)
1378 return ErrorExp.get();
1379 assert(fd.type.ty == Tfunction);
1380 Expression e = new CallExp(loc, e1, e2);
1381 return e.expressionSemantic(sc);
1385 FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet);
1386 if (fd && fd.type)
1388 if (fd.errors)
1389 return ErrorExp.get();
1390 TypeFunction tf = fd.type.isTypeFunction();
1391 if (!e2 || tf.isref)
1393 Expression e = new CallExp(loc, e1);
1394 if (e2)
1396 e = new AssignExp(loc, e, e2);
1397 if (saveAtts)
1399 (cast(BinExp)e).att1 = saveAtts.att1;
1400 (cast(BinExp)e).att2 = saveAtts.att2;
1403 return e.expressionSemantic(sc);
1407 if (FuncDeclaration fd = s.isFuncDeclaration())
1409 // Keep better diagnostic message for invalid property usage of functions
1410 assert(fd.type.ty == Tfunction);
1411 Expression e = new CallExp(loc, e1, e2);
1412 return e.expressionSemantic(sc);
1414 if (e2)
1415 goto Leprop;
1417 if (auto ve = e1.isVarExp())
1419 if (auto v = ve.var.isVarDeclaration())
1421 if (ve.checkPurity(sc, v))
1422 return ErrorExp.get();
1425 if (e2)
1426 return null;
1428 if (e1.type && !e1.isTypeExp()) // function type is not a property
1430 /* Look for e1 being a lazy parameter; rewrite as delegate call
1431 * only if the symbol wasn't already treated as a delegate
1433 auto ve = e1.isVarExp();
1434 if (ve && ve.var.storage_class & STC.lazy_ && !ve.delegateWasExtracted)
1436 Expression e = new CallExp(loc, e1);
1437 return e.expressionSemantic(sc);
1439 else if (e1.isDotVarExp())
1441 // Check for reading overlapped pointer field in @safe code.
1442 if (checkUnsafeAccess(sc, e1, true, true))
1443 return ErrorExp.get();
1445 else if (auto ce = e1.isCallExp())
1447 // Check for reading overlapped pointer field in @safe code.
1448 if (checkUnsafeAccess(sc, ce.e1, true, true))
1449 return ErrorExp.get();
1453 if (!e1.type)
1455 error(loc, "cannot resolve type for %s", e1.toChars());
1456 e1 = ErrorExp.get();
1458 return e1;
1460 Leprop:
1461 error(loc, "not a property %s", e1.toChars());
1462 return ErrorExp.get();
1465 extern (C++) Expression resolveProperties(Scope* sc, Expression e)
1467 //printf("resolveProperties(%s)\n", e.toChars());
1468 e = resolvePropertiesX(sc, e);
1469 if (e.checkRightThis(sc))
1470 return ErrorExp.get();
1471 return e;
1474 /****************************************
1475 * The common type is determined by applying ?: to each pair.
1476 * Output:
1477 * exps[] properties resolved, implicitly cast to common type, rewritten in place
1478 * Returns:
1479 * The common type, or `null` if an error has occured
1481 private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
1483 /* Still have a problem with:
1484 * ubyte[][] = [ cast(ubyte[])"hello", [1]];
1485 * which works if the array literal is initialized top down with the ubyte[][]
1486 * type, but fails with this function doing bottom up typing.
1489 //printf("arrayExpressionToCommonType()\n");
1490 scope IntegerExp integerexp = IntegerExp.literal!0;
1491 scope CondExp condexp = new CondExp(Loc.initial, integerexp, null, null);
1493 Type t0 = null;
1494 Expression e0 = null;
1495 bool foundType;
1497 for (size_t i = 0; i < exps.length; i++)
1499 Expression e = exps[i];
1500 if (!e)
1501 continue;
1503 e = resolveProperties(sc, e);
1504 if (!e.type)
1506 e.error("`%s` has no value", e.toChars());
1507 t0 = Type.terror;
1508 continue;
1510 if (e.op == EXP.type)
1512 foundType = true; // do not break immediately, there might be more errors
1513 e.checkValue(); // report an error "type T has no value"
1514 t0 = Type.terror;
1515 continue;
1517 if (e.type.ty == Tvoid)
1519 // void expressions do not concur to the determination of the common
1520 // type.
1521 continue;
1523 if (checkNonAssignmentArrayOp(e))
1525 t0 = Type.terror;
1526 continue;
1529 e = doCopyOrMove(sc, e);
1531 if (!foundType && t0 && !t0.equals(e.type))
1533 /* This applies ?: to merge the types. It's backwards;
1534 * ?: should call this function to merge types.
1536 condexp.type = null;
1537 condexp.e1 = e0;
1538 condexp.e2 = e;
1539 condexp.loc = e.loc;
1540 Expression ex = condexp.expressionSemantic(sc);
1541 if (ex.op == EXP.error)
1542 e = ex;
1543 else
1545 // Convert to common type
1546 exps[i] = condexp.e1.castTo(sc, condexp.type);
1547 e = condexp.e2.castTo(sc, condexp.type);
1550 e0 = e;
1551 t0 = e.type;
1552 if (e.op != EXP.error)
1553 exps[i] = e;
1556 // [] is typed as void[]
1557 if (!t0)
1558 return Type.tvoid;
1560 // It's an error, don't do the cast
1561 if (t0.ty == Terror)
1562 return null;
1564 for (size_t i = 0; i < exps.length; i++)
1566 Expression e = exps[i];
1567 if (!e)
1568 continue;
1570 e = e.implicitCastTo(sc, t0);
1571 if (e.op == EXP.error)
1573 /* https://issues.dlang.org/show_bug.cgi?id=13024
1574 * a workaround for the bug in typeMerge -
1575 * it should paint e1 and e2 by deduced common type,
1576 * but doesn't in this particular case.
1578 return null;
1580 exps[i] = e;
1582 return t0;
1585 private Expression opAssignToOp(const ref Loc loc, EXP op, Expression e1, Expression e2)
1587 Expression e;
1588 switch (op)
1590 case EXP.addAssign:
1591 e = new AddExp(loc, e1, e2);
1592 break;
1594 case EXP.minAssign:
1595 e = new MinExp(loc, e1, e2);
1596 break;
1598 case EXP.mulAssign:
1599 e = new MulExp(loc, e1, e2);
1600 break;
1602 case EXP.divAssign:
1603 e = new DivExp(loc, e1, e2);
1604 break;
1606 case EXP.modAssign:
1607 e = new ModExp(loc, e1, e2);
1608 break;
1610 case EXP.andAssign:
1611 e = new AndExp(loc, e1, e2);
1612 break;
1614 case EXP.orAssign:
1615 e = new OrExp(loc, e1, e2);
1616 break;
1618 case EXP.xorAssign:
1619 e = new XorExp(loc, e1, e2);
1620 break;
1622 case EXP.leftShiftAssign:
1623 e = new ShlExp(loc, e1, e2);
1624 break;
1626 case EXP.rightShiftAssign:
1627 e = new ShrExp(loc, e1, e2);
1628 break;
1630 case EXP.unsignedRightShiftAssign:
1631 e = new UshrExp(loc, e1, e2);
1632 break;
1634 default:
1635 assert(0);
1637 return e;
1640 /*********************
1641 * Rewrite:
1642 * array.length op= e2
1644 private Expression rewriteOpAssign(BinExp exp)
1646 ArrayLengthExp ale = exp.e1.isArrayLengthExp();
1647 if (ale.e1.isVarExp())
1649 // array.length = array.length op e2
1650 Expression e = opAssignToOp(exp.loc, exp.op, ale, exp.e2);
1651 e = new AssignExp(exp.loc, ale.syntaxCopy(), e);
1652 return e;
1654 else
1656 // (ref tmp = array;), tmp.length = tmp.length op e2
1657 auto tmp = copyToTemp(STC.ref_, "__arraylength", ale.e1);
1658 Expression e1 = new ArrayLengthExp(ale.loc, new VarExp(ale.loc, tmp));
1659 Expression elvalue = e1.syntaxCopy();
1660 Expression e = opAssignToOp(exp.loc, exp.op, e1, exp.e2);
1661 e = new AssignExp(exp.loc, elvalue, e);
1662 e = new CommaExp(exp.loc, new DeclarationExp(ale.loc, tmp), e);
1663 return e;
1667 /****************************************
1668 * Preprocess arguments to function.
1670 * Tuples in argumentList get expanded, properties resolved, rewritten in place
1672 * Params:
1673 * sc = scope
1674 * argumentList = arguments to function
1675 * reportErrors = whether or not to report errors here. Some callers are not
1676 * checking actual function params, so they'll do their own error reporting
1677 * Returns:
1678 * `true` when a semantic error occurred
1680 private bool preFunctionParameters(Scope* sc, ArgumentList argumentList, const bool reportErrors = true)
1682 Expressions* exps = argumentList.arguments;
1683 bool err = false;
1684 if (exps)
1686 expandTuples(exps, argumentList.names);
1688 for (size_t i = 0; i < exps.length; i++)
1690 Expression arg = (*exps)[i];
1691 arg = resolveProperties(sc, arg);
1692 arg = arg.arrayFuncConv(sc);
1693 if (arg.op == EXP.type)
1695 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
1696 arg = resolveAliasThis(sc, arg);
1698 if (arg.op == EXP.type)
1700 if (reportErrors)
1702 arg.error("cannot pass type `%s` as a function argument", arg.toChars());
1703 arg = ErrorExp.get();
1705 err = true;
1708 else if (arg.type.toBasetype().ty == Tfunction)
1710 if (reportErrors)
1712 arg.error("cannot pass function `%s` as a function argument", arg.toChars());
1713 arg = ErrorExp.get();
1715 err = true;
1717 else if (checkNonAssignmentArrayOp(arg))
1719 arg = ErrorExp.get();
1720 err = true;
1722 (*exps)[i] = arg;
1725 return err;
1728 /********************************************
1729 * Issue an error if default construction is disabled for type t.
1730 * Default construction is required for arrays and 'out' parameters.
1731 * Returns:
1732 * true an error was issued
1734 private bool checkDefCtor(Loc loc, Type t)
1736 if (auto ts = t.baseElemOf().isTypeStruct())
1738 StructDeclaration sd = ts.sym;
1739 if (sd.noDefaultCtor)
1741 sd.error(loc, "default construction is disabled");
1742 return true;
1745 return false;
1748 /****************************************
1749 * Now that we know the exact type of the function we're calling,
1750 * the arguments[] need to be adjusted:
1751 * 1. implicitly convert argument to the corresponding parameter type
1752 * 2. add default arguments for any missing arguments
1753 * 3. do default promotions on arguments corresponding to ...
1754 * 4. add hidden _arguments[] argument
1755 * 5. call copy constructor for struct value arguments
1756 * Params:
1757 * loc = location of function call
1758 * sc = context
1759 * tf = type of the function
1760 * ethis = `this` argument, `null` if none or not known
1761 * tthis = type of `this` argument, `null` if no `this` argument
1762 * argumentsList = array of actual arguments to function call
1763 * fd = the function being called, `null` if called indirectly
1764 * prettype = set to return type of function
1765 * peprefix = set to expression to execute before `arguments[]` are evaluated, `null` if none
1766 * Returns:
1767 * true errors happened
1769 private bool functionParameters(const ref Loc loc, Scope* sc,
1770 TypeFunction tf, Expression ethis, Type tthis, ArgumentList argumentList, FuncDeclaration fd,
1771 Type* prettype, Expression* peprefix)
1773 Expressions* arguments = argumentList.arguments;
1774 //printf("functionParameters() %s\n", fd ? fd.toChars() : "");
1775 assert(arguments);
1776 assert(fd || tf.next);
1777 const size_t nparams = tf.parameterList.length;
1778 const olderrors = global.errors;
1779 bool err = false;
1780 Expression eprefix = null;
1781 *peprefix = null;
1783 if (argumentList.names)
1785 const(char)* msg = null;
1786 auto resolvedArgs = tf.resolveNamedArgs(argumentList, &msg);
1787 if (!resolvedArgs)
1789 // while errors are usually already caught by `tf.callMatch`,
1790 // this can happen when calling `typeof(freefunc)`
1791 if (msg)
1792 error(loc, "%s", msg);
1793 return true;
1795 // note: the argument list should be mutated with named arguments / default arguments,
1796 // so we can't simply change the pointer like `arguments = resolvedArgs;`
1797 arguments.setDim(0);
1798 arguments.pushSlice((*resolvedArgs)[]);
1800 size_t nargs = arguments ? arguments.length : 0;
1802 if (nargs > nparams && tf.parameterList.varargs == VarArg.none)
1804 error(loc, "expected %llu arguments, not %llu for non-variadic function type `%s`", cast(ulong)nparams, cast(ulong)nargs, tf.toChars());
1805 return true;
1808 // If inferring return type, and semantic3() needs to be run if not already run
1809 if (!tf.next && fd.inferRetType)
1811 fd.functionSemantic();
1813 else if (fd && fd.parent)
1815 TemplateInstance ti = fd.parent.isTemplateInstance();
1816 if (ti && ti.tempdecl)
1818 fd.functionSemantic3();
1822 /* If calling a pragma(inline, true) function,
1823 * set flag to later scan for inlines.
1825 if (fd && fd.inlining == PINLINE.always)
1827 if (sc._module)
1828 sc._module.hasAlwaysInlines = true;
1829 if (sc.func)
1830 sc.func.hasAlwaysInlines = true;
1833 const isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration();
1835 const size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams)
1837 /* If the function return type has wildcards in it, we'll need to figure out the actual type
1838 * based on the actual argument types.
1839 * Start with the `this` argument, later on merge into wildmatch the mod bits of the rest
1840 * of the arguments.
1842 MOD wildmatch = (tthis && !isCtorCall) ? tthis.Type.deduceWild(tf, false) : 0;
1844 bool done = false;
1845 foreach (const i; 0 .. n)
1847 Expression arg = (i < nargs) ? (*arguments)[i] : null;
1849 if (i < nparams)
1851 bool errorArgs()
1853 error(loc, "expected %llu function arguments, not %llu", cast(ulong)nparams, cast(ulong)nargs);
1854 return true;
1857 Parameter p = tf.parameterList[i];
1859 if (!arg)
1861 if (!p.defaultArg)
1863 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams)
1864 goto L2;
1865 return errorArgs();
1867 arg = p.defaultArg;
1868 if (!arg.type)
1869 arg = arg.expressionSemantic(sc);
1870 arg = inlineCopy(arg, sc);
1871 // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
1872 arg = arg.resolveLoc(loc, sc);
1873 if (i >= nargs)
1875 arguments.push(arg);
1876 nargs++;
1878 else
1879 (*arguments)[i] = arg;
1881 else
1883 if (isDefaultInitOp(arg.op))
1885 arg = arg.resolveLoc(loc, sc);
1886 (*arguments)[i] = arg;
1891 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams) // https://dlang.org/spec/function.html#variadic
1893 //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars());
1895 MATCH m;
1896 if ((m = arg.implicitConvTo(p.type)) > MATCH.nomatch)
1898 if (p.type.nextOf() && arg.implicitConvTo(p.type.nextOf()) >= m)
1899 goto L2;
1900 else if (nargs != nparams)
1901 return errorArgs();
1902 goto L1;
1906 Type tb = p.type.toBasetype();
1907 switch (tb.ty)
1909 case Tsarray:
1910 case Tarray:
1912 /* Create a static array variable v of type arg.type:
1913 * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
1915 * The array literal in the initializer of the hidden variable
1916 * is now optimized.
1917 * https://issues.dlang.org/show_bug.cgi?id=2356
1919 Type tbn = (cast(TypeArray)tb).next; // array element type
1920 Type tret = p.isLazyArray();
1922 auto elements = new Expressions(nargs - i);
1923 foreach (u; 0 .. elements.length)
1925 Expression a = (*arguments)[i + u];
1926 if (tret && a.implicitConvTo(tret))
1928 // p is a lazy array of delegates, tret is return type of the delegates
1929 a = a.implicitCastTo(sc, tret)
1930 .optimize(WANTvalue)
1931 .toDelegate(tret, sc);
1933 else
1934 a = a.implicitCastTo(sc, tbn);
1935 a = a.addDtorHook(sc);
1936 (*elements)[u] = a;
1938 // https://issues.dlang.org/show_bug.cgi?id=14395
1939 // Convert to a static array literal, or its slice.
1940 arg = new ArrayLiteralExp(loc, tbn.sarrayOf(nargs - i), elements);
1941 if (tb.ty == Tarray)
1943 arg = new SliceExp(loc, arg, null, null);
1944 arg.type = p.type;
1946 break;
1948 case Tclass:
1950 /* Set arg to be:
1951 * new Tclass(arg0, arg1, ..., argn)
1953 auto args = new Expressions(nargs - i);
1954 foreach (u; i .. nargs)
1955 (*args)[u - i] = (*arguments)[u];
1956 arg = new NewExp(loc, null, p.type, args);
1957 break;
1959 default:
1960 if (!arg)
1962 error(loc, "not enough arguments");
1963 return true;
1965 break;
1967 arg = arg.expressionSemantic(sc);
1968 //printf("\targ = '%s'\n", arg.toChars());
1969 arguments.setDim(i + 1);
1970 (*arguments)[i] = arg;
1971 nargs = i + 1;
1972 done = true;
1976 if (!(p.isLazy() && p.type.ty == Tvoid))
1978 if (ubyte wm = arg.type.deduceWild(p.type, p.isReference()))
1980 wildmatch = wildmatch ? MODmerge(wildmatch, wm) : wm;
1981 //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p.type.toChars(), arg.type.toChars(), wm, wildmatch);
1985 if (done)
1986 break;
1988 if ((wildmatch == MODFlags.mutable || wildmatch == MODFlags.immutable_) &&
1989 tf.next && tf.next.hasWild() &&
1990 (tf.isref || !tf.next.implicitConvTo(tf.next.immutableOf())))
1992 bool errorInout(MOD wildmatch)
1994 const(char)* s = wildmatch == MODFlags.mutable ? "mutable" : MODtoChars(wildmatch);
1995 error(loc, "modify `inout` to `%s` is not allowed inside `inout` function", s);
1996 return true;
1999 if (fd)
2001 /* If the called function may return the reference to
2002 * outer inout data, it should be rejected.
2004 * void foo(ref inout(int) x) {
2005 * ref inout(int) bar(inout(int)) { return x; }
2006 * struct S {
2007 * ref inout(int) bar() inout { return x; }
2008 * ref inout(int) baz(alias a)() inout { return x; }
2010 * bar(int.init) = 1; // bad!
2011 * S().bar() = 1; // bad!
2013 * void test() {
2014 * int a;
2015 * auto s = foo(a);
2016 * s.baz!a() = 1; // bad!
2020 bool checkEnclosingWild(Dsymbol s)
2022 bool checkWild(Dsymbol s)
2024 if (!s)
2025 return false;
2026 if (auto ad = s.isAggregateDeclaration())
2028 if (ad.isNested())
2029 return checkEnclosingWild(s);
2031 else if (auto ff = s.isFuncDeclaration())
2033 if (ff.type.isTypeFunction().iswild)
2034 return errorInout(wildmatch);
2036 if (ff.isNested() || ff.isThis())
2037 return checkEnclosingWild(s);
2039 return false;
2042 Dsymbol ctx0 = s.toParent2();
2043 Dsymbol ctx1 = s.toParentLocal();
2044 if (checkWild(ctx0))
2045 return true;
2046 if (ctx0 != ctx1)
2047 return checkWild(ctx1);
2048 return false;
2050 if ((fd.isThis() || fd.isNested()) && checkEnclosingWild(fd))
2051 return true;
2053 else if (tf.isWild())
2054 return errorInout(wildmatch);
2057 Expression firstArg = null;
2058 final switch (returnParamDest(tf, tthis))
2060 case ReturnParamDest.returnVal:
2061 break;
2062 case ReturnParamDest.firstArg:
2063 firstArg = nargs > 0 ? (*arguments)[0] : null;
2064 break;
2065 case ReturnParamDest.this_:
2066 firstArg = ethis;
2067 break;
2070 assert(nargs >= nparams);
2071 foreach (const i, arg; (*arguments)[0 .. nargs])
2073 assert(arg);
2074 if (i < nparams)
2076 Parameter p = tf.parameterList[i];
2077 Type targ = arg.type; // keep original type for isCopyable() because alias this
2078 // resolution may hide an uncopyable type
2080 if (!(p.isLazy() && p.type.ty == Tvoid))
2082 Type tprm = p.type.hasWild()
2083 ? p.type.substWildTo(wildmatch)
2084 : p.type;
2086 const hasCopyCtor = arg.type.isTypeStruct() && arg.type.isTypeStruct().sym.hasCopyCtor;
2087 const typesMatch = arg.type.mutableOf().unSharedOf().equals(tprm.mutableOf().unSharedOf());
2088 if (!((hasCopyCtor && typesMatch) || tprm.equals(arg.type)))
2090 //printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars());
2091 arg = arg.implicitCastTo(sc, tprm);
2092 arg = arg.optimize(WANTvalue, p.isReference());
2096 // Support passing rvalue to `in` parameters
2097 if ((p.storageClass & (STC.in_ | STC.ref_)) == (STC.in_ | STC.ref_))
2099 if (!arg.isLvalue())
2101 auto v = copyToTemp(STC.exptemp, "__rvalue", arg);
2102 Expression ev = new DeclarationExp(arg.loc, v);
2103 ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
2104 arg = ev.expressionSemantic(sc);
2106 arg = arg.toLvalue(sc, arg);
2108 // Look for mutable misaligned pointer, etc., in @safe mode
2109 err |= checkUnsafeAccess(sc, arg, false, true);
2111 else if (p.storageClass & STC.ref_)
2113 if (global.params.rvalueRefParam == FeatureState.enabled &&
2114 !arg.isLvalue() &&
2115 targ.isCopyable())
2116 { /* allow rvalues to be passed to ref parameters by copying
2117 * them to a temp, then pass the temp as the argument
2119 auto v = copyToTemp(0, "__rvalue", arg);
2120 Expression ev = new DeclarationExp(arg.loc, v);
2121 ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
2122 arg = ev.expressionSemantic(sc);
2124 arg = arg.toLvalue(sc, arg);
2126 // Look for mutable misaligned pointer, etc., in @safe mode
2127 err |= checkUnsafeAccess(sc, arg, false, true);
2129 else if (p.storageClass & STC.out_)
2131 Type t = arg.type;
2132 if (!t.isMutable() || !t.isAssignable()) // check blit assignable
2134 arg.error("cannot modify struct `%s` with immutable members", arg.toChars());
2135 err = true;
2137 else
2139 // Look for misaligned pointer, etc., in @safe mode
2140 err |= checkUnsafeAccess(sc, arg, false, true);
2141 err |= checkDefCtor(arg.loc, t); // t must be default constructible
2143 arg = arg.toLvalue(sc, arg);
2145 else if (p.isLazy())
2147 // Convert lazy argument to a delegate
2148 auto t = (p.type.ty == Tvoid) ? p.type : arg.type;
2149 arg = toDelegate(arg, t, sc);
2151 //printf("arg: %s\n", arg.toChars());
2152 //printf("type: %s\n", arg.type.toChars());
2153 //printf("param: %s\n", p.toChars());
2155 const pStc = tf.parameterStorageClass(tthis, p);
2157 if (firstArg && (pStc & STC.return_))
2159 /* Argument value can be assigned to firstArg.
2160 * Check arg to see if it matters.
2162 err |= checkParamArgumentReturn(sc, firstArg, arg, p, false);
2164 // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along
2165 // as lazy parameters to the next function, but that isn't escaping.
2166 // The arguments of `_d_arraycatnTX` are already handled in
2167 // expressionsem.d, via `checkNewEscape`. Without `-dip1000`, the
2168 // check does not return an error, so the lowering of `a ~ b` to
2169 // `_d_arraycatnTX(a, b)` still occurs.
2170 else if (!(pStc & STC.lazy_) && (!fd || fd.ident != Id._d_arraycatnTX))
2172 /* Argument value can escape from the called function.
2173 * Check arg to see if it matters.
2175 VarDeclaration vPar = fd ? (fd.parameters ? (*fd.parameters)[i] : null) : null;
2176 err |= checkParamArgumentEscape(sc, fd, p.ident, vPar, cast(STC) pStc, arg, false, false);
2179 // Turning heap allocations into stack allocations is dangerous without dip1000, since `scope` inference
2180 // may be unreliable when scope violations only manifest as deprecation warnings.
2181 // However, existing `@nogc` code may rely on it, so still do it when the parameter is explicitly marked `scope`
2182 const explicitScope = p.isLazy() ||
2183 ((p.storageClass & STC.scope_) && !(p.storageClass & STC.scopeinferred));
2184 if ((pStc & (STC.scope_ | STC.lazy_)) &&
2185 ((global.params.useDIP1000 == FeatureState.enabled) || explicitScope) &&
2186 !(pStc & STC.return_))
2188 /* Argument value cannot escape from the called function.
2190 Expression a = arg;
2191 if (auto ce = a.isCastExp())
2192 a = ce.e1;
2194 ArrayLiteralExp ale;
2195 if (p.type.toBasetype().ty == Tarray &&
2196 (ale = a.isArrayLiteralExp()) !is null && ale.elements && ale.elements.length > 0)
2198 // allocate the array literal as temporary static array on the stack
2199 ale.type = ale.type.nextOf().sarrayOf(ale.elements.length);
2200 auto tmp = copyToTemp(0, "__arrayliteral_on_stack", ale);
2201 tmp.storage_class |= STC.exptemp;
2202 auto declareTmp = new DeclarationExp(ale.loc, tmp);
2203 auto castToSlice = new CastExp(ale.loc, new VarExp(ale.loc, tmp),
2204 p.type.substWildTo(MODFlags.mutable));
2205 arg = CommaExp.combine(declareTmp, castToSlice);
2206 arg = arg.expressionSemantic(sc);
2208 else if (auto fe = a.isFuncExp())
2210 /* Function literals can only appear once, so if this
2211 * appearance was scoped, there cannot be any others.
2213 fe.fd.tookAddressOf = 0;
2215 else if (auto de = a.isDelegateExp())
2217 /* For passing a delegate to a scoped parameter,
2218 * this doesn't count as taking the address of it.
2219 * We only worry about 'escaping' references to the function.
2221 if (auto ve = de.e1.isVarExp())
2223 if (auto f = ve.var.isFuncDeclaration())
2225 if (f.tookAddressOf)
2226 --f.tookAddressOf;
2227 //printf("--tookAddressOf = %d\n", f.tookAddressOf);
2232 if (!p.isReference())
2233 err |= arg.checkSharedAccess(sc);
2235 arg = arg.optimize(WANTvalue, p.isReference());
2237 else
2239 // These will be the trailing ... arguments
2240 // If not D linkage, do promotions
2241 if (tf.linkage != LINK.d)
2243 // Promote bytes, words, etc., to ints
2244 arg = integralPromotions(arg, sc);
2246 // Promote floats to doubles
2247 switch (arg.type.ty)
2249 case Tfloat32:
2250 arg = arg.castTo(sc, Type.tfloat64);
2251 break;
2253 case Timaginary32:
2254 arg = arg.castTo(sc, Type.timaginary64);
2255 break;
2257 default:
2258 break;
2260 if (tf.parameterList.varargs == VarArg.variadic ||
2261 tf.parameterList.varargs == VarArg.KRvariadic)
2263 const(char)* p = tf.linkage == LINK.c ? "extern(C)" : "extern(C++)";
2264 if (arg.type.ty == Tarray)
2266 arg.error("cannot pass dynamic arrays to `%s` vararg functions", p);
2267 err = true;
2269 if (arg.type.ty == Tsarray)
2271 arg.error("cannot pass static arrays to `%s` vararg functions", p);
2272 err = true;
2277 // Do not allow types that need destructors or copy constructors.
2278 if (arg.type.needsDestruction())
2280 arg.error("cannot pass types that need destruction as variadic arguments");
2281 err = true;
2283 if (arg.type.needsCopyOrPostblit())
2285 arg.error("cannot pass types with postblits or copy constructors as variadic arguments");
2286 err = true;
2289 // Convert static arrays to dynamic arrays
2290 // BUG: I don't think this is right for D2
2291 Type tb = arg.type.toBasetype();
2292 if (auto ts = tb.isTypeSArray())
2294 Type ta = ts.next.arrayOf();
2295 if (ts.size(arg.loc) == 0)
2296 arg = new NullExp(arg.loc, ta);
2297 else
2298 arg = arg.castTo(sc, ta);
2300 if (tb.ty == Tstruct)
2302 //arg = callCpCtor(sc, arg);
2304 // Give error for overloaded function addresses
2305 if (auto se = arg.isSymOffExp())
2307 if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique())
2309 arg.error("function `%s` is overloaded", arg.toChars());
2310 err = true;
2313 err |= arg.checkValue();
2314 err |= arg.checkSharedAccess(sc);
2315 arg = arg.optimize(WANTvalue);
2317 (*arguments)[i] = arg;
2320 /* If calling C scanf(), printf(), or any variants, check the format string against the arguments
2322 const isVa_list = tf.parameterList.varargs == VarArg.none;
2323 if (fd && fd.printf)
2325 if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp())
2327 checkPrintfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list);
2330 else if (fd && fd.scanf)
2332 if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp())
2334 checkScanfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list);
2337 else
2339 // TODO: not checking the "v" functions yet (for those, check format string only, not args)
2342 /* Remaining problems:
2343 * 1. value structs (or static arrays of them) that need to be copy constructed
2344 * 2. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
2345 * function gets called.
2346 * 3. value structs need to be destructed after the function call for platforms where the caller destroys the arguments.
2347 * Those are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
2348 * up properly. Pushing arguments on the stack then cannot fail.
2351 /* Does Problem (3) apply?
2353 const bool callerDestroysArgs = !target.isCalleeDestroyingArgs(tf);
2355 /* Compute indices of last throwing argument and first arg needing destruction.
2356 * Used to not set up destructors unless an arg needs destruction on a throw
2357 * in a later argument.
2359 ptrdiff_t lastthrow = -1; // last argument that may throw
2360 ptrdiff_t firstdtor = -1; // first argument that needs destruction
2361 ptrdiff_t lastdtor = -1; // last argument that needs destruction
2362 for (ptrdiff_t i = 0; i != nargs; i++)
2364 Expression arg = (*arguments)[i];
2365 if (canThrow(arg, sc.func, false))
2366 lastthrow = i;
2367 if (arg.type.needsDestruction())
2369 Parameter p = (i >= nparams ? null : tf.parameterList[i]);
2370 if (!(p && (p.isLazy() || p.isReference())))
2372 if (firstdtor == -1)
2373 firstdtor = i;
2374 lastdtor = i;
2379 /* Do we need 'eprefix' for problems 2 or 3?
2381 const bool needsPrefix = callerDestroysArgs
2382 ? firstdtor >= 0 // true if any argument needs destruction
2383 : firstdtor >= 0 && lastthrow >= 0 &&
2384 (lastthrow - firstdtor) > 0; // last throw after first destruction
2385 const ptrdiff_t lastPrefix = callerDestroysArgs
2386 ? lastdtor // up to last argument requiring destruction
2387 : lastthrow; // up to last potentially throwing argument
2389 /* Problem 3: initialize 'eprefix' by declaring the gate
2391 VarDeclaration gate;
2392 if (needsPrefix && !callerDestroysArgs)
2394 // eprefix => bool __gate [= false]
2395 Identifier idtmp = Identifier.generateId("__gate");
2396 gate = new VarDeclaration(loc, Type.tbool, idtmp, null);
2397 gate.storage_class |= STC.temp | STC.ctfe | STC.volatile_;
2398 gate.dsymbolSemantic(sc);
2400 auto ae = new DeclarationExp(loc, gate);
2401 eprefix = ae.expressionSemantic(sc);
2404 for (ptrdiff_t i = 0; i != nargs; i++)
2406 Expression arg = (*arguments)[i];
2407 //printf("arg[%d]: %s\n", cast(int)i, arg.toChars());
2409 Parameter parameter = (i >= nparams ? null : tf.parameterList[i]);
2410 const bool isRef = parameter && parameter.isReference();
2411 const bool isLazy = parameter && parameter.isLazy();
2413 /* Skip lazy parameters
2415 if (isLazy)
2416 continue;
2418 /* Do we have 'eprefix' and aren't past 'lastPrefix' yet?
2419 * Then declare a temporary variable for this arg and append that declaration
2420 * to 'eprefix', which will implicitly take care of potential problem 1) for
2421 * this arg.
2422 * 'eprefix' will therefore finally contain all args up to and including 'lastPrefix',
2423 * excluding all lazy parameters.
2425 if (needsPrefix && (lastPrefix - i) >= 0)
2427 const bool needsDtor = !isRef && arg.type.needsDestruction() &&
2428 // Problem 3: last throwing arg doesn't require dtor patching
2429 (callerDestroysArgs || i != lastPrefix);
2431 /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
2433 auto tmp = copyToTemp(
2434 (parameter ? parameter.storageClass : tf.parameterList.stc) & (STC.scope_),
2435 needsDtor ? "__pfx" : "__pfy",
2436 !isRef ? arg : arg.addressOf());
2437 tmp.dsymbolSemantic(sc);
2439 if (callerDestroysArgs)
2441 /* Problem 4: Normal temporary, destructed after the call
2443 if (needsDtor)
2444 tmp.isArgDtorVar = true; // mark it so that the backend passes it by ref to the function being called
2446 else
2448 /* Problem 2: Modify the destructor so it only runs if gate==false,
2449 * i.e., only if there was a throw while constructing the args
2451 if (!needsDtor)
2453 if (tmp.edtor)
2455 assert(i == lastPrefix);
2456 tmp.edtor = null;
2459 else
2461 // edtor => (__gate || edtor)
2462 assert(tmp.edtor);
2463 Expression e = tmp.edtor;
2464 e = new LogicalExp(e.loc, EXP.orOr, new VarExp(e.loc, gate), e);
2465 tmp.edtor = e.expressionSemantic(sc);
2466 //printf("edtor: %s\n", tmp.edtor.toChars());
2470 // eprefix => (eprefix, auto __pfx/y = arg)
2471 auto ae = new DeclarationExp(loc, tmp);
2472 eprefix = Expression.combine(eprefix, ae.expressionSemantic(sc));
2474 // arg => __pfx/y
2475 arg = new VarExp(loc, tmp);
2476 arg = arg.expressionSemantic(sc);
2477 if (isRef)
2479 arg = new PtrExp(loc, arg);
2480 arg = arg.expressionSemantic(sc);
2483 /* Problem 2: Last throwing arg?
2484 * Then finalize eprefix => (eprefix, gate = true), i.e., disable the
2485 * dtors right after constructing the last throwing arg.
2486 * From now on, the callee will take care of destructing the args because
2487 * the args are implicitly moved into function parameters.
2489 if (!callerDestroysArgs && i == lastPrefix)
2491 auto e = new AssignExp(gate.loc, new VarExp(gate.loc, gate), IntegerExp.createBool(true));
2492 eprefix = Expression.combine(eprefix, e.expressionSemantic(sc));
2495 else // not part of 'eprefix'
2497 /* Handle problem 1) by calling the copy constructor for value structs
2498 * (or static arrays of them) if appropriate.
2500 Type tv = arg.type.baseElemOf();
2501 if (!isRef && tv.ty == Tstruct)
2502 arg = doCopyOrMove(sc, arg, parameter ? parameter.type : null);
2505 (*arguments)[i] = arg;
2508 //if (eprefix) printf("eprefix: %s\n", eprefix.toChars());
2510 /* Test compliance with DIP1021 Argument Ownership and Function Calls
2512 if (global.params.useDIP1021 && (tf.trust == TRUST.safe || tf.trust == TRUST.default_) ||
2513 tf.islive)
2514 err |= checkMutableArguments(sc, fd, tf, ethis, arguments, false);
2516 // If D linkage and variadic, add _arguments[] as first argument
2517 if (tf.isDstyleVariadic())
2519 assert(arguments.length >= nparams);
2521 auto args = new Parameters(arguments.length - nparams);
2522 for (size_t i = 0; i < arguments.length - nparams; i++)
2524 auto arg = new Parameter(STC.in_, (*arguments)[nparams + i].type, null, null, null);
2525 (*args)[i] = arg;
2527 auto tup = new TypeTuple(args);
2528 Expression e = (new TypeidExp(loc, tup)).expressionSemantic(sc);
2529 arguments.insert(0, e);
2532 /* Determine function return type: tret
2534 Type tret = tf.next;
2535 if (isCtorCall)
2537 //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd.toChars(), fd.type.toChars(),
2538 // wildmatch, tf.isWild(), fd.isReturnIsolated());
2539 if (!tthis)
2541 assert(sc.intypeof || global.errors);
2542 tthis = fd.isThis().type.addMod(fd.type.mod);
2544 if (tf.isWild() && !fd.isReturnIsolated())
2546 if (wildmatch)
2547 tret = tret.substWildTo(wildmatch);
2548 int offset;
2549 if (!tret.implicitConvTo(tthis) && !(MODimplicitConv(tret.mod, tthis.mod) && tret.isBaseOf(tthis, &offset) && offset == 0))
2551 const(char)* s1 = tret.isNaked() ? " mutable" : tret.modToChars();
2552 const(char)* s2 = tthis.isNaked() ? " mutable" : tthis.modToChars();
2553 .error(loc, "`inout` constructor `%s` creates%s object, not%s", fd.toPrettyChars(), s1, s2);
2554 err = true;
2557 tret = tthis;
2559 else if (wildmatch && tret)
2561 /* Adjust function return type based on wildmatch
2563 //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret.toChars());
2564 tret = tret.substWildTo(wildmatch);
2567 *prettype = tret;
2568 *peprefix = eprefix;
2569 return (err || olderrors != global.errors);
2573 * Determines whether a symbol represents a module or package
2574 * (Used as a helper for is(type == module) and is(type == package))
2576 * Params:
2577 * sym = the symbol to be checked
2579 * Returns:
2580 * the symbol which `sym` represents (or `null` if it doesn't represent a `Package`)
2582 Package resolveIsPackage(Dsymbol sym)
2584 Package pkg;
2585 if (Import imp = sym.isImport())
2587 if (imp.pkg is null)
2589 .error(sym.loc, "internal compiler error: unable to process forward-referenced import `%s`",
2590 imp.toChars());
2591 assert(0);
2593 pkg = imp.pkg;
2595 else if (auto mod = sym.isModule())
2596 pkg = mod.isPackageFile ? mod.pkg : sym.isPackage();
2597 else
2598 pkg = sym.isPackage();
2599 if (pkg)
2600 pkg.resolvePKGunknown();
2601 return pkg;
2605 private extern (C++) final class ExpressionSemanticVisitor : Visitor
2607 alias visit = Visitor.visit;
2609 Scope* sc;
2610 Expression result;
2612 this(Scope* sc) scope
2614 this.sc = sc;
2617 private void setError()
2619 result = ErrorExp.get();
2622 /**************************
2623 * Semantically analyze Expression.
2624 * Determine types, fold constants, etc.
2626 override void visit(Expression e)
2628 static if (LOGSEMANTIC)
2630 printf("Expression::semantic() %s\n", e.toChars());
2632 if (e.type)
2633 e.type = e.type.typeSemantic(e.loc, sc);
2634 else
2635 e.type = Type.tvoid;
2636 result = e;
2639 override void visit(IntegerExp e)
2641 assert(e.type);
2642 if (e.type.ty == Terror)
2643 return setError();
2645 assert(e.type.deco);
2646 e.setInteger(e.getInteger());
2647 result = e;
2650 override void visit(RealExp e)
2652 if (!e.type)
2653 e.type = Type.tfloat64;
2654 else if (e.type.isimaginary && sc.flags & SCOPE.Cfile)
2656 /* Convert to core.stdc.config.complex
2658 Type t = getComplexLibraryType(e.loc, sc, e.type.ty);
2659 if (t.ty == Terror)
2660 return setError();
2662 Type tf;
2663 switch (e.type.ty)
2665 case Timaginary32: tf = Type.tfloat32; break;
2666 case Timaginary64: tf = Type.tfloat64; break;
2667 case Timaginary80: tf = Type.tfloat80; break;
2668 default:
2669 assert(0);
2672 /* Construct ts{re : 0.0, im : e}
2674 TypeStruct ts = t.isTypeStruct;
2675 Expressions* elements = new Expressions(2);
2676 (*elements)[0] = new RealExp(e.loc, CTFloat.zero, tf);
2677 (*elements)[1] = new RealExp(e.loc, e.toImaginary(), tf);
2678 Expression sle = new StructLiteralExp(e.loc, ts.sym, elements);
2679 result = sle.expressionSemantic(sc);
2680 return;
2682 else
2683 e.type = e.type.typeSemantic(e.loc, sc);
2684 result = e;
2687 override void visit(ComplexExp e)
2689 if (!e.type)
2690 e.type = Type.tcomplex80;
2691 else
2692 e.type = e.type.typeSemantic(e.loc, sc);
2693 result = e;
2696 override void visit(IdentifierExp exp)
2698 static if (LOGSEMANTIC)
2700 printf("IdentifierExp::semantic('%s')\n", exp.ident.toChars());
2702 if (exp.type) // This is used as the dummy expression
2704 result = exp;
2705 return;
2708 Dsymbol scopesym;
2709 Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym);
2710 if (s)
2712 if (s.errors)
2713 return setError();
2715 Expression e;
2717 /* See if the symbol was a member of an enclosing 'with'
2719 WithScopeSymbol withsym = scopesym.isWithScopeSymbol();
2720 if (withsym && withsym.withstate.wthis && symbolIsVisible(sc, s))
2722 /* Disallow shadowing
2724 // First find the scope of the with
2725 Scope* scwith = sc;
2726 while (scwith.scopesym != scopesym)
2728 scwith = scwith.enclosing;
2729 assert(scwith);
2731 // Look at enclosing scopes for symbols with the same name,
2732 // in the same function
2733 for (Scope* scx = scwith; scx && scx.func == scwith.func; scx = scx.enclosing)
2735 Dsymbol s2;
2736 if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2)
2738 exp.error("with symbol `%s` is shadowing local symbol `%s`", s.toPrettyChars(), s2.toPrettyChars());
2739 return setError();
2742 s = s.toAlias();
2744 // Same as wthis.ident
2745 // TODO: DotIdExp.semantic will find 'ident' from 'wthis' again.
2746 // The redudancy should be removed.
2747 e = new VarExp(exp.loc, withsym.withstate.wthis);
2748 e = new DotIdExp(exp.loc, e, exp.ident);
2749 e = e.expressionSemantic(sc);
2751 else
2753 if (withsym)
2755 if (withsym.withstate.exp.type.ty != Tvoid)
2757 // 'with (exp)' is a type expression
2758 // or 's' is not visible there (for error message)
2759 e = new TypeExp(exp.loc, withsym.withstate.exp.type);
2761 else
2763 // 'with (exp)' is a Package/Module
2764 e = withsym.withstate.exp;
2766 e = new DotIdExp(exp.loc, e, exp.ident);
2767 result = e.expressionSemantic(sc);
2768 return;
2771 /* If f is really a function template,
2772 * then replace f with the function template declaration.
2774 FuncDeclaration f = s.isFuncDeclaration();
2775 if (f)
2777 TemplateDeclaration td = getFuncTemplateDecl(f);
2778 if (td)
2780 if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
2781 td = td.overroot; // then get the start
2782 e = new TemplateExp(exp.loc, td, f);
2783 e = e.expressionSemantic(sc);
2784 result = e;
2785 return;
2789 if (global.params.fixAliasThis)
2791 ExpressionDsymbol expDsym = scopesym.isExpressionDsymbol();
2792 if (expDsym)
2794 //printf("expDsym = %s\n", expDsym.exp.toChars());
2795 result = expDsym.exp.expressionSemantic(sc);
2796 return;
2799 // Haven't done overload resolution yet, so pass 1
2800 e = symbolToExp(s, exp.loc, sc, true);
2802 result = e;
2803 return;
2806 if (!global.params.fixAliasThis && hasThis(sc))
2808 for (AggregateDeclaration ad = sc.getStructClassScope(); ad;)
2810 if (ad.aliasthis)
2812 Expression e;
2813 e = new ThisExp(exp.loc);
2814 e = new DotIdExp(exp.loc, e, ad.aliasthis.ident);
2815 e = new DotIdExp(exp.loc, e, exp.ident);
2816 e = e.trySemantic(sc);
2817 if (e)
2819 result = e;
2820 return;
2824 auto cd = ad.isClassDeclaration();
2825 if (cd && cd.baseClass && cd.baseClass != ClassDeclaration.object)
2827 ad = cd.baseClass;
2828 continue;
2830 break;
2834 if (exp.ident == Id.ctfe)
2836 if (sc.flags & SCOPE.ctfe)
2838 exp.error("variable `__ctfe` cannot be read at compile time");
2839 return setError();
2842 // Create the magic __ctfe bool variable
2843 auto vd = new VarDeclaration(exp.loc, Type.tbool, Id.ctfe, null);
2844 vd.storage_class |= STC.temp;
2845 vd.semanticRun = PASS.semanticdone;
2846 Expression e = new VarExp(exp.loc, vd);
2847 e = e.expressionSemantic(sc);
2848 result = e;
2849 return;
2852 // If we've reached this point and are inside a with() scope then we may
2853 // try one last attempt by checking whether the 'wthis' object supports
2854 // dynamic dispatching via opDispatch.
2855 // This is done by rewriting this expression as wthis.ident.
2856 // The innermost with() scope of the hierarchy to satisfy the condition
2857 // above wins.
2858 // https://issues.dlang.org/show_bug.cgi?id=6400
2859 for (Scope* sc2 = sc; sc2; sc2 = sc2.enclosing)
2861 if (!sc2.scopesym)
2862 continue;
2864 if (auto ss = sc2.scopesym.isWithScopeSymbol())
2866 if (ss.withstate.wthis)
2868 Expression e;
2869 e = new VarExp(exp.loc, ss.withstate.wthis);
2870 e = new DotIdExp(exp.loc, e, exp.ident);
2871 e = e.trySemantic(sc);
2872 if (e)
2874 result = e;
2875 return;
2878 // Try Type.opDispatch (so the static version)
2879 else if (ss.withstate.exp && ss.withstate.exp.op == EXP.type)
2881 if (Type t = ss.withstate.exp.isTypeExp().type)
2883 Expression e;
2884 e = new TypeExp(exp.loc, t);
2885 e = new DotIdExp(exp.loc, e, exp.ident);
2886 e = e.trySemantic(sc);
2887 if (e)
2889 result = e;
2890 return;
2897 /* Look for what user might have meant
2899 if (const n = importHint(exp.ident.toString()))
2900 exp.error("`%s` is not defined, perhaps `import %.*s;` is needed?", exp.ident.toChars(), cast(int)n.length, n.ptr);
2901 else if (auto s2 = sc.search_correct(exp.ident))
2902 exp.error("undefined identifier `%s`, did you mean %s `%s`?", exp.ident.toChars(), s2.kind(), s2.toChars());
2903 else if (const p = Scope.search_correct_C(exp.ident))
2904 exp.error("undefined identifier `%s`, did you mean `%s`?", exp.ident.toChars(), p);
2905 else if (exp.ident == Id.dollar)
2906 exp.error("undefined identifier `$`");
2907 else
2908 exp.error("undefined identifier `%s`", exp.ident.toChars());
2910 result = ErrorExp.get();
2913 override void visit(DsymbolExp e)
2915 result = symbolToExp(e.s, e.loc, sc, e.hasOverloads);
2918 override void visit(ThisExp e)
2920 static if (LOGSEMANTIC)
2922 printf("ThisExp::semantic()\n");
2924 if (e.type)
2926 result = e;
2927 return;
2930 FuncDeclaration fd = hasThis(sc); // fd is the uplevel function with the 'this' variable
2931 AggregateDeclaration ad;
2933 /* Special case for typeof(this) and typeof(super) since both
2934 * should work even if they are not inside a non-static member function
2936 if (!fd && sc.intypeof == 1)
2938 // Find enclosing struct or class
2939 for (Dsymbol s = sc.getStructClassScope(); 1; s = s.parent)
2941 if (!s)
2943 e.error("`%s` is not in a class or struct scope", e.toChars());
2944 return setError();
2946 ClassDeclaration cd = s.isClassDeclaration();
2947 if (cd)
2949 e.type = cd.type;
2950 result = e;
2951 return;
2953 StructDeclaration sd = s.isStructDeclaration();
2954 if (sd)
2956 e.type = sd.type;
2957 result = e;
2958 return;
2962 if (!fd)
2964 e.error("`this` is only defined in non-static member functions, not `%s`", sc.parent.toChars());
2965 return setError();
2968 assert(fd.vthis);
2969 e.var = fd.vthis;
2970 assert(e.var.parent);
2971 ad = fd.isMemberLocal();
2972 if (!ad)
2973 ad = fd.isMember2();
2974 assert(ad);
2975 e.type = ad.type.addMod(e.var.type.mod);
2977 if (e.var.checkNestedReference(sc, e.loc))
2978 return setError();
2980 result = e;
2983 override void visit(SuperExp e)
2985 static if (LOGSEMANTIC)
2987 printf("SuperExp::semantic('%s')\n", e.toChars());
2989 if (e.type)
2991 result = e;
2992 return;
2995 FuncDeclaration fd = hasThis(sc);
2996 ClassDeclaration cd;
2997 Dsymbol s;
2999 /* Special case for typeof(this) and typeof(super) since both
3000 * should work even if they are not inside a non-static member function
3002 if (!fd && sc.intypeof == 1)
3004 // Find enclosing class
3005 for (s = sc.getStructClassScope(); 1; s = s.parent)
3007 if (!s)
3009 e.error("`%s` is not in a class scope", e.toChars());
3010 return setError();
3012 cd = s.isClassDeclaration();
3013 if (cd)
3015 cd = cd.baseClass;
3016 if (!cd)
3018 e.error("class `%s` has no `super`", s.toChars());
3019 return setError();
3021 e.type = cd.type;
3022 result = e;
3023 return;
3027 if (!fd)
3028 goto Lerr;
3030 e.var = fd.vthis;
3031 assert(e.var && e.var.parent);
3033 s = fd.toParentDecl();
3034 if (s.isTemplateDeclaration()) // allow inside template constraint
3035 s = s.toParent();
3036 assert(s);
3037 cd = s.isClassDeclaration();
3038 //printf("parent is %s %s\n", fd.toParent().kind(), fd.toParent().toChars());
3039 if (!cd)
3040 goto Lerr;
3041 if (!cd.baseClass)
3043 e.error("no base class for `%s`", cd.toChars());
3044 e.type = cd.type.addMod(e.var.type.mod);
3046 else
3048 e.type = cd.baseClass.type;
3049 e.type = e.type.castMod(e.var.type.mod);
3052 if (e.var.checkNestedReference(sc, e.loc))
3053 return setError();
3055 result = e;
3056 return;
3058 Lerr:
3059 e.error("`super` is only allowed in non-static class member functions");
3060 result = ErrorExp.get();
3063 override void visit(NullExp e)
3065 static if (LOGSEMANTIC)
3067 printf("NullExp::semantic('%s')\n", e.toChars());
3069 // NULL is the same as (void *)0
3070 if (e.type)
3072 result = e;
3073 return;
3075 e.type = Type.tnull;
3076 result = e;
3079 override void visit(StringExp e)
3081 static if (LOGSEMANTIC)
3083 printf("StringExp::semantic() %s\n", e.toChars());
3085 if (e.type)
3087 result = e;
3088 return;
3091 OutBuffer buffer;
3092 size_t newlen = 0;
3093 size_t u;
3094 dchar c;
3096 switch (e.postfix)
3098 case 'd':
3099 for (u = 0; u < e.len;)
3101 if (const p = utf_decodeChar(e.peekString(), u, c))
3103 e.error("%.*s", cast(int)p.length, p.ptr);
3104 return setError();
3106 else
3108 buffer.write4(c);
3109 newlen++;
3112 buffer.write4(0);
3113 e.setData(buffer.extractData(), newlen, 4);
3114 if (sc && sc.flags & SCOPE.Cfile)
3115 e.type = Type.tuns32.sarrayOf(e.len + 1);
3116 else
3117 e.type = Type.tdchar.immutableOf().arrayOf();
3118 e.committed = true;
3119 break;
3121 case 'w':
3122 for (u = 0; u < e.len;)
3124 if (const p = utf_decodeChar(e.peekString(), u, c))
3126 e.error("%.*s", cast(int)p.length, p.ptr);
3127 return setError();
3129 else
3131 buffer.writeUTF16(c);
3132 newlen++;
3133 if (c >= 0x10000)
3134 newlen++;
3137 buffer.writeUTF16(0);
3138 e.setData(buffer.extractData(), newlen, 2);
3139 if (sc && sc.flags & SCOPE.Cfile)
3140 e.type = Type.tuns16.sarrayOf(e.len + 1);
3141 else
3142 e.type = Type.twchar.immutableOf().arrayOf();
3143 e.committed = true;
3144 break;
3146 case 'c':
3147 e.committed = true;
3148 goto default;
3150 default:
3151 if (sc && sc.flags & SCOPE.Cfile)
3152 e.type = Type.tchar.sarrayOf(e.len + 1);
3153 else
3154 e.type = Type.tchar.immutableOf().arrayOf();
3155 break;
3157 e.type = e.type.typeSemantic(e.loc, sc);
3158 //type = type.immutableOf();
3159 //printf("type = %s\n", type.toChars());
3161 result = e;
3164 override void visit(TupleExp exp)
3166 static if (LOGSEMANTIC)
3168 printf("+TupleExp::semantic(%s)\n", exp.toChars());
3170 if (exp.type)
3172 result = exp;
3173 return;
3176 if (exp.e0)
3177 exp.e0 = exp.e0.expressionSemantic(sc);
3179 // Run semantic() on each argument
3180 bool err = false;
3181 for (size_t i = 0; i < exp.exps.length; i++)
3183 Expression e = (*exp.exps)[i];
3184 e = e.expressionSemantic(sc);
3185 if (!e.type)
3187 exp.error("`%s` has no value", e.toChars());
3188 err = true;
3190 else if (e.op == EXP.error)
3191 err = true;
3192 else
3193 (*exp.exps)[i] = e;
3195 if (err)
3196 return setError();
3198 expandTuples(exp.exps);
3200 exp.type = new TypeTuple(exp.exps);
3201 exp.type = exp.type.typeSemantic(exp.loc, sc);
3202 //printf("-TupleExp::semantic(%s)\n", toChars());
3203 result = exp;
3206 override void visit(ArrayLiteralExp e)
3208 static if (LOGSEMANTIC)
3210 printf("ArrayLiteralExp::semantic('%s')\n", e.toChars());
3212 if (e.type)
3214 result = e;
3215 return;
3218 /* Perhaps an empty array literal [ ] should be rewritten as null?
3221 if (e.basis)
3222 e.basis = e.basis.expressionSemantic(sc);
3223 if (arrayExpressionSemantic(e.elements.peekSlice(), sc) || (e.basis && e.basis.op == EXP.error))
3224 return setError();
3226 expandTuples(e.elements);
3228 if (e.basis)
3229 e.elements.push(e.basis);
3230 Type t0 = arrayExpressionToCommonType(sc, *e.elements);
3231 if (e.basis)
3232 e.basis = e.elements.pop();
3233 if (t0 is null)
3234 return setError();
3236 e.type = t0.arrayOf();
3237 e.type = e.type.typeSemantic(e.loc, sc);
3239 /* Disallow array literals of type void being used.
3241 if (e.elements.length > 0 && t0.ty == Tvoid)
3243 e.error("`%s` of type `%s` has no value", e.toChars(), e.type.toChars());
3244 return setError();
3247 if (global.params.useTypeInfo && Type.dtypeinfo)
3248 semanticTypeInfo(sc, e.type);
3250 result = e;
3253 override void visit(AssocArrayLiteralExp e)
3255 static if (LOGSEMANTIC)
3257 printf("AssocArrayLiteralExp::semantic('%s')\n", e.toChars());
3259 if (e.type)
3261 result = e;
3262 return;
3265 // Run semantic() on each element
3266 bool err_keys = arrayExpressionSemantic(e.keys.peekSlice(), sc);
3267 bool err_vals = arrayExpressionSemantic(e.values.peekSlice(), sc);
3268 if (err_keys || err_vals)
3269 return setError();
3271 expandTuples(e.keys);
3272 expandTuples(e.values);
3273 if (e.keys.length != e.values.length)
3275 e.error("number of keys is %llu, must match number of values %llu",
3276 cast(ulong) e.keys.length, cast(ulong) e.values.length);
3277 return setError();
3280 Type tkey = arrayExpressionToCommonType(sc, *e.keys);
3281 Type tvalue = arrayExpressionToCommonType(sc, *e.values);
3282 if (tkey is null || tvalue is null)
3283 return setError();
3285 e.type = new TypeAArray(tvalue, tkey);
3286 e.type = e.type.typeSemantic(e.loc, sc);
3288 semanticTypeInfo(sc, e.type);
3290 if (checkAssocArrayLiteralEscape(sc, e, false))
3291 return setError();
3293 result = e;
3296 override void visit(StructLiteralExp e)
3298 static if (LOGSEMANTIC)
3300 printf("StructLiteralExp::semantic('%s')\n", e.toChars());
3302 if (e.type)
3304 result = e;
3305 return;
3308 e.sd.size(e.loc);
3309 if (e.sd.sizeok != Sizeok.done)
3310 return setError();
3312 // run semantic() on each element
3313 if (arrayExpressionSemantic(e.elements.peekSlice(), sc))
3314 return setError();
3316 expandTuples(e.elements);
3318 /* Fit elements[] to the corresponding type of field[].
3320 if (!e.sd.fit(e.loc, sc, e.elements, e.stype))
3321 return setError();
3323 /* Fill out remainder of elements[] with default initializers for fields[]
3325 if (!e.sd.fill(e.loc, *e.elements, false))
3327 /* An error in the initializer needs to be recorded as an error
3328 * in the enclosing function or template, since the initializer
3329 * will be part of the stuct declaration.
3331 global.increaseErrorCount();
3332 return setError();
3335 if (checkFrameAccess(e.loc, sc, e.sd, e.elements.length))
3336 return setError();
3338 e.type = e.stype ? e.stype : e.sd.type;
3339 result = e;
3342 override void visit(CompoundLiteralExp cle)
3344 static if (LOGSEMANTIC)
3346 printf("CompoundLiteralExp::semantic('%s')\n", cle.toChars());
3348 Type t = cle.type.typeSemantic(cle.loc, sc);
3349 auto init = initializerSemantic(cle.initializer, sc, t, INITnointerpret);
3350 auto e = initializerToExpression(init, t, (sc.flags & SCOPE.Cfile) != 0);
3351 if (!e)
3353 error(cle.loc, "cannot convert initializer `%s` to expression", init.toChars());
3354 return setError();
3356 result = e;
3357 return;
3360 override void visit(TypeExp exp)
3362 if (exp.type.ty == Terror)
3363 return setError();
3365 //printf("TypeExp::semantic(%s)\n", exp.type.toChars());
3366 Expression e;
3367 Type t;
3368 Dsymbol s;
3370 dmd.typesem.resolve(exp.type, exp.loc, sc, e, t, s, true);
3371 if (e)
3373 // `(Type)` is actually `(var)` so if `(var)` is a member requiring `this`
3374 // then rewrite as `(this.var)` in case it would be followed by a DotVar
3375 // to fix https://issues.dlang.org/show_bug.cgi?id=9490
3376 VarExp ve = e.isVarExp();
3377 if (ve && ve.var && exp.parens && !ve.var.isStatic() && !(sc.stc & STC.static_) &&
3378 sc.func && sc.func.needThis && ve.var.isMember2())
3380 // printf("apply fix for bugzilla issue 9490: add `this.` to `%s`...\n", e.toChars());
3381 e = new DotVarExp(exp.loc, new ThisExp(exp.loc), ve.var, false);
3383 //printf("e = %s %s\n", Token.toChars(e.op), e.toChars());
3384 e = e.expressionSemantic(sc);
3386 else if (t)
3388 //printf("t = %d %s\n", t.ty, t.toChars());
3389 exp.type = t.typeSemantic(exp.loc, sc);
3390 e = exp;
3392 else if (s)
3394 //printf("s = %s %s\n", s.kind(), s.toChars());
3395 e = symbolToExp(s, exp.loc, sc, true);
3397 else
3398 assert(0);
3400 exp.type.checkComplexTransition(exp.loc, sc);
3402 result = e;
3405 override void visit(ScopeExp exp)
3407 static if (LOGSEMANTIC)
3409 printf("+ScopeExp::semantic(%p '%s')\n", exp, exp.toChars());
3411 if (exp.type)
3413 result = exp;
3414 return;
3417 ScopeDsymbol sds2 = exp.sds;
3418 TemplateInstance ti = sds2.isTemplateInstance();
3419 while (ti)
3421 WithScopeSymbol withsym;
3422 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc))
3423 return setError();
3424 if (withsym && withsym.withstate.wthis)
3426 Expression e = new VarExp(exp.loc, withsym.withstate.wthis);
3427 e = new DotTemplateInstanceExp(exp.loc, e, ti);
3428 result = e.expressionSemantic(sc);
3429 return;
3431 if (ti.needsTypeInference(sc))
3433 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
3435 Dsymbol p = td.toParentLocal();
3436 FuncDeclaration fdthis = hasThis(sc);
3437 AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null;
3438 if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0)
3440 Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti);
3441 result = e.expressionSemantic(sc);
3442 return;
3445 else if (OverloadSet os = ti.tempdecl.isOverloadSet())
3447 FuncDeclaration fdthis = hasThis(sc);
3448 AggregateDeclaration ad = os.parent.isAggregateDeclaration();
3449 if (fdthis && ad && fdthis.isMemberLocal() == ad)
3451 Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti);
3452 result = e.expressionSemantic(sc);
3453 return;
3456 // ti is an instance which requires IFTI.
3457 exp.sds = ti;
3458 exp.type = Type.tvoid;
3459 result = exp;
3460 return;
3462 ti.dsymbolSemantic(sc);
3463 if (!ti.inst || ti.errors)
3464 return setError();
3466 Dsymbol s = ti.toAlias();
3467 if (s == ti)
3469 exp.sds = ti;
3470 exp.type = Type.tvoid;
3471 result = exp;
3472 return;
3474 sds2 = s.isScopeDsymbol();
3475 if (sds2)
3477 ti = sds2.isTemplateInstance();
3478 //printf("+ sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
3479 continue;
3482 if (auto v = s.isVarDeclaration())
3484 if (!v.type)
3486 exp.error("forward reference of %s `%s`", v.kind(), v.toChars());
3487 return setError();
3489 if ((v.storage_class & STC.manifest) && v._init)
3491 /* When an instance that will be converted to a constant exists,
3492 * the instance representation "foo!tiargs" is treated like a
3493 * variable name, and its recursive appearance check (note that
3494 * it's equivalent with a recursive instantiation of foo) is done
3495 * separately from the circular initialization check for the
3496 * eponymous enum variable declaration.
3498 * template foo(T) {
3499 * enum bool foo = foo; // recursive definition check (v.inuse)
3501 * template bar(T) {
3502 * enum bool bar = bar!T; // recursive instantiation check (ti.inuse)
3505 if (ti.inuse)
3507 exp.error("recursive expansion of %s `%s`", ti.kind(), ti.toPrettyChars());
3508 return setError();
3510 v.checkDeprecated(exp.loc, sc);
3511 auto e = v.expandInitializer(exp.loc);
3512 ti.inuse++;
3513 e = e.expressionSemantic(sc);
3514 ti.inuse--;
3515 result = e;
3516 return;
3520 //printf("s = %s, '%s'\n", s.kind(), s.toChars());
3521 auto e = symbolToExp(s, exp.loc, sc, true);
3522 //printf("-1ScopeExp::semantic()\n");
3523 result = e;
3524 return;
3527 //printf("sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
3528 //printf("\tparent = '%s'\n", sds2.parent.toChars());
3529 sds2.dsymbolSemantic(sc);
3531 // (Aggregate|Enum)Declaration
3532 if (auto t = sds2.getType())
3534 result = (new TypeExp(exp.loc, t)).expressionSemantic(sc);
3535 return;
3538 if (auto td = sds2.isTemplateDeclaration())
3540 result = (new TemplateExp(exp.loc, td)).expressionSemantic(sc);
3541 return;
3544 exp.sds = sds2;
3545 exp.type = Type.tvoid;
3546 //printf("-2ScopeExp::semantic() %s\n", toChars());
3547 result = exp;
3551 * Sets the `lowering` field of a `NewExp` to a call to `_d_newitemT` unless
3552 * compiling with `-betterC` or within `__traits(compiles)`.
3554 * Params:
3555 * ne = the `NewExp` to lower
3557 private void tryLowerToNewItem(NewExp ne)
3559 if (!global.params.useGC || !sc.needsCodegen())
3560 return;
3562 auto hook = global.params.tracegc ? Id._d_newitemTTrace : Id._d_newitemT;
3563 if (!verifyHookExist(ne.loc, *sc, hook, "new struct"))
3564 return;
3566 /* Lower the memory allocation and initialization of `new T()` to
3567 * `_d_newitemT!T()`.
3569 Expression id = new IdentifierExp(ne.loc, Id.empty);
3570 id = new DotIdExp(ne.loc, id, Id.object);
3571 auto tiargs = new Objects();
3573 * Remove `inout`, `const`, `immutable` and `shared` to reduce the
3574 * number of generated `_d_newitemT` instances.
3576 auto t = ne.type.nextOf.unqualify(MODFlags.wild | MODFlags.const_ |
3577 MODFlags.immutable_ | MODFlags.shared_);
3578 tiargs.push(t);
3579 id = new DotTemplateInstanceExp(ne.loc, id, hook, tiargs);
3581 auto arguments = new Expressions();
3582 if (global.params.tracegc)
3584 auto funcname = (sc.callsc && sc.callsc.func) ?
3585 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
3586 arguments.push(new StringExp(ne.loc, ne.loc.filename.toDString()));
3587 arguments.push(new IntegerExp(ne.loc, ne.loc.linnum, Type.tint32));
3588 arguments.push(new StringExp(ne.loc, funcname.toDString()));
3590 id = new CallExp(ne.loc, id, arguments);
3592 ne.lowering = id.expressionSemantic(sc);
3595 override void visit(NewExp exp)
3597 static if (LOGSEMANTIC)
3599 printf("NewExp::semantic() %s\n", exp.toChars());
3600 if (exp.thisexp)
3601 printf("\tthisexp = %s\n", exp.thisexp.toChars());
3602 printf("\tnewtype: %s\n", exp.newtype.toChars());
3604 if (exp.type) // if semantic() already run
3606 result = exp;
3607 return;
3610 //for error messages if the argument in [] is not convertible to size_t
3611 const originalNewtype = exp.newtype;
3613 // https://issues.dlang.org/show_bug.cgi?id=11581
3614 // With the syntax `new T[edim]` or `thisexp.new T[edim]`,
3615 // T should be analyzed first and edim should go into arguments iff it's
3616 // not a tuple.
3617 Expression edim = null;
3618 if (!exp.arguments && exp.newtype.isTypeSArray())
3620 auto ts = exp.newtype.isTypeSArray();
3621 // check `new Value[Key]`
3622 ts.dim = ts.dim.expressionSemantic(sc);
3623 if (ts.dim.op == EXP.type)
3625 exp.newtype = new TypeAArray(ts.next, ts.dim.isTypeExp().type);
3627 else
3629 edim = ts.dim;
3630 exp.newtype = ts.next;
3634 ClassDeclaration cdthis = null;
3635 if (exp.thisexp)
3637 exp.thisexp = exp.thisexp.expressionSemantic(sc);
3638 if (exp.thisexp.op == EXP.error)
3639 return setError();
3641 cdthis = exp.thisexp.type.isClassHandle();
3642 if (!cdthis)
3644 exp.error("`this` for nested class must be a class type, not `%s`", exp.thisexp.type.toChars());
3645 return setError();
3648 sc = sc.push(cdthis);
3649 exp.type = exp.newtype.typeSemantic(exp.loc, sc);
3650 sc = sc.pop();
3652 else
3654 exp.type = exp.newtype.typeSemantic(exp.loc, sc);
3656 if (exp.type.ty == Terror)
3657 return setError();
3659 if (edim)
3661 if (exp.type.toBasetype().ty == Ttuple)
3663 // --> new T[edim]
3664 exp.type = new TypeSArray(exp.type, edim);
3665 exp.type = exp.type.typeSemantic(exp.loc, sc);
3666 if (exp.type.ty == Terror)
3667 return setError();
3669 else
3671 // --> new T[](edim)
3672 exp.arguments = new Expressions();
3673 exp.arguments.push(edim);
3674 exp.type = exp.type.arrayOf();
3678 exp.newtype = exp.type; // in case type gets cast to something else
3679 Type tb = exp.type.toBasetype();
3680 //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco);
3681 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc))
3683 return setError();
3685 if (preFunctionParameters(sc, exp.argumentList))
3687 return setError();
3690 if (exp.thisexp && tb.ty != Tclass)
3692 exp.error("`.new` is only for allocating nested classes, not `%s`", tb.toChars());
3693 return setError();
3696 const size_t nargs = exp.arguments ? exp.arguments.length : 0;
3697 Expression newprefix = null;
3699 if (auto tc = tb.isTypeClass())
3701 auto cd = tc.sym;
3702 if (cd.errors)
3703 return setError();
3704 cd.size(exp.loc);
3705 if (cd.sizeok != Sizeok.done)
3706 return setError();
3707 if (!cd.ctor)
3708 cd.ctor = cd.searchCtor();
3709 if (cd.noDefaultCtor && !nargs && !cd.defaultCtor)
3711 exp.error("default construction is disabled for type `%s`", cd.type.toChars());
3712 return setError();
3715 if (cd.isInterfaceDeclaration())
3717 exp.error("cannot create instance of interface `%s`", cd.toChars());
3718 return setError();
3721 if (cd.isAbstract())
3723 exp.error("cannot create instance of abstract class `%s`", cd.toChars());
3724 for (size_t i = 0; i < cd.vtbl.length; i++)
3726 FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration();
3727 if (fd && fd.isAbstract())
3729 errorSupplemental(exp.loc, "function `%s` is not implemented",
3730 fd.toFullSignature());
3733 return setError();
3735 // checkDeprecated() is already done in newtype.typeSemantic().
3737 if (cd.isNested())
3739 /* We need a 'this' pointer for the nested class.
3740 * Ensure we have the right one.
3742 Dsymbol s = cd.toParentLocal();
3744 //printf("cd isNested, parent = %s '%s'\n", s.kind(), s.toPrettyChars());
3745 if (auto cdn = s.isClassDeclaration())
3747 if (!cdthis)
3749 void noReferenceToOuterClass()
3751 if (cd.isAnonymous)
3752 exp.error("cannot construct anonymous nested class because no implicit `this` reference to outer class is available");
3753 else
3754 exp.error("cannot construct nested class `%s` because no implicit `this` reference to outer class `%s` is available",
3755 cd.toChars(), cdn.toChars());
3756 return setError();
3759 if (!sc.hasThis)
3760 return noReferenceToOuterClass();
3762 // Supply an implicit 'this' and try again
3763 exp.thisexp = new ThisExp(exp.loc);
3764 for (Dsymbol sp = sc.parent; 1; sp = sp.toParentLocal())
3766 if (!sp)
3767 return noReferenceToOuterClass();
3768 ClassDeclaration cdp = sp.isClassDeclaration();
3769 if (!cdp)
3770 continue;
3771 if (cdp == cdn || cdn.isBaseOf(cdp, null))
3772 break;
3773 // Add a '.outer' and try again
3774 exp.thisexp = new DotIdExp(exp.loc, exp.thisexp, Id.outer);
3777 exp.thisexp = exp.thisexp.expressionSemantic(sc);
3778 if (exp.thisexp.op == EXP.error)
3779 return setError();
3780 cdthis = exp.thisexp.type.isClassHandle();
3782 if (cdthis != cdn && !cdn.isBaseOf(cdthis, null))
3784 //printf("cdthis = %s\n", cdthis.toChars());
3785 exp.error("`this` for nested class must be of type `%s`, not `%s`",
3786 cdn.toChars(), exp.thisexp.type.toChars());
3787 return setError();
3789 if (!MODimplicitConv(exp.thisexp.type.mod, exp.newtype.mod))
3791 exp.error("nested type `%s` should have the same or weaker constancy as enclosing type `%s`",
3792 exp.newtype.toChars(), exp.thisexp.type.toChars());
3793 return setError();
3796 else if (exp.thisexp)
3798 exp.error("`.new` is only for allocating nested classes");
3799 return setError();
3801 else if (auto fdn = s.isFuncDeclaration())
3803 // make sure the parent context fdn of cd is reachable from sc
3804 if (!ensureStaticLinkTo(sc.parent, fdn))
3806 exp.error("outer function context of `%s` is needed to `new` nested class `%s`",
3807 fdn.toPrettyChars(), cd.toPrettyChars());
3808 return setError();
3811 else
3812 assert(0);
3814 else if (exp.thisexp)
3816 exp.error("`.new` is only for allocating nested classes");
3817 return setError();
3820 if (cd.vthis2)
3822 if (AggregateDeclaration ad2 = cd.isMember2())
3824 Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
3825 if (te.op != EXP.error)
3826 te = getRightThis(exp.loc, sc, ad2, te, cd);
3827 if (te.op == EXP.error)
3829 exp.error("need `this` of type `%s` needed to `new` nested class `%s`", ad2.toChars(), cd.toChars());
3830 return setError();
3835 if (cd.disableNew && !exp.onstack)
3837 exp.error("cannot allocate `class %s` with `new` because it is annotated with `@disable new()`",
3838 originalNewtype.toChars());
3839 return setError();
3842 if (cd.ctor)
3844 FuncDeclaration f = resolveFuncCall(exp.loc, sc, cd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard);
3845 if (!f || f.errors)
3846 return setError();
3848 checkFunctionAttributes(exp, sc, f);
3849 checkAccess(cd, exp.loc, sc, f);
3851 TypeFunction tf = f.type.isTypeFunction();
3852 if (!exp.arguments)
3853 exp.arguments = new Expressions();
3854 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix))
3855 return setError();
3857 exp.member = f.isCtorDeclaration();
3858 assert(exp.member);
3860 else
3862 if (nargs)
3864 exp.error("no constructor for `%s`", cd.toChars());
3865 return setError();
3868 // https://issues.dlang.org/show_bug.cgi?id=19941
3869 // Run semantic on all field initializers to resolve any forward
3870 // references. This is the same as done for structs in sd.fill().
3871 for (ClassDeclaration c = cd; c; c = c.baseClass)
3873 foreach (v; c.fields)
3875 if (v.inuse || v._scope is null || v._init is null ||
3876 v._init.isVoidInitializer())
3877 continue;
3878 v.inuse++;
3879 v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret);
3880 v.inuse--;
3885 // When using `@nogc` exception handling, lower `throw new E(args)` to
3886 // `throw (__tmp = _d_newThrowable!E(), __tmp.__ctor(args), __tmp)`.
3887 if (global.params.ehnogc && exp.thrownew &&
3888 !cd.isCOMclass() && !cd.isCPPclass())
3890 assert(cd.ctor);
3892 Expression id = new IdentifierExp(exp.loc, Id.empty);
3893 id = new DotIdExp(exp.loc, id, Id.object);
3895 auto tiargs = new Objects();
3896 tiargs.push(exp.newtype);
3897 id = new DotTemplateInstanceExp(exp.loc, id, Id._d_newThrowable, tiargs);
3898 id = new CallExp(exp.loc, id).expressionSemantic(sc);
3900 Expression idVal;
3901 Expression tmp = extractSideEffect(sc, "__tmpThrowable", idVal, id, true);
3902 // auto castTmp = new CastExp(exp.loc, tmp, exp.type);
3904 auto ctor = new DotIdExp(exp.loc, tmp, Id.ctor).expressionSemantic(sc);
3905 auto ctorCall = new CallExp(exp.loc, ctor, exp.arguments);
3907 id = Expression.combine(idVal, exp.argprefix).expressionSemantic(sc);
3908 id = Expression.combine(id, ctorCall).expressionSemantic(sc);
3909 // id = Expression.combine(id, castTmp).expressionSemantic(sc);
3911 result = id.expressionSemantic(sc);
3912 return;
3914 else if (sc.needsCodegen() && // interpreter doesn't need this lowered
3915 !exp.onstack && !exp.type.isscope()) // these won't use the GC
3917 /* replace `new T(arguments)` with `core.lifetime._d_newclassT!T(arguments)`
3918 * or `_d_newclassTTrace`
3920 auto hook = global.params.tracegc ? Id._d_newclassTTrace : Id._d_newclassT;
3921 if (!verifyHookExist(exp.loc, *sc, hook, "new class"))
3922 return setError();
3924 Expression id = new IdentifierExp(exp.loc, Id.empty);
3925 id = new DotIdExp(exp.loc, id, Id.object);
3927 auto tiargs = new Objects();
3928 auto t = exp.newtype.unqualify(MODFlags.wild); // remove `inout`
3929 tiargs.push(t);
3930 id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs);
3931 auto arguments = new Expressions();
3932 if (global.params.tracegc)
3934 auto funcname = (sc.callsc && sc.callsc.func) ?
3935 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
3936 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
3937 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
3938 arguments.push(new StringExp(exp.loc, funcname.toDString()));
3940 id = new CallExp(exp.loc, id, arguments);
3942 exp.lowering = id.expressionSemantic(sc);
3945 else if (auto ts = tb.isTypeStruct())
3947 auto sd = ts.sym;
3948 sd.size(exp.loc);
3949 if (sd.sizeok != Sizeok.done)
3950 return setError();
3951 if (!sd.ctor)
3952 sd.ctor = sd.searchCtor();
3953 if (sd.noDefaultCtor && !nargs)
3955 exp.error("default construction is disabled for type `%s`", sd.type.toChars());
3956 return setError();
3958 // checkDeprecated() is already done in newtype.typeSemantic().
3960 if (sd.disableNew)
3962 exp.error("cannot allocate `struct %s` with `new` because it is annotated with `@disable new()`",
3963 originalNewtype.toChars());
3964 return setError();
3967 // https://issues.dlang.org/show_bug.cgi?id=22639
3968 // If the new expression has arguments, we either should call a
3969 // regular constructor of a copy constructor if the first argument
3970 // is the same type as the struct
3971 if (nargs && (sd.hasRegularCtor() || (sd.ctor && (*exp.arguments)[0].type.mutableOf() == sd.type.mutableOf())))
3973 FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard);
3974 if (!f || f.errors)
3975 return setError();
3977 checkFunctionAttributes(exp, sc, f);
3978 checkAccess(sd, exp.loc, sc, f);
3980 TypeFunction tf = f.type.isTypeFunction();
3981 if (!exp.arguments)
3982 exp.arguments = new Expressions();
3983 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix))
3984 return setError();
3986 exp.member = f.isCtorDeclaration();
3987 assert(exp.member);
3989 if (checkFrameAccess(exp.loc, sc, sd, sd.fields.length))
3990 return setError();
3992 else
3994 if (exp.names)
3996 exp.arguments = resolveStructLiteralNamedArgs(sd, exp.type, sc, exp.loc,
3997 exp.names ? (*exp.names)[] : null,
3998 (size_t i, Type t) => (*exp.arguments)[i],
3999 i => (*exp.arguments)[i].loc
4001 if (!exp.arguments)
4002 return setError();
4004 else if (!exp.arguments)
4006 exp.arguments = new Expressions();
4009 if (!sd.fit(exp.loc, sc, exp.arguments, tb))
4010 return setError();
4012 if (!sd.fill(exp.loc, *exp.arguments, false))
4013 return setError();
4015 if (checkFrameAccess(exp.loc, sc, sd, exp.arguments ? exp.arguments.length : 0))
4016 return setError();
4018 /* Since a `new` allocation may escape, check each of the arguments for escaping
4020 foreach (arg; *exp.arguments)
4022 if (arg && checkNewEscape(sc, arg, false))
4023 return setError();
4027 exp.type = exp.type.pointerTo();
4028 tryLowerToNewItem(exp);
4030 else if (tb.ty == Tarray)
4032 if (!nargs)
4034 // https://issues.dlang.org/show_bug.cgi?id=20422
4035 // Without this check the compiler would give a misleading error
4036 exp.error("missing length argument for array");
4037 return setError();
4040 Type tn = tb.nextOf().baseElemOf();
4041 Dsymbol s = tn.toDsymbol(sc);
4042 AggregateDeclaration ad = s ? s.isAggregateDeclaration() : null;
4043 if (ad && ad.noDefaultCtor)
4045 exp.error("default construction is disabled for type `%s`", tb.nextOf().toChars());
4046 return setError();
4048 for (size_t i = 0; i < nargs; i++)
4050 if (tb.ty != Tarray)
4052 exp.error("too many arguments for array");
4053 return setError();
4056 Expression arg = (*exp.arguments)[i];
4057 if (exp.names && (*exp.names)[i])
4059 exp.error("no named argument `%s` allowed for array dimension", (*exp.names)[i].toChars());
4060 return setError();
4063 arg = resolveProperties(sc, arg);
4064 arg = arg.implicitCastTo(sc, Type.tsize_t);
4065 if (arg.op == EXP.error)
4066 return setError();
4067 arg = arg.optimize(WANTvalue);
4068 if (arg.op == EXP.int64 && (target.isLP64 ?
4069 cast(sinteger_t)arg.toInteger() : cast(int)arg.toInteger()) < 0)
4071 exp.error("negative array dimension `%s`", (*exp.arguments)[i].toChars());
4072 return setError();
4074 (*exp.arguments)[i] = arg;
4075 tb = tb.isTypeDArray().next.toBasetype();
4078 else if (tb.isscalar())
4080 if (!nargs)
4083 else if (nargs == 1)
4085 if (exp.names && (*exp.names)[0])
4087 exp.error("no named argument `%s` allowed for scalar", (*exp.names)[0].toChars());
4088 return setError();
4090 Expression e = (*exp.arguments)[0];
4091 e = e.implicitCastTo(sc, tb);
4092 (*exp.arguments)[0] = e;
4094 else
4096 exp.error("more than one argument for construction of `%s`", exp.type.toChars());
4097 return setError();
4100 exp.type = exp.type.pointerTo();
4101 tryLowerToNewItem(exp);
4103 else if (tb.ty == Taarray)
4105 // e.g. `new Alias(args)`
4106 if (nargs)
4108 exp.error("`new` cannot take arguments for an associative array");
4109 return setError();
4112 else
4114 exp.error("cannot create a `%s` with `new`", exp.type.toChars());
4115 return setError();
4118 //printf("NewExp: '%s'\n", toChars());
4119 //printf("NewExp:type '%s'\n", type.toChars());
4120 semanticTypeInfo(sc, exp.type);
4122 if (newprefix)
4124 result = Expression.combine(newprefix, exp);
4125 return;
4127 result = exp;
4130 override void visit(NewAnonClassExp e)
4132 static if (LOGSEMANTIC)
4134 printf("NewAnonClassExp::semantic() %s\n", e.toChars());
4135 //printf("thisexp = %p\n", thisexp);
4136 //printf("type: %s\n", type.toChars());
4139 Expression d = new DeclarationExp(e.loc, e.cd);
4140 sc = sc.push(); // just create new scope
4141 sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
4142 d = d.expressionSemantic(sc);
4143 sc = sc.pop();
4145 if (!e.cd.errors && sc.intypeof && !sc.parent.inNonRoot())
4147 ScopeDsymbol sds = sc.tinst ? cast(ScopeDsymbol)sc.tinst : sc._module;
4148 if (!sds.members)
4149 sds.members = new Dsymbols();
4150 sds.members.push(e.cd);
4153 Expression n = new NewExp(e.loc, e.thisexp, e.cd.type, e.arguments);
4155 Expression c = new CommaExp(e.loc, d, n);
4156 result = c.expressionSemantic(sc);
4159 override void visit(SymOffExp e)
4161 static if (LOGSEMANTIC)
4163 printf("SymOffExp::semantic('%s')\n", e.toChars());
4165 //var.dsymbolSemantic(sc);
4166 if (!e.type)
4167 e.type = e.var.type.pointerTo();
4169 if (auto v = e.var.isVarDeclaration())
4171 if (v.checkNestedReference(sc, e.loc))
4172 return setError();
4174 else if (auto f = e.var.isFuncDeclaration())
4176 if (f.checkNestedReference(sc, e.loc))
4177 return setError();
4180 result = e;
4183 override void visit(VarExp e)
4185 static if (LOGSEMANTIC)
4187 printf("VarExp::semantic(%s)\n", e.toChars());
4190 auto vd = e.var.isVarDeclaration();
4191 auto fd = e.var.isFuncDeclaration();
4193 if (fd)
4195 //printf("L%d fd = %s\n", __LINE__, f.toChars());
4196 if (!fd.functionSemantic())
4197 return setError();
4200 if (!e.type)
4201 e.type = e.var.type;
4202 if (e.type && !e.type.deco)
4204 auto decl = e.var.isDeclaration();
4205 if (decl)
4206 decl.inuse++;
4207 e.type = e.type.typeSemantic(e.loc, sc);
4208 if (decl)
4209 decl.inuse--;
4212 /* Fix for 1161 doesn't work because it causes visibility
4213 * problems when instantiating imported templates passing private
4214 * variables as alias template parameters.
4216 //checkAccess(loc, sc, NULL, var);
4218 if (vd)
4220 if (vd.checkNestedReference(sc, e.loc))
4221 return setError();
4223 // https://issues.dlang.org/show_bug.cgi?id=12025
4224 // If the variable is not actually used in runtime code,
4225 // the purity violation error is redundant.
4226 //checkPurity(sc, vd);
4228 else if (fd)
4230 // TODO: If fd isn't yet resolved its overload, the checkNestedReference
4231 // call would cause incorrect validation.
4232 // Maybe here should be moved in CallExp, or AddrExp for functions.
4233 if (fd.checkNestedReference(sc, e.loc))
4234 return setError();
4236 else if (auto od = e.var.isOverDeclaration())
4238 e.type = Type.tvoid; // ambiguous type?
4241 result = e;
4244 override void visit(FuncExp exp)
4246 static if (LOGSEMANTIC)
4248 printf("FuncExp::semantic(%s)\n", exp.toChars());
4249 if (exp.fd.treq)
4250 printf(" treq = %s\n", exp.fd.treq.toChars());
4253 if (exp.type)
4255 result = exp;
4256 return;
4259 Expression e = exp;
4260 uint olderrors;
4262 sc = sc.push(); // just create new scope
4263 sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
4264 sc.visibility = Visibility(Visibility.Kind.public_); // https://issues.dlang.org/show_bug.cgi?id=12506
4266 /* fd.treq might be incomplete type,
4267 * so should not semantic it.
4268 * void foo(T)(T delegate(int) dg){}
4269 * foo(a=>a); // in IFTI, treq == T delegate(int)
4271 //if (fd.treq)
4272 // fd.treq = fd.treq.dsymbolSemantic(loc, sc);
4274 exp.genIdent(sc);
4276 // Set target of return type inference
4277 if (exp.fd.treq && !exp.fd.type.nextOf())
4279 TypeFunction tfv = null;
4280 if (exp.fd.treq.ty == Tdelegate || exp.fd.treq.isPtrToFunction())
4281 tfv = cast(TypeFunction)exp.fd.treq.nextOf();
4282 if (tfv)
4284 TypeFunction tfl = cast(TypeFunction)exp.fd.type;
4285 tfl.next = tfv.nextOf();
4289 //printf("td = %p, treq = %p\n", td, fd.treq);
4290 if (exp.td)
4292 assert(exp.td.parameters && exp.td.parameters.length);
4293 exp.td.dsymbolSemantic(sc);
4294 exp.type = Type.tvoid; // temporary type
4296 if (exp.fd.treq) // defer type determination
4298 FuncExp fe;
4299 if (exp.matchType(exp.fd.treq, sc, &fe) > MATCH.nomatch)
4300 e = fe;
4301 else
4302 e = ErrorExp.get();
4304 goto Ldone;
4307 olderrors = global.errors;
4308 exp.fd.dsymbolSemantic(sc);
4309 if (olderrors == global.errors)
4311 exp.fd.semantic2(sc);
4312 if (olderrors == global.errors)
4313 exp.fd.semantic3(sc);
4315 if (olderrors != global.errors)
4317 if (exp.fd.type && exp.fd.type.ty == Tfunction && !exp.fd.type.nextOf())
4318 (cast(TypeFunction)exp.fd.type).next = Type.terror;
4319 e = ErrorExp.get();
4320 goto Ldone;
4323 // Type is a "delegate to" or "pointer to" the function literal
4324 if ((exp.fd.isNested() && exp.fd.tok == TOK.delegate_) || (exp.tok == TOK.reserved && exp.fd.treq && exp.fd.treq.ty == Tdelegate))
4326 // https://issues.dlang.org/show_bug.cgi?id=22686
4327 // if the delegate return type is an error
4328 // abort semantic of the FuncExp and propagate
4329 // the error
4330 if (exp.fd.type.isTypeError())
4332 e = ErrorExp.get();
4333 goto Ldone;
4335 exp.type = new TypeDelegate(exp.fd.type.isTypeFunction());
4336 exp.type = exp.type.typeSemantic(exp.loc, sc);
4338 exp.fd.tok = TOK.delegate_;
4340 else
4342 exp.type = new TypePointer(exp.fd.type);
4343 exp.type = exp.type.typeSemantic(exp.loc, sc);
4344 //type = fd.type.pointerTo();
4346 /* A lambda expression deduced to function pointer might become
4347 * to a delegate literal implicitly.
4349 * auto foo(void function() fp) { return 1; }
4350 * assert(foo({}) == 1);
4352 * So, should keep fd.tok == TOK.reserve if fd.treq == NULL.
4354 if (exp.fd.treq && exp.fd.treq.ty == Tpointer)
4356 // change to non-nested
4357 exp.fd.tok = TOK.function_;
4358 exp.fd.vthis = null;
4361 exp.fd.tookAddressOf++;
4363 Ldone:
4364 sc = sc.pop();
4365 result = e;
4369 * Perform semantic analysis on function literals
4371 * Test the following construct:
4372 * ---
4373 * (x, y, z) { return x + y + z; }(42, 84, 1992);
4374 * ---
4376 Expression callExpSemantic(FuncExp exp, Scope* sc, Expressions* arguments)
4378 if ((!exp.type || exp.type == Type.tvoid) && exp.td && arguments && arguments.length)
4380 for (size_t k = 0; k < arguments.length; k++)
4382 Expression checkarg = (*arguments)[k];
4383 if (checkarg.op == EXP.error)
4384 return checkarg;
4387 exp.genIdent(sc);
4389 assert(exp.td.parameters && exp.td.parameters.length);
4390 exp.td.dsymbolSemantic(sc);
4392 TypeFunction tfl = cast(TypeFunction)exp.fd.type;
4393 size_t dim = tfl.parameterList.length;
4394 if (arguments.length < dim)
4396 // Default arguments are always typed, so they don't need inference.
4397 Parameter p = tfl.parameterList[arguments.length];
4398 if (p.defaultArg)
4399 dim = arguments.length;
4402 if ((tfl.parameterList.varargs == VarArg.none && arguments.length > dim) ||
4403 arguments.length < dim)
4405 OutBuffer buf;
4406 foreach (idx, ref arg; *arguments)
4407 buf.printf("%s%s", (idx ? ", ".ptr : "".ptr), arg.type.toChars());
4408 exp.error("function literal `%s%s` is not callable using argument types `(%s)`",
4409 exp.fd.toChars(), parametersTypeToChars(tfl.parameterList),
4410 buf.peekChars());
4411 exp.errorSupplemental("too %s arguments, expected %d, got %d",
4412 arguments.length < dim ? "few".ptr : "many".ptr,
4413 cast(int)dim, cast(int)arguments.length);
4414 return ErrorExp.get();
4417 auto tiargs = new Objects();
4418 tiargs.reserve(exp.td.parameters.length);
4420 for (size_t i = 0; i < exp.td.parameters.length; i++)
4422 TemplateParameter tp = (*exp.td.parameters)[i];
4423 assert(dim <= tfl.parameterList.length);
4424 foreach (u, p; tfl.parameterList)
4426 if (u == dim)
4427 break;
4429 if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident)
4431 Expression e = (*arguments)[u];
4432 tiargs.push(e.type);
4433 break;
4438 auto ti = new TemplateInstance(exp.loc, exp.td, tiargs);
4439 return (new ScopeExp(exp.loc, ti)).expressionSemantic(sc);
4441 return exp.expressionSemantic(sc);
4444 override void visit(CallExp exp)
4446 static if (LOGSEMANTIC)
4448 printf("CallExp::semantic() %s\n", exp.toChars());
4450 if (exp.type)
4452 result = exp;
4453 return; // semantic() already run
4456 Objects* tiargs = null; // initial list of template arguments
4457 Expression ethis = null;
4458 Type tthis = null;
4459 Expression e1org = exp.e1;
4461 if (auto ce = exp.e1.isCommaExp())
4463 /* Rewrite (a,b)(args) as (a,(b(args)))
4465 exp.e1 = ce.e2;
4466 ce.e2 = exp;
4467 result = ce.expressionSemantic(sc);
4468 return;
4470 if (DelegateExp de = exp.e1.isDelegateExp())
4472 exp.e1 = new DotVarExp(de.loc, de.e1, de.func, de.hasOverloads);
4473 visit(exp);
4474 return;
4476 if (FuncExp fe = exp.e1.isFuncExp())
4478 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
4479 preFunctionParameters(sc, exp.argumentList))
4480 return setError();
4482 // Run e1 semantic even if arguments have any errors
4483 exp.e1 = callExpSemantic(fe, sc, exp.arguments);
4484 if (exp.e1.op == EXP.error)
4486 result = exp.e1;
4487 return;
4490 if (sc.flags & SCOPE.Cfile)
4492 /* See if need to rewrite the AST because of cast/call ambiguity
4494 if (auto e = castCallAmbiguity(exp, sc))
4496 result = expressionSemantic(e, sc);
4497 return;
4501 if (Expression ex = resolveUFCS(sc, exp))
4503 result = ex;
4504 return;
4507 /* This recognizes:
4508 * foo!(tiargs)(funcargs)
4510 if (ScopeExp se = exp.e1.isScopeExp())
4512 TemplateInstance ti = se.sds.isTemplateInstance();
4513 if (ti)
4515 /* Attempt to instantiate ti. If that works, go with it.
4516 * If not, go with partial explicit specialization.
4518 WithScopeSymbol withsym;
4519 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc))
4520 return setError();
4521 if (withsym && withsym.withstate.wthis)
4523 exp.e1 = new VarExp(exp.e1.loc, withsym.withstate.wthis);
4524 exp.e1 = new DotTemplateInstanceExp(exp.e1.loc, exp.e1, ti);
4525 goto Ldotti;
4527 if (ti.needsTypeInference(sc, 1))
4529 /* Go with partial explicit specialization
4531 tiargs = ti.tiargs;
4532 assert(ti.tempdecl);
4533 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
4534 exp.e1 = new TemplateExp(exp.loc, td);
4535 else if (OverDeclaration od = ti.tempdecl.isOverDeclaration())
4536 exp.e1 = new VarExp(exp.loc, od);
4537 else
4538 exp.e1 = new OverExp(exp.loc, ti.tempdecl.isOverloadSet());
4540 else
4542 Expression e1x = exp.e1.expressionSemantic(sc);
4543 if (e1x.op == EXP.error)
4545 result = e1x;
4546 return;
4548 exp.e1 = e1x;
4553 /* This recognizes:
4554 * expr.foo!(tiargs)(funcargs)
4556 Ldotti:
4557 if (DotTemplateInstanceExp se = exp.e1.isDotTemplateInstanceExp())
4559 TemplateInstance ti = se.ti;
4561 /* Attempt to instantiate ti. If that works, go with it.
4562 * If not, go with partial explicit specialization.
4564 if (!se.findTempDecl(sc) || !ti.semanticTiargs(sc))
4565 return setError();
4566 if (ti.needsTypeInference(sc, 1))
4568 /* Go with partial explicit specialization
4570 tiargs = ti.tiargs;
4571 assert(ti.tempdecl);
4572 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
4573 exp.e1 = new DotTemplateExp(exp.loc, se.e1, td);
4574 else if (OverDeclaration od = ti.tempdecl.isOverDeclaration())
4576 exp.e1 = new DotVarExp(exp.loc, se.e1, od, true);
4578 else
4579 exp.e1 = new DotExp(exp.loc, se.e1, new OverExp(exp.loc, ti.tempdecl.isOverloadSet()));
4581 else
4583 Expression e1x = exp.e1.expressionSemantic(sc);
4584 if (e1x.op == EXP.error)
4586 result = e1x;
4587 return;
4589 exp.e1 = e1x;
4594 Type att = null;
4595 Lagain:
4596 //printf("Lagain: %s\n", toChars());
4597 exp.f = null;
4598 if (exp.e1.op == EXP.this_ || exp.e1.op == EXP.super_)
4600 // semantic() run later for these
4602 else
4604 if (DotIdExp die = exp.e1.isDotIdExp())
4606 exp.e1 = die.expressionSemantic(sc);
4607 /* Look for e1 having been rewritten to expr.opDispatch!(string)
4608 * We handle such earlier, so go back.
4609 * Note that in the rewrite, we carefully did not run semantic() on e1
4611 if (exp.e1.op == EXP.dotTemplateInstance)
4613 goto Ldotti;
4616 else
4618 __gshared int nest;
4619 if (++nest > global.recursionLimit)
4621 exp.error("recursive evaluation of `%s`", exp.toChars());
4622 --nest;
4623 return setError();
4625 Expression ex = unaSemantic(exp, sc);
4626 --nest;
4627 if (ex)
4629 result = ex;
4630 return;
4634 /* Look for e1 being a lazy parameter
4636 if (VarExp ve = exp.e1.isVarExp())
4638 if (ve.var.storage_class & STC.lazy_)
4640 // lazy parameters can be called without violating purity and safety
4641 Type tw = ve.var.type;
4642 Type tc = ve.var.type.substWildTo(MODFlags.const_);
4643 auto tf = new TypeFunction(ParameterList(), tc, LINK.d, STC.safe | STC.pure_);
4644 (tf = cast(TypeFunction)tf.typeSemantic(exp.loc, sc)).next = tw; // hack for bug7757
4645 auto t = new TypeDelegate(tf);
4646 ve.type = t.typeSemantic(exp.loc, sc);
4648 VarDeclaration v = ve.var.isVarDeclaration();
4649 if (v && ve.checkPurity(sc, v))
4650 return setError();
4653 if (exp.e1.op == EXP.symbolOffset && (cast(SymOffExp)exp.e1).hasOverloads)
4655 SymOffExp se = cast(SymOffExp)exp.e1;
4656 exp.e1 = new VarExp(se.loc, se.var, true);
4657 exp.e1 = exp.e1.expressionSemantic(sc);
4659 else if (DotExp de = exp.e1.isDotExp())
4661 if (de.e2.op == EXP.overloadSet)
4663 ethis = de.e1;
4664 tthis = de.e1.type;
4665 exp.e1 = de.e2;
4668 else if (exp.e1.op == EXP.star && exp.e1.type.ty == Tfunction)
4670 // Rewrite (*fp)(arguments) to fp(arguments)
4671 exp.e1 = (cast(PtrExp)exp.e1).e1;
4673 else if (exp.e1.op == EXP.type && (sc && sc.flags & SCOPE.Cfile))
4675 const numArgs = exp.arguments ? exp.arguments.length : 0;
4677 /* Ambiguous cases arise from CParser where there is not enough
4678 * information to determine if we have a function call or declaration.
4679 * type-name ( identifier ) ;
4680 * identifier ( identifier ) ;
4681 * If exp.e1 is a type-name, then this is a declaration. C11 does not
4682 * have type construction syntax, so don't convert this to a cast().
4684 if (numArgs == 1)
4686 Expression arg = (*exp.arguments)[0];
4687 if (auto ie = (*exp.arguments)[0].isIdentifierExp())
4689 TypeExp te = cast(TypeExp)exp.e1;
4690 auto initializer = new VoidInitializer(ie.loc);
4691 Dsymbol s = new VarDeclaration(ie.loc, te.type, ie.ident, initializer);
4692 auto decls = new Dsymbols(1);
4693 (*decls)[0] = s;
4694 s = new LinkDeclaration(s.loc, LINK.c, decls);
4695 result = new DeclarationExp(exp.loc, s);
4696 result = result.expressionSemantic(sc);
4698 else
4700 arg.error("identifier or `(` expected");
4701 result = ErrorExp.get();
4703 return;
4705 exp.error("identifier or `(` expected before `)`");
4706 result = ErrorExp.get();
4707 return;
4711 Type t1 = exp.e1.type ? exp.e1.type.toBasetype() : null;
4713 if (exp.e1.op == EXP.error)
4715 result = exp.e1;
4716 return;
4718 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
4719 preFunctionParameters(sc, exp.argumentList))
4720 return setError();
4722 // Check for call operator overload
4723 if (t1)
4725 if (t1.ty == Tstruct)
4727 auto sd = (cast(TypeStruct)t1).sym;
4728 sd.size(exp.loc); // Resolve forward references to construct object
4729 if (sd.sizeok != Sizeok.done)
4730 return setError();
4731 if (!sd.ctor)
4732 sd.ctor = sd.searchCtor();
4733 /* If `sd.ctor` is a generated copy constructor, this means that it
4734 is the single constructor that this struct has. In order to not
4735 disable default construction, the ctor is nullified. The side effect
4736 of this is that the generated copy constructor cannot be called
4737 explicitly, but that is ok, because when calling a constructor the
4738 default constructor should have priority over the generated copy
4739 constructor.
4741 if (sd.ctor)
4743 auto ctor = sd.ctor.isCtorDeclaration();
4744 if (ctor && ctor.isCpCtor && ctor.isGenerated())
4745 sd.ctor = null;
4748 // First look for constructor
4749 if (exp.e1.op == EXP.type && sd.ctor)
4751 if (!sd.noDefaultCtor && !(exp.arguments && exp.arguments.length))
4752 goto Lx;
4754 /* https://issues.dlang.org/show_bug.cgi?id=20695
4755 If all constructors are copy constructors, then
4756 try default construction.
4758 if (!sd.hasRegularCtor &&
4759 // https://issues.dlang.org/show_bug.cgi?id=22639
4760 // we might still have a copy constructor that could be called
4761 (*exp.arguments)[0].type.mutableOf != sd.type.mutableOf())
4762 goto Lx;
4764 auto sle = new StructLiteralExp(exp.loc, sd, null, exp.e1.type);
4765 if (!sd.fill(exp.loc, *sle.elements, true))
4766 return setError();
4767 if (checkFrameAccess(exp.loc, sc, sd, sle.elements.length))
4768 return setError();
4770 // https://issues.dlang.org/show_bug.cgi?id=14556
4771 // Set concrete type to avoid further redundant semantic().
4772 sle.type = exp.e1.type;
4774 /* Constructor takes a mutable object, so don't use
4775 * the immutable initializer symbol.
4777 sle.useStaticInit = false;
4779 Expression e = sle;
4780 if (auto cf = sd.ctor.isCtorDeclaration())
4782 e = new DotVarExp(exp.loc, e, cf, true);
4784 else if (auto td = sd.ctor.isTemplateDeclaration())
4786 e = new DotIdExp(exp.loc, e, td.ident);
4788 else if (auto os = sd.ctor.isOverloadSet())
4790 e = new DotExp(exp.loc, e, new OverExp(exp.loc, os));
4792 else
4793 assert(0);
4794 e = new CallExp(exp.loc, e, exp.arguments);
4795 e = e.expressionSemantic(sc);
4796 result = e;
4797 return;
4799 // No constructor, look for overload of opCall
4800 if (search_function(sd, Id.call))
4801 goto L1;
4802 // overload of opCall, therefore it's a call
4803 if (exp.e1.op != EXP.type)
4805 if (sd.aliasthis && !isRecursiveAliasThis(att, exp.e1.type))
4807 exp.e1 = resolveAliasThis(sc, exp.e1);
4808 goto Lagain;
4810 exp.error("%s `%s` does not overload ()", sd.kind(), sd.toChars());
4811 return setError();
4814 /* It's a struct literal
4817 Expressions* resolvedArgs = exp.arguments;
4818 if (exp.names)
4820 resolvedArgs = resolveStructLiteralNamedArgs(sd, exp.e1.type, sc, exp.loc,
4821 (*exp.names)[],
4822 (size_t i, Type t) => (*exp.arguments)[i],
4823 i => (*exp.arguments)[i].loc
4825 if (!resolvedArgs)
4827 result = ErrorExp.get();
4828 return;
4832 Expression e = new StructLiteralExp(exp.loc, sd, resolvedArgs, exp.e1.type);
4833 e = e.expressionSemantic(sc);
4834 result = e;
4835 return;
4837 else if (t1.ty == Tclass)
4840 // Rewrite as e1.call(arguments)
4841 Expression e = new DotIdExp(exp.loc, exp.e1, Id.call);
4842 e = new CallExp(exp.loc, e, exp.arguments, exp.names);
4843 e = e.expressionSemantic(sc);
4844 result = e;
4845 return;
4847 else if (exp.e1.op == EXP.type && t1.isscalar())
4849 Expression e;
4851 // Make sure to use the enum type itself rather than its
4852 // base type
4853 // https://issues.dlang.org/show_bug.cgi?id=16346
4854 if (exp.e1.type.ty == Tenum)
4856 t1 = exp.e1.type;
4859 if (!exp.arguments || exp.arguments.length == 0)
4861 e = t1.defaultInitLiteral(exp.loc);
4863 else if (exp.arguments.length == 1)
4865 e = (*exp.arguments)[0];
4866 e = e.implicitCastTo(sc, t1);
4867 e = new CastExp(exp.loc, e, t1);
4869 else
4871 exp.error("more than one argument for construction of `%s`", t1.toChars());
4872 return setError();
4874 e = e.expressionSemantic(sc);
4875 result = e;
4876 return;
4880 FuncDeclaration resolveOverloadSet(Loc loc, Scope* sc,
4881 OverloadSet os, Objects* tiargs, Type tthis, ArgumentList argumentList)
4883 FuncDeclaration f = null;
4884 foreach (s; os.a)
4886 if (tiargs && s.isFuncDeclaration())
4887 continue;
4888 if (auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, argumentList, FuncResolveFlag.quiet))
4890 if (f2.errors)
4891 return null;
4892 if (f)
4894 /* Match in more than one overload set,
4895 * even if one is a 'better' match than the other.
4897 if (f.isCsymbol() && f2.isCsymbol())
4899 /* C has global name space, so just pick one, such as f.
4900 * If f and f2 are not compatible, that's how C rolls.
4903 else
4904 ScopeDsymbol.multiplyDefined(loc, f, f2); // issue error
4906 else
4907 f = f2;
4910 if (!f)
4912 .error(loc, "no overload matches for `%s`", exp.toChars());
4913 errorSupplemental(loc, "Candidates are:");
4914 foreach (s; os.a)
4916 overloadApply(s, (ds){
4917 if (auto fd = ds.isFuncDeclaration())
4918 .errorSupplemental(ds.loc, "%s%s", fd.toChars(),
4919 fd.type.toTypeFunction().parameterList.parametersTypeToChars());
4920 else
4921 .errorSupplemental(ds.loc, "%s", ds.toChars());
4922 return 0;
4926 else if (f.errors)
4927 f = null;
4928 return f;
4931 bool isSuper = false;
4932 if (exp.e1.op == EXP.dotVariable && t1.ty == Tfunction || exp.e1.op == EXP.dotTemplateDeclaration)
4934 UnaExp ue = cast(UnaExp)exp.e1;
4936 Expression ue1old = ue.e1; // need for 'right this' check
4937 DotVarExp dve;
4938 DotTemplateExp dte;
4939 Dsymbol s;
4940 if (exp.e1.op == EXP.dotVariable)
4942 dve = cast(DotVarExp)exp.e1;
4943 dte = null;
4944 s = dve.var;
4945 tiargs = null;
4947 else
4949 dve = null;
4950 dte = cast(DotTemplateExp)exp.e1;
4951 s = dte.td;
4954 // Do overload resolution
4955 exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, ue.e1.type, exp.argumentList, FuncResolveFlag.standard);
4956 if (!exp.f || exp.f.errors || exp.f.type.ty == Terror)
4957 return setError();
4959 if (exp.f.interfaceVirtual)
4961 /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent
4963 auto b = exp.f.interfaceVirtual;
4964 auto ad2 = b.sym;
4965 ue.e1 = ue.e1.castTo(sc, ad2.type.addMod(ue.e1.type.mod));
4966 ue.e1 = ue.e1.expressionSemantic(sc);
4967 auto vi = exp.f.findVtblIndex(&ad2.vtbl, cast(int)ad2.vtbl.length);
4968 assert(vi >= 0);
4969 exp.f = ad2.vtbl[vi].isFuncDeclaration();
4970 assert(exp.f);
4972 if (exp.f.needThis())
4974 AggregateDeclaration ad = exp.f.isMemberLocal();
4975 ue.e1 = getRightThis(exp.loc, sc, ad, ue.e1, exp.f);
4976 if (ue.e1.op == EXP.error)
4978 result = ue.e1;
4979 return;
4981 ethis = ue.e1;
4982 tthis = ue.e1.type;
4983 if (!(exp.f.type.ty == Tfunction && (cast(TypeFunction)exp.f.type).isScopeQual))
4985 if (checkParamArgumentEscape(sc, exp.f, Id.This, exp.f.vthis, STC.undefined_, ethis, false, false))
4986 return setError();
4990 /* Cannot call public functions from inside invariant
4991 * (because then the invariant would have infinite recursion)
4993 if (sc.func && sc.func.isInvariantDeclaration() && ue.e1.op == EXP.this_ && exp.f.addPostInvariant())
4995 exp.error("cannot call `public`/`export` function `%s` from invariant", exp.f.toChars());
4996 return setError();
4999 if (!exp.ignoreAttributes)
5000 checkFunctionAttributes(exp, sc, exp.f);
5002 // Cut-down version of checkAccess() that doesn't use the "most visible" version of exp.f.
5003 // We've already selected an overload here.
5004 const parent = exp.f.toParent();
5005 if (parent && parent.isTemplateInstance())
5007 // already a deprecation
5009 else if (!checkSymbolAccess(sc, exp.f))
5011 exp.error("%s `%s` of type `%s` is not accessible from module `%s`",
5012 exp.f.kind(), exp.f.toPrettyChars(), exp.f.type.toChars(), sc._module.toChars);
5013 return setError();
5016 if (!exp.f.needThis())
5018 exp.e1 = Expression.combine(ue.e1, new VarExp(exp.loc, exp.f, false));
5020 else
5022 if (ue1old.checkRightThis(sc))
5023 return setError();
5024 if (exp.e1.op == EXP.dotVariable)
5026 dve.var = exp.f;
5027 exp.e1.type = exp.f.type;
5029 else
5031 exp.e1 = new DotVarExp(exp.loc, dte.e1, exp.f, false);
5032 exp.e1 = exp.e1.expressionSemantic(sc);
5033 if (exp.e1.op == EXP.error)
5034 return setError();
5035 ue = cast(UnaExp)exp.e1;
5037 version (none)
5039 printf("ue.e1 = %s\n", ue.e1.toChars());
5040 printf("f = %s\n", exp.f.toChars());
5041 printf("t1 = %s\n", t1.toChars());
5042 printf("e1 = %s\n", exp.e1.toChars());
5043 printf("e1.type = %s\n", exp.e1.type.toChars());
5046 // See if we need to adjust the 'this' pointer
5047 AggregateDeclaration ad = exp.f.isThis();
5048 ClassDeclaration cd = ue.e1.type.isClassHandle();
5049 if (ad && cd && ad.isClassDeclaration())
5051 if (ue.e1.op == EXP.dotType)
5053 ue.e1 = (cast(DotTypeExp)ue.e1).e1;
5054 exp.directcall = true;
5056 else if (ue.e1.op == EXP.super_)
5057 exp.directcall = true;
5058 else if ((cd.storage_class & STC.final_) != 0) // https://issues.dlang.org/show_bug.cgi?id=14211
5059 exp.directcall = true;
5061 if (ad != cd)
5063 ue.e1 = ue.e1.castTo(sc, ad.type.addMod(ue.e1.type.mod));
5064 ue.e1 = ue.e1.expressionSemantic(sc);
5068 // If we've got a pointer to a function then deference it
5069 // https://issues.dlang.org/show_bug.cgi?id=16483
5070 if (exp.e1.type.isPtrToFunction())
5072 Expression e = new PtrExp(exp.loc, exp.e1);
5073 e.type = exp.e1.type.nextOf();
5074 exp.e1 = e;
5076 t1 = exp.e1.type;
5078 else if (exp.e1.op == EXP.super_ || exp.e1.op == EXP.this_)
5080 auto ad = sc.func ? sc.func.isThis() : null;
5081 auto cd = ad ? ad.isClassDeclaration() : null;
5083 isSuper = exp.e1.op == EXP.super_;
5084 if (isSuper)
5086 // Base class constructor call
5087 if (!cd || !cd.baseClass || !sc.func.isCtorDeclaration())
5089 exp.error("super class constructor call must be in a constructor");
5090 return setError();
5092 if (!cd.baseClass.ctor)
5094 exp.error("no super class constructor for `%s`", cd.baseClass.toChars());
5095 return setError();
5098 else
5100 // `this` call expression must be inside a
5101 // constructor
5102 if (!ad || !sc.func.isCtorDeclaration())
5104 exp.error("constructor call must be in a constructor");
5105 return setError();
5108 // https://issues.dlang.org/show_bug.cgi?id=18719
5109 // If `exp` is a call expression to another constructor
5110 // then it means that all struct/class fields will be
5111 // initialized after this call.
5112 foreach (ref field; sc.ctorflow.fieldinit)
5114 field.csx |= CSX.this_ctor;
5118 if (!sc.intypeof && !(sc.ctorflow.callSuper & CSX.halt))
5120 if (sc.inLoop || sc.ctorflow.callSuper & CSX.label)
5121 exp.error("constructor calls not allowed in loops or after labels");
5122 if (sc.ctorflow.callSuper & (CSX.super_ctor | CSX.this_ctor))
5123 exp.error("multiple constructor calls");
5124 if ((sc.ctorflow.callSuper & CSX.return_) && !(sc.ctorflow.callSuper & CSX.any_ctor))
5125 exp.error("an earlier `return` statement skips constructor");
5126 sc.ctorflow.callSuper |= CSX.any_ctor | (isSuper ? CSX.super_ctor : CSX.this_ctor);
5129 tthis = ad.type.addMod(sc.func.type.mod);
5130 auto ctor = isSuper ? cd.baseClass.ctor : ad.ctor;
5131 if (auto os = ctor.isOverloadSet())
5132 exp.f = resolveOverloadSet(exp.loc, sc, os, null, tthis, exp.argumentList);
5133 else
5134 exp.f = resolveFuncCall(exp.loc, sc, ctor, null, tthis, exp.argumentList, FuncResolveFlag.standard);
5136 if (!exp.f || exp.f.errors)
5137 return setError();
5139 checkFunctionAttributes(exp, sc, exp.f);
5140 checkAccess(exp.loc, sc, null, exp.f);
5142 exp.e1 = new DotVarExp(exp.e1.loc, exp.e1, exp.f, false);
5143 exp.e1 = exp.e1.expressionSemantic(sc);
5144 // https://issues.dlang.org/show_bug.cgi?id=21095
5145 if (exp.e1.op == EXP.error)
5146 return setError();
5147 t1 = exp.e1.type;
5149 // BUG: this should really be done by checking the static
5150 // call graph
5151 if (exp.f == sc.func)
5153 exp.error("cyclic constructor call");
5154 return setError();
5157 else if (auto oe = exp.e1.isOverExp())
5159 exp.f = resolveOverloadSet(exp.loc, sc, oe.vars, tiargs, tthis, exp.argumentList);
5160 if (!exp.f)
5161 return setError();
5162 if (ethis)
5163 exp.e1 = new DotVarExp(exp.loc, ethis, exp.f, false);
5164 else
5165 exp.e1 = new VarExp(exp.loc, exp.f, false);
5166 goto Lagain;
5168 else if (!t1)
5170 exp.error("function expected before `()`, not `%s`", exp.e1.toChars());
5171 return setError();
5173 else if (t1.ty == Terror)
5175 return setError();
5177 else if (t1.ty != Tfunction)
5179 TypeFunction tf;
5180 const(char)* p;
5181 Dsymbol s;
5182 exp.f = null;
5183 if (auto fe = exp.e1.isFuncExp())
5185 // function literal that direct called is always inferred.
5186 assert(fe.fd);
5187 exp.f = fe.fd;
5188 tf = cast(TypeFunction)exp.f.type;
5189 p = "function literal";
5191 else if (t1.ty == Tdelegate)
5193 TypeDelegate td = cast(TypeDelegate)t1;
5194 assert(td.next.ty == Tfunction);
5195 tf = cast(TypeFunction)td.next;
5196 p = "delegate";
5198 else if (auto tfx = t1.isPtrToFunction())
5200 tf = tfx;
5201 p = "function pointer";
5203 else if (exp.e1.op == EXP.dotVariable && (cast(DotVarExp)exp.e1).var.isOverDeclaration())
5205 DotVarExp dve = cast(DotVarExp)exp.e1;
5206 exp.f = resolveFuncCall(exp.loc, sc, dve.var, tiargs, dve.e1.type, exp.argumentList, FuncResolveFlag.overloadOnly);
5207 if (!exp.f)
5208 return setError();
5209 if (exp.f.needThis())
5211 dve.var = exp.f;
5212 dve.type = exp.f.type;
5213 dve.hasOverloads = false;
5214 goto Lagain;
5216 exp.e1 = new VarExp(dve.loc, exp.f, false);
5217 Expression e = new CommaExp(exp.loc, dve.e1, exp);
5218 result = e.expressionSemantic(sc);
5219 return;
5221 else if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.isOverDeclaration())
5223 s = (cast(VarExp)exp.e1).var;
5224 goto L2;
5226 else if (exp.e1.op == EXP.template_)
5228 s = (cast(TemplateExp)exp.e1).td;
5230 exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, null, exp.argumentList,
5231 exp.isUfcsRewrite ? FuncResolveFlag.ufcs : FuncResolveFlag.standard);
5232 if (!exp.f || exp.f.errors)
5233 return setError();
5234 if (exp.f.needThis())
5236 if (hasThis(sc))
5238 // Supply an implicit 'this', as in
5239 // this.ident
5240 exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), exp.f, false);
5241 goto Lagain;
5243 else if (isNeedThisScope(sc, exp.f))
5245 exp.error("need `this` for `%s` of type `%s`", exp.f.toChars(), exp.f.type.toChars());
5246 return setError();
5249 exp.e1 = new VarExp(exp.e1.loc, exp.f, false);
5250 goto Lagain;
5252 else
5254 exp.error("function expected before `()`, not `%s` of type `%s`", exp.e1.toChars(), exp.e1.type.toChars());
5255 return setError();
5258 const(char)* failMessage;
5259 if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc))
5261 OutBuffer buf;
5262 buf.writeByte('(');
5263 argExpTypesToCBuffer(&buf, exp.arguments);
5264 buf.writeByte(')');
5265 if (tthis)
5266 tthis.modToBuffer(&buf);
5268 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
5269 .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`",
5270 p, exp.e1.toChars(), parametersTypeToChars(tf.parameterList), buf.peekChars());
5271 if (failMessage)
5272 errorSupplemental(exp.loc, "%s", failMessage);
5273 return setError();
5275 // Purity and safety check should run after testing arguments matching
5276 if (exp.f)
5278 exp.checkPurity(sc, exp.f);
5279 exp.checkSafety(sc, exp.f);
5280 exp.checkNogc(sc, exp.f);
5281 if (exp.f.checkNestedReference(sc, exp.loc))
5282 return setError();
5284 else if (sc.func && sc.intypeof != 1 && !(sc.flags & (SCOPE.ctfe | SCOPE.debug_)))
5286 bool err = false;
5287 if (!tf.purity && sc.func.setImpure(exp.loc, "`pure` %s `%s` cannot call impure `%s`", exp.e1))
5289 exp.error("`pure` %s `%s` cannot call impure %s `%s`",
5290 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
5291 err = true;
5293 if (!tf.isnogc && sc.func.setGC(exp.loc, "`@nogc` %s `%s` cannot call non-@nogc `%s`", exp.e1))
5295 exp.error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
5296 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
5297 err = true;
5299 if (tf.trust <= TRUST.system && sc.setUnsafe(true, exp.loc,
5300 "`@safe` function `%s` cannot call `@system` `%s`", sc.func, exp.e1))
5302 exp.error("`@safe` %s `%s` cannot call `@system` %s `%s`",
5303 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
5304 err = true;
5306 if (err)
5307 return setError();
5310 if (t1.ty == Tpointer)
5312 Expression e = new PtrExp(exp.loc, exp.e1);
5313 e.type = tf;
5314 exp.e1 = e;
5316 t1 = tf;
5318 else if (VarExp ve = exp.e1.isVarExp())
5320 // Do overload resolution
5321 exp.f = ve.var.isFuncDeclaration();
5322 assert(exp.f);
5323 tiargs = null;
5325 if (exp.f.overnext)
5326 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.overloadOnly);
5327 else
5329 exp.f = exp.f.toAliasFunc();
5330 TypeFunction tf = cast(TypeFunction)exp.f.type;
5331 const(char)* failMessage;
5332 if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc))
5334 OutBuffer buf;
5335 buf.writeByte('(');
5336 argExpTypesToCBuffer(&buf, exp.arguments);
5337 buf.writeByte(')');
5339 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
5340 if (exp.isUfcsRewrite)
5342 const arg = (*exp.argumentList.arguments)[0];
5343 .error(exp.loc, "no property `%s` for `%s` of type `%s`", exp.f.ident.toChars(), arg.toChars(), arg.type.toChars());
5344 .errorSupplemental(exp.loc, "the following error occured while looking for a UFCS match");
5347 .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`",
5348 exp.f.kind(), exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList), buf.peekChars());
5349 if (failMessage)
5350 errorSupplemental(exp.loc, "%s", failMessage);
5351 exp.f = null;
5354 if (!exp.f || exp.f.errors)
5355 return setError();
5357 if (exp.f.needThis())
5359 // Change the ancestor lambdas to delegate before hasThis(sc) call.
5360 if (exp.f.checkNestedReference(sc, exp.loc))
5361 return setError();
5363 auto memberFunc = hasThis(sc);
5364 if (memberFunc && haveSameThis(memberFunc, exp.f))
5366 // Supply an implicit 'this', as in
5367 // this.ident
5368 exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), ve.var);
5369 // Note: we cannot use f directly, because further overload resolution
5370 // through the supplied 'this' may cause different result.
5371 goto Lagain;
5373 else if (isNeedThisScope(sc, exp.f))
5375 // At this point it is possible that `exp.f` had an ambiguity error that was
5376 // silenced because the previous call to `resolveFuncCall` was done using
5377 // `FuncResolveFlag.overloadOnly`. To make sure that a proper error message
5378 // is printed, redo the call with `FuncResolveFlag.standard`.
5380 // https://issues.dlang.org/show_bug.cgi?id=22157
5381 if (exp.f.overnext)
5382 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.standard);
5384 if (!exp.f || exp.f.errors)
5385 return setError();
5387 // If no error is printed, it means that `f` is the single matching overload
5388 // and it needs `this`.
5389 exp.error("need `this` for `%s` of type `%s`", exp.f.toChars(), exp.f.type.toChars());
5390 return setError();
5394 checkFunctionAttributes(exp, sc, exp.f);
5395 checkAccess(exp.loc, sc, null, exp.f);
5396 if (exp.f.checkNestedReference(sc, exp.loc))
5397 return setError();
5399 ethis = null;
5400 tthis = null;
5402 if (ve.hasOverloads)
5404 exp.e1 = new VarExp(ve.loc, exp.f, false);
5405 exp.e1.type = exp.f.type;
5407 t1 = exp.f.type;
5409 assert(t1.ty == Tfunction);
5411 Expression argprefix;
5412 if (!exp.arguments)
5413 exp.arguments = new Expressions();
5414 if (functionParameters(exp.loc, sc, cast(TypeFunction)t1, ethis, tthis, exp.argumentList, exp.f, &exp.type, &argprefix))
5415 return setError();
5417 if (!exp.type)
5419 exp.e1 = e1org; // https://issues.dlang.org/show_bug.cgi?id=10922
5420 // avoid recursive expression printing
5421 exp.error("forward reference to inferred return type of function call `%s`", exp.toChars());
5422 return setError();
5425 if (exp.f && exp.f.tintro)
5427 Type t = exp.type;
5428 int offset = 0;
5429 TypeFunction tf = cast(TypeFunction)exp.f.tintro;
5430 if (tf.next.isBaseOf(t, &offset) && offset)
5432 exp.type = tf.next;
5433 result = Expression.combine(argprefix, exp.castTo(sc, t));
5434 return;
5438 // Handle the case of a direct lambda call
5439 if (exp.f && exp.f.isFuncLiteralDeclaration() && sc.func && !sc.intypeof)
5441 exp.f.tookAddressOf = 0;
5444 result = Expression.combine(argprefix, exp);
5446 if (isSuper)
5448 auto ad = sc.func ? sc.func.isThis() : null;
5449 auto cd = ad ? ad.isClassDeclaration() : null;
5450 if (cd && cd.classKind == ClassKind.cpp && exp.f && !exp.f.fbody)
5452 // if super is defined in C++, it sets the vtable pointer to the base class
5453 // so we have to restore it, but still return 'this' from super() call:
5454 // (auto __vptrTmp = this.__vptr, auto __superTmp = super()), (this.__vptr = __vptrTmp, __superTmp)
5455 Loc loc = exp.loc;
5457 auto vptr = new DotIdExp(loc, new ThisExp(loc), Id.__vptr);
5458 auto vptrTmpDecl = copyToTemp(0, "__vptrTmp", vptr);
5459 auto declareVptrTmp = new DeclarationExp(loc, vptrTmpDecl);
5461 auto superTmpDecl = copyToTemp(0, "__superTmp", result);
5462 auto declareSuperTmp = new DeclarationExp(loc, superTmpDecl);
5464 auto declareTmps = new CommaExp(loc, declareVptrTmp, declareSuperTmp);
5466 auto restoreVptr = new AssignExp(loc, vptr.syntaxCopy(), new VarExp(loc, vptrTmpDecl));
5468 Expression e = new CommaExp(loc, declareTmps, new CommaExp(loc, restoreVptr, new VarExp(loc, superTmpDecl)));
5469 result = e.expressionSemantic(sc);
5473 // declare dual-context container
5474 if (exp.f && exp.f.hasDualContext() && !sc.intypeof && sc.func)
5476 // check access to second `this`
5477 if (AggregateDeclaration ad2 = exp.f.isMember2())
5479 Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
5480 if (te.op != EXP.error)
5481 te = getRightThis(exp.loc, sc, ad2, te, exp.f);
5482 if (te.op == EXP.error)
5484 exp.error("need `this` of type `%s` to call function `%s`", ad2.toChars(), exp.f.toChars());
5485 return setError();
5488 exp.vthis2 = makeThis2Argument(exp.loc, sc, exp.f);
5489 Expression de = new DeclarationExp(exp.loc, exp.vthis2);
5490 result = Expression.combine(de, result);
5491 result = result.expressionSemantic(sc);
5495 override void visit(DeclarationExp e)
5497 if (e.type)
5499 result = e;
5500 return;
5502 static if (LOGSEMANTIC)
5504 printf("DeclarationExp::semantic() %s\n", e.toChars());
5507 uint olderrors = global.errors;
5509 /* This is here to support extern(linkage) declaration,
5510 * where the extern(linkage) winds up being an AttribDeclaration
5511 * wrapper.
5513 Dsymbol s = e.declaration;
5515 while (1)
5517 AttribDeclaration ad = s.isAttribDeclaration();
5518 if (ad)
5520 if (ad.decl && ad.decl.length == 1)
5522 s = (*ad.decl)[0];
5523 continue;
5526 break;
5529 //printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc);
5530 // Insert into both local scope and function scope.
5531 // Must be unique in both.
5532 if (s.ident)
5534 VarDeclaration v = s.isVarDeclaration();
5535 if (v)
5537 if (sc.flags & SCOPE.Cfile)
5539 /* Do semantic() on the type before inserting v into the symbol table
5541 if (!v.originalType)
5542 v.originalType = v.type.syntaxCopy();
5543 Scope* sc2 = sc.push();
5544 sc2.stc |= v.storage_class & STC.FUNCATTR;
5545 sc2.linkage = LINK.c; // account for the extern(C) in front of the declaration
5546 v.inuse++;
5547 v.type = v.type.typeSemantic(v.loc, sc2);
5548 v.inuse--;
5549 sc2.pop();
5551 else
5553 /* Do semantic() on initializer first so this will be illegal:
5554 * int a = a;
5556 e.declaration.dsymbolSemantic(sc);
5557 s.parent = sc.parent;
5561 if (!sc.insert(s))
5563 auto conflict = sc.search(Loc.initial, s.ident, null);
5564 e.error("declaration `%s` is already defined", s.toPrettyChars());
5565 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
5566 conflict.kind(), conflict.toChars());
5567 return setError();
5570 if (v && (sc.flags & SCOPE.Cfile))
5572 /* Do semantic() on initializer last so this will be legal:
5573 * int a = a;
5575 e.declaration.dsymbolSemantic(sc);
5576 s.parent = sc.parent;
5579 if (sc.func)
5581 // https://issues.dlang.org/show_bug.cgi?id=11720
5582 if ((s.isFuncDeclaration() ||
5583 s.isAggregateDeclaration() ||
5584 s.isEnumDeclaration() ||
5585 s.isTemplateDeclaration() ||
5587 ) && !sc.func.localsymtab.insert(s))
5589 // Get the previous symbol
5590 Dsymbol originalSymbol = sc.func.localsymtab.lookup(s.ident);
5592 // Perturb the name mangling so that the symbols can co-exist
5593 // instead of colliding
5594 s.localNum = cast(ushort)(originalSymbol.localNum + 1);
5595 // 65535 should be enough for anyone
5596 if (!s.localNum)
5598 e.error("more than 65535 symbols with name `%s` generated", s.ident.toChars());
5599 return setError();
5602 // Replace originalSymbol with s, which updates the localCount
5603 sc.func.localsymtab.update(s);
5605 // The mangling change only works for D mangling
5608 if (!(sc.flags & SCOPE.Cfile))
5610 /* https://issues.dlang.org/show_bug.cgi?id=21272
5611 * If we are in a foreach body we need to extract the
5612 * function containing the foreach
5614 FuncDeclaration fes_enclosing_func;
5615 if (sc.func && sc.func.fes)
5616 fes_enclosing_func = sc.enclosing.enclosing.func;
5618 // Disallow shadowing
5619 for (Scope* scx = sc.enclosing; scx && (scx.func == sc.func || (fes_enclosing_func && scx.func == fes_enclosing_func)); scx = scx.enclosing)
5621 Dsymbol s2;
5622 if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2)
5624 // allow STC.local symbols to be shadowed
5625 // TODO: not really an optimal design
5626 auto decl = s2.isDeclaration();
5627 if (!decl || !(decl.storage_class & STC.local))
5629 if (sc.func.fes)
5631 e.deprecation("%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
5633 else
5635 e.error("%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
5636 return setError();
5644 if (!s.isVarDeclaration())
5646 Scope* sc2 = sc;
5647 if (sc2.stc & (STC.pure_ | STC.nothrow_ | STC.nogc))
5648 sc2 = sc.push();
5649 sc2.stc &= ~(STC.pure_ | STC.nothrow_ | STC.nogc);
5650 e.declaration.dsymbolSemantic(sc2);
5651 if (sc2 != sc)
5652 sc2.pop();
5653 s.parent = sc.parent;
5655 if (global.errors == olderrors)
5657 e.declaration.semantic2(sc);
5658 if (global.errors == olderrors)
5660 e.declaration.semantic3(sc);
5663 // todo: error in declaration should be propagated.
5665 e.type = Type.tvoid;
5666 result = e;
5669 override void visit(TypeidExp exp)
5671 static if (LOGSEMANTIC)
5673 printf("TypeidExp::semantic() %s\n", exp.toChars());
5675 Type ta = isType(exp.obj);
5676 Expression ea = isExpression(exp.obj);
5677 Dsymbol sa = isDsymbol(exp.obj);
5678 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
5680 if (ta)
5682 dmd.typesem.resolve(ta, exp.loc, sc, ea, ta, sa, true);
5685 if (ea)
5687 if (auto sym = getDsymbol(ea))
5688 ea = symbolToExp(sym, exp.loc, sc, false);
5689 else
5690 ea = ea.expressionSemantic(sc);
5691 ea = resolveProperties(sc, ea);
5692 ta = ea.type;
5693 if (ea.op == EXP.type)
5694 ea = null;
5697 if (!ta)
5699 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
5700 exp.error("no type for `typeid(%s)`", ea ? ea.toChars() : (sa ? sa.toChars() : ""));
5701 return setError();
5704 ta.checkComplexTransition(exp.loc, sc);
5706 Expression e;
5707 auto tb = ta.toBasetype();
5708 if (ea && tb.ty == Tclass)
5710 if (tb.toDsymbol(sc).isClassDeclaration().classKind == ClassKind.cpp)
5712 error(exp.loc, "runtime type information is not supported for `extern(C++)` classes");
5713 e = ErrorExp.get();
5715 else if (!Type.typeinfoclass)
5717 error(exp.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
5718 e = ErrorExp.get();
5720 else
5722 /* Get the dynamic type, which is .classinfo
5724 ea = ea.expressionSemantic(sc);
5725 e = new TypeidExp(ea.loc, ea);
5726 e.type = Type.typeinfoclass.type;
5729 else if (ta.ty == Terror)
5731 e = ErrorExp.get();
5733 else
5735 // Handle this in the glue layer
5736 e = new TypeidExp(exp.loc, ta);
5738 bool genObjCode = true;
5740 // https://issues.dlang.org/show_bug.cgi?id=23650
5741 // We generate object code for typeinfo, required
5742 // by typeid, only if in non-speculative context
5743 if (sc.flags & SCOPE.compile)
5745 genObjCode = false;
5748 e.type = getTypeInfoType(exp.loc, ta, sc, genObjCode);
5749 semanticTypeInfo(sc, ta);
5751 if (ea)
5753 e = new CommaExp(exp.loc, ea, e); // execute ea
5754 e = e.expressionSemantic(sc);
5757 result = e;
5760 override void visit(TraitsExp e)
5762 result = semanticTraits(e, sc);
5765 override void visit(HaltExp e)
5767 static if (LOGSEMANTIC)
5769 printf("HaltExp::semantic()\n");
5771 e.type = Type.tnoreturn;
5772 result = e;
5775 override void visit(IsExp e)
5777 /* is(targ id tok tspec)
5778 * is(targ id : tok2)
5779 * is(targ id == tok2)
5781 Type tded = null;
5783 void yes()
5785 //printf("yes\n");
5786 if (!e.id)
5788 result = IntegerExp.createBool(true);
5789 return;
5792 Dsymbol s;
5793 Tuple tup = isTuple(tded);
5794 if (tup)
5795 s = new TupleDeclaration(e.loc, e.id, &tup.objects);
5796 else
5797 s = new AliasDeclaration(e.loc, e.id, tded);
5798 s.dsymbolSemantic(sc);
5800 /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there.
5801 * More investigation is needed.
5803 if (!tup && !sc.insert(s))
5805 auto conflict = sc.search(Loc.initial, s.ident, null);
5806 e.error("declaration `%s` is already defined", s.toPrettyChars());
5807 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
5808 conflict.kind(), conflict.toChars());
5811 unSpeculative(sc, s);
5813 result = IntegerExp.createBool(true);
5815 void no()
5817 result = IntegerExp.createBool(false);
5818 //printf("no\n");
5821 static if (LOGSEMANTIC)
5823 printf("IsExp::semantic(%s)\n", e.toChars());
5825 if (e.id && !(sc.flags & SCOPE.condition))
5827 e.error("can only declare type aliases within `static if` conditionals or `static assert`s");
5828 return setError();
5831 if (e.tok2 == TOK.package_ || e.tok2 == TOK.module_) // These is() expressions are special because they can work on modules, not just types.
5833 const oldErrors = global.startGagging();
5834 Dsymbol sym = e.targ.toDsymbol(sc);
5835 global.endGagging(oldErrors);
5837 if (sym is null)
5838 return no();
5839 Package p = resolveIsPackage(sym);
5840 if (p is null)
5841 return no();
5842 if (e.tok2 == TOK.package_ && p.isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module.
5843 return no();
5844 else if(e.tok2 == TOK.module_ && !(p.isModule() || p.isPackageMod()))
5845 return no();
5846 tded = e.targ;
5847 return yes();
5851 Scope* sc2 = sc.copy(); // keep sc.flags
5852 sc2.tinst = null;
5853 sc2.minst = null;
5854 sc2.flags |= SCOPE.fullinst;
5855 Type t = e.targ.trySemantic(e.loc, sc2);
5856 sc2.pop();
5857 if (!t) // errors, so condition is false
5858 return no();
5859 e.targ = t;
5862 if (e.tok2 != TOK.reserved)
5864 switch (e.tok2)
5866 case TOK.struct_:
5867 if (e.targ.ty != Tstruct)
5868 return no();
5869 if ((cast(TypeStruct)e.targ).sym.isUnionDeclaration())
5870 return no();
5871 tded = e.targ;
5872 break;
5874 case TOK.union_:
5875 if (e.targ.ty != Tstruct)
5876 return no();
5877 if (!(cast(TypeStruct)e.targ).sym.isUnionDeclaration())
5878 return no();
5879 tded = e.targ;
5880 break;
5882 case TOK.class_:
5883 if (e.targ.ty != Tclass)
5884 return no();
5885 if ((cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
5886 return no();
5887 tded = e.targ;
5888 break;
5890 case TOK.interface_:
5891 if (e.targ.ty != Tclass)
5892 return no();
5893 if (!(cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
5894 return no();
5895 tded = e.targ;
5896 break;
5898 case TOK.const_:
5899 if (!e.targ.isConst())
5900 return no();
5901 tded = e.targ;
5902 break;
5904 case TOK.immutable_:
5905 if (!e.targ.isImmutable())
5906 return no();
5907 tded = e.targ;
5908 break;
5910 case TOK.shared_:
5911 if (!e.targ.isShared())
5912 return no();
5913 tded = e.targ;
5914 break;
5916 case TOK.inout_:
5917 if (!e.targ.isWild())
5918 return no();
5919 tded = e.targ;
5920 break;
5922 case TOK.super_:
5923 // If class or interface, get the base class and interfaces
5924 if (e.targ.ty != Tclass)
5925 return no();
5926 else
5928 ClassDeclaration cd = (cast(TypeClass)e.targ).sym;
5929 auto args = new Parameters();
5930 args.reserve(cd.baseclasses.length);
5931 if (cd.semanticRun < PASS.semanticdone)
5932 cd.dsymbolSemantic(null);
5933 for (size_t i = 0; i < cd.baseclasses.length; i++)
5935 BaseClass* b = (*cd.baseclasses)[i];
5936 args.push(new Parameter(STC.in_, b.type, null, null, null));
5938 tded = new TypeTuple(args);
5940 break;
5942 case TOK.enum_:
5943 if (e.targ.ty != Tenum)
5944 return no();
5945 if (e.id)
5946 tded = (cast(TypeEnum)e.targ).sym.getMemtype(e.loc);
5947 else
5948 tded = e.targ;
5950 if (tded.ty == Terror)
5951 return setError();
5952 break;
5954 case TOK.delegate_:
5955 if (e.targ.ty != Tdelegate)
5956 return no();
5957 tded = (cast(TypeDelegate)e.targ).next; // the underlying function type
5958 break;
5960 case TOK.function_:
5961 case TOK.parameters:
5963 if (e.targ.ty != Tfunction)
5964 return no();
5965 tded = e.targ;
5967 /* Generate tuple from function parameter types.
5969 assert(tded.ty == Tfunction);
5970 auto tdedf = tded.isTypeFunction();
5971 auto args = new Parameters();
5972 foreach (i, arg; tdedf.parameterList)
5974 assert(arg && arg.type);
5975 /* If one of the default arguments was an error,
5976 don't return an invalid tuple
5978 if (e.tok2 == TOK.parameters && arg.defaultArg && arg.defaultArg.op == EXP.error)
5979 return setError();
5980 args.push(new Parameter(arg.storageClass, arg.type, (e.tok2 == TOK.parameters) ? arg.ident : null, (e.tok2 == TOK.parameters) ? arg.defaultArg : null, arg.userAttribDecl));
5982 tded = new TypeTuple(args);
5983 break;
5985 case TOK.return_:
5986 /* Get the 'return type' for the function,
5987 * delegate, or pointer to function.
5989 if (auto tf = e.targ.isFunction_Delegate_PtrToFunction())
5990 tded = tf.next;
5991 else
5992 return no();
5993 break;
5995 case TOK.argumentTypes:
5996 /* Generate a type tuple of the equivalent types used to determine if a
5997 * function argument of this type can be passed in registers.
5998 * The results of this are highly platform dependent, and intended
5999 * primarly for use in implementing va_arg().
6001 tded = target.toArgTypes(e.targ);
6002 if (!tded)
6003 return no();
6004 // not valid for a parameter
6005 break;
6007 case TOK.vector:
6008 if (e.targ.ty != Tvector)
6009 return no();
6010 tded = (cast(TypeVector)e.targ).basetype;
6011 break;
6013 default:
6014 assert(0);
6017 // https://issues.dlang.org/show_bug.cgi?id=18753
6018 if (tded)
6019 return yes();
6020 return no();
6022 else if (e.tspec && !e.id && !(e.parameters && e.parameters.length))
6024 /* Evaluate to true if targ matches tspec
6025 * is(targ == tspec)
6026 * is(targ : tspec)
6028 e.tspec = e.tspec.typeSemantic(e.loc, sc);
6029 //printf("targ = %s, %s\n", e.targ.toChars(), e.targ.deco);
6030 //printf("tspec = %s, %s\n", e.tspec.toChars(), e.tspec.deco);
6032 if (e.tok == TOK.colon)
6034 // current scope is itself deprecated, or deprecations are not errors
6035 const bool deprecationAllowed = sc.isDeprecated
6036 || global.params.useDeprecated != DiagnosticReporting.error;
6037 const bool preventAliasThis = e.targ.hasDeprecatedAliasThis && !deprecationAllowed;
6039 if (preventAliasThis && e.targ.ty == Tstruct)
6041 if ((cast(TypeStruct) e.targ).implicitConvToWithoutAliasThis(e.tspec))
6042 return yes();
6043 else
6044 return no();
6046 else if (preventAliasThis && e.targ.ty == Tclass)
6048 if ((cast(TypeClass) e.targ).implicitConvToWithoutAliasThis(e.tspec))
6049 return yes();
6050 else
6051 return no();
6053 else if (e.targ.implicitConvTo(e.tspec))
6054 return yes();
6055 else
6056 return no();
6058 else /* == */
6060 if (e.targ.equals(e.tspec))
6061 return yes();
6062 else
6063 return no();
6066 else if (e.tspec)
6068 /* Evaluate to true if targ matches tspec.
6069 * If true, declare id as an alias for the specialized type.
6070 * is(targ == tspec, tpl)
6071 * is(targ : tspec, tpl)
6072 * is(targ id == tspec)
6073 * is(targ id : tspec)
6074 * is(targ id == tspec, tpl)
6075 * is(targ id : tspec, tpl)
6077 Identifier tid = e.id ? e.id : Identifier.generateId("__isexp_id");
6078 e.parameters.insert(0, new TemplateTypeParameter(e.loc, tid, null, null));
6080 Objects dedtypes = Objects(e.parameters.length);
6081 dedtypes.zero();
6083 MATCH m = deduceType(e.targ, sc, e.tspec, e.parameters, &dedtypes, null, 0, e.tok == TOK.equal);
6085 if (m == MATCH.nomatch || (m != MATCH.exact && e.tok == TOK.equal))
6087 return no();
6089 else
6091 tded = cast(Type)dedtypes[0];
6092 if (!tded)
6093 tded = e.targ;
6094 Objects tiargs = Objects(1);
6095 tiargs[0] = e.targ;
6097 /* Declare trailing parameters
6099 for (size_t i = 1; i < e.parameters.length; i++)
6101 TemplateParameter tp = (*e.parameters)[i];
6102 Declaration s = null;
6104 m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, &dedtypes, &s);
6105 if (m == MATCH.nomatch)
6106 return no();
6107 s.dsymbolSemantic(sc);
6108 if (!sc.insert(s))
6110 auto conflict = sc.search(Loc.initial, s.ident, null);
6111 e.error("declaration `%s` is already defined", s.toPrettyChars());
6112 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
6113 conflict.kind(), conflict.toChars());
6116 unSpeculative(sc, s);
6118 return yes();
6121 else if (e.id)
6123 /* Declare id as an alias for type targ. Evaluate to true
6124 * is(targ id)
6126 tded = e.targ;
6128 return yes();
6131 override void visit(BinAssignExp exp)
6133 if (exp.type)
6135 result = exp;
6136 return;
6139 Expression e = exp.op_overload(sc);
6140 if (e)
6142 result = e;
6143 return;
6146 if (exp.e1.op == EXP.arrayLength)
6148 // arr.length op= e2;
6149 e = rewriteOpAssign(exp);
6150 e = e.expressionSemantic(sc);
6151 result = e;
6152 return;
6154 if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
6156 if (checkNonAssignmentArrayOp(exp.e1))
6157 return setError();
6159 if (exp.e1.op == EXP.slice)
6160 (cast(SliceExp)exp.e1).arrayop = true;
6162 // T[] op= ...
6163 if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
6165 // T[] op= T
6166 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
6168 else if (Expression ex = typeCombine(exp, sc))
6170 result = ex;
6171 return;
6173 exp.type = exp.e1.type;
6174 result = arrayOp(exp, sc);
6175 return;
6178 exp.e1 = exp.e1.expressionSemantic(sc);
6179 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
6180 exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
6181 exp.type = exp.e1.type;
6183 if (auto ad = isAggregate(exp.e1.type))
6185 if (const s = search_function(ad, Id.opOpAssign))
6187 error(exp.loc, "none of the `opOpAssign` overloads of `%s` are callable for `%s` of type `%s`", ad.toChars(), exp.e1.toChars(), exp.e1.type.toChars());
6188 return setError();
6191 if (exp.e1.checkScalar() ||
6192 exp.e1.checkReadModifyWrite(exp.op, exp.e2) ||
6193 exp.e1.checkSharedAccess(sc))
6194 return setError();
6196 int arith = (exp.op == EXP.addAssign || exp.op == EXP.minAssign || exp.op == EXP.mulAssign || exp.op == EXP.divAssign || exp.op == EXP.modAssign || exp.op == EXP.powAssign);
6197 int bitwise = (exp.op == EXP.andAssign || exp.op == EXP.orAssign || exp.op == EXP.xorAssign);
6198 int shift = (exp.op == EXP.leftShiftAssign || exp.op == EXP.rightShiftAssign || exp.op == EXP.unsignedRightShiftAssign);
6200 if (bitwise && exp.type.toBasetype().ty == Tbool)
6201 exp.e2 = exp.e2.implicitCastTo(sc, exp.type);
6202 else if (exp.checkNoBool())
6203 return setError();
6205 if ((exp.op == EXP.addAssign || exp.op == EXP.minAssign) && exp.e1.type.toBasetype().ty == Tpointer && exp.e2.type.toBasetype().isintegral())
6207 result = scaleFactor(exp, sc);
6208 return;
6211 if (Expression ex = typeCombine(exp, sc))
6213 result = ex;
6214 return;
6217 if (arith && (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)))
6218 return setError();
6219 if ((bitwise || shift) && (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)))
6220 return setError();
6222 if (shift)
6224 if (exp.e2.type.toBasetype().ty != Tvector)
6225 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
6228 if (!target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
6230 result = exp.incompatibleTypes();
6231 return;
6234 if (exp.e1.op == EXP.error || exp.e2.op == EXP.error)
6235 return setError();
6237 e = exp.checkOpAssignTypes(sc);
6238 if (e.op == EXP.error)
6240 result = e;
6241 return;
6244 assert(e.op == EXP.assign || e == exp);
6245 result = (cast(BinExp)e).reorderSettingAAElem(sc);
6248 private Expression compileIt(MixinExp exp)
6250 OutBuffer buf;
6251 if (expressionsToString(buf, sc, exp.exps))
6252 return null;
6254 uint errors = global.errors;
6255 const len = buf.length;
6256 const str = buf.extractChars()[0 .. len];
6257 const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput;
6258 auto loc = adjustLocForMixin(str, exp.loc, global.params.mixinOut);
6259 scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
6260 p.transitionIn = global.params.vin;
6261 p.nextToken();
6262 //printf("p.loc.linnum = %d\n", p.loc.linnum);
6264 Expression e = p.parseExpression();
6265 if (global.errors != errors)
6266 return null;
6268 if (p.token.value != TOK.endOfFile)
6270 exp.error("incomplete mixin expression `%s`", str.ptr);
6271 return null;
6273 return e;
6276 override void visit(MixinExp exp)
6278 /* https://dlang.org/spec/expression.html#mixin_expressions
6281 static if (LOGSEMANTIC)
6283 printf("MixinExp::semantic('%s')\n", exp.toChars());
6286 auto e = compileIt(exp);
6287 if (!e)
6288 return setError();
6289 result = e.expressionSemantic(sc);
6292 override void visit(ImportExp e)
6294 static if (LOGSEMANTIC)
6296 printf("ImportExp::semantic('%s')\n", e.toChars());
6299 auto se = semanticString(sc, e.e1, "file name argument");
6300 if (!se)
6301 return setError();
6302 se = se.toUTF8(sc);
6304 auto namez = se.toStringz();
6305 if (!global.filePath)
6307 e.error("need `-J` switch to import text file `%s`", namez.ptr);
6308 return setError();
6311 /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
6312 * ('Path Traversal') attacks.
6313 * https://cwe.mitre.org/data/definitions/22.html
6316 if (FileName.absolute(namez))
6318 e.error("absolute path is not allowed in import expression: `%s`", se.toChars());
6319 return setError();
6322 auto idxReserved = FileName.findReservedChar(namez);
6323 if (idxReserved != size_t.max)
6325 e.error("`%s` is not a valid filename on this platform", se.toChars());
6326 e.errorSupplemental("Character `'%c'` is reserved and cannot be used", namez[idxReserved]);
6327 return setError();
6330 if (FileName.refersToParentDir(namez))
6332 e.error("path refers to parent (`..`) directory: `%s`", se.toChars());
6333 return setError();
6336 auto resolvedNamez = FileName.searchPath(global.filePath, namez, false);
6337 if (!resolvedNamez)
6339 e.error("file `%s` cannot be found or not in a path specified with `-J`", se.toChars());
6340 e.errorSupplemental("Path(s) searched (as provided by `-J`):");
6341 foreach (idx, path; *global.filePath)
6343 const attr = FileName.exists(path);
6344 const(char)* err = attr == 2 ? "" :
6345 (attr == 1 ? " (not a directory)" : " (path not found)");
6346 e.errorSupplemental("[%llu]: `%s`%s", cast(ulong)idx, path, err);
6348 return setError();
6351 sc._module.contentImportedFiles.push(resolvedNamez.ptr);
6352 if (global.params.verbose)
6354 const slice = se.peekString();
6355 message("file %.*s\t(%s)", cast(int)slice.length, slice.ptr, resolvedNamez.ptr);
6357 if (global.params.moduleDeps.buffer !is null)
6359 OutBuffer* ob = global.params.moduleDeps.buffer;
6360 Module imod = sc._module;
6362 if (!global.params.moduleDeps.name)
6363 ob.writestring("depsFile ");
6364 ob.writestring(imod.toPrettyChars());
6365 ob.writestring(" (");
6366 escapePath(ob, imod.srcfile.toChars());
6367 ob.writestring(") : ");
6368 if (global.params.moduleDeps.name)
6369 ob.writestring("string : ");
6370 ob.write(se.peekString());
6371 ob.writestring(" (");
6372 escapePath(ob, resolvedNamez.ptr);
6373 ob.writestring(")");
6374 ob.writenl();
6376 if (global.params.makeDeps.doOutput)
6378 global.params.makeDeps.files.push(resolvedNamez.ptr);
6382 auto fileName = FileName(resolvedNamez);
6383 if (auto fmResult = global.fileManager.lookup(fileName))
6385 se = new StringExp(e.loc, fmResult);
6387 else
6389 e.error("cannot read file `%s`", resolvedNamez.ptr);
6390 return setError();
6393 result = se.expressionSemantic(sc);
6396 override void visit(AssertExp exp)
6398 // https://dlang.org/spec/expression.html#assert_expressions
6399 static if (LOGSEMANTIC)
6401 printf("AssertExp::semantic('%s')\n", exp.toChars());
6404 const generateMsg = !exp.msg &&
6405 sc.needsCodegen() && // let ctfe interpreter handle the error message
6406 global.params.checkAction == CHECKACTION.context &&
6407 global.params.useAssert == CHECKENABLE.on;
6408 Expression temporariesPrefix;
6410 if (generateMsg)
6411 // no message - use assert expression as msg
6413 if (!verifyHookExist(exp.loc, *sc, Id._d_assert_fail, "generating assert messages"))
6414 return setError();
6418 auto a = e1, b = e2;
6419 assert(a == b, _d_assert_fail!"=="(a, b));
6424 Stores the result of an operand expression into a temporary
6425 if necessary, e.g. if it is an impure fuction call containing side
6426 effects as in https://issues.dlang.org/show_bug.cgi?id=20114
6428 Params:
6429 op = an expression which may require a temporary (added to
6430 `temporariesPrefix`: `auto tmp = op`) and will be replaced
6431 by `tmp` if necessary
6433 Returns: (possibly replaced) `op`
6435 Expression maybePromoteToTmp(ref Expression op)
6437 // https://issues.dlang.org/show_bug.cgi?id=20989
6438 // Flag that _d_assert_fail will never dereference `array.ptr` to avoid safety
6439 // errors for `assert(!array.ptr)` => `_d_assert_fail!"!"(array.ptr)`
6441 auto die = op.isDotIdExp();
6442 if (die && die.ident == Id.ptr)
6443 die.noderef = true;
6446 op = op.expressionSemantic(sc);
6447 op = resolveProperties(sc, op);
6449 // Detect assert's using static operator overloads (e.g. `"var" in environment`)
6450 if (auto te = op.isTypeExp())
6452 // Replace the TypeExp with it's textual representation
6453 // Including "..." in the error message isn't quite right but
6454 // proper solutions require more drastic changes, e.g. directly
6455 // using miniFormat and combine instead of calling _d_assert_fail
6456 auto name = new StringExp(te.loc, te.toString());
6457 return name.expressionSemantic(sc);
6460 // Create a temporary for expressions with side effects
6461 // Defensively assume that function calls may have side effects even
6462 // though it's not detected by hasSideEffect (e.g. `debug puts("Hello")` )
6463 // Rewriting CallExp's also avoids some issues with the inliner/debug generation
6464 if (op.hasSideEffect(true))
6466 // Don't create an invalid temporary for void-expressions
6467 // Further semantic will issue an appropriate error
6468 if (op.type.ty == Tvoid)
6469 return op;
6471 // https://issues.dlang.org/show_bug.cgi?id=21590
6472 // Don't create unnecessary temporaries and detect `assert(a = b)`
6473 if (op.isAssignExp() || op.isBinAssignExp())
6475 auto left = (cast(BinExp) op).e1;
6477 // Find leftmost expression to handle other rewrites,
6478 // e.g. --(++a) => a += 1 -= 1
6479 while (left.isAssignExp() || left.isBinAssignExp())
6480 left = (cast(BinExp) left).e1;
6482 // Only use the assignee if it's a variable and skip
6483 // other lvalues (e.g. ref's returned by functions)
6484 if (left.isVarExp())
6485 return left;
6487 // Sanity check that `op` can be converted to boolean
6488 // But don't raise errors for assignments enclosed in another expression
6489 if (op is exp.e1)
6490 op.toBoolean(sc);
6493 // Tuples with side-effects already receive a temporary during semantic
6494 if (op.type.isTypeTuple())
6496 auto te = op.isTupleExp();
6497 assert(te);
6499 // Create a new tuple without the associated temporary
6500 auto res = new TupleExp(op.loc, te.exps);
6501 return res.expressionSemantic(sc);
6504 const stc = op.isLvalue() ? STC.ref_ : 0;
6505 auto tmp = copyToTemp(stc, "__assertOp", op);
6506 tmp.dsymbolSemantic(sc);
6508 auto decl = new DeclarationExp(op.loc, tmp);
6509 temporariesPrefix = Expression.combine(temporariesPrefix, decl);
6511 op = new VarExp(op.loc, tmp);
6512 op = op.expressionSemantic(sc);
6514 return op;
6517 // if the assert condition is a mixin expression, try to compile it
6518 if (auto ce = exp.e1.isMixinExp())
6520 if (auto e1 = compileIt(ce))
6521 exp.e1 = e1;
6524 Expressions* es;
6525 Objects* tiargs;
6526 Loc loc = exp.e1.loc;
6528 const op = exp.e1.op;
6529 bool isEqualsCallExpression;
6530 if (const callExp = exp.e1.isCallExp())
6532 // https://issues.dlang.org/show_bug.cgi?id=20331
6533 // callExp.f may be null if the assert contains a call to
6534 // a function pointer or literal
6535 if (const callExpFunc = callExp.f)
6537 const callExpIdent = callExpFunc.ident;
6538 isEqualsCallExpression = callExpIdent == Id.__equals ||
6539 callExpIdent == Id.eq;
6542 if (op == EXP.equal || op == EXP.notEqual ||
6543 op == EXP.lessThan || op == EXP.greaterThan ||
6544 op == EXP.lessOrEqual || op == EXP.greaterOrEqual ||
6545 op == EXP.identity || op == EXP.notIdentity ||
6546 op == EXP.in_ ||
6547 isEqualsCallExpression)
6549 es = new Expressions(3);
6550 tiargs = new Objects(1);
6552 if (isEqualsCallExpression)
6554 auto callExp = cast(CallExp) exp.e1;
6555 auto args = callExp.arguments;
6557 // structs with opEquals get rewritten to a DotVarExp:
6558 // a.opEquals(b)
6559 // https://issues.dlang.org/show_bug.cgi?id=20100
6560 if (args.length == 1)
6562 auto dv = callExp.e1.isDotVarExp();
6563 assert(dv);
6565 // runtime args
6566 (*es)[1] = maybePromoteToTmp(dv.e1);
6567 (*es)[2] = maybePromoteToTmp((*args)[0]);
6569 else
6571 // runtime args
6572 (*es)[1] = maybePromoteToTmp((*args)[0]);
6573 (*es)[2] = maybePromoteToTmp((*args)[1]);
6576 else
6578 auto binExp = cast(EqualExp) exp.e1;
6580 // runtime args
6581 (*es)[1] = maybePromoteToTmp(binExp.e1);
6582 (*es)[2] = maybePromoteToTmp(binExp.e2);
6585 // template args
6586 Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : EXPtoString(exp.e1.op));
6587 comp = comp.expressionSemantic(sc);
6588 (*es)[0] = comp;
6589 (*tiargs)[0] = (*es)[1].type;
6592 // Format exp.e1 before any additional boolean conversion
6593 // Ignore &&/|| because "assert(...) failed" is more informative than "false != true"
6594 else if (op != EXP.andAnd && op != EXP.orOr)
6596 es = new Expressions(2);
6597 tiargs = new Objects(1);
6599 if (auto ne = exp.e1.isNotExp())
6601 // Fetch the (potential non-bool) expression and fold
6602 // (n) negations into (n % 2) negations, e.g. !!a => a
6603 for (bool neg = true; ; neg = !neg)
6605 if (auto ne2 = ne.e1.isNotExp())
6606 ne = ne2;
6607 else
6609 (*es)[0] = new StringExp(loc, neg ? "!" : "");
6610 (*es)[1] = maybePromoteToTmp(ne.e1);
6611 break;
6615 else
6616 { // Simply format exp.e1
6617 (*es)[0] = new StringExp(loc, "");
6618 (*es)[1] = maybePromoteToTmp(exp.e1);
6621 (*tiargs)[0] = (*es)[1].type;
6623 // Passing __ctfe to auto ref infers ref and aborts compilation:
6624 // "cannot modify compiler-generated variable __ctfe"
6625 auto ve = (*es)[1].isVarExp();
6626 if (ve && ve.var.ident == Id.ctfe)
6628 exp.msg = new StringExp(loc, "assert(__ctfe) failed!");
6629 goto LSkip;
6632 else
6634 OutBuffer buf;
6635 buf.printf("%s failed", exp.toChars());
6636 exp.msg = new StringExp(Loc.initial, buf.extractSlice());
6637 goto LSkip;
6640 Expression __assertFail = new IdentifierExp(exp.loc, Id.empty);
6641 auto assertFail = new DotIdExp(loc, __assertFail, Id.object);
6643 auto dt = new DotTemplateInstanceExp(loc, assertFail, Id._d_assert_fail, tiargs);
6644 auto ec = CallExp.create(loc, dt, es);
6645 exp.msg = ec;
6648 LSkip:
6649 if (Expression ex = unaSemantic(exp, sc))
6651 result = ex;
6652 return;
6655 exp.e1 = resolveProperties(sc, exp.e1);
6656 // BUG: see if we can do compile time elimination of the Assert
6657 exp.e1 = exp.e1.optimize(WANTvalue);
6658 exp.e1 = exp.e1.toBoolean(sc);
6660 if (exp.e1.op == EXP.error)
6662 result = exp.e1;
6663 return;
6666 if (exp.msg)
6668 exp.msg = expressionSemantic(exp.msg, sc);
6669 exp.msg = resolveProperties(sc, exp.msg);
6670 exp.msg = exp.msg.implicitCastTo(sc, Type.tchar.constOf().arrayOf());
6671 exp.msg = exp.msg.optimize(WANTvalue);
6672 checkParamArgumentEscape(sc, null, null, null, STC.undefined_, exp.msg, true, false);
6675 if (exp.msg && exp.msg.op == EXP.error)
6677 result = exp.msg;
6678 return;
6681 auto f1 = checkNonAssignmentArrayOp(exp.e1);
6682 auto f2 = exp.msg && checkNonAssignmentArrayOp(exp.msg);
6683 if (f1 || f2)
6684 return setError();
6686 if (exp.e1.toBool().hasValue(false))
6688 /* This is an `assert(0)` which means halt program execution
6690 FuncDeclaration fd = sc.parent.isFuncDeclaration();
6691 if (fd)
6692 fd.hasReturnExp |= 4;
6693 sc.ctorflow.orCSX(CSX.halt);
6695 if (global.params.useAssert == CHECKENABLE.off)
6697 Expression e = new HaltExp(exp.loc);
6698 e = e.expressionSemantic(sc);
6699 result = e;
6700 return;
6703 // Only override the type when it isn't already some flavour of noreturn,
6704 // e.g. when this assert was generated by defaultInitLiteral
6705 if (!exp.type || !exp.type.isTypeNoreturn())
6706 exp.type = Type.tnoreturn;
6708 else
6709 exp.type = Type.tvoid;
6711 result = !temporariesPrefix
6712 ? exp
6713 : Expression.combine(temporariesPrefix, exp).expressionSemantic(sc);
6716 override void visit(ThrowExp te)
6718 import dmd.statementsem;
6720 if (throwSemantic(te.loc, te.e1, sc))
6721 result = te;
6722 else
6723 setError();
6726 override void visit(DotIdExp exp)
6728 static if (LOGSEMANTIC)
6730 printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars());
6731 //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op));
6734 if (sc.flags & SCOPE.Cfile)
6736 /* See if need to rewrite the AST because of cast/call ambiguity
6738 if (auto e = castCallAmbiguity(exp, sc))
6740 result = expressionSemantic(e, sc);
6741 return;
6744 if (exp.arrow) // ImportC only
6745 exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
6747 if (exp.ident == Id.__xalignof && exp.e1.isTypeExp())
6749 // C11 6.5.3 says _Alignof only applies to types
6750 Expression e;
6751 Type t;
6752 Dsymbol s;
6753 dmd.typesem.resolve(exp.e1.type, exp.e1.loc, sc, e, t, s, true);
6754 if (e)
6756 exp.e1.error("argument to `_Alignof` must be a type");
6757 return setError();
6759 else if (t)
6761 // Note similarity to getProperty() implementation of __xalignof
6762 const explicitAlignment = t.alignment();
6763 const naturalAlignment = t.alignsize();
6764 const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get());
6765 result = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
6767 else if (s)
6769 exp.e1.error("argument to `_Alignof` must be a type");
6770 return setError();
6772 else
6773 assert(0);
6774 return;
6777 if (exp.ident != Id.__sizeof)
6779 result = fieldLookup(exp.e1, sc, exp.ident, exp.arrow);
6780 return;
6784 Expression e = exp.dotIdSemanticProp(sc, 1);
6786 if (e && isDotOpDispatch(e))
6788 auto ode = e;
6789 uint errors = global.startGagging();
6790 e = resolvePropertiesX(sc, e);
6791 // Any error or if 'e' is not resolved, go to UFCS
6792 if (global.endGagging(errors) || e is ode)
6793 e = null; /* fall down to UFCS */
6794 else
6796 result = e;
6797 return;
6800 if (!e) // if failed to find the property
6802 /* If ident is not a valid property, rewrite:
6803 * e1.ident
6804 * as:
6805 * .ident(e1)
6807 e = resolveUFCSProperties(sc, exp);
6809 result = e;
6812 override void visit(DotTemplateExp e)
6814 if (e.type)
6816 result = e;
6817 return;
6819 if (Expression ex = unaSemantic(e, sc))
6821 result = ex;
6822 return;
6824 // 'void' like TemplateExp
6825 e.type = Type.tvoid;
6826 result = e;
6829 override void visit(DotVarExp exp)
6831 static if (LOGSEMANTIC)
6833 printf("DotVarExp::semantic('%s')\n", exp.toChars());
6835 if (exp.type)
6837 result = exp;
6838 return;
6841 exp.var = exp.var.toAlias().isDeclaration();
6843 exp.e1 = exp.e1.expressionSemantic(sc);
6845 if (auto tup = exp.var.isTupleDeclaration())
6847 /* Replace:
6848 * e1.tuple(a, b, c)
6849 * with:
6850 * tuple(e1.a, e1.b, e1.c)
6852 Expression e0;
6853 Expression ev = sc.func ? extractSideEffect(sc, "__tup", e0, exp.e1) : exp.e1;
6855 auto exps = new Expressions();
6856 exps.reserve(tup.objects.length);
6857 for (size_t i = 0; i < tup.objects.length; i++)
6859 RootObject o = (*tup.objects)[i];
6860 Expression e;
6861 Declaration var;
6862 switch (o.dyncast()) with (DYNCAST)
6864 case expression:
6865 e = cast(Expression)o;
6866 if (auto se = e.isDsymbolExp())
6867 var = se.s.isDeclaration();
6868 else if (auto ve = e.isVarExp())
6869 if (!ve.var.isFuncDeclaration())
6870 // Exempt functions for backwards compatibility reasons.
6871 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
6872 var = ve.var;
6873 break;
6874 case dsymbol:
6875 Dsymbol s = cast(Dsymbol) o;
6876 Declaration d = s.isDeclaration();
6877 if (!d || d.isFuncDeclaration())
6878 // Exempt functions for backwards compatibility reasons.
6879 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
6880 e = new DsymbolExp(exp.loc, s);
6881 else
6882 var = d;
6883 break;
6884 case type:
6885 e = new TypeExp(exp.loc, cast(Type)o);
6886 break;
6887 default:
6888 exp.error("`%s` is not an expression", o.toChars());
6889 return setError();
6891 if (var)
6892 e = new DotVarExp(exp.loc, ev, var);
6893 exps.push(e);
6896 Expression e = new TupleExp(exp.loc, e0, exps);
6897 e = e.expressionSemantic(sc);
6898 result = e;
6899 return;
6901 else if (auto ad = exp.var.isAliasDeclaration())
6903 if (auto t = ad.getType())
6905 result = new TypeExp(exp.loc, t).expressionSemantic(sc);
6906 return;
6910 exp.e1 = exp.e1.addDtorHook(sc);
6912 Type t1 = exp.e1.type;
6914 if (FuncDeclaration fd = exp.var.isFuncDeclaration())
6916 // for functions, do checks after overload resolution
6917 if (!fd.functionSemantic())
6918 return setError();
6920 /* https://issues.dlang.org/show_bug.cgi?id=13843
6921 * If fd obviously has no overloads, we should
6922 * normalize AST, and it will give a chance to wrap fd with FuncExp.
6924 if ((fd.isNested() && !fd.isThis()) || fd.isFuncLiteralDeclaration())
6926 // (e1, fd)
6927 auto e = symbolToExp(fd, exp.loc, sc, false);
6928 result = Expression.combine(exp.e1, e);
6929 return;
6932 exp.type = fd.type;
6933 assert(exp.type);
6935 else if (OverDeclaration od = exp.var.isOverDeclaration())
6937 exp.type = Type.tvoid; // ambiguous type?
6939 else
6941 exp.type = exp.var.type;
6942 if (!exp.type && global.errors) // var is goofed up, just return error.
6943 return setError();
6944 assert(exp.type);
6946 if (t1.ty == Tpointer)
6947 t1 = t1.nextOf();
6949 exp.type = exp.type.addMod(t1.mod);
6951 // https://issues.dlang.org/show_bug.cgi?id=23109
6952 // Run semantic on the DotVarExp type
6953 if (auto handle = exp.type.isClassHandle())
6955 if (handle.semanticRun < PASS.semanticdone && !handle.isBaseInfoComplete())
6956 handle.dsymbolSemantic(null);
6959 Dsymbol vparent = exp.var.toParent();
6960 AggregateDeclaration ad = vparent ? vparent.isAggregateDeclaration() : null;
6961 if (Expression e1x = getRightThis(exp.loc, sc, ad, exp.e1, exp.var, 1))
6962 exp.e1 = e1x;
6963 else
6965 /* Later checkRightThis will report correct error for invalid field variable access.
6967 Expression e = new VarExp(exp.loc, exp.var);
6968 e = e.expressionSemantic(sc);
6969 result = e;
6970 return;
6972 checkAccess(exp.loc, sc, exp.e1, exp.var);
6974 VarDeclaration v = exp.var.isVarDeclaration();
6975 if (v && (v.isDataseg() || (v.storage_class & STC.manifest)))
6977 Expression e = expandVar(WANTvalue, v);
6978 if (e)
6980 result = e;
6981 return;
6985 if (v && (v.isDataseg() || // fix https://issues.dlang.org/show_bug.cgi?id=8238
6986 (!v.needThis() && v.semanticRun > PASS.initial))) // fix https://issues.dlang.org/show_bug.cgi?id=17258
6988 // (e1, v)
6989 checkAccess(exp.loc, sc, exp.e1, v);
6990 Expression e = new VarExp(exp.loc, v);
6991 e = new CommaExp(exp.loc, exp.e1, e);
6992 e = e.expressionSemantic(sc);
6993 result = e;
6994 return;
6997 //printf("-DotVarExp::semantic('%s')\n", toChars());
6998 result = exp;
7001 override void visit(DotTemplateInstanceExp exp)
7003 static if (LOGSEMANTIC)
7005 printf("DotTemplateInstanceExp::semantic('%s')\n", exp.toChars());
7007 if (exp.type)
7009 result = exp;
7010 return;
7012 // Indicate we need to resolve by UFCS.
7013 Expression e = exp.dotTemplateSemanticProp(sc, DotExpFlag.gag);
7014 if (!e)
7015 e = resolveUFCSProperties(sc, exp);
7016 if (e is exp)
7017 e.type = Type.tvoid; // Unresolved type, because it needs inference
7018 result = e;
7021 override void visit(DelegateExp e)
7023 static if (LOGSEMANTIC)
7025 printf("DelegateExp::semantic('%s')\n", e.toChars());
7027 if (e.type)
7029 result = e;
7030 return;
7033 e.e1 = e.e1.expressionSemantic(sc);
7035 e.type = new TypeDelegate(e.func.type.isTypeFunction());
7036 e.type = e.type.typeSemantic(e.loc, sc);
7038 FuncDeclaration f = e.func.toAliasFunc();
7039 AggregateDeclaration ad = f.isMemberLocal();
7040 if (f.needThis())
7041 e.e1 = getRightThis(e.loc, sc, ad, e.e1, f);
7043 if (f.type.ty == Tfunction)
7045 TypeFunction tf = cast(TypeFunction)f.type;
7046 if (!MODmethodConv(e.e1.type.mod, f.type.mod))
7048 OutBuffer thisBuf, funcBuf;
7049 MODMatchToBuffer(&thisBuf, e.e1.type.mod, tf.mod);
7050 MODMatchToBuffer(&funcBuf, tf.mod, e.e1.type.mod);
7051 e.error("%smethod `%s` is not callable using a %s`%s`",
7052 funcBuf.peekChars(), f.toPrettyChars(), thisBuf.peekChars(), e.e1.toChars());
7053 return setError();
7056 if (ad && ad.isClassDeclaration() && ad.type != e.e1.type)
7058 // A downcast is required for interfaces
7059 // https://issues.dlang.org/show_bug.cgi?id=3706
7060 e.e1 = new CastExp(e.loc, e.e1, ad.type);
7061 e.e1 = e.e1.expressionSemantic(sc);
7063 result = e;
7064 // declare dual-context container
7065 if (f.hasDualContext() && !sc.intypeof && sc.func)
7067 // check access to second `this`
7068 if (AggregateDeclaration ad2 = f.isMember2())
7070 Expression te = new ThisExp(e.loc).expressionSemantic(sc);
7071 if (te.op != EXP.error)
7072 te = getRightThis(e.loc, sc, ad2, te, f);
7073 if (te.op == EXP.error)
7075 e.error("need `this` of type `%s` to make delegate from function `%s`", ad2.toChars(), f.toChars());
7076 return setError();
7079 VarDeclaration vthis2 = makeThis2Argument(e.loc, sc, f);
7080 e.vthis2 = vthis2;
7081 Expression de = new DeclarationExp(e.loc, vthis2);
7082 result = Expression.combine(de, result);
7083 result = result.expressionSemantic(sc);
7087 override void visit(DotTypeExp exp)
7089 static if (LOGSEMANTIC)
7091 printf("DotTypeExp::semantic('%s')\n", exp.toChars());
7093 if (exp.type)
7095 result = exp;
7096 return;
7099 if (auto e = unaSemantic(exp, sc))
7101 result = e;
7102 return;
7105 exp.type = exp.sym.getType().addMod(exp.e1.type.mod);
7106 result = exp;
7109 override void visit(AddrExp exp)
7111 static if (LOGSEMANTIC)
7113 printf("AddrExp::semantic('%s')\n", exp.toChars());
7115 if (exp.type)
7117 result = exp;
7118 return;
7121 if (Expression ex = unaSemantic(exp, sc))
7123 result = ex;
7124 return;
7127 if (sc.flags & SCOPE.Cfile)
7129 /* Special handling for &"string"/&(T[]){0, 1}
7130 * since C regards string/array literals as lvalues
7132 auto e = exp.e1;
7133 if(e.isStringExp() || e.isArrayLiteralExp())
7135 e.type = typeSemantic(e.type, Loc.initial, sc);
7136 // if type is already a pointer exp is an illegal expression of the form `&(&"")`
7137 if (!e.type.isTypePointer())
7139 e.type = e.type.pointerTo();
7140 result = e;
7141 return;
7143 else
7145 // `toLvalue` call further below is upon exp.e1, omitting & from the error message
7146 exp.toLvalue(sc, null);
7147 return setError();
7152 int wasCond = exp.e1.op == EXP.question;
7154 if (exp.e1.op == EXP.dotTemplateInstance)
7156 DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)exp.e1;
7157 TemplateInstance ti = dti.ti;
7159 //assert(ti.needsTypeInference(sc));
7160 ti.dsymbolSemantic(sc);
7161 if (!ti.inst || ti.errors) // if template failed to expand
7162 return setError();
7164 Dsymbol s = ti.toAlias();
7165 FuncDeclaration f = s.isFuncDeclaration();
7166 if (f)
7168 exp.e1 = new DotVarExp(exp.e1.loc, dti.e1, f);
7169 exp.e1 = exp.e1.expressionSemantic(sc);
7173 else if (exp.e1.op == EXP.scope_)
7175 TemplateInstance ti = (cast(ScopeExp)exp.e1).sds.isTemplateInstance();
7176 if (ti)
7178 //assert(ti.needsTypeInference(sc));
7179 ti.dsymbolSemantic(sc);
7180 if (!ti.inst || ti.errors) // if template failed to expand
7181 return setError();
7183 Dsymbol s = ti.toAlias();
7184 FuncDeclaration f = s.isFuncDeclaration();
7185 if (f)
7187 exp.e1 = new VarExp(exp.e1.loc, f);
7188 exp.e1 = exp.e1.expressionSemantic(sc);
7192 /* https://issues.dlang.org/show_bug.cgi?id=809
7194 * If the address of a lazy variable is taken,
7195 * the expression is rewritten so that the type
7196 * of it is the delegate type. This means that
7197 * the symbol is not going to represent a call
7198 * to the delegate anymore, but rather, the
7199 * actual symbol.
7201 if (auto ve = exp.e1.isVarExp())
7203 if (ve.var.storage_class & STC.lazy_)
7205 exp.e1 = exp.e1.expressionSemantic(sc);
7206 exp.e1 = resolveProperties(sc, exp.e1);
7207 if (auto callExp = exp.e1.isCallExp())
7209 if (callExp.e1.type.toBasetype().ty == Tdelegate)
7211 /* https://issues.dlang.org/show_bug.cgi?id=20551
7213 * Cannot take address of lazy parameter in @safe code
7214 * because it might end up being a pointer to undefined
7215 * memory.
7217 if (1)
7219 if (sc.setUnsafe(false, exp.loc,
7220 "cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve, sc.func))
7222 setError();
7223 return;
7226 VarExp ve2 = callExp.e1.isVarExp();
7227 ve2.delegateWasExtracted = true;
7228 ve2.var.storage_class |= STC.scope_;
7229 result = ve2;
7230 return;
7236 exp.e1 = exp.e1.toLvalue(sc, null);
7237 if (exp.e1.op == EXP.error)
7239 result = exp.e1;
7240 return;
7242 if (checkNonAssignmentArrayOp(exp.e1))
7243 return setError();
7245 if (!exp.e1.type)
7247 exp.error("cannot take address of `%s`", exp.e1.toChars());
7248 return setError();
7250 if (!checkAddressable(exp, sc))
7251 return setError();
7253 bool hasOverloads;
7254 if (auto f = isFuncAddress(exp, &hasOverloads))
7256 if (!hasOverloads && f.checkForwardRef(exp.loc))
7257 return setError();
7259 else if (!exp.e1.type.deco)
7261 // try to resolve the type
7262 exp.e1.type = exp.e1.type.typeSemantic(exp.e1.loc, null);
7263 if (!exp.e1.type.deco) // still couldn't resolve it
7265 if (auto ve = exp.e1.isVarExp())
7267 Declaration d = ve.var;
7268 exp.error("forward reference to %s `%s`", d.kind(), d.toChars());
7270 else
7271 exp.error("forward reference to type `%s` of expression `%s`", exp.e1.type.toChars(), exp.e1.toChars());
7272 return setError();
7276 exp.type = exp.e1.type.pointerTo();
7278 // See if this should really be a delegate
7279 if (exp.e1.op == EXP.dotVariable)
7281 DotVarExp dve = cast(DotVarExp)exp.e1;
7282 FuncDeclaration f = dve.var.isFuncDeclaration();
7283 if (f)
7285 f = f.toAliasFunc(); // FIXME, should see overloads
7286 // https://issues.dlang.org/show_bug.cgi?id=1983
7287 if (!dve.hasOverloads)
7288 f.tookAddressOf++;
7290 Expression e;
7291 if (f.needThis())
7292 e = new DelegateExp(exp.loc, dve.e1, f, dve.hasOverloads);
7293 else // It is a function pointer. Convert &v.f() --> (v, &V.f())
7294 e = new CommaExp(exp.loc, dve.e1, new AddrExp(exp.loc, new VarExp(exp.loc, f, dve.hasOverloads)));
7295 e = e.expressionSemantic(sc);
7296 result = e;
7297 return;
7300 // Look for misaligned pointer in @safe mode
7301 if (checkUnsafeAccess(sc, dve, !exp.type.isMutable(), true))
7302 return setError();
7304 else if (exp.e1.op == EXP.variable)
7306 VarExp ve = cast(VarExp)exp.e1;
7307 VarDeclaration v = ve.var.isVarDeclaration();
7308 if (v)
7310 if (!checkAddressVar(sc, exp.e1, v))
7311 return setError();
7313 ve.checkPurity(sc, v);
7315 FuncDeclaration f = ve.var.isFuncDeclaration();
7316 if (f)
7318 /* Because nested functions cannot be overloaded,
7319 * mark here that we took its address because castTo()
7320 * may not be called with an exact match.
7322 * https://issues.dlang.org/show_bug.cgi?id=19285 :
7323 * We also need to make sure we aren't inside a typeof. Ideally the compiler
7324 * would do typeof(...) semantic analysis speculatively then collect information
7325 * about what it used rather than relying on what are effectively semantically-global
7326 * variables but it doesn't.
7328 if (!sc.isFromSpeculativeSemanticContext() && (!ve.hasOverloads || (f.isNested() && !f.needThis())))
7330 // TODO: Refactor to use a proper interface that can keep track of causes.
7331 f.tookAddressOf++;
7334 if (f.isNested() && !f.needThis())
7336 if (f.isFuncLiteralDeclaration())
7338 if (!f.FuncDeclaration.isNested())
7340 /* Supply a 'null' for a this pointer if no this is available
7342 Expression e = new DelegateExp(exp.loc, new NullExp(exp.loc, Type.tnull), f, ve.hasOverloads);
7343 e = e.expressionSemantic(sc);
7344 result = e;
7345 return;
7348 Expression e = new DelegateExp(exp.loc, exp.e1, f, ve.hasOverloads);
7349 e = e.expressionSemantic(sc);
7350 result = e;
7351 return;
7353 if (f.needThis())
7355 auto memberFunc = hasThis(sc);
7356 if (memberFunc && haveSameThis(memberFunc, f))
7358 /* Should probably supply 'this' after overload resolution,
7359 * not before.
7361 Expression ethis = new ThisExp(exp.loc);
7362 Expression e = new DelegateExp(exp.loc, ethis, f, ve.hasOverloads);
7363 e = e.expressionSemantic(sc);
7364 result = e;
7365 return;
7367 if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_))
7369 sc.setUnsafe(false, exp.loc,
7370 "`this` reference necessary to take address of member `%s` in `@safe` function `%s`",
7371 f, sc.func);
7376 else if (exp.e1.op == EXP.index)
7378 /* For:
7379 * int[3] a;
7380 * &a[i]
7381 * check 'a' the same as for a regular variable
7383 if (VarDeclaration v = expToVariable(exp.e1))
7385 exp.e1.checkPurity(sc, v);
7388 else if (wasCond)
7390 /* a ? b : c was transformed to *(a ? &b : &c), but we still
7391 * need to do safety checks
7393 assert(exp.e1.op == EXP.star);
7394 PtrExp pe = cast(PtrExp)exp.e1;
7395 assert(pe.e1.op == EXP.question);
7396 CondExp ce = cast(CondExp)pe.e1;
7397 assert(ce.e1.op == EXP.address);
7398 assert(ce.e2.op == EXP.address);
7400 // Re-run semantic on the address expressions only
7401 ce.e1.type = null;
7402 ce.e1 = ce.e1.expressionSemantic(sc);
7403 ce.e2.type = null;
7404 ce.e2 = ce.e2.expressionSemantic(sc);
7406 result = exp.optimize(WANTvalue);
7409 override void visit(PtrExp exp)
7411 static if (LOGSEMANTIC)
7413 printf("PtrExp::semantic('%s')\n", exp.toChars());
7415 if (exp.type)
7417 result = exp;
7418 return;
7421 Expression e = exp.op_overload(sc);
7422 if (e)
7424 result = e;
7425 return;
7428 exp.e1 = exp.e1.arrayFuncConv(sc);
7430 Type tb = exp.e1.type.toBasetype();
7431 switch (tb.ty)
7433 case Tpointer:
7434 exp.type = (cast(TypePointer)tb).next;
7435 break;
7437 case Tsarray:
7438 case Tarray:
7439 if (isNonAssignmentArrayOp(exp.e1))
7440 goto default;
7441 exp.error("using `*` on an array is no longer supported; use `*(%s).ptr` instead", exp.e1.toChars());
7442 exp.type = (cast(TypeArray)tb).next;
7443 exp.e1 = exp.e1.castTo(sc, exp.type.pointerTo());
7444 break;
7446 case Terror:
7447 return setError();
7449 case Tnull:
7450 exp.type = Type.tnoreturn; // typeof(*null) is bottom type
7451 break;
7453 default:
7454 exp.error("can only `*` a pointer, not a `%s`", exp.e1.type.toChars());
7455 goto case Terror;
7458 if (sc.flags & SCOPE.Cfile && exp.type && exp.type.toBasetype().ty == Tvoid)
7460 // https://issues.dlang.org/show_bug.cgi?id=23752
7461 // `&*((void*)(0))` is allowed in C
7462 result = exp;
7463 return;
7466 if (exp.checkValue())
7467 return setError();
7469 result = exp;
7472 override void visit(NegExp exp)
7474 static if (LOGSEMANTIC)
7476 printf("NegExp::semantic('%s')\n", exp.toChars());
7478 if (exp.type)
7480 result = exp;
7481 return;
7484 Expression e = exp.op_overload(sc);
7485 if (e)
7487 result = e;
7488 return;
7491 fix16997(sc, exp);
7492 exp.type = exp.e1.type;
7493 Type tb = exp.type.toBasetype();
7494 if (tb.ty == Tarray || tb.ty == Tsarray)
7496 if (!isArrayOpValid(exp.e1))
7498 result = arrayOpInvalidError(exp);
7499 return;
7501 result = exp;
7502 return;
7504 if (!target.isVectorOpSupported(tb, exp.op))
7506 result = exp.incompatibleTypes();
7507 return;
7509 if (exp.e1.checkNoBool())
7510 return setError();
7511 if (exp.e1.checkArithmetic() ||
7512 exp.e1.checkSharedAccess(sc))
7513 return setError();
7515 result = exp;
7518 override void visit(UAddExp exp)
7520 static if (LOGSEMANTIC)
7522 printf("UAddExp::semantic('%s')\n", exp.toChars());
7524 assert(!exp.type);
7526 Expression e = exp.op_overload(sc);
7527 if (e)
7529 result = e;
7530 return;
7533 fix16997(sc, exp);
7534 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op))
7536 result = exp.incompatibleTypes();
7537 return;
7539 if (exp.e1.checkNoBool())
7540 return setError();
7541 if (exp.e1.checkArithmetic())
7542 return setError();
7543 if (exp.e1.checkSharedAccess(sc))
7544 return setError();
7546 result = exp.e1;
7549 override void visit(ComExp exp)
7551 if (exp.type)
7553 result = exp;
7554 return;
7557 Expression e = exp.op_overload(sc);
7558 if (e)
7560 result = e;
7561 return;
7564 fix16997(sc, exp);
7565 exp.type = exp.e1.type;
7566 Type tb = exp.type.toBasetype();
7567 if (tb.ty == Tarray || tb.ty == Tsarray)
7569 if (!isArrayOpValid(exp.e1))
7571 result = arrayOpInvalidError(exp);
7572 return;
7574 result = exp;
7575 return;
7577 if (!target.isVectorOpSupported(tb, exp.op))
7579 result = exp.incompatibleTypes();
7580 return;
7582 if (exp.e1.checkNoBool())
7583 return setError();
7584 if (exp.e1.checkIntegral() ||
7585 exp.e1.checkSharedAccess(sc))
7586 return setError();
7588 result = exp;
7591 override void visit(NotExp e)
7593 if (e.type)
7595 result = e;
7596 return;
7599 e.setNoderefOperand();
7601 // Note there is no operator overload
7602 if (Expression ex = unaSemantic(e, sc))
7604 result = ex;
7605 return;
7608 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
7609 if (e.e1.op == EXP.type)
7610 e.e1 = resolveAliasThis(sc, e.e1);
7612 e.e1 = resolveProperties(sc, e.e1);
7613 e.e1 = e.e1.toBoolean(sc);
7614 if (e.e1.type == Type.terror)
7616 result = e.e1;
7617 return;
7620 if (!target.isVectorOpSupported(e.e1.type.toBasetype(), e.op))
7622 result = e.incompatibleTypes();
7624 // https://issues.dlang.org/show_bug.cgi?id=13910
7625 // Today NotExp can take an array as its operand.
7626 if (checkNonAssignmentArrayOp(e.e1))
7627 return setError();
7629 e.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
7630 result = e;
7633 override void visit(DeleteExp exp)
7635 // @@@DEPRECATED_2.109@@@
7636 // 1. Deprecated since 2.079
7637 // 2. Error since 2.099
7638 // 3. Removal of keyword, "delete" can be used for other identities
7639 if (!exp.isRAII)
7641 error(exp.loc, "the `delete` keyword is obsolete");
7642 errorSupplemental(exp.loc, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead");
7643 return setError();
7646 Expression e = exp;
7648 if (Expression ex = unaSemantic(exp, sc))
7650 result = ex;
7651 return;
7653 exp.e1 = resolveProperties(sc, exp.e1);
7654 exp.e1 = exp.e1.modifiableLvalue(sc, null);
7655 if (exp.e1.op == EXP.error)
7657 result = exp.e1;
7658 return;
7660 exp.type = Type.tvoid;
7662 Type tb = exp.e1.type.toBasetype();
7664 /* Now that `delete` in user code is an error, we only get here when
7665 * `isRAII` has been set to true for the deletion of a `scope class`. */
7666 if (tb.ty != Tclass)
7668 exp.error("cannot delete type `%s`", exp.e1.type.toChars());
7669 return setError();
7672 ClassDeclaration cd = (cast(TypeClass)tb).sym;
7673 if (cd.isCOMinterface())
7675 /* Because COM classes are deleted by IUnknown.Release()
7677 exp.error("cannot `delete` instance of COM interface `%s`", cd.toChars());
7678 return setError();
7681 bool err = false;
7682 if (cd.dtor)
7684 err |= !cd.dtor.functionSemantic();
7685 err |= exp.checkPurity(sc, cd.dtor);
7686 err |= exp.checkSafety(sc, cd.dtor);
7687 err |= exp.checkNogc(sc, cd.dtor);
7689 if (err)
7690 return setError();
7692 result = e;
7695 override void visit(CastExp exp)
7697 static if (LOGSEMANTIC)
7699 printf("CastExp::semantic('%s')\n", exp.toChars());
7701 //static int x; assert(++x < 10);
7702 if (exp.type)
7704 result = exp;
7705 return;
7708 if ((sc && sc.flags & SCOPE.Cfile) &&
7709 exp.to && (exp.to.ty == Tident || exp.to.ty == Tsarray) &&
7710 (exp.e1.op == EXP.address || exp.e1.op == EXP.star ||
7711 exp.e1.op == EXP.uadd || exp.e1.op == EXP.negate))
7713 /* Ambiguous cases arise from CParser if type-name is just an identifier.
7714 * ( identifier ) cast-expression
7715 * ( identifier [expression]) cast-expression
7716 * If we determine that `identifier` is a variable, and cast-expression
7717 * is one of the unary operators (& * + -), then rewrite this cast
7718 * as a binary expression.
7720 Loc loc = exp.loc;
7721 Type t;
7722 Expression e;
7723 Dsymbol s;
7724 exp.to.resolve(loc, sc, e, t, s);
7725 if (e !is null)
7727 if (auto ex = exp.e1.isAddrExp()) // (ident) &exp -> (ident & exp)
7728 result = new AndExp(loc, e, ex.e1);
7729 else if (auto ex = exp.e1.isPtrExp()) // (ident) *exp -> (ident * exp)
7730 result = new MulExp(loc, e, ex.e1);
7731 else if (auto ex = exp.e1.isUAddExp()) // (ident) +exp -> (ident + exp)
7732 result = new AddExp(loc, e, ex.e1);
7733 else if (auto ex = exp.e1.isNegExp()) // (ident) -exp -> (ident - exp)
7734 result = new MinExp(loc, e, ex.e1);
7736 assert(result);
7737 result = result.expressionSemantic(sc);
7738 return;
7742 if (exp.to)
7744 exp.to = exp.to.typeSemantic(exp.loc, sc);
7745 if (exp.to == Type.terror)
7746 return setError();
7748 if (!exp.to.hasPointers())
7749 exp.setNoderefOperand();
7751 // When e1 is a template lambda, this cast may instantiate it with
7752 // the type 'to'.
7753 exp.e1 = inferType(exp.e1, exp.to);
7756 if (auto e = unaSemantic(exp, sc))
7758 result = e;
7759 return;
7762 if (exp.to && !exp.to.isTypeSArray() && !exp.to.isTypeFunction())
7763 exp.e1 = exp.e1.arrayFuncConv(sc);
7765 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
7766 if (exp.e1.op == EXP.type)
7767 exp.e1 = resolveAliasThis(sc, exp.e1);
7769 auto e1x = resolveProperties(sc, exp.e1);
7770 if (e1x.op == EXP.error)
7772 result = e1x;
7773 return;
7775 if (e1x.checkType())
7776 return setError();
7777 exp.e1 = e1x;
7779 if (!exp.e1.type)
7781 exp.error("cannot cast `%s`", exp.e1.toChars());
7782 return setError();
7785 // https://issues.dlang.org/show_bug.cgi?id=19954
7786 if (exp.e1.type.ty == Ttuple)
7788 if (exp.to)
7790 if (TypeTuple tt = exp.to.isTypeTuple())
7792 if (exp.e1.type.implicitConvTo(tt))
7794 result = exp.e1.castTo(sc, tt);
7795 return;
7799 TupleExp te = exp.e1.isTupleExp();
7800 if (te.exps.length == 1)
7801 exp.e1 = (*te.exps)[0];
7804 // only allow S(x) rewrite if cast specified S explicitly.
7805 // See https://issues.dlang.org/show_bug.cgi?id=18545
7806 const bool allowImplicitConstruction = exp.to !is null;
7808 if (!exp.to) // Handle cast(const) and cast(immutable), etc.
7810 exp.to = exp.e1.type.castMod(exp.mod);
7811 exp.to = exp.to.typeSemantic(exp.loc, sc);
7813 if (exp.to == Type.terror)
7814 return setError();
7817 if (exp.to.ty == Ttuple)
7819 exp.error("cannot cast `%s` of type `%s` to type sequence `%s`", exp.e1.toChars(), exp.e1.type.toChars(), exp.to.toChars());
7820 return setError();
7823 // cast(void) is used to mark e1 as unused, so it is safe
7824 if (exp.to.ty == Tvoid)
7826 exp.type = exp.to;
7827 result = exp;
7828 return;
7831 if (!exp.to.equals(exp.e1.type) && exp.mod == cast(ubyte)~0)
7833 if (Expression e = exp.op_overload(sc))
7835 result = e.implicitCastTo(sc, exp.to);
7836 return;
7840 Type t1b = exp.e1.type.toBasetype();
7841 Type tob = exp.to.toBasetype();
7843 if (allowImplicitConstruction && tob.ty == Tstruct && !tob.equals(t1b))
7845 /* Look to replace:
7846 * cast(S)t
7847 * with:
7848 * S(t)
7851 // Rewrite as to.call(e1)
7852 Expression e = new TypeExp(exp.loc, exp.to);
7853 e = new CallExp(exp.loc, e, exp.e1);
7854 e = e.trySemantic(sc);
7855 if (e)
7857 result = e;
7858 return;
7862 if (!t1b.equals(tob) && (t1b.ty == Tarray || t1b.ty == Tsarray))
7864 if (checkNonAssignmentArrayOp(exp.e1))
7865 return setError();
7868 // Look for casting to a vector type
7869 if (tob.ty == Tvector && t1b.ty != Tvector)
7871 result = new VectorExp(exp.loc, exp.e1, exp.to);
7872 result = result.expressionSemantic(sc);
7873 return;
7876 Expression ex = exp.e1.castTo(sc, exp.to);
7877 if (ex.op == EXP.error)
7879 result = ex;
7880 return;
7883 // Check for unsafe casts
7884 if (!isSafeCast(ex, t1b, tob))
7886 if (sc.setUnsafe(false, exp.loc, "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to))
7888 return setError();
7892 // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built
7893 // to handle certain casts. Those casts which `object.__ArrayCast` does not support are filtered out.
7894 // See `e2ir.toElemCast` for other types of casts. If `object.__ArrayCast` is improved to support more
7895 // casts these conditions and potentially some logic in `e2ir.toElemCast` can be removed.
7896 if (tob.ty == Tarray)
7898 // https://issues.dlang.org/show_bug.cgi?id=19840
7899 if (auto ad = isAggregate(t1b))
7901 if (ad.aliasthis)
7903 Expression e = resolveAliasThis(sc, exp.e1);
7904 e = new CastExp(exp.loc, e, exp.to);
7905 result = e.expressionSemantic(sc);
7906 return;
7910 if(t1b.ty == Tarray && exp.e1.op != EXP.arrayLiteral && sc.needsCodegen())
7912 auto tFrom = t1b.nextOf();
7913 auto tTo = tob.nextOf();
7915 // https://issues.dlang.org/show_bug.cgi?id=20130
7916 if (exp.e1.op != EXP.string_ || !ex.isStringExp)
7918 const uint fromSize = cast(uint)tFrom.size();
7919 const uint toSize = cast(uint)tTo.size();
7920 if (fromSize == SIZE_INVALID || toSize == SIZE_INVALID)
7921 return setError();
7923 // If array element sizes do not match, we must adjust the dimensions
7924 if (fromSize != toSize)
7926 if (!verifyHookExist(exp.loc, *sc, Id.__ArrayCast, "casting array of structs"))
7927 return setError();
7929 // A runtime check is needed in case arrays don't line up. That check should
7930 // be done in the implementation of `object.__ArrayCast`
7931 if (toSize == 0 || (fromSize % toSize) != 0)
7933 // lower to `object.__ArrayCast!(TFrom, TTo)(from)`
7935 // fully qualify as `object.__ArrayCast`
7936 Expression id = new IdentifierExp(exp.loc, Id.empty);
7937 auto dotid = new DotIdExp(exp.loc, id, Id.object);
7939 auto tiargs = new Objects();
7940 tiargs.push(tFrom);
7941 tiargs.push(tTo);
7942 auto dt = new DotTemplateInstanceExp(exp.loc, dotid, Id.__ArrayCast, tiargs);
7944 auto arguments = new Expressions();
7945 arguments.push(exp.e1);
7946 Expression ce = new CallExp(exp.loc, dt, arguments);
7948 result = expressionSemantic(ce, sc);
7949 return;
7956 if (sc && sc.flags & SCOPE.Cfile)
7958 /* C11 6.5.4-5: A cast does not yield an lvalue.
7959 * So ensure that castTo does not strip away the cast so that this
7960 * can be enforced in other semantic visitor methods.
7962 if (!ex.isCastExp())
7964 ex = new CastExp(exp.loc, ex, exp.to);
7965 ex.type = exp.to;
7968 result = ex;
7971 override void visit(VectorExp exp)
7973 static if (LOGSEMANTIC)
7975 printf("VectorExp::semantic('%s')\n", exp.toChars());
7977 if (exp.type)
7979 result = exp;
7980 return;
7983 exp.e1 = exp.e1.expressionSemantic(sc);
7984 exp.type = exp.to.typeSemantic(exp.loc, sc);
7985 if (exp.e1.op == EXP.error || exp.type.ty == Terror)
7987 result = exp.e1;
7988 return;
7991 Type tb = exp.type.toBasetype();
7992 assert(tb.ty == Tvector);
7993 TypeVector tv = cast(TypeVector)tb;
7994 Type te = tv.elementType();
7995 exp.dim = cast(int)(tv.size(exp.loc) / te.size(exp.loc));
7997 bool checkElem(Expression elem)
7999 if (elem.isConst() == 1)
8000 return false;
8002 exp.error("constant expression expected, not `%s`", elem.toChars());
8003 return true;
8006 exp.e1 = exp.e1.optimize(WANTvalue);
8007 bool res;
8008 if (exp.e1.op == EXP.arrayLiteral)
8010 foreach (i; 0 .. exp.dim)
8012 // Do not stop on first error - check all AST nodes even if error found
8013 res |= checkElem(exp.e1.isArrayLiteralExp()[i]);
8016 else if (exp.e1.type.ty == Tvoid)
8017 checkElem(exp.e1);
8019 result = res ? ErrorExp.get() : exp;
8022 override void visit(VectorArrayExp e)
8024 static if (LOGSEMANTIC)
8026 printf("VectorArrayExp::semantic('%s')\n", e.toChars());
8028 if (!e.type)
8030 unaSemantic(e, sc);
8031 e.e1 = resolveProperties(sc, e.e1);
8033 if (e.e1.op == EXP.error)
8035 result = e.e1;
8036 return;
8038 assert(e.e1.type.ty == Tvector);
8039 e.type = e.e1.type.isTypeVector().basetype;
8041 result = e;
8044 override void visit(SliceExp exp)
8046 static if (LOGSEMANTIC)
8048 printf("SliceExp::semantic('%s')\n", exp.toChars());
8050 if (exp.type)
8052 result = exp;
8053 return;
8056 // operator overloading should be handled in ArrayExp already.
8057 if (Expression ex = unaSemantic(exp, sc))
8059 result = ex;
8060 return;
8062 exp.e1 = resolveProperties(sc, exp.e1);
8063 if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
8065 if (exp.lwr || exp.upr)
8067 exp.error("cannot slice type `%s`", exp.e1.toChars());
8068 return setError();
8070 Expression e = new TypeExp(exp.loc, exp.e1.type.arrayOf());
8071 result = e.expressionSemantic(sc);
8072 return;
8074 if (!exp.lwr && !exp.upr)
8076 if (exp.e1.op == EXP.arrayLiteral)
8078 // Convert [a,b,c][] to [a,b,c]
8079 Type t1b = exp.e1.type.toBasetype();
8080 Expression e = exp.e1;
8081 if (t1b.ty == Tsarray)
8083 e = e.copy();
8084 e.type = t1b.nextOf().arrayOf();
8086 result = e;
8087 return;
8089 if (exp.e1.op == EXP.slice)
8091 // Convert e[][] to e[]
8092 SliceExp se = cast(SliceExp)exp.e1;
8093 if (!se.lwr && !se.upr)
8095 result = se;
8096 return;
8099 if (isArrayOpOperand(exp.e1))
8101 // Convert (a[]+b[])[] to a[]+b[]
8102 result = exp.e1;
8103 return;
8106 if (exp.e1.op == EXP.error)
8108 result = exp.e1;
8109 return;
8111 if (exp.e1.type.ty == Terror)
8112 return setError();
8114 Type t1b = exp.e1.type.toBasetype();
8115 if (auto tp = t1b.isTypePointer())
8117 if (t1b.isPtrToFunction())
8119 exp.error("cannot slice function pointer `%s`", exp.e1.toChars());
8120 return setError();
8122 if (!exp.lwr || !exp.upr)
8124 exp.error("upper and lower bounds are needed to slice a pointer");
8125 if (auto ad = isAggregate(tp.next.toBasetype()))
8127 auto s = search_function(ad, Id.index);
8128 if (!s) s = search_function(ad, Id.slice);
8129 if (s)
8131 auto fd = s.isFuncDeclaration();
8132 if ((fd && !fd.getParameterList().length) || s.isTemplateDeclaration())
8134 exp.errorSupplemental(
8135 "pointer `%s` points to an aggregate that defines an `%s`, perhaps you meant `(*%s)[]`",
8136 exp.e1.toChars(),
8137 s.ident.toChars(),
8138 exp.e1.toChars()
8145 return setError();
8147 if (sc.setUnsafe(false, exp.loc, "pointer slicing not allowed in safe functions"))
8148 return setError();
8150 else if (t1b.ty == Tarray)
8153 else if (t1b.ty == Tsarray)
8156 else if (t1b.ty == Ttuple)
8158 if (!exp.lwr && !exp.upr)
8160 result = exp.e1;
8161 return;
8163 if (!exp.lwr || !exp.upr)
8165 exp.error("need upper and lower bound to slice a sequence");
8166 return setError();
8169 else if (t1b.ty == Tvector && exp.e1.isLvalue())
8171 // Convert e1 to corresponding static array
8172 TypeVector tv1 = cast(TypeVector)t1b;
8173 t1b = tv1.basetype;
8174 t1b = t1b.castMod(tv1.mod);
8175 exp.e1.type = t1b;
8177 else
8179 exp.error("`%s` cannot be sliced with `[]`", t1b.ty == Tvoid ? exp.e1.toChars() : t1b.toChars());
8180 return setError();
8183 /* Run semantic on lwr and upr.
8185 Scope* scx = sc;
8186 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
8188 // Create scope for 'length' variable
8189 ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
8190 sym.parent = sc.scopesym;
8191 sc = sc.push(sym);
8193 if (exp.lwr)
8195 if (t1b.ty == Ttuple)
8196 sc = sc.startCTFE();
8197 exp.lwr = exp.lwr.expressionSemantic(sc);
8198 exp.lwr = resolveProperties(sc, exp.lwr);
8199 if (t1b.ty == Ttuple)
8200 sc = sc.endCTFE();
8201 exp.lwr = exp.lwr.implicitCastTo(sc, Type.tsize_t);
8203 if (exp.upr)
8205 if (t1b.ty == Ttuple)
8206 sc = sc.startCTFE();
8207 exp.upr = exp.upr.expressionSemantic(sc);
8208 exp.upr = resolveProperties(sc, exp.upr);
8209 if (t1b.ty == Ttuple)
8210 sc = sc.endCTFE();
8211 exp.upr = exp.upr.implicitCastTo(sc, Type.tsize_t);
8213 if (sc != scx)
8214 sc = sc.pop();
8215 if (exp.lwr && exp.lwr.type == Type.terror || exp.upr && exp.upr.type == Type.terror)
8216 return setError();
8218 if (t1b.ty == Ttuple)
8220 exp.lwr = exp.lwr.ctfeInterpret();
8221 exp.upr = exp.upr.ctfeInterpret();
8222 uinteger_t i1 = exp.lwr.toUInteger();
8223 uinteger_t i2 = exp.upr.toUInteger();
8225 TupleExp te;
8226 TypeTuple tup;
8227 size_t length;
8228 if (exp.e1.op == EXP.tuple) // slicing an expression tuple
8230 te = cast(TupleExp)exp.e1;
8231 tup = null;
8232 length = te.exps.length;
8234 else if (exp.e1.op == EXP.type) // slicing a type tuple
8236 te = null;
8237 tup = cast(TypeTuple)t1b;
8238 length = Parameter.dim(tup.arguments);
8240 else
8241 assert(0);
8243 if (i2 < i1 || length < i2)
8245 exp.error("string slice `[%llu .. %llu]` is out of bounds", i1, i2);
8246 return setError();
8249 size_t j1 = cast(size_t)i1;
8250 size_t j2 = cast(size_t)i2;
8251 Expression e;
8252 if (exp.e1.op == EXP.tuple)
8254 auto exps = new Expressions(j2 - j1);
8255 for (size_t i = 0; i < j2 - j1; i++)
8257 (*exps)[i] = (*te.exps)[j1 + i];
8259 e = new TupleExp(exp.loc, te.e0, exps);
8261 else
8263 auto args = new Parameters();
8264 args.reserve(j2 - j1);
8265 for (size_t i = j1; i < j2; i++)
8267 Parameter arg = Parameter.getNth(tup.arguments, i);
8268 args.push(arg);
8270 e = new TypeExp(exp.e1.loc, new TypeTuple(args));
8272 e = e.expressionSemantic(sc);
8273 result = e;
8274 return;
8277 exp.type = t1b.nextOf().arrayOf();
8278 // Allow typedef[] -> typedef[]
8279 if (exp.type.equals(t1b))
8280 exp.type = exp.e1.type;
8282 // We might know $ now
8283 setLengthVarIfKnown(exp.lengthVar, t1b);
8285 if (exp.lwr && exp.upr)
8287 exp.lwr = exp.lwr.optimize(WANTvalue);
8288 exp.upr = exp.upr.optimize(WANTvalue);
8290 IntRange lwrRange = getIntRange(exp.lwr);
8291 IntRange uprRange = getIntRange(exp.upr);
8293 if (t1b.ty == Tsarray || t1b.ty == Tarray)
8295 Expression el = new ArrayLengthExp(exp.loc, exp.e1);
8296 el = el.expressionSemantic(sc);
8297 el = el.optimize(WANTvalue);
8298 if (el.op == EXP.int64)
8300 // Array length is known at compile-time. Upper is in bounds if it fits length.
8301 dinteger_t length = el.toInteger();
8302 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length));
8303 exp.upperIsInBounds = bounds.contains(uprRange);
8305 else if (exp.upr.op == EXP.int64 && exp.upr.toInteger() == 0)
8307 // Upper slice expression is '0'. Value is always in bounds.
8308 exp.upperIsInBounds = true;
8310 else if (exp.upr.op == EXP.variable && (cast(VarExp)exp.upr).var.ident == Id.dollar)
8312 // Upper slice expression is '$'. Value is always in bounds.
8313 exp.upperIsInBounds = true;
8316 else if (t1b.ty == Tpointer)
8318 exp.upperIsInBounds = true;
8320 else
8321 assert(0);
8323 exp.lowerIsLessThanUpper = (lwrRange.imax <= uprRange.imin);
8325 //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", exp.upperIsInBounds, exp.lowerIsLessThanUpper);
8328 result = exp;
8331 override void visit(ArrayLengthExp e)
8333 static if (LOGSEMANTIC)
8335 printf("ArrayLengthExp::semantic('%s')\n", e.toChars());
8337 if (e.type)
8339 result = e;
8340 return;
8343 if (Expression ex = unaSemantic(e, sc))
8345 result = ex;
8346 return;
8348 e.e1 = resolveProperties(sc, e.e1);
8350 e.type = Type.tsize_t;
8351 result = e;
8354 override void visit(ArrayExp exp)
8356 static if (LOGSEMANTIC)
8358 printf("ArrayExp::semantic('%s')\n", exp.toChars());
8360 assert(!exp.type);
8362 if (sc.flags & SCOPE.Cfile)
8364 /* See if need to rewrite the AST because of cast/call ambiguity
8366 if (auto e = castCallAmbiguity(exp, sc))
8368 result = expressionSemantic(e, sc);
8369 return;
8373 result = exp.carraySemantic(sc); // C semantics
8374 if (result)
8375 return;
8377 Expression e = exp.op_overload(sc);
8378 if (e)
8380 result = e;
8381 return;
8384 if (isAggregate(exp.e1.type))
8385 exp.error("no `[]` operator overload for type `%s`", exp.e1.type.toChars());
8386 else if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
8387 exp.error("static array of `%s` with multiple lengths not allowed", exp.e1.type.toChars());
8388 else if (isIndexableNonAggregate(exp.e1.type))
8389 exp.error("only one index allowed to index `%s`", exp.e1.type.toChars());
8390 else
8391 exp.error("cannot use `[]` operator on expression of type `%s`", exp.e1.type.toChars());
8393 result = ErrorExp.get();
8396 override void visit(DotExp exp)
8398 static if (LOGSEMANTIC)
8400 printf("DotExp::semantic('%s')\n", exp.toChars());
8401 if (exp.type)
8402 printf("\ttype = %s\n", exp.type.toChars());
8404 exp.e1 = exp.e1.expressionSemantic(sc);
8405 exp.e2 = exp.e2.expressionSemantic(sc);
8407 if (exp.e1.op == EXP.type)
8409 result = exp.e2;
8410 return;
8412 if (exp.e2.op == EXP.type)
8414 result = exp.e2;
8415 return;
8417 if (auto te = exp.e2.isTemplateExp())
8419 Expression e = new DotTemplateExp(exp.loc, exp.e1, te.td);
8420 result = e.expressionSemantic(sc);
8421 return;
8423 if (!exp.type)
8424 exp.type = exp.e2.type;
8425 result = exp;
8428 override void visit(CommaExp e)
8430 //printf("Semantic.CommaExp() %s\n", e.toChars());
8431 if (e.type)
8433 result = e;
8434 return;
8437 // Allow `((a,b),(x,y))`
8438 if (e.allowCommaExp)
8440 CommaExp.allow(e.e1);
8441 CommaExp.allow(e.e2);
8444 if (Expression ex = binSemanticProp(e, sc))
8446 result = ex;
8447 return;
8449 e.e1 = e.e1.addDtorHook(sc);
8451 if (checkNonAssignmentArrayOp(e.e1))
8452 return setError();
8454 // Comma expressions trigger this conversion
8455 e.e2 = e.e2.arrayFuncConv(sc);
8457 e.type = e.e2.type;
8458 result = e;
8460 if (sc.flags & SCOPE.Cfile)
8461 return;
8463 if (e.type is Type.tvoid)
8465 checkMustUse(e.e1, sc);
8466 discardValue(e.e1);
8468 else if (!e.allowCommaExp && !e.isGenerated)
8469 e.error("using the result of a comma expression is not allowed");
8472 override void visit(IntervalExp e)
8474 static if (LOGSEMANTIC)
8476 printf("IntervalExp::semantic('%s')\n", e.toChars());
8478 if (e.type)
8480 result = e;
8481 return;
8484 Expression le = e.lwr;
8485 le = le.expressionSemantic(sc);
8486 le = resolveProperties(sc, le);
8488 Expression ue = e.upr;
8489 ue = ue.expressionSemantic(sc);
8490 ue = resolveProperties(sc, ue);
8492 if (le.op == EXP.error)
8494 result = le;
8495 return;
8497 if (ue.op == EXP.error)
8499 result = ue;
8500 return;
8503 e.lwr = le;
8504 e.upr = ue;
8506 e.type = Type.tvoid;
8507 result = e;
8510 override void visit(DelegatePtrExp e)
8512 static if (LOGSEMANTIC)
8514 printf("DelegatePtrExp::semantic('%s')\n", e.toChars());
8516 if (!e.type)
8518 unaSemantic(e, sc);
8519 e.e1 = resolveProperties(sc, e.e1);
8521 if (e.e1.op == EXP.error)
8523 result = e.e1;
8524 return;
8526 e.type = Type.tvoidptr;
8528 result = e;
8531 override void visit(DelegateFuncptrExp e)
8533 static if (LOGSEMANTIC)
8535 printf("DelegateFuncptrExp::semantic('%s')\n", e.toChars());
8537 if (!e.type)
8539 unaSemantic(e, sc);
8540 e.e1 = resolveProperties(sc, e.e1);
8541 if (e.e1.op == EXP.error)
8543 result = e.e1;
8544 return;
8546 e.type = e.e1.type.nextOf().pointerTo();
8548 result = e;
8551 override void visit(IndexExp exp)
8553 static if (LOGSEMANTIC)
8555 printf("IndexExp::semantic('%s')\n", exp.toChars());
8557 if (exp.type)
8559 result = exp;
8560 return;
8563 // operator overloading should be handled in ArrayExp already.
8564 if (!exp.e1.type)
8565 exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
8566 assert(exp.e1.type); // semantic() should already be run on it
8567 if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
8569 exp.e2 = exp.e2.expressionSemantic(sc);
8570 exp.e2 = resolveProperties(sc, exp.e2);
8571 Type nt;
8572 if (exp.e2.op == EXP.type)
8573 nt = new TypeAArray(exp.e1.type, exp.e2.type);
8574 else
8575 nt = new TypeSArray(exp.e1.type, exp.e2);
8576 Expression e = new TypeExp(exp.loc, nt);
8577 result = e.expressionSemantic(sc);
8578 return;
8580 if (exp.e1.op == EXP.error)
8582 result = exp.e1;
8583 return;
8585 if (exp.e1.type.ty == Terror)
8586 return setError();
8588 // Note that unlike C we do not implement the int[ptr]
8590 Type t1b = exp.e1.type.toBasetype();
8592 if (TypeVector tv1 = t1b.isTypeVector())
8594 // Convert e1 to corresponding static array
8595 t1b = tv1.basetype;
8596 t1b = t1b.castMod(tv1.mod);
8597 exp.e1 = exp.e1.castTo(sc, t1b);
8599 if (t1b.ty == Tsarray || t1b.ty == Tarray)
8601 if (!checkAddressable(exp, sc))
8602 return setError();
8605 /* Run semantic on e2
8607 Scope* scx = sc;
8608 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
8610 // Create scope for 'length' variable
8611 ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
8612 sym.parent = sc.scopesym;
8613 sc = sc.push(sym);
8615 if (t1b.ty == Ttuple)
8616 sc = sc.startCTFE();
8617 exp.e2 = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
8618 exp.e2 = resolveProperties(sc, exp.e2);
8619 if (t1b.ty == Ttuple)
8620 sc = sc.endCTFE();
8621 if (exp.e2.op == EXP.tuple)
8623 TupleExp te = cast(TupleExp)exp.e2;
8624 if (te.exps && te.exps.length == 1)
8625 exp.e2 = Expression.combine(te.e0, (*te.exps)[0]); // bug 4444 fix
8627 if (sc != scx)
8628 sc = sc.pop();
8629 if (exp.e2.type == Type.terror)
8630 return setError();
8632 if (checkNonAssignmentArrayOp(exp.e1))
8633 return setError();
8635 switch (t1b.ty)
8637 case Tpointer:
8638 if (t1b.isPtrToFunction())
8640 exp.error("cannot index function pointer `%s`", exp.e1.toChars());
8641 return setError();
8643 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8644 if (exp.e2.type == Type.terror)
8645 return setError();
8646 exp.e2 = exp.e2.optimize(WANTvalue);
8647 if (exp.e2.op == EXP.int64 && exp.e2.toInteger() == 0)
8650 else if (sc.setUnsafe(false, exp.loc, "`@safe` function `%s` cannot index pointer `%s`", sc.func, exp.e1))
8652 return setError();
8654 exp.type = (cast(TypeNext)t1b).next;
8655 break;
8657 case Tarray:
8658 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8659 if (exp.e2.type == Type.terror)
8660 return setError();
8661 exp.type = (cast(TypeNext)t1b).next;
8662 break;
8664 case Tsarray:
8666 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8667 if (exp.e2.type == Type.terror)
8668 return setError();
8669 exp.type = t1b.nextOf();
8670 break;
8672 case Taarray:
8674 TypeAArray taa = cast(TypeAArray)t1b;
8675 /* We can skip the implicit conversion if they differ only by
8676 * constness
8677 * https://issues.dlang.org/show_bug.cgi?id=2684
8678 * see also bug https://issues.dlang.org/show_bug.cgi?id=2954 b
8680 if (!arrayTypeCompatibleWithoutCasting(exp.e2.type, taa.index))
8682 exp.e2 = exp.e2.implicitCastTo(sc, taa.index); // type checking
8683 if (exp.e2.type == Type.terror)
8684 return setError();
8687 semanticTypeInfo(sc, taa);
8688 checkNewEscape(sc, exp.e2, false);
8690 exp.type = taa.next;
8691 break;
8693 case Ttuple:
8695 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8696 if (exp.e2.type == Type.terror)
8697 return setError();
8699 exp.e2 = exp.e2.ctfeInterpret();
8700 uinteger_t index = exp.e2.toUInteger();
8702 TupleExp te;
8703 TypeTuple tup;
8704 size_t length;
8705 if (exp.e1.op == EXP.tuple)
8707 te = cast(TupleExp)exp.e1;
8708 tup = null;
8709 length = te.exps.length;
8711 else if (exp.e1.op == EXP.type)
8713 te = null;
8714 tup = cast(TypeTuple)t1b;
8715 length = Parameter.dim(tup.arguments);
8717 else
8718 assert(0);
8720 if (length <= index)
8722 exp.error("array index `[%llu]` is outside array bounds `[0 .. %llu]`", index, cast(ulong)length);
8723 return setError();
8725 Expression e;
8726 if (exp.e1.op == EXP.tuple)
8728 e = (*te.exps)[cast(size_t)index];
8729 e = Expression.combine(te.e0, e);
8731 else
8732 e = new TypeExp(exp.e1.loc, Parameter.getNth(tup.arguments, cast(size_t)index).type);
8733 result = e;
8734 return;
8736 default:
8737 exp.error("`%s` must be an array or pointer type, not `%s`", exp.e1.toChars(), exp.e1.type.toChars());
8738 return setError();
8741 // We might know $ now
8742 setLengthVarIfKnown(exp.lengthVar, t1b);
8744 if (t1b.ty == Tsarray || t1b.ty == Tarray)
8746 Expression el = new ArrayLengthExp(exp.loc, exp.e1);
8747 el = el.expressionSemantic(sc);
8748 el = el.optimize(WANTvalue);
8749 if (el.op == EXP.int64)
8751 exp.e2 = exp.e2.optimize(WANTvalue);
8752 dinteger_t length = el.toInteger();
8753 if (length)
8755 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length - 1));
8756 // OR it in, because it might already be set for C array indexing
8757 exp.indexIsInBounds |= bounds.contains(getIntRange(exp.e2));
8759 else if (sc.flags & SCOPE.Cfile && t1b.ty == Tsarray)
8761 if (auto ve = exp.e1.isVarExp())
8763 /* Rewrite 0-length C array ve[exp.e2] as *(ve + exp.e2)
8765 auto vp = ve.castTo(sc, t1b.isTypeSArray().next.pointerTo());
8766 auto e = new AddExp(exp.loc, vp, exp.e2);
8767 auto pe = new PtrExp(exp.loc, e);
8768 result = pe.expressionSemantic(sc).optimize(WANTvalue);
8769 return;
8775 result = exp;
8778 override void visit(PostExp exp)
8780 static if (LOGSEMANTIC)
8782 printf("PostExp::semantic('%s')\n", exp.toChars());
8784 if (exp.type)
8786 result = exp;
8787 return;
8790 if (sc.flags & SCOPE.Cfile)
8792 /* See if need to rewrite the AST because of cast/call ambiguity
8794 if (auto e = castCallAmbiguity(exp, sc))
8796 result = expressionSemantic(e, sc);
8797 return;
8801 if (Expression ex = binSemantic(exp, sc))
8803 result = ex;
8804 return;
8806 Expression e1x = resolveProperties(sc, exp.e1);
8807 if (e1x.op == EXP.error)
8809 result = e1x;
8810 return;
8812 exp.e1 = e1x;
8814 Expression e = exp.op_overload(sc);
8815 if (e)
8817 result = e;
8818 return;
8821 if (exp.e1.checkReadModifyWrite(exp.op))
8822 return setError();
8824 if (exp.e1.op == EXP.slice)
8826 const(char)* s = exp.op == EXP.plusPlus ? "increment" : "decrement";
8827 exp.error("cannot post-%s array slice `%s`, use pre-%s instead", s, exp.e1.toChars(), s);
8828 return setError();
8831 Type t1 = exp.e1.type.toBasetype();
8832 if (t1.ty == Tclass || t1.ty == Tstruct || exp.e1.op == EXP.arrayLength)
8834 /* Check for operator overloading,
8835 * but rewrite in terms of ++e instead of e++
8838 /* If e1 is not trivial, take a reference to it
8840 Expression de = null;
8841 if (exp.e1.op != EXP.variable && exp.e1.op != EXP.arrayLength)
8843 // ref v = e1;
8844 auto v = copyToTemp(STC.ref_, "__postref", exp.e1);
8845 de = new DeclarationExp(exp.loc, v);
8846 exp.e1 = new VarExp(exp.e1.loc, v);
8849 /* Rewrite as:
8850 * auto tmp = e1; ++e1; tmp
8852 auto tmp = copyToTemp(0, "__pitmp", exp.e1);
8853 Expression ea = new DeclarationExp(exp.loc, tmp);
8855 Expression eb = exp.e1.syntaxCopy();
8856 eb = new PreExp(exp.op == EXP.plusPlus ? EXP.prePlusPlus : EXP.preMinusMinus, exp.loc, eb);
8858 Expression ec = new VarExp(exp.loc, tmp);
8860 // Combine de,ea,eb,ec
8861 if (de)
8862 ea = new CommaExp(exp.loc, de, ea);
8863 e = new CommaExp(exp.loc, ea, eb);
8864 e = new CommaExp(exp.loc, e, ec);
8865 e = e.expressionSemantic(sc);
8866 result = e;
8867 return;
8870 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
8871 exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
8873 e = exp;
8874 if (exp.e1.checkScalar() ||
8875 exp.e1.checkSharedAccess(sc))
8876 return setError();
8877 if (exp.e1.checkNoBool())
8878 return setError();
8880 if (exp.e1.type.ty == Tpointer)
8881 e = scaleFactor(exp, sc);
8882 else
8883 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
8884 e.type = exp.e1.type;
8885 result = e;
8888 override void visit(PreExp exp)
8890 Expression e = exp.op_overload(sc);
8891 // printf("PreExp::semantic('%s')\n", toChars());
8892 if (e)
8894 result = e;
8895 return;
8898 // Rewrite as e1+=1 or e1-=1
8899 if (exp.op == EXP.prePlusPlus)
8900 e = new AddAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
8901 else
8902 e = new MinAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
8903 result = e.expressionSemantic(sc);
8907 * Get the expression initializer for a specific struct
8909 * Params:
8910 * sd = the struct for which the expression initializer is needed
8911 * loc = the location of the initializer
8912 * sc = the scope where the expression is located
8913 * t = the type of the expression
8915 * Returns:
8916 * The expression initializer or error expression if any errors occured
8918 private Expression getInitExp(StructDeclaration sd, Loc loc, Scope* sc, Type t)
8920 if (sd.zeroInit && !sd.isNested())
8922 // https://issues.dlang.org/show_bug.cgi?id=14606
8923 // Always use BlitExp for the special expression: (struct = 0)
8924 return IntegerExp.literal!0;
8927 if (sd.isNested())
8929 auto sle = new StructLiteralExp(loc, sd, null, t);
8930 if (!sd.fill(loc, *sle.elements, true))
8931 return ErrorExp.get();
8932 if (checkFrameAccess(loc, sc, sd, sle.elements.length))
8933 return ErrorExp.get();
8935 sle.type = t;
8936 return sle;
8939 return t.defaultInit(loc);
8942 override void visit(AssignExp exp)
8944 static if (LOGSEMANTIC)
8946 if (exp.op == EXP.blit) printf("BlitExp.toElem('%s')\n", exp.toChars());
8947 if (exp.op == EXP.assign) printf("AssignExp.toElem('%s')\n", exp.toChars());
8948 if (exp.op == EXP.construct) printf("ConstructExp.toElem('%s')\n", exp.toChars());
8951 void setResult(Expression e, int line = __LINE__)
8953 //printf("line %d\n", line);
8954 result = e;
8957 if (exp.type)
8959 return setResult(exp);
8962 Expression e1old = exp.e1;
8964 if (auto e2comma = exp.e2.isCommaExp())
8966 if (!e2comma.isGenerated && !(sc.flags & SCOPE.Cfile))
8967 exp.error("using the result of a comma expression is not allowed");
8969 /* Rewrite to get rid of the comma from rvalue
8970 * e1=(e0,e2) => e0,(e1=e2)
8972 Expression e0;
8973 exp.e2 = Expression.extractLast(e2comma, e0);
8974 Expression e = Expression.combine(e0, exp);
8975 return setResult(e.expressionSemantic(sc));
8978 /* Look for operator overloading of a[arguments] = e2.
8979 * Do it before e1.expressionSemantic() otherwise the ArrayExp will have been
8980 * converted to unary operator overloading already.
8982 if (auto ae = exp.e1.isArrayExp())
8984 Expression res;
8986 ae.e1 = ae.e1.expressionSemantic(sc);
8987 ae.e1 = resolveProperties(sc, ae.e1);
8988 Expression ae1old = ae.e1;
8990 const(bool) maybeSlice =
8991 (ae.arguments.length == 0 ||
8992 ae.arguments.length == 1 && (*ae.arguments)[0].op == EXP.interval);
8994 IntervalExp ie = null;
8995 if (maybeSlice && ae.arguments.length)
8997 assert((*ae.arguments)[0].op == EXP.interval);
8998 ie = cast(IntervalExp)(*ae.arguments)[0];
9000 Type att = null; // first cyclic `alias this` type
9001 while (true)
9003 if (ae.e1.op == EXP.error)
9004 return setResult(ae.e1);
9006 Expression e0 = null;
9007 Expression ae1save = ae.e1;
9008 ae.lengthVar = null;
9010 Type t1b = ae.e1.type.toBasetype();
9011 AggregateDeclaration ad = isAggregate(t1b);
9012 if (!ad)
9013 break;
9014 if (search_function(ad, Id.indexass))
9016 // Deal with $
9017 res = resolveOpDollar(sc, ae, &e0);
9018 if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
9019 goto Lfallback;
9020 if (res.op == EXP.error)
9021 return setResult(res);
9023 res = exp.e2.expressionSemantic(sc);
9024 if (res.op == EXP.error)
9025 return setResult(res);
9026 exp.e2 = res;
9028 /* Rewrite (a[arguments] = e2) as:
9029 * a.opIndexAssign(e2, arguments)
9031 Expressions* a = ae.arguments.copy();
9032 a.insert(0, exp.e2);
9033 res = new DotIdExp(exp.loc, ae.e1, Id.indexass);
9034 res = new CallExp(exp.loc, res, a);
9035 if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2)
9036 res = res.trySemantic(sc);
9037 else
9038 res = res.expressionSemantic(sc);
9039 if (res)
9040 return setResult(Expression.combine(e0, res));
9043 Lfallback:
9044 if (maybeSlice && search_function(ad, Id.sliceass))
9046 // Deal with $
9047 res = resolveOpDollar(sc, ae, ie, &e0);
9048 if (res.op == EXP.error)
9049 return setResult(res);
9051 res = exp.e2.expressionSemantic(sc);
9052 if (res.op == EXP.error)
9053 return setResult(res);
9055 exp.e2 = res;
9057 /* Rewrite (a[i..j] = e2) as:
9058 * a.opSliceAssign(e2, i, j)
9060 auto a = new Expressions();
9061 a.push(exp.e2);
9062 if (ie)
9064 a.push(ie.lwr);
9065 a.push(ie.upr);
9067 res = new DotIdExp(exp.loc, ae.e1, Id.sliceass);
9068 res = new CallExp(exp.loc, res, a);
9069 res = res.expressionSemantic(sc);
9070 return setResult(Expression.combine(e0, res));
9073 // No operator overloading member function found yet, but
9074 // there might be an alias this to try.
9075 if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type))
9077 /* Rewrite (a[arguments] op e2) as:
9078 * a.aliasthis[arguments] op e2
9080 ae.e1 = resolveAliasThis(sc, ae1save, true);
9081 if (ae.e1)
9082 continue;
9084 break;
9086 ae.e1 = ae1old; // recovery
9087 ae.lengthVar = null;
9090 /* Run this.e1 semantic.
9093 Expression e1x = exp.e1;
9095 /* With UFCS, e.f = value
9096 * Could mean:
9097 * .f(e, value)
9098 * or:
9099 * .f(e) = value
9101 if (auto dti = e1x.isDotTemplateInstanceExp())
9103 Expression e = dti.dotTemplateSemanticProp(sc, DotExpFlag.gag);
9104 if (!e)
9106 return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
9109 e1x = e;
9111 else if (sc.flags & SCOPE.Cfile && e1x.isDotIdExp())
9113 auto die = e1x.isDotIdExp();
9114 e1x = fieldLookup(die.e1, sc, die.ident, die.arrow);
9116 else if (auto die = e1x.isDotIdExp())
9118 Expression e = die.dotIdSemanticProp(sc, 1);
9119 if (e && isDotOpDispatch(e))
9121 /* https://issues.dlang.org/show_bug.cgi?id=19687
9123 * On this branch, e2 is semantically analyzed in resolvePropertiesX,
9124 * but that call is done with gagged errors. That is the only time when
9125 * semantic gets ran on e2, that is why the error never gets to be printed.
9126 * In order to make sure that UFCS is tried with correct parameters, e2
9127 * needs to have semantic ran on it.
9129 auto ode = e;
9130 exp.e2 = exp.e2.expressionSemantic(sc);
9131 uint errors = global.startGagging();
9132 e = resolvePropertiesX(sc, e, exp.e2);
9133 // Any error or if 'e' is not resolved, go to UFCS
9134 if (global.endGagging(errors) || e is ode)
9135 e = null; /* fall down to UFCS */
9136 else
9137 return setResult(e);
9139 if (!e)
9140 return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
9141 e1x = e;
9143 else
9145 if (auto se = e1x.isSliceExp())
9146 se.arrayop = true;
9148 e1x = e1x.expressionSemantic(sc);
9151 /* We have f = value.
9152 * Could mean:
9153 * f(value)
9154 * or:
9155 * f() = value
9157 if (Expression e = resolvePropertiesX(sc, e1x, exp.e2, exp))
9158 return setResult(e);
9160 if (e1x.checkRightThis(sc))
9162 return setError();
9164 exp.e1 = e1x;
9165 assert(exp.e1.type);
9167 Type t1 = exp.e1.type.isTypeEnum() ? exp.e1.type : exp.e1.type.toBasetype();
9169 /* Run this.e2 semantic.
9170 * Different from other binary expressions, the analysis of e2
9171 * depends on the result of e1 in assignments.
9174 Expression e2x = inferType(exp.e2, t1.baseElemOf());
9175 e2x = e2x.expressionSemantic(sc);
9176 if (!t1.isTypeSArray())
9177 e2x = e2x.arrayFuncConv(sc);
9178 e2x = resolveProperties(sc, e2x);
9179 if (e2x.op == EXP.type)
9180 e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684
9181 if (e2x.op == EXP.error)
9182 return setResult(e2x);
9183 // We delay checking the value for structs/classes as these might have
9184 // an opAssign defined.
9185 if ((t1.ty != Tstruct && t1.ty != Tclass && e2x.checkValue()) ||
9186 e2x.checkSharedAccess(sc))
9187 return setError();
9189 auto etmp = checkNoreturnVarAccess(e2x);
9190 if (etmp != e2x)
9191 return setResult(etmp);
9193 exp.e2 = e2x;
9196 /* Rewrite tuple assignment as a tuple of assignments.
9199 Expression e2x = exp.e2;
9201 Ltupleassign:
9202 if (exp.e1.op == EXP.tuple && e2x.op == EXP.tuple)
9204 TupleExp tup1 = cast(TupleExp)exp.e1;
9205 TupleExp tup2 = cast(TupleExp)e2x;
9206 size_t dim = tup1.exps.length;
9207 Expression e = null;
9208 if (dim != tup2.exps.length)
9210 exp.error("mismatched sequence lengths, %d and %d", cast(int)dim, cast(int)tup2.exps.length);
9211 return setError();
9213 if (dim == 0)
9215 e = IntegerExp.literal!0;
9216 e = new CastExp(exp.loc, e, Type.tvoid); // avoid "has no effect" error
9217 e = Expression.combine(tup1.e0, tup2.e0, e);
9219 else
9221 auto exps = new Expressions(dim);
9222 for (size_t i = 0; i < dim; i++)
9224 Expression ex1 = (*tup1.exps)[i];
9225 Expression ex2 = (*tup2.exps)[i];
9226 (*exps)[i] = new AssignExp(exp.loc, ex1, ex2);
9228 e = new TupleExp(exp.loc, Expression.combine(tup1.e0, tup2.e0), exps);
9230 return setResult(e.expressionSemantic(sc));
9233 /* Look for form: e1 = e2.aliasthis.
9235 if (exp.e1.op == EXP.tuple)
9237 TupleDeclaration td = isAliasThisTuple(e2x);
9238 if (!td)
9239 goto Lnomatch;
9241 assert(exp.e1.type.ty == Ttuple);
9242 TypeTuple tt = cast(TypeTuple)exp.e1.type;
9244 Expression e0;
9245 Expression ev = extractSideEffect(sc, "__tup", e0, e2x);
9247 auto iexps = new Expressions();
9248 iexps.push(ev);
9249 for (size_t u = 0; u < iexps.length; u++)
9251 Lexpand:
9252 Expression e = (*iexps)[u];
9254 Parameter arg = Parameter.getNth(tt.arguments, u);
9255 //printf("[%d] iexps.length = %d, ", u, iexps.length);
9256 //printf("e = (%s %s, %s), ", Token.toChars[e.op], e.toChars(), e.type.toChars());
9257 //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
9259 if (!arg || !e.type.implicitConvTo(arg.type))
9261 // expand initializer to tuple
9262 if (expandAliasThisTuples(iexps, u) != -1)
9264 if (iexps.length <= u)
9265 break;
9266 goto Lexpand;
9268 goto Lnomatch;
9271 e2x = new TupleExp(e2x.loc, e0, iexps);
9272 e2x = e2x.expressionSemantic(sc);
9273 if (e2x.op == EXP.error)
9275 result = e2x;
9276 return;
9278 // Do not need to overwrite this.e2
9279 goto Ltupleassign;
9281 Lnomatch:
9284 /* Inside constructor, if this is the first assignment of object field,
9285 * rewrite this to initializing the field.
9287 if (exp.op == EXP.assign
9288 && exp.e1.checkModifiable(sc) == Modifiable.initialization)
9290 //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars());
9291 auto t = exp.type;
9292 exp = new ConstructExp(exp.loc, exp.e1, exp.e2);
9293 exp.type = t;
9295 // https://issues.dlang.org/show_bug.cgi?id=13515
9296 // set Index::modifiable flag for complex AA element initialization
9297 if (auto ie1 = exp.e1.isIndexExp())
9299 Expression e1x = ie1.markSettingAAElem();
9300 if (e1x.op == EXP.error)
9302 result = e1x;
9303 return;
9307 else if (exp.op == EXP.construct && exp.e1.op == EXP.variable &&
9308 (cast(VarExp)exp.e1).var.storage_class & (STC.out_ | STC.ref_))
9310 exp.memset = MemorySet.referenceInit;
9313 if (exp.op == EXP.assign) // skip EXP.blit and EXP.construct, which are initializations
9315 exp.e1.checkSharedAccess(sc);
9316 checkUnsafeAccess(sc, exp.e1, false, true);
9319 checkUnsafeAccess(sc, exp.e2, true, true); // Initializer must always be checked
9321 /* If it is an assignment from a 'foreign' type,
9322 * check for operator overloading.
9324 if (exp.memset == MemorySet.referenceInit)
9326 // If this is an initialization of a reference,
9327 // do nothing
9329 else if (t1.ty == Tstruct)
9331 auto e1x = exp.e1;
9332 auto e2x = exp.e2;
9333 auto sd = (cast(TypeStruct)t1).sym;
9335 if (exp.op == EXP.construct)
9337 Type t2 = e2x.type.toBasetype();
9338 if (t2.ty == Tstruct && sd == (cast(TypeStruct)t2).sym)
9340 sd.size(exp.loc);
9341 if (sd.sizeok != Sizeok.done)
9342 return setError();
9343 if (!sd.ctor)
9344 sd.ctor = sd.searchCtor();
9346 // https://issues.dlang.org/show_bug.cgi?id=15661
9347 // Look for the form from last of comma chain.
9348 auto e2y = lastComma(e2x);
9350 CallExp ce = (e2y.op == EXP.call) ? cast(CallExp)e2y : null;
9351 DotVarExp dve = (ce && ce.e1.op == EXP.dotVariable)
9352 ? cast(DotVarExp)ce.e1 : null;
9353 if (sd.ctor && ce && dve && dve.var.isCtorDeclaration() &&
9354 // https://issues.dlang.org/show_bug.cgi?id=19389
9355 dve.e1.op != EXP.dotVariable &&
9356 e2y.type.implicitConvTo(t1))
9358 /* Look for form of constructor call which is:
9359 * __ctmp.ctor(arguments...)
9362 /* Before calling the constructor, initialize
9363 * variable with a bit copy of the default
9364 * initializer
9366 Expression einit = getInitExp(sd, exp.loc, sc, t1);
9367 if (einit.op == EXP.error)
9369 result = einit;
9370 return;
9373 auto ae = new BlitExp(exp.loc, exp.e1, einit);
9374 ae.type = e1x.type;
9376 /* Replace __ctmp being constructed with e1.
9377 * We need to copy constructor call expression,
9378 * because it may be used in other place.
9380 auto dvx = cast(DotVarExp)dve.copy();
9381 dvx.e1 = e1x;
9382 auto cx = cast(CallExp)ce.copy();
9383 cx.e1 = dvx;
9384 if (checkConstructorEscape(sc, cx, false))
9385 return setError();
9387 Expression e0;
9388 Expression.extractLast(e2x, e0);
9390 auto e = Expression.combine(e0, ae, cx);
9391 e = e.expressionSemantic(sc);
9392 result = e;
9393 return;
9395 // https://issues.dlang.org/show_bug.cgi?id=21586
9396 // Rewrite CondExp or e1 will miss direct construction, e.g.
9397 // e1 = a ? S(1) : ...; -> AST: e1 = a ? (S(0)).this(1) : ...;
9398 // a temporary created and an extra destructor call.
9399 // AST will be rewritten to:
9400 // a ? e1 = 0, e1.this(1) : ...; -> blitting plus construction
9401 if (e2x.op == EXP.question)
9403 /* Rewrite as:
9404 * a ? e1 = b : e1 = c;
9406 CondExp econd = cast(CondExp)e2x;
9407 Expression ea1 = new ConstructExp(econd.e1.loc, e1x, econd.e1);
9408 Expression ea2 = new ConstructExp(econd.e2.loc, e1x, econd.e2);
9409 Expression e = new CondExp(exp.loc, econd.econd, ea1, ea2);
9410 result = e.expressionSemantic(sc);
9411 return;
9413 if (sd.postblit || sd.hasCopyCtor)
9415 /* We have a copy constructor for this
9418 if (e2x.isLvalue())
9420 if (sd.hasCopyCtor)
9422 /* Rewrite as:
9423 * e1 = init, e1.copyCtor(e2);
9425 Expression einit = new BlitExp(exp.loc, exp.e1, getInitExp(sd, exp.loc, sc, t1));
9426 einit.type = e1x.type;
9428 Expression e;
9429 e = new DotIdExp(exp.loc, e1x, Id.ctor);
9430 e = new CallExp(exp.loc, e, e2x);
9431 e = new CommaExp(exp.loc, einit, e);
9433 //printf("e: %s\n", e.toChars());
9435 result = e.expressionSemantic(sc);
9436 return;
9438 else
9440 if (!e2x.type.implicitConvTo(e1x.type))
9442 exp.error("conversion error from `%s` to `%s`",
9443 e2x.type.toChars(), e1x.type.toChars());
9444 return setError();
9447 /* Rewrite as:
9448 * (e1 = e2).postblit();
9450 * Blit assignment e1 = e2 returns a reference to the original e1,
9451 * then call the postblit on it.
9453 Expression e = e1x.copy();
9454 e.type = e.type.mutableOf();
9455 if (e.type.isShared && !sd.type.isShared)
9456 e.type = e.type.unSharedOf();
9457 e = new BlitExp(exp.loc, e, e2x);
9458 e = new DotVarExp(exp.loc, e, sd.postblit, false);
9459 e = new CallExp(exp.loc, e);
9460 result = e.expressionSemantic(sc);
9461 return;
9464 else
9466 /* The struct value returned from the function is transferred
9467 * so should not call the destructor on it.
9469 e2x = valueNoDtor(e2x);
9473 // https://issues.dlang.org/show_bug.cgi?id=19251
9474 // if e2 cannot be converted to e1.type, maybe there is an alias this
9475 if (!e2x.implicitConvTo(t1))
9477 AggregateDeclaration ad2 = isAggregate(e2x.type);
9478 if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
9480 /* Rewrite (e1 op e2) as:
9481 * (e1 op e2.aliasthis)
9483 exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
9484 result = exp.expressionSemantic(sc);
9485 return;
9489 else if (!e2x.implicitConvTo(t1))
9491 sd.size(exp.loc);
9492 if (sd.sizeok != Sizeok.done)
9493 return setError();
9494 if (!sd.ctor)
9495 sd.ctor = sd.searchCtor();
9497 if (sd.ctor)
9499 /* Look for implicit constructor call
9500 * Rewrite as:
9501 * e1 = init, e1.ctor(e2)
9504 /* Fix Issue 5153 : https://issues.dlang.org/show_bug.cgi?id=5153
9505 * Using `new` to initialize a struct object is a common mistake, but
9506 * the error message from the compiler is not very helpful in that
9507 * case. If exp.e2 is a NewExp and the type of new is the same as
9508 * the type as exp.e1 (struct in this case), then we know for sure
9509 * that the user wants to instantiate a struct. This is done to avoid
9510 * issuing an error when the user actually wants to call a constructor
9511 * which receives a class object.
9513 * Foo f = new Foo2(0); is a valid expression if Foo has a constructor
9514 * which receives an instance of a Foo2 class
9516 if (exp.e2.op == EXP.new_)
9518 auto newExp = cast(NewExp)(exp.e2);
9519 if (newExp.newtype && newExp.newtype == t1)
9521 error(exp.loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
9522 newExp.toChars(), newExp.type.toChars(), t1.toChars());
9523 errorSupplemental(exp.loc, "Perhaps remove the `new` keyword?");
9524 return setError();
9528 Expression einit = new BlitExp(exp.loc, e1x, getInitExp(sd, exp.loc, sc, t1));
9529 einit.type = e1x.type;
9531 Expression e;
9532 e = new DotIdExp(exp.loc, e1x, Id.ctor);
9533 e = new CallExp(exp.loc, e, e2x);
9534 e = new CommaExp(exp.loc, einit, e);
9535 e = e.expressionSemantic(sc);
9536 result = e;
9537 return;
9539 if (search_function(sd, Id.call))
9541 /* Look for static opCall
9542 * https://issues.dlang.org/show_bug.cgi?id=2702
9543 * Rewrite as:
9544 * e1 = typeof(e1).opCall(arguments)
9546 e2x = typeDotIdExp(e2x.loc, e1x.type, Id.call);
9547 e2x = new CallExp(exp.loc, e2x, exp.e2);
9549 e2x = e2x.expressionSemantic(sc);
9550 e2x = resolveProperties(sc, e2x);
9551 if (e2x.op == EXP.error)
9553 result = e2x;
9554 return;
9556 if (e2x.checkValue() || e2x.checkSharedAccess(sc))
9557 return setError();
9560 else // https://issues.dlang.org/show_bug.cgi?id=11355
9562 AggregateDeclaration ad2 = isAggregate(e2x.type);
9563 if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
9565 /* Rewrite (e1 op e2) as:
9566 * (e1 op e2.aliasthis)
9568 exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
9569 result = exp.expressionSemantic(sc);
9570 return;
9574 else if (exp.op == EXP.assign)
9576 if (e1x.op == EXP.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray)
9579 * Rewrite:
9580 * aa[key] = e2;
9581 * as:
9582 * ref __aatmp = aa;
9583 * ref __aakey = key;
9584 * ref __aaval = e2;
9585 * (__aakey in __aatmp
9586 * ? __aatmp[__aakey].opAssign(__aaval)
9587 * : ConstructExp(__aatmp[__aakey], __aaval));
9589 // ensure we keep the expr modifiable
9590 Expression esetting = (cast(IndexExp)e1x).markSettingAAElem();
9591 if (esetting.op == EXP.error)
9593 result = esetting;
9594 return;
9596 assert(esetting.op == EXP.index);
9597 IndexExp ie = cast(IndexExp) esetting;
9598 Type t2 = e2x.type.toBasetype();
9600 Expression e0 = null;
9601 Expression ea = extractSideEffect(sc, "__aatmp", e0, ie.e1);
9602 Expression ek = extractSideEffect(sc, "__aakey", e0, ie.e2);
9603 Expression ev = extractSideEffect(sc, "__aaval", e0, e2x);
9605 AssignExp ae = cast(AssignExp)exp.copy();
9606 ae.e1 = new IndexExp(exp.loc, ea, ek);
9607 ae.e1 = ae.e1.expressionSemantic(sc);
9608 ae.e1 = ae.e1.optimize(WANTvalue);
9609 ae.e2 = ev;
9610 Expression e = ae.op_overload(sc);
9611 if (e)
9613 Expression ey = null;
9614 if (t2.ty == Tstruct && sd == t2.toDsymbol(sc))
9616 ey = ev;
9618 else if (!ev.implicitConvTo(ie.type) && sd.ctor)
9620 // Look for implicit constructor call
9621 // Rewrite as S().ctor(e2)
9622 ey = new StructLiteralExp(exp.loc, sd, null);
9623 ey = new DotIdExp(exp.loc, ey, Id.ctor);
9624 ey = new CallExp(exp.loc, ey, ev);
9625 ey = ey.trySemantic(sc);
9627 if (ey)
9629 Expression ex;
9630 ex = new IndexExp(exp.loc, ea, ek);
9631 ex = ex.expressionSemantic(sc);
9632 ex = ex.modifiableLvalue(sc, ex); // allocate new slot
9633 ex = ex.optimize(WANTvalue);
9635 ey = new ConstructExp(exp.loc, ex, ey);
9636 ey = ey.expressionSemantic(sc);
9637 if (ey.op == EXP.error)
9639 result = ey;
9640 return;
9642 ex = e;
9644 // https://issues.dlang.org/show_bug.cgi?id=14144
9645 // The whole expression should have the common type
9646 // of opAssign() return and assigned AA entry.
9647 // Even if there's no common type, expression should be typed as void.
9648 if (!typeMerge(sc, EXP.question, ex, ey))
9650 ex = new CastExp(ex.loc, ex, Type.tvoid);
9651 ey = new CastExp(ey.loc, ey, Type.tvoid);
9653 e = new CondExp(exp.loc, new InExp(exp.loc, ek, ea), ex, ey);
9655 e = Expression.combine(e0, e);
9656 e = e.expressionSemantic(sc);
9657 result = e;
9658 return;
9661 else
9663 Expression e = exp.op_overload(sc);
9664 if (e)
9666 result = e;
9667 return;
9671 else
9672 assert(exp.op == EXP.blit);
9674 if (e2x.checkValue())
9675 return setError();
9677 exp.e1 = e1x;
9678 exp.e2 = e2x;
9680 else if (t1.ty == Tclass)
9682 // Disallow assignment operator overloads for same type
9683 if (exp.op == EXP.assign && !exp.e2.implicitConvTo(exp.e1.type))
9685 Expression e = exp.op_overload(sc);
9686 if (e)
9688 result = e;
9689 return;
9692 if (exp.e2.checkValue())
9693 return setError();
9695 else if (t1.ty == Tsarray)
9697 // SliceExp cannot have static array type without context inference.
9698 assert(exp.e1.op != EXP.slice);
9699 Expression e1x = exp.e1;
9700 Expression e2x = exp.e2;
9702 /* C strings come through as static arrays. May need to adjust the size of the
9703 * string to match the size of e1.
9705 Type t2 = e2x.type.toBasetype();
9706 if (sc.flags & SCOPE.Cfile && e2x.isStringExp() && t2.isTypeSArray())
9708 uinteger_t dim1 = t1.isTypeSArray().dim.toInteger();
9709 uinteger_t dim2 = t2.isTypeSArray().dim.toInteger();
9710 if (dim1 + 1 == dim2 || dim2 < dim1)
9712 auto tsa2 = t2.isTypeSArray();
9713 auto newt = tsa2.next.sarrayOf(dim1).immutableOf();
9714 e2x = castTo(e2x, sc, newt);
9715 exp.e2 = e2x;
9719 if (e2x.implicitConvTo(e1x.type))
9721 if (exp.op != EXP.blit && (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op != EXP.slice && e2x.isLvalue()))
9723 if (e1x.checkPostblit(sc, t1))
9724 return setError();
9727 // e2 matches to t1 because of the implicit length match, so
9728 if (isUnaArrayOp(e2x.op) || isBinArrayOp(e2x.op))
9730 // convert e1 to e1[]
9731 // e.g. e1[] = a[] + b[];
9732 auto sle = new SliceExp(e1x.loc, e1x, null, null);
9733 sle.arrayop = true;
9734 e1x = sle.expressionSemantic(sc);
9736 else
9738 // convert e2 to t1 later
9739 // e.g. e1 = [1, 2, 3];
9742 else
9744 if (e2x.implicitConvTo(t1.nextOf().arrayOf()) > MATCH.nomatch)
9746 uinteger_t dim1 = (cast(TypeSArray)t1).dim.toInteger();
9747 uinteger_t dim2 = dim1;
9748 if (auto ale = e2x.isArrayLiteralExp())
9750 dim2 = ale.elements ? ale.elements.length : 0;
9752 else if (auto se = e2x.isSliceExp())
9754 Type tx = toStaticArrayType(se);
9755 if (tx)
9756 dim2 = (cast(TypeSArray)tx).dim.toInteger();
9758 if (dim1 != dim2)
9760 exp.error("mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2);
9761 return setError();
9765 // May be block or element-wise assignment, so
9766 // convert e1 to e1[]
9767 if (exp.op != EXP.assign)
9769 // If multidimensional static array, treat as one large array
9771 // Find the appropriate array type depending on the assignment, e.g.
9772 // int[3] = int => int[3]
9773 // int[3][2] = int => int[6]
9774 // int[3][2] = int[] => int[3][2]
9775 // int[3][2][4] + int => int[24]
9776 // int[3][2][4] + int[] => int[3][8]
9777 ulong dim = t1.isTypeSArray().dim.toUInteger();
9778 auto type = t1.nextOf();
9780 for (TypeSArray tsa; (tsa = type.isTypeSArray()) !is null; )
9782 import core.checkedint : mulu;
9784 // Accumulate skipped dimensions
9785 bool overflow = false;
9786 dim = mulu(dim, tsa.dim.toUInteger(), overflow);
9787 if (overflow || dim >= uint.max)
9789 // dym exceeds maximum array size
9790 exp.error("static array `%s` size overflowed to %llu",
9791 e1x.type.toChars(), cast(ulong) dim);
9792 return setError();
9795 // Move to the element type
9796 type = tsa.nextOf().toBasetype();
9798 // Rewrite ex1 as a static array if a matching type was found
9799 if (e2x.implicitConvTo(type) > MATCH.nomatch)
9801 e1x.type = type.sarrayOf(dim);
9802 break;
9806 auto sle = new SliceExp(e1x.loc, e1x, null, null);
9807 sle.arrayop = true;
9808 e1x = sle.expressionSemantic(sc);
9810 if (e1x.op == EXP.error)
9811 return setResult(e1x);
9812 if (e2x.op == EXP.error)
9813 return setResult(e2x);
9815 exp.e1 = e1x;
9816 exp.e2 = e2x;
9817 t1 = e1x.type.toBasetype();
9819 /* Check the mutability of e1.
9821 if (auto ale = exp.e1.isArrayLengthExp())
9823 // e1 is not an lvalue, but we let code generator handle it
9825 auto ale1x = ale.e1.modifiableLvalue(sc, exp.e1);
9826 if (ale1x.op == EXP.error)
9827 return setResult(ale1x);
9828 ale.e1 = ale1x;
9830 Type tn = ale.e1.type.toBasetype().nextOf();
9831 checkDefCtor(ale.loc, tn);
9833 Identifier hook = global.params.tracegc ? Id._d_arraysetlengthTTrace : Id._d_arraysetlengthT;
9834 if (!verifyHookExist(exp.loc, *sc, Id._d_arraysetlengthTImpl, "resizing arrays"))
9835 return setError();
9837 exp.e2 = exp.e2.expressionSemantic(sc);
9838 auto lc = lastComma(exp.e2);
9839 lc = lc.optimize(WANTvalue);
9840 // use slice expression when arr.length = 0 to avoid runtime call
9841 if(lc.op == EXP.int64 && lc.toInteger() == 0)
9843 Expression se = new SliceExp(ale.loc, ale.e1, lc, lc);
9844 Expression as = new AssignExp(ale.loc, ale.e1, se);
9845 as = as.expressionSemantic(sc);
9846 auto res = Expression.combine(as, exp.e2);
9847 res.type = ale.type;
9848 return setResult(res);
9851 if (!sc.needsCodegen()) // if compile time creature only
9853 exp.type = Type.tsize_t;
9854 return setResult(exp);
9857 // Lower to object._d_arraysetlengthTImpl!(typeof(e1))._d_arraysetlengthT{,Trace}(e1, e2)
9858 Expression id = new IdentifierExp(ale.loc, Id.empty);
9859 id = new DotIdExp(ale.loc, id, Id.object);
9860 auto tiargs = new Objects();
9861 tiargs.push(ale.e1.type);
9862 id = new DotTemplateInstanceExp(ale.loc, id, Id._d_arraysetlengthTImpl, tiargs);
9863 id = new DotIdExp(ale.loc, id, hook);
9864 id = id.expressionSemantic(sc);
9866 auto arguments = new Expressions();
9867 arguments.reserve(5);
9868 if (global.params.tracegc)
9870 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
9871 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
9872 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
9873 arguments.push(new StringExp(exp.loc, funcname.toDString()));
9875 arguments.push(ale.e1);
9876 arguments.push(exp.e2);
9878 Expression ce = new CallExp(ale.loc, id, arguments).expressionSemantic(sc);
9879 auto res = new LoweredAssignExp(exp, ce);
9880 // if (global.params.verbose)
9881 // message("lowered %s =>\n %s", exp.toChars(), res.toChars());
9882 res.type = Type.tsize_t;
9883 return setResult(res);
9885 else if (auto se = exp.e1.isSliceExp())
9887 Type tn = se.type.nextOf();
9888 const fun = sc.func;
9889 if (exp.op == EXP.assign && !tn.isMutable() &&
9890 // allow modifiation in module ctor, see
9891 // https://issues.dlang.org/show_bug.cgi?id=9884
9892 (!fun || (fun && !fun.isStaticCtorDeclaration())))
9894 exp.error("slice `%s` is not mutable", se.toChars());
9895 return setError();
9898 if (exp.op == EXP.assign && !tn.baseElemOf().isAssignable())
9900 exp.error("slice `%s` is not mutable, struct `%s` has immutable members",
9901 exp.e1.toChars(), tn.baseElemOf().toChars());
9902 result = ErrorExp.get();
9903 return;
9906 // For conditional operator, both branches need conversion.
9907 while (se.e1.op == EXP.slice)
9908 se = cast(SliceExp)se.e1;
9909 if (se.e1.op == EXP.question && se.e1.type.toBasetype().ty == Tsarray)
9911 se.e1 = se.e1.modifiableLvalue(sc, exp.e1);
9912 if (se.e1.op == EXP.error)
9913 return setResult(se.e1);
9916 else
9918 if (t1.ty == Tsarray && exp.op == EXP.assign)
9920 Type tn = exp.e1.type.nextOf();
9921 if (tn && !tn.baseElemOf().isAssignable())
9923 exp.error("array `%s` is not mutable, struct `%s` has immutable members",
9924 exp.e1.toChars(), tn.baseElemOf().toChars());
9925 result = ErrorExp.get();
9926 return;
9930 Expression e1x = exp.e1;
9932 // Try to do a decent error message with the expression
9933 // before it gets constant folded
9934 if (exp.op == EXP.assign)
9935 e1x = e1x.modifiableLvalue(sc, e1old);
9937 e1x = e1x.optimize(WANTvalue, /*keepLvalue*/ true);
9939 if (e1x.op == EXP.error)
9941 result = e1x;
9942 return;
9944 exp.e1 = e1x;
9947 /* Tweak e2 based on the type of e1.
9949 Expression e2x = exp.e2;
9950 Type t2 = e2x.type.toBasetype();
9952 // If it is a array, get the element type. Note that it may be
9953 // multi-dimensional.
9954 Type telem = t1;
9955 while (telem.ty == Tarray)
9956 telem = telem.nextOf();
9958 if (exp.e1.op == EXP.slice && t1.nextOf() &&
9959 (telem.ty != Tvoid || e2x.op == EXP.null_) &&
9960 e2x.implicitConvTo(t1.nextOf()))
9962 // Check for block assignment. If it is of type void[], void[][], etc,
9963 // '= null' is the only allowable block assignment (Bug 7493)
9964 exp.memset = MemorySet.blockAssign; // make it easy for back end to tell what this is
9965 e2x = e2x.implicitCastTo(sc, t1.nextOf());
9966 if (exp.op != EXP.blit && e2x.isLvalue() && exp.e1.checkPostblit(sc, t1.nextOf()))
9967 return setError();
9969 else if (exp.e1.op == EXP.slice &&
9970 (t2.ty == Tarray || t2.ty == Tsarray) &&
9971 t2.nextOf().implicitConvTo(t1.nextOf()))
9973 // Check element-wise assignment.
9975 /* If assigned elements number is known at compile time,
9976 * check the mismatch.
9978 SliceExp se1 = cast(SliceExp)exp.e1;
9979 TypeSArray tsa1 = cast(TypeSArray)toStaticArrayType(se1);
9980 TypeSArray tsa2 = null;
9981 if (auto ale = e2x.isArrayLiteralExp())
9982 tsa2 = cast(TypeSArray)t2.nextOf().sarrayOf(ale.elements.length);
9983 else if (auto se = e2x.isSliceExp())
9984 tsa2 = cast(TypeSArray)toStaticArrayType(se);
9985 else
9986 tsa2 = t2.isTypeSArray();
9988 if (tsa1 && tsa2)
9990 uinteger_t dim1 = tsa1.dim.toInteger();
9991 uinteger_t dim2 = tsa2.dim.toInteger();
9992 if (dim1 != dim2)
9994 exp.error("mismatched array lengths %d and %d for assignment `%s`", cast(int)dim1, cast(int)dim2, exp.toChars());
9995 return setError();
9999 if (exp.op != EXP.blit &&
10000 (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() ||
10001 e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() ||
10002 e2x.op != EXP.slice && e2x.isLvalue()))
10004 if (exp.e1.checkPostblit(sc, t1.nextOf()))
10005 return setError();
10008 if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign &&
10009 e2x.op != EXP.slice && e2x.op != EXP.assign &&
10010 e2x.op != EXP.arrayLiteral && e2x.op != EXP.string_ &&
10011 !(e2x.op == EXP.add || e2x.op == EXP.min ||
10012 e2x.op == EXP.mul || e2x.op == EXP.div ||
10013 e2x.op == EXP.mod || e2x.op == EXP.xor ||
10014 e2x.op == EXP.and || e2x.op == EXP.or ||
10015 e2x.op == EXP.pow ||
10016 e2x.op == EXP.tilde || e2x.op == EXP.negate))
10018 const(char)* e1str = exp.e1.toChars();
10019 const(char)* e2str = e2x.toChars();
10020 exp.warning("explicit element-wise assignment `%s = (%s)[]` is better than `%s = %s`", e1str, e2str, e1str, e2str);
10023 Type t2n = t2.nextOf();
10024 Type t1n = t1.nextOf();
10025 int offset;
10026 if (t2n.equivalent(t1n) ||
10027 t1n.isBaseOf(t2n, &offset) && offset == 0)
10029 /* Allow copy of distinct qualifier elements.
10030 * eg.
10031 * char[] dst; const(char)[] src;
10032 * dst[] = src;
10034 * class C {} class D : C {}
10035 * C[2] ca; D[] da;
10036 * ca[] = da;
10038 if (isArrayOpValid(e2x))
10040 // Don't add CastExp to keep AST for array operations
10041 e2x = e2x.copy();
10042 e2x.type = exp.e1.type.constOf();
10044 else
10045 e2x = e2x.castTo(sc, exp.e1.type.constOf());
10047 else
10049 /* https://issues.dlang.org/show_bug.cgi?id=15778
10050 * A string literal has an array type of immutable
10051 * elements by default, and normally it cannot be convertible to
10052 * array type of mutable elements. But for element-wise assignment,
10053 * elements need to be const at best. So we should give a chance
10054 * to change code unit size for polysemous string literal.
10056 if (e2x.op == EXP.string_)
10057 e2x = e2x.implicitCastTo(sc, exp.e1.type.constOf());
10058 else
10059 e2x = e2x.implicitCastTo(sc, exp.e1.type);
10061 if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid)
10063 if (sc.setUnsafe(false, exp.loc, "cannot copy `void[]` to `void[]` in `@safe` code"))
10064 return setError();
10067 else
10069 if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign &&
10070 t1.ty == Tarray && t2.ty == Tsarray &&
10071 e2x.op != EXP.slice &&
10072 t2.implicitConvTo(t1))
10074 // Disallow ar[] = sa (Converted to ar[] = sa[])
10075 // Disallow da = sa (Converted to da = sa[])
10076 const(char)* e1str = exp.e1.toChars();
10077 const(char)* e2str = e2x.toChars();
10078 const(char)* atypestr = exp.e1.op == EXP.slice ? "element-wise" : "slice";
10079 exp.warning("explicit %s assignment `%s = (%s)[]` is better than `%s = %s`", atypestr, e1str, e2str, e1str, e2str);
10081 if (exp.op == EXP.blit)
10082 e2x = e2x.castTo(sc, exp.e1.type);
10083 else
10085 e2x = e2x.implicitCastTo(sc, exp.e1.type);
10087 // Fix Issue 13435: https://issues.dlang.org/show_bug.cgi?id=13435
10089 // If the implicit cast has failed and the assign expression is
10090 // the initialization of a struct member field
10091 if (e2x.op == EXP.error && exp.op == EXP.construct && t1.ty == Tstruct)
10093 scope sd = (cast(TypeStruct)t1).sym;
10094 Dsymbol opAssign = search_function(sd, Id.assign);
10096 // and the struct defines an opAssign
10097 if (opAssign)
10099 // offer more information about the cause of the problem
10100 errorSupplemental(exp.loc,
10101 "`%s` is the first assignment of `%s` therefore it represents its initialization",
10102 exp.toChars(), exp.e1.toChars());
10103 errorSupplemental(exp.loc,
10104 "`opAssign` methods are not used for initialization, but for subsequent assignments");
10109 if (e2x.op == EXP.error)
10111 result = e2x;
10112 return;
10114 exp.e2 = e2x;
10115 t2 = exp.e2.type.toBasetype();
10117 /* Look for array operations
10119 if ((t2.ty == Tarray || t2.ty == Tsarray) && isArrayOpValid(exp.e2))
10121 // Look for valid array operations
10122 if (exp.memset != MemorySet.blockAssign &&
10123 exp.e1.op == EXP.slice &&
10124 (isUnaArrayOp(exp.e2.op) || isBinArrayOp(exp.e2.op)))
10126 exp.type = exp.e1.type;
10127 if (exp.op == EXP.construct) // https://issues.dlang.org/show_bug.cgi?id=10282
10128 // tweak mutability of e1 element
10129 exp.e1.type = exp.e1.type.nextOf().mutableOf().arrayOf();
10130 result = arrayOp(exp, sc);
10131 return;
10134 // Drop invalid array operations in e2
10135 // d = a[] + b[], d = (a[] + b[])[0..2], etc
10136 if (checkNonAssignmentArrayOp(exp.e2, exp.memset != MemorySet.blockAssign && exp.op == EXP.assign))
10137 return setError();
10139 // Remains valid array assignments
10140 // d = d[], d = [1,2,3], etc
10143 /* Don't allow assignment to classes that were allocated on the stack with:
10144 * scope Class c = new Class();
10146 if (exp.e1.op == EXP.variable && exp.op == EXP.assign)
10148 VarExp ve = cast(VarExp)exp.e1;
10149 VarDeclaration vd = ve.var.isVarDeclaration();
10150 if (vd && vd.onstack)
10152 assert(t1.ty == Tclass);
10153 exp.error("cannot rebind scope variables");
10157 if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.ident == Id.ctfe)
10159 exp.error("cannot modify compiler-generated variable `__ctfe`");
10162 exp.type = exp.e1.type;
10163 assert(exp.type);
10164 auto assignElem = exp.e2;
10165 auto res = exp.op == EXP.assign ? exp.reorderSettingAAElem(sc) : exp;
10166 /* https://issues.dlang.org/show_bug.cgi?id=22366
10168 * `reorderSettingAAElem` creates a tree of comma expressions, however,
10169 * `checkAssignExp` expects only AssignExps.
10171 if (res == exp) // no `AA[k] = v` rewrite was performed
10172 checkAssignEscape(sc, res, false, false);
10173 else
10174 checkNewEscape(sc, assignElem, false); // assigning to AA puts it on heap
10176 if (auto ae = res.isConstructExp())
10178 Type t1b = ae.e1.type.toBasetype();
10179 if (t1b.ty != Tsarray && t1b.ty != Tarray)
10180 return setResult(res);
10182 // only non-trivial array constructions may need to be lowered (non-POD elements basically)
10183 Type t1e = t1b.nextOf();
10184 TypeStruct ts = t1e.baseElemOf().isTypeStruct();
10185 if (!ts || (!ts.sym.postblit && !ts.sym.hasCopyCtor && !ts.sym.dtor))
10186 return setResult(res);
10188 // don't lower ref-constructions etc.
10189 if (!(t1b.ty == Tsarray || ae.e1.isSliceExp) ||
10190 (ae.e1.isVarExp && ae.e1.isVarExp.var.isVarDeclaration.isReference))
10191 return setResult(res);
10193 // Construction from an equivalent other array?
10194 // Only lower with lvalue RHS elements; let the glue layer move rvalue elements.
10195 Type t2b = ae.e2.type.toBasetype();
10196 // skip over a (possibly implicit) cast of a static array RHS to a slice
10197 Expression rhs = ae.e2;
10198 Type rhsType = t2b;
10199 if (t2b.ty == Tarray)
10201 if (auto ce = rhs.isCastExp())
10203 auto ct = ce.e1.type.toBasetype();
10204 if (ct.ty == Tsarray)
10206 rhs = ce.e1;
10207 rhsType = ct;
10212 if (!sc.needsCodegen()) // interpreter can handle these
10213 return setResult(res);
10215 const lowerToArrayCtor =
10216 ( (rhsType.ty == Tarray && !rhs.isArrayLiteralExp) ||
10217 (rhsType.ty == Tsarray && rhs.isLvalue) ) &&
10218 t1e.equivalent(t2b.nextOf);
10220 // Construction from a single element?
10221 // If the RHS is an rvalue, then we'll need to make a temporary for it (copied multiple times).
10222 const lowerToArraySetCtor = !lowerToArrayCtor && t1e.equivalent(t2b);
10224 if (lowerToArrayCtor || lowerToArraySetCtor)
10226 auto func = lowerToArrayCtor ? Id._d_arrayctor : Id._d_arraysetctor;
10227 const other = lowerToArrayCtor ? "other array" : "value";
10228 if (!verifyHookExist(exp.loc, *sc, func, "construct array with " ~ other, Id.object))
10229 return setError();
10231 // Lower to object._d_array{,set}ctor(e1, e2)
10232 Expression id = new IdentifierExp(exp.loc, Id.empty);
10233 id = new DotIdExp(exp.loc, id, Id.object);
10234 id = new DotIdExp(exp.loc, id, func);
10236 auto arguments = new Expressions();
10237 arguments.push(new CastExp(ae.loc, ae.e1, t1e.arrayOf).expressionSemantic(sc));
10238 if (lowerToArrayCtor)
10240 arguments.push(new CastExp(ae.loc, rhs, t2b.nextOf.arrayOf).expressionSemantic(sc));
10241 Expression ce = new CallExp(exp.loc, id, arguments);
10242 res = ce.expressionSemantic(sc);
10244 else
10246 Expression e0;
10247 // promote an rvalue RHS element to a temporary, it's passed by ref to _d_arraysetctor
10248 if (!ae.e2.isLvalue)
10250 auto vd = copyToTemp(STC.scope_, "__setctor", ae.e2);
10251 e0 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc);
10252 arguments.push(new VarExp(vd.loc, vd).expressionSemantic(sc));
10254 else
10255 arguments.push(ae.e2);
10257 Expression ce = new CallExp(exp.loc, id, arguments);
10258 res = Expression.combine(e0, ce).expressionSemantic(sc);
10261 if (global.params.verbose)
10262 message("lowered %s =>\n %s", exp.toChars(), res.toChars());
10265 else if (auto ae = res.isAssignExp())
10266 res = lowerArrayAssign(ae);
10267 else if (auto ce = res.isCommaExp())
10269 if (auto ae1 = ce.e1.isAssignExp())
10270 ce.e1 = lowerArrayAssign(ae1, true);
10271 if (auto ae2 = ce.e2.isAssignExp())
10272 ce.e2 = lowerArrayAssign(ae2, true);
10275 return setResult(res);
10278 /***************************************
10279 * Lower AssignExp to `_d_array{setassign,assign_l,assign_r}` if needed.
10281 * Params:
10282 * ae = the AssignExp to be lowered
10283 * fromCommaExp = indicates whether `ae` is part of a CommaExp or not,
10284 * so no unnecessary temporay variable is created.
10285 * Returns:
10286 * a CommaExp contiaining call a to `_d_array{setassign,assign_l,assign_r}`
10287 * if needed or `ae` otherwise
10289 private Expression lowerArrayAssign(AssignExp ae, bool fromCommaExp = false)
10291 Type t1b = ae.e1.type.toBasetype();
10292 if (t1b.ty != Tsarray && t1b.ty != Tarray)
10293 return ae;
10295 const isArrayAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) &&
10296 (ae.e2.type.ty == Tsarray || ae.e2.type.ty == Tarray) &&
10297 (ae.e1.type.nextOf() && ae.e2.type.nextOf() && ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf()));
10299 const isArraySetAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) &&
10300 (ae.e1.type.nextOf() && ae.e2.type.implicitConvTo(ae.e1.type.nextOf()));
10302 if (!isArrayAssign && !isArraySetAssign)
10303 return ae;
10305 const ts = t1b.nextOf().baseElemOf().isTypeStruct();
10306 if (!ts || (!ts.sym.postblit && !ts.sym.dtor))
10307 return ae;
10309 Expression res;
10310 Identifier func = isArraySetAssign ? Id._d_arraysetassign :
10311 ae.e2.isLvalue() || ae.e2.isSliceExp() ? Id._d_arrayassign_l : Id._d_arrayassign_r;
10313 // Lower to `.object._d_array{setassign,assign_l,assign_r}(e1, e2)``
10314 Expression id = new IdentifierExp(ae.loc, Id.empty);
10315 id = new DotIdExp(ae.loc, id, Id.object);
10316 id = new DotIdExp(ae.loc, id, func);
10318 auto arguments = new Expressions();
10319 arguments.push(new CastExp(ae.loc, ae.e1, ae.e1.type.nextOf.arrayOf)
10320 .expressionSemantic(sc));
10322 Expression eValue2, value2 = ae.e2;
10323 if (isArrayAssign && value2.isLvalue())
10324 value2 = new CastExp(ae.loc, ae.e2, ae.e2.type.nextOf.arrayOf())
10325 .expressionSemantic(sc);
10326 else if (!fromCommaExp &&
10327 (isArrayAssign || (isArraySetAssign && !value2.isLvalue())))
10329 // Rvalues from CommaExps were introduced in `visit(AssignExp)`
10330 // and are temporary variables themselves. Rvalues from trivial
10331 // SliceExps are simply passed by reference without any copying.
10333 // `__assigntmp` will be destroyed together with the array `ae.e1`.
10334 // When `ae.e2` is a variadic arg array, it is also `scope`, so
10335 // `__assigntmp` may also be scope.
10336 StorageClass stc = STC.nodtor;
10337 if (isArrayAssign)
10338 stc |= STC.rvalue | STC.scope_;
10340 auto vd = copyToTemp(stc, "__assigntmp", ae.e2);
10341 eValue2 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc);
10342 value2 = new VarExp(vd.loc, vd).expressionSemantic(sc);
10344 arguments.push(value2);
10346 Expression ce = new CallExp(ae.loc, id, arguments);
10347 res = Expression.combine(eValue2, ce).expressionSemantic(sc);
10348 if (isArrayAssign)
10349 res = Expression.combine(res, ae.e1).expressionSemantic(sc);
10351 if (global.params.verbose)
10352 message("lowered %s =>\n %s", ae.toChars(), res.toChars());
10354 res = new LoweredAssignExp(ae, res);
10355 res.type = ae.type;
10357 return res;
10360 override void visit(PowAssignExp exp)
10362 if (exp.type)
10364 result = exp;
10365 return;
10368 Expression e = exp.op_overload(sc);
10369 if (e)
10371 result = e;
10372 return;
10375 if (exp.e1.checkReadModifyWrite(exp.op, exp.e2))
10376 return setError();
10378 assert(exp.e1.type && exp.e2.type);
10379 if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
10381 if (checkNonAssignmentArrayOp(exp.e1))
10382 return setError();
10384 // T[] ^^= ...
10385 if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
10387 // T[] ^^= T
10388 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
10390 else if (Expression ex = typeCombine(exp, sc))
10392 result = ex;
10393 return;
10396 // Check element types are arithmetic
10397 Type tb1 = exp.e1.type.nextOf().toBasetype();
10398 Type tb2 = exp.e2.type.toBasetype();
10399 if (tb2.ty == Tarray || tb2.ty == Tsarray)
10400 tb2 = tb2.nextOf().toBasetype();
10401 if ((tb1.isintegral() || tb1.isfloating()) && (tb2.isintegral() || tb2.isfloating()))
10403 exp.type = exp.e1.type;
10404 result = arrayOp(exp, sc);
10405 return;
10408 else
10410 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
10413 if ((exp.e1.type.isintegral() || exp.e1.type.isfloating()) && (exp.e2.type.isintegral() || exp.e2.type.isfloating()))
10415 Expression e0 = null;
10416 e = exp.reorderSettingAAElem(sc);
10417 e = Expression.extractLast(e, e0);
10418 assert(e == exp);
10420 if (exp.e1.op == EXP.variable)
10422 // Rewrite: e1 = e1 ^^ e2
10423 e = new PowExp(exp.loc, exp.e1.syntaxCopy(), exp.e2);
10424 e = new AssignExp(exp.loc, exp.e1, e);
10426 else
10428 // Rewrite: ref tmp = e1; tmp = tmp ^^ e2
10429 auto v = copyToTemp(STC.ref_, "__powtmp", exp.e1);
10430 auto de = new DeclarationExp(exp.e1.loc, v);
10431 auto ve = new VarExp(exp.e1.loc, v);
10432 e = new PowExp(exp.loc, ve, exp.e2);
10433 e = new AssignExp(exp.loc, new VarExp(exp.e1.loc, v), e);
10434 e = new CommaExp(exp.loc, de, e);
10436 e = Expression.combine(e0, e);
10437 e = e.expressionSemantic(sc);
10438 result = e;
10439 return;
10441 result = exp.incompatibleTypes();
10444 override void visit(CatAssignExp exp)
10446 if (exp.type)
10448 result = exp;
10449 return;
10452 //printf("CatAssignExp::semantic() %s\n", exp.toChars());
10453 Expression e = exp.op_overload(sc);
10454 if (e)
10456 result = e;
10457 return;
10460 if (SliceExp se = exp.e1.isSliceExp())
10462 if (se.e1.type.toBasetype().ty == Tsarray)
10464 exp.error("cannot append to static array `%s`", se.e1.type.toChars());
10465 return setError();
10469 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
10470 if (exp.e1.op == EXP.error)
10472 result = exp.e1;
10473 return;
10475 if (exp.e2.op == EXP.error)
10477 result = exp.e2;
10478 return;
10481 if (checkNonAssignmentArrayOp(exp.e2))
10482 return setError();
10484 Type tb1 = exp.e1.type.toBasetype();
10485 Type tb1next = tb1.nextOf();
10486 Type tb2 = exp.e2.type.toBasetype();
10488 /* Possibilities:
10489 * EXP.concatenateAssign: appending T[] to T[]
10490 * EXP.concatenateElemAssign: appending T to T[]
10491 * EXP.concatenateDcharAssign: appending dchar to T[]
10493 if ((tb1.ty == Tarray) &&
10494 (tb2.ty == Tarray || tb2.ty == Tsarray) &&
10495 (exp.e2.implicitConvTo(exp.e1.type) ||
10496 (tb2.nextOf().implicitConvTo(tb1next) &&
10497 (tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial)))))
10499 // EXP.concatenateAssign
10500 assert(exp.op == EXP.concatenateAssign);
10501 if (exp.e1.checkPostblit(sc, tb1next))
10502 return setError();
10504 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
10506 else if ((tb1.ty == Tarray) && exp.e2.implicitConvTo(tb1next))
10508 /* https://issues.dlang.org/show_bug.cgi?id=19782
10510 * If e2 is implicitly convertible to tb1next, the conversion
10511 * might be done through alias this, in which case, e2 needs to
10512 * be modified accordingly (e2 => e2.aliasthis).
10514 if (tb2.ty == Tstruct && (cast(TypeStruct)tb2).implicitConvToThroughAliasThis(tb1next))
10515 goto Laliasthis;
10516 if (tb2.ty == Tclass && (cast(TypeClass)tb2).implicitConvToThroughAliasThis(tb1next))
10517 goto Laliasthis;
10518 // Append element
10519 if (exp.e2.checkPostblit(sc, tb2))
10520 return setError();
10522 if (checkNewEscape(sc, exp.e2, false))
10523 return setError();
10525 exp = new CatElemAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, tb1next));
10526 exp.e2 = doCopyOrMove(sc, exp.e2);
10528 else if (tb1.ty == Tarray &&
10529 (tb1next.ty == Tchar || tb1next.ty == Twchar) &&
10530 exp.e2.type.ty != tb1next.ty &&
10531 exp.e2.implicitConvTo(Type.tdchar))
10533 // Append dchar to char[] or wchar[]
10534 exp = new CatDcharAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, Type.tdchar));
10536 /* Do not allow appending wchar to char[] because if wchar happens
10537 * to be a surrogate pair, nothing good can result.
10540 else
10542 // Try alias this on first operand
10543 static Expression tryAliasThisForLhs(BinAssignExp exp, Scope* sc)
10545 AggregateDeclaration ad1 = isAggregate(exp.e1.type);
10546 if (!ad1 || !ad1.aliasthis)
10547 return null;
10549 /* Rewrite (e1 op e2) as:
10550 * (e1.aliasthis op e2)
10552 if (isRecursiveAliasThis(exp.att1, exp.e1.type))
10553 return null;
10554 //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
10555 Expression e1 = new DotIdExp(exp.loc, exp.e1, ad1.aliasthis.ident);
10556 BinExp be = cast(BinExp)exp.copy();
10557 be.e1 = e1;
10558 return be.trySemantic(sc);
10561 // Try alias this on second operand
10562 static Expression tryAliasThisForRhs(BinAssignExp exp, Scope* sc)
10564 AggregateDeclaration ad2 = isAggregate(exp.e2.type);
10565 if (!ad2 || !ad2.aliasthis)
10566 return null;
10567 /* Rewrite (e1 op e2) as:
10568 * (e1 op e2.aliasthis)
10570 if (isRecursiveAliasThis(exp.att2, exp.e2.type))
10571 return null;
10572 //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
10573 Expression e2 = new DotIdExp(exp.loc, exp.e2, ad2.aliasthis.ident);
10574 BinExp be = cast(BinExp)exp.copy();
10575 be.e2 = e2;
10576 return be.trySemantic(sc);
10579 Laliasthis:
10580 result = tryAliasThisForLhs(exp, sc);
10581 if (result)
10582 return;
10584 result = tryAliasThisForRhs(exp, sc);
10585 if (result)
10586 return;
10588 exp.error("cannot append type `%s` to type `%s`", tb2.toChars(), tb1.toChars());
10589 return setError();
10592 if (exp.e2.checkValue() || exp.e2.checkSharedAccess(sc))
10593 return setError();
10595 exp.type = exp.e1.type;
10596 auto assignElem = exp.e2;
10597 auto res = exp.reorderSettingAAElem(sc);
10598 if (res != exp) // `AA[k] = v` rewrite was performed
10599 checkNewEscape(sc, assignElem, false);
10600 else if (exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign)
10601 checkAssignEscape(sc, res, false, false);
10603 result = res;
10605 if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) &&
10606 sc.needsCodegen())
10608 // if aa ordering is triggered, `res` will be a CommaExp
10609 // and `.e2` will be the rewritten original expression.
10611 // `output` will point to the expression that the lowering will overwrite
10612 Expression* output;
10613 if (auto comma = res.isCommaExp())
10615 output = &comma.e2;
10616 // manual cast because it could be either CatAssignExp or CatElemAssignExp
10617 exp = cast(CatAssignExp)comma.e2;
10619 else
10621 output = &result;
10622 exp = cast(CatAssignExp)result;
10625 if (exp.op == EXP.concatenateAssign)
10627 Identifier hook = global.params.tracegc ? Id._d_arrayappendTTrace : Id._d_arrayappendT;
10629 if (!verifyHookExist(exp.loc, *sc, hook, "appending array to arrays", Id.object))
10630 return setError();
10632 // Lower to object._d_arrayappendT{,Trace}({file, line, funcname}, e1, e2)
10633 Expression id = new IdentifierExp(exp.loc, Id.empty);
10634 id = new DotIdExp(exp.loc, id, Id.object);
10635 id = new DotIdExp(exp.loc, id, hook);
10637 auto arguments = new Expressions();
10638 arguments.reserve(5);
10639 if (global.params.tracegc)
10641 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
10642 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
10643 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
10644 arguments.push(new StringExp(exp.loc, funcname.toDString()));
10647 arguments.push(exp.e1);
10648 arguments.push(exp.e2);
10649 Expression ce = new CallExp(exp.loc, id, arguments);
10650 *output = ce.expressionSemantic(sc);
10652 else if (exp.op == EXP.concatenateElemAssign)
10654 /* Do not lower concats to the indices array returned by
10655 *`static foreach`, as this array is only used at compile-time.
10657 if (auto ve = exp.e1.isVarExp)
10659 import core.stdc.ctype : isdigit;
10660 // The name of the indices array that static foreach loops uses.
10661 // See dmd.cond.lowerNonArrayAggregate
10662 enum varName = "__res";
10663 const(char)[] id = ve.var.ident.toString;
10664 if (ve.var.storage_class & STC.temp && id.length > varName.length &&
10665 id[0 .. varName.length] == varName && id[varName.length].isdigit)
10666 return;
10669 Identifier hook = global.params.tracegc ? Id._d_arrayappendcTXTrace : Id._d_arrayappendcTX;
10670 if (!verifyHookExist(exp.loc, *sc, Id._d_arrayappendcTXImpl, "appending element to arrays", Id.object))
10671 return setError();
10673 // Lower to object._d_arrayappendcTXImpl!(typeof(e1))._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2
10674 Expression id = new IdentifierExp(exp.loc, Id.empty);
10675 id = new DotIdExp(exp.loc, id, Id.object);
10676 auto tiargs = new Objects();
10677 tiargs.push(exp.e1.type);
10678 id = new DotTemplateInstanceExp(exp.loc, id, Id._d_arrayappendcTXImpl, tiargs);
10679 id = new DotIdExp(exp.loc, id, hook);
10681 auto arguments = new Expressions();
10682 arguments.reserve(5);
10683 if (global.params.tracegc)
10685 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
10686 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
10687 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
10688 arguments.push(new StringExp(exp.loc, funcname.toDString()));
10691 Expression eValue1;
10692 Expression value1 = extractSideEffect(sc, "__appendtmp", eValue1, exp.e1);
10694 arguments.push(value1);
10695 arguments.push(new IntegerExp(exp.loc, 1, Type.tsize_t));
10697 Expression ce = new CallExp(exp.loc, id, arguments);
10699 Expression eValue2;
10700 Expression value2 = exp.e2;
10701 if (!value2.isVarExp() && !value2.isConst())
10703 /* Before the template hook, this check was performed in e2ir.d
10704 * for expressions like `a ~= a[$-1]`. Here, $ will be modified
10705 * by calling `_d_arrayappendcT`, so we need to save `a[$-1]` in
10706 * a temporary variable.
10708 value2 = extractSideEffect(sc, "__appendtmp", eValue2, value2, true);
10709 exp.e2 = value2;
10711 // `__appendtmp*` will be destroyed together with the array `exp.e1`.
10712 auto vd = eValue2.isDeclarationExp().declaration.isVarDeclaration();
10713 vd.storage_class |= STC.nodtor;
10714 // Be more explicit that this "declaration" is local to the expression
10715 vd.storage_class |= STC.exptemp;
10718 auto ale = new ArrayLengthExp(exp.loc, value1);
10719 auto elem = new IndexExp(exp.loc, value1, new MinExp(exp.loc, ale, IntegerExp.literal!1));
10720 auto ae = new ConstructExp(exp.loc, elem, value2);
10722 auto e0 = Expression.combine(ce, ae).expressionSemantic(sc);
10723 e0 = Expression.combine(e0, value1);
10724 e0 = Expression.combine(eValue1, e0);
10726 e0 = Expression.combine(eValue2, e0);
10728 *output = e0.expressionSemantic(sc);
10734 override void visit(AddExp exp)
10736 static if (LOGSEMANTIC)
10738 printf("AddExp::semantic('%s')\n", exp.toChars());
10740 if (exp.type)
10742 result = exp;
10743 return;
10746 if (Expression ex = binSemanticProp(exp, sc))
10748 result = ex;
10749 return;
10751 Expression e = exp.op_overload(sc);
10752 if (e)
10754 result = e;
10755 return;
10758 /* ImportC: convert arrays to pointers, functions to pointers to functions
10760 exp.e1 = exp.e1.arrayFuncConv(sc);
10761 exp.e2 = exp.e2.arrayFuncConv(sc);
10763 Type tb1 = exp.e1.type.toBasetype();
10764 Type tb2 = exp.e2.type.toBasetype();
10766 bool err = false;
10767 if (tb1.ty == Tdelegate || tb1.isPtrToFunction())
10769 err |= exp.e1.checkArithmetic() || exp.e1.checkSharedAccess(sc);
10771 if (tb2.ty == Tdelegate || tb2.isPtrToFunction())
10773 err |= exp.e2.checkArithmetic() || exp.e2.checkSharedAccess(sc);
10775 if (err)
10776 return setError();
10778 if (tb1.ty == Tpointer && exp.e2.type.isintegral() || tb2.ty == Tpointer && exp.e1.type.isintegral())
10780 result = scaleFactor(exp, sc);
10781 return;
10784 if (tb1.ty == Tpointer && tb2.ty == Tpointer)
10786 result = exp.incompatibleTypes();
10787 return;
10790 if (Expression ex = typeCombine(exp, sc))
10792 result = ex;
10793 return;
10796 Type tb = exp.type.toBasetype();
10797 if (tb.ty == Tarray || tb.ty == Tsarray)
10799 if (!isArrayOpValid(exp))
10801 result = arrayOpInvalidError(exp);
10802 return;
10804 result = exp;
10805 return;
10808 tb1 = exp.e1.type.toBasetype();
10809 if (!target.isVectorOpSupported(tb1, exp.op, tb2))
10811 result = exp.incompatibleTypes();
10812 return;
10814 if ((tb1.isreal() && exp.e2.type.isimaginary()) || (tb1.isimaginary() && exp.e2.type.isreal()))
10816 switch (exp.type.toBasetype().ty)
10818 case Tfloat32:
10819 case Timaginary32:
10820 exp.type = Type.tcomplex32;
10821 break;
10823 case Tfloat64:
10824 case Timaginary64:
10825 exp.type = Type.tcomplex64;
10826 break;
10828 case Tfloat80:
10829 case Timaginary80:
10830 exp.type = Type.tcomplex80;
10831 break;
10833 default:
10834 assert(0);
10837 result = exp;
10840 override void visit(MinExp exp)
10842 static if (LOGSEMANTIC)
10844 printf("MinExp::semantic('%s')\n", exp.toChars());
10846 if (exp.type)
10848 result = exp;
10849 return;
10852 if (Expression ex = binSemanticProp(exp, sc))
10854 result = ex;
10855 return;
10857 Expression e = exp.op_overload(sc);
10858 if (e)
10860 result = e;
10861 return;
10864 /* ImportC: convert arrays to pointers, functions to pointers to functions
10866 exp.e1 = exp.e1.arrayFuncConv(sc);
10867 exp.e2 = exp.e2.arrayFuncConv(sc);
10869 Type t1 = exp.e1.type.toBasetype();
10870 Type t2 = exp.e2.type.toBasetype();
10872 bool err = false;
10873 if (t1.ty == Tdelegate || t1.isPtrToFunction())
10875 err |= exp.e1.checkArithmetic() || exp.e1.checkSharedAccess(sc);
10877 if (t2.ty == Tdelegate || t2.isPtrToFunction())
10879 err |= exp.e2.checkArithmetic() || exp.e2.checkSharedAccess(sc);
10881 if (err)
10882 return setError();
10884 if (t1.ty == Tpointer)
10886 if (t2.ty == Tpointer)
10888 // https://dlang.org/spec/expression.html#add_expressions
10889 // "If both operands are pointers, and the operator is -, the pointers are
10890 // subtracted and the result is divided by the size of the type pointed to
10891 // by the operands. It is an error if the pointers point to different types."
10892 Type p1 = t1.nextOf();
10893 Type p2 = t2.nextOf();
10895 if (!p1.equivalent(p2))
10897 // Deprecation to remain for at least a year, after which this should be
10898 // changed to an error
10899 // See https://github.com/dlang/dmd/pull/7332
10900 deprecation(exp.loc,
10901 "cannot subtract pointers to different types: `%s` and `%s`.",
10902 t1.toChars(), t2.toChars());
10905 // Need to divide the result by the stride
10906 // Replace (ptr - ptr) with (ptr - ptr) / stride
10907 long stride;
10909 // make sure pointer types are compatible
10910 if (Expression ex = typeCombine(exp, sc))
10912 result = ex;
10913 return;
10916 exp.type = Type.tptrdiff_t;
10917 stride = t2.nextOf().size();
10918 if (stride == 0)
10920 e = new IntegerExp(exp.loc, 0, Type.tptrdiff_t);
10922 else if (stride == cast(long)SIZE_INVALID)
10923 e = ErrorExp.get();
10924 else
10926 e = new DivExp(exp.loc, exp, new IntegerExp(Loc.initial, stride, Type.tptrdiff_t));
10927 e.type = Type.tptrdiff_t;
10930 else if (t2.isintegral())
10931 e = scaleFactor(exp, sc);
10932 else
10934 exp.error("can't subtract `%s` from pointer", t2.toChars());
10935 e = ErrorExp.get();
10937 result = e;
10938 return;
10940 if (t2.ty == Tpointer)
10942 exp.type = exp.e2.type;
10943 exp.error("can't subtract pointer from `%s`", exp.e1.type.toChars());
10944 return setError();
10947 if (Expression ex = typeCombine(exp, sc))
10949 result = ex;
10950 return;
10953 Type tb = exp.type.toBasetype();
10954 if (tb.ty == Tarray || tb.ty == Tsarray)
10956 if (!isArrayOpValid(exp))
10958 result = arrayOpInvalidError(exp);
10959 return;
10961 result = exp;
10962 return;
10965 t1 = exp.e1.type.toBasetype();
10966 t2 = exp.e2.type.toBasetype();
10967 if (!target.isVectorOpSupported(t1, exp.op, t2))
10969 result = exp.incompatibleTypes();
10970 return;
10972 if ((t1.isreal() && t2.isimaginary()) || (t1.isimaginary() && t2.isreal()))
10974 switch (exp.type.ty)
10976 case Tfloat32:
10977 case Timaginary32:
10978 exp.type = Type.tcomplex32;
10979 break;
10981 case Tfloat64:
10982 case Timaginary64:
10983 exp.type = Type.tcomplex64;
10984 break;
10986 case Tfloat80:
10987 case Timaginary80:
10988 exp.type = Type.tcomplex80;
10989 break;
10991 default:
10992 assert(0);
10995 result = exp;
10996 return;
11000 * If the given expression is a `CatExp`, the function tries to lower it to
11001 * `_d_arraycatnTX`.
11003 * Params:
11004 * ee = the `CatExp` to lower
11005 * Returns:
11006 * `_d_arraycatnTX(e1, e2, ..., en)` if `ee` is `e1 ~ e2 ~ ... en`
11007 * `ee` otherwise
11009 private Expression lowerToArrayCat(CatExp exp)
11011 // String literals are concatenated by the compiler. No lowering is needed.
11012 if ((exp.e1.isStringExp() && (exp.e2.isIntegerExp() || exp.e2.isStringExp())) ||
11013 (exp.e2.isStringExp() && (exp.e1.isIntegerExp() || exp.e1.isStringExp())))
11014 return exp;
11016 Identifier hook = global.params.tracegc ? Id._d_arraycatnTXTrace : Id._d_arraycatnTX;
11017 if (!verifyHookExist(exp.loc, *sc, hook, "concatenating arrays"))
11019 setError();
11020 return result;
11023 void handleCatArgument(Expressions *arguments, Expression e)
11025 if (auto ce = e.isCatExp())
11027 Expression lowering = ce.lowering;
11029 /* Skip `file`, `line`, and `funcname` if the hook of the parent
11030 * `CatExp` is `_d_arraycatnTXTrace`.
11032 if (auto callExp = isRuntimeHook(lowering, hook))
11034 if (hook == Id._d_arraycatnTX)
11035 arguments.pushSlice((*callExp.arguments)[]);
11036 else
11037 arguments.pushSlice((*callExp.arguments)[3 .. $]);
11040 else
11041 arguments.push(e);
11044 auto arguments = new Expressions();
11045 if (global.params.tracegc)
11047 auto funcname = (sc.callsc && sc.callsc.func) ?
11048 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
11049 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
11050 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
11051 arguments.push(new StringExp(exp.loc, funcname.toDString()));
11054 handleCatArgument(arguments, exp.e1);
11055 handleCatArgument(arguments, exp.e2);
11057 Expression id = new IdentifierExp(exp.loc, Id.empty);
11058 id = new DotIdExp(exp.loc, id, Id.object);
11060 auto tiargs = new Objects();
11061 tiargs.push(exp.type);
11062 id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs);
11063 id = new CallExp(exp.loc, id, arguments);
11064 return id.expressionSemantic(sc);
11067 void trySetCatExpLowering(Expression exp)
11069 /* `_d_arraycatnTX` canot be used with `-betterC`, but `CatExp`s may be
11070 * used with `-betterC`, but only during CTFE.
11072 if (!global.params.useGC || !sc.needsCodegen())
11073 return;
11075 if (auto ce = exp.isCatExp())
11076 ce.lowering = lowerToArrayCat(ce);
11079 override void visit(CatExp exp)
11081 // https://dlang.org/spec/expression.html#cat_expressions
11082 //printf("CatExp.semantic() %s\n", toChars());
11083 if (exp.type)
11085 result = exp;
11086 return;
11089 if (Expression ex = binSemanticProp(exp, sc))
11091 result = ex;
11092 return;
11094 Expression e = exp.op_overload(sc);
11095 if (e)
11097 result = e;
11098 return;
11101 Type tb1 = exp.e1.type.toBasetype();
11102 Type tb2 = exp.e2.type.toBasetype();
11104 auto f1 = checkNonAssignmentArrayOp(exp.e1);
11105 auto f2 = checkNonAssignmentArrayOp(exp.e2);
11106 if (f1 || f2)
11107 return setError();
11109 Type tb1next = tb1.nextOf();
11110 Type tb2next = tb2.nextOf();
11112 // Check for: array ~ array
11113 if (tb1next && tb2next && (tb1next.implicitConvTo(tb2next) >= MATCH.constant || tb2next.implicitConvTo(tb1next) >= MATCH.constant || exp.e1.op == EXP.arrayLiteral && exp.e1.implicitConvTo(tb2) || exp.e2.op == EXP.arrayLiteral && exp.e2.implicitConvTo(tb1)))
11115 /* https://issues.dlang.org/show_bug.cgi?id=9248
11116 * Here to avoid the case of:
11117 * void*[] a = [cast(void*)1];
11118 * void*[] b = [cast(void*)2];
11119 * a ~ b;
11120 * becoming:
11121 * a ~ [cast(void*)b];
11124 /* https://issues.dlang.org/show_bug.cgi?id=14682
11125 * Also to avoid the case of:
11126 * int[][] a;
11127 * a ~ [];
11128 * becoming:
11129 * a ~ cast(int[])[];
11131 goto Lpeer;
11134 // Check for: array ~ element
11135 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && tb2.ty != Tvoid)
11137 if (exp.e1.op == EXP.arrayLiteral)
11139 exp.e2 = doCopyOrMove(sc, exp.e2);
11140 // https://issues.dlang.org/show_bug.cgi?id=14686
11141 // Postblit call appears in AST, and this is
11142 // finally translated to an ArrayLiteralExp in below optimize().
11144 else if (exp.e1.op == EXP.string_)
11146 // No postblit call exists on character (integer) value.
11148 else
11150 if (exp.e2.checkPostblit(sc, tb2))
11151 return setError();
11152 // Postblit call will be done in runtime helper function
11155 if (exp.e1.op == EXP.arrayLiteral && exp.e1.implicitConvTo(tb2.arrayOf()))
11157 exp.e1 = exp.e1.implicitCastTo(sc, tb2.arrayOf());
11158 exp.type = tb2.arrayOf();
11159 goto L2elem;
11161 if (exp.e2.implicitConvTo(tb1next) >= MATCH.convert)
11163 exp.e2 = exp.e2.implicitCastTo(sc, tb1next);
11164 exp.type = tb1next.arrayOf();
11165 L2elem:
11166 if (checkNewEscape(sc, exp.e2, false))
11167 return setError();
11168 result = exp.optimize(WANTvalue);
11169 trySetCatExpLowering(result);
11170 return;
11173 // Check for: element ~ array
11174 if ((tb2.ty == Tsarray || tb2.ty == Tarray) && tb1.ty != Tvoid)
11176 if (exp.e2.op == EXP.arrayLiteral)
11178 exp.e1 = doCopyOrMove(sc, exp.e1);
11180 else if (exp.e2.op == EXP.string_)
11183 else
11185 if (exp.e1.checkPostblit(sc, tb1))
11186 return setError();
11189 if (exp.e2.op == EXP.arrayLiteral && exp.e2.implicitConvTo(tb1.arrayOf()))
11191 exp.e2 = exp.e2.implicitCastTo(sc, tb1.arrayOf());
11192 exp.type = tb1.arrayOf();
11193 goto L1elem;
11195 if (exp.e1.implicitConvTo(tb2next) >= MATCH.convert)
11197 exp.e1 = exp.e1.implicitCastTo(sc, tb2next);
11198 exp.type = tb2next.arrayOf();
11199 L1elem:
11200 if (checkNewEscape(sc, exp.e1, false))
11201 return setError();
11202 result = exp.optimize(WANTvalue);
11203 trySetCatExpLowering(result);
11204 return;
11208 Lpeer:
11209 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && (tb2.ty == Tsarray || tb2.ty == Tarray) && (tb1next.mod || tb2next.mod) && (tb1next.mod != tb2next.mod))
11211 Type t1 = tb1next.mutableOf().constOf().arrayOf();
11212 Type t2 = tb2next.mutableOf().constOf().arrayOf();
11213 if (exp.e1.op == EXP.string_ && !(cast(StringExp)exp.e1).committed)
11214 exp.e1.type = t1;
11215 else
11216 exp.e1 = exp.e1.castTo(sc, t1);
11217 if (exp.e2.op == EXP.string_ && !(cast(StringExp)exp.e2).committed)
11218 exp.e2.type = t2;
11219 else
11220 exp.e2 = exp.e2.castTo(sc, t2);
11223 if (Expression ex = typeCombine(exp, sc))
11225 result = ex;
11226 trySetCatExpLowering(result);
11227 return;
11229 exp.type = exp.type.toHeadMutable();
11231 Type tb = exp.type.toBasetype();
11232 if (tb.ty == Tsarray)
11233 exp.type = tb.nextOf().arrayOf();
11234 if (exp.type.ty == Tarray && tb1next && tb2next && tb1next.mod != tb2next.mod)
11236 exp.type = exp.type.nextOf().toHeadMutable().arrayOf();
11238 if (Type tbn = tb.nextOf())
11240 if (exp.checkPostblit(sc, tbn))
11241 return setError();
11243 Type t1 = exp.e1.type.toBasetype();
11244 Type t2 = exp.e2.type.toBasetype();
11245 if ((t1.ty == Tarray || t1.ty == Tsarray) &&
11246 (t2.ty == Tarray || t2.ty == Tsarray))
11248 // Normalize to ArrayLiteralExp or StringExp as far as possible
11249 e = exp.optimize(WANTvalue);
11251 else
11253 //printf("(%s) ~ (%s)\n", e1.toChars(), e2.toChars());
11254 result = exp.incompatibleTypes();
11255 return;
11258 result = e;
11259 trySetCatExpLowering(result);
11262 override void visit(MulExp exp)
11264 version (none)
11266 printf("MulExp::semantic() %s\n", exp.toChars());
11268 if (exp.type)
11270 result = exp;
11271 return;
11274 if (Expression ex = binSemanticProp(exp, sc))
11276 result = ex;
11277 return;
11279 Expression e = exp.op_overload(sc);
11280 if (e)
11282 result = e;
11283 return;
11286 if (Expression ex = typeCombine(exp, sc))
11288 result = ex;
11289 return;
11292 Type tb = exp.type.toBasetype();
11293 if (tb.ty == Tarray || tb.ty == Tsarray)
11295 if (!isArrayOpValid(exp))
11297 result = arrayOpInvalidError(exp);
11298 return;
11300 result = exp;
11301 return;
11304 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
11305 return setError();
11307 if (exp.type.isfloating())
11309 Type t1 = exp.e1.type;
11310 Type t2 = exp.e2.type;
11312 if (t1.isreal())
11314 exp.type = t2;
11316 else if (t2.isreal())
11318 exp.type = t1;
11320 else if (t1.isimaginary())
11322 if (t2.isimaginary())
11324 switch (t1.toBasetype().ty)
11326 case Timaginary32:
11327 exp.type = Type.tfloat32;
11328 break;
11330 case Timaginary64:
11331 exp.type = Type.tfloat64;
11332 break;
11334 case Timaginary80:
11335 exp.type = Type.tfloat80;
11336 break;
11338 default:
11339 assert(0);
11342 // iy * iv = -yv
11343 exp.e1.type = exp.type;
11344 exp.e2.type = exp.type;
11345 e = new NegExp(exp.loc, exp);
11346 e = e.expressionSemantic(sc);
11347 result = e;
11348 return;
11350 else
11351 exp.type = t2; // t2 is complex
11353 else if (t2.isimaginary())
11355 exp.type = t1; // t1 is complex
11358 else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11360 result = exp.incompatibleTypes();
11361 return;
11363 result = exp;
11366 override void visit(DivExp exp)
11368 if (exp.type)
11370 result = exp;
11371 return;
11374 if (Expression ex = binSemanticProp(exp, sc))
11376 result = ex;
11377 return;
11379 Expression e = exp.op_overload(sc);
11380 if (e)
11382 result = e;
11383 return;
11386 if (Expression ex = typeCombine(exp, sc))
11388 result = ex;
11389 return;
11392 Type tb = exp.type.toBasetype();
11393 if (tb.ty == Tarray || tb.ty == Tsarray)
11395 if (!isArrayOpValid(exp))
11397 result = arrayOpInvalidError(exp);
11398 return;
11400 result = exp;
11401 return;
11404 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
11405 return setError();
11407 if (exp.type.isfloating())
11409 Type t1 = exp.e1.type;
11410 Type t2 = exp.e2.type;
11412 if (t1.isreal())
11414 exp.type = t2;
11415 if (t2.isimaginary())
11417 // x/iv = i(-x/v)
11418 exp.e2.type = t1;
11419 e = new NegExp(exp.loc, exp);
11420 e = e.expressionSemantic(sc);
11421 result = e;
11422 return;
11425 else if (t2.isreal())
11427 exp.type = t1;
11429 else if (t1.isimaginary())
11431 if (t2.isimaginary())
11433 switch (t1.toBasetype().ty)
11435 case Timaginary32:
11436 exp.type = Type.tfloat32;
11437 break;
11439 case Timaginary64:
11440 exp.type = Type.tfloat64;
11441 break;
11443 case Timaginary80:
11444 exp.type = Type.tfloat80;
11445 break;
11447 default:
11448 assert(0);
11451 else
11452 exp.type = t2; // t2 is complex
11454 else if (t2.isimaginary())
11456 exp.type = t1; // t1 is complex
11459 else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11461 result = exp.incompatibleTypes();
11462 return;
11464 result = exp;
11467 override void visit(ModExp exp)
11469 if (exp.type)
11471 result = exp;
11472 return;
11475 if (Expression ex = binSemanticProp(exp, sc))
11477 result = ex;
11478 return;
11480 Expression e = exp.op_overload(sc);
11481 if (e)
11483 result = e;
11484 return;
11487 if (Expression ex = typeCombine(exp, sc))
11489 result = ex;
11490 return;
11493 Type tb = exp.type.toBasetype();
11494 if (tb.ty == Tarray || tb.ty == Tsarray)
11496 if (!isArrayOpValid(exp))
11498 result = arrayOpInvalidError(exp);
11499 return;
11501 result = exp;
11502 return;
11504 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11506 result = exp.incompatibleTypes();
11507 return;
11510 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
11511 return setError();
11513 if (exp.type.isfloating())
11515 exp.type = exp.e1.type;
11516 if (exp.e2.type.iscomplex())
11518 exp.error("cannot perform modulo complex arithmetic");
11519 return setError();
11522 result = exp;
11525 override void visit(PowExp exp)
11527 if (exp.type)
11529 result = exp;
11530 return;
11533 //printf("PowExp::semantic() %s\n", toChars());
11534 if (Expression ex = binSemanticProp(exp, sc))
11536 result = ex;
11537 return;
11539 Expression e = exp.op_overload(sc);
11540 if (e)
11542 result = e;
11543 return;
11546 if (Expression ex = typeCombine(exp, sc))
11548 result = ex;
11549 return;
11552 Type tb = exp.type.toBasetype();
11553 if (tb.ty == Tarray || tb.ty == Tsarray)
11555 if (!isArrayOpValid(exp))
11557 result = arrayOpInvalidError(exp);
11558 return;
11560 result = exp;
11561 return;
11564 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
11565 return setError();
11567 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11569 result = exp.incompatibleTypes();
11570 return;
11573 // First, attempt to fold the expression.
11574 e = exp.optimize(WANTvalue);
11575 if (e.op != EXP.pow)
11577 e = e.expressionSemantic(sc);
11578 result = e;
11579 return;
11582 Module mmath = Module.loadStdMath();
11583 if (!mmath)
11585 e.error("`%s` requires `std.math` for `^^` operators", e.toChars());
11586 return setError();
11588 e = new ScopeExp(exp.loc, mmath);
11590 if (exp.e2.op == EXP.float64 && exp.e2.toReal() == CTFloat.half)
11592 // Replace e1 ^^ 0.5 with .std.math.sqrt(e1)
11593 e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._sqrt), exp.e1);
11595 else
11597 // Replace e1 ^^ e2 with .std.math.pow(e1, e2)
11598 e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._pow), exp.e1, exp.e2);
11600 e = e.expressionSemantic(sc);
11601 result = e;
11602 return;
11605 override void visit(ShlExp exp)
11607 //printf("ShlExp::semantic(), type = %p\n", type);
11608 if (exp.type)
11610 result = exp;
11611 return;
11614 if (Expression ex = binSemanticProp(exp, sc))
11616 result = ex;
11617 return;
11619 Expression e = exp.op_overload(sc);
11620 if (e)
11622 result = e;
11623 return;
11626 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11627 return setError();
11629 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
11631 result = exp.incompatibleTypes();
11632 return;
11634 exp.e1 = integralPromotions(exp.e1, sc);
11635 if (exp.e2.type.toBasetype().ty != Tvector)
11636 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
11638 exp.type = exp.e1.type;
11639 result = exp;
11642 override void visit(ShrExp exp)
11644 if (exp.type)
11646 result = exp;
11647 return;
11650 if (Expression ex = binSemanticProp(exp, sc))
11652 result = ex;
11653 return;
11655 Expression e = exp.op_overload(sc);
11656 if (e)
11658 result = e;
11659 return;
11662 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11663 return setError();
11665 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
11667 result = exp.incompatibleTypes();
11668 return;
11670 exp.e1 = integralPromotions(exp.e1, sc);
11671 if (exp.e2.type.toBasetype().ty != Tvector)
11672 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
11674 exp.type = exp.e1.type;
11675 result = exp;
11678 override void visit(UshrExp exp)
11680 if (exp.type)
11682 result = exp;
11683 return;
11686 if (Expression ex = binSemanticProp(exp, sc))
11688 result = ex;
11689 return;
11691 Expression e = exp.op_overload(sc);
11692 if (e)
11694 result = e;
11695 return;
11698 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11699 return setError();
11701 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
11703 result = exp.incompatibleTypes();
11704 return;
11706 exp.e1 = integralPromotions(exp.e1, sc);
11707 if (exp.e2.type.toBasetype().ty != Tvector)
11708 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
11710 exp.type = exp.e1.type;
11711 result = exp;
11714 override void visit(AndExp exp)
11716 if (exp.type)
11718 result = exp;
11719 return;
11722 if (Expression ex = binSemanticProp(exp, sc))
11724 result = ex;
11725 return;
11727 Expression e = exp.op_overload(sc);
11728 if (e)
11730 result = e;
11731 return;
11734 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
11736 exp.type = exp.e1.type;
11737 result = exp;
11738 return;
11741 if (Expression ex = typeCombine(exp, sc))
11743 result = ex;
11744 return;
11747 Type tb = exp.type.toBasetype();
11748 if (tb.ty == Tarray || tb.ty == Tsarray)
11750 if (!isArrayOpValid(exp))
11752 result = arrayOpInvalidError(exp);
11753 return;
11755 result = exp;
11756 return;
11758 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11760 result = exp.incompatibleTypes();
11761 return;
11763 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11764 return setError();
11766 result = exp;
11769 override void visit(OrExp exp)
11771 if (exp.type)
11773 result = exp;
11774 return;
11777 if (Expression ex = binSemanticProp(exp, sc))
11779 result = ex;
11780 return;
11782 Expression e = exp.op_overload(sc);
11783 if (e)
11785 result = e;
11786 return;
11789 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
11791 exp.type = exp.e1.type;
11792 result = exp;
11793 return;
11796 if (Expression ex = typeCombine(exp, sc))
11798 result = ex;
11799 return;
11802 Type tb = exp.type.toBasetype();
11803 if (tb.ty == Tarray || tb.ty == Tsarray)
11805 if (!isArrayOpValid(exp))
11807 result = arrayOpInvalidError(exp);
11808 return;
11810 result = exp;
11811 return;
11813 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11815 result = exp.incompatibleTypes();
11816 return;
11818 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11819 return setError();
11821 result = exp;
11824 override void visit(XorExp exp)
11826 if (exp.type)
11828 result = exp;
11829 return;
11832 if (Expression ex = binSemanticProp(exp, sc))
11834 result = ex;
11835 return;
11837 Expression e = exp.op_overload(sc);
11838 if (e)
11840 result = e;
11841 return;
11844 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
11846 exp.type = exp.e1.type;
11847 result = exp;
11848 return;
11851 if (Expression ex = typeCombine(exp, sc))
11853 result = ex;
11854 return;
11857 Type tb = exp.type.toBasetype();
11858 if (tb.ty == Tarray || tb.ty == Tsarray)
11860 if (!isArrayOpValid(exp))
11862 result = arrayOpInvalidError(exp);
11863 return;
11865 result = exp;
11866 return;
11868 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11870 result = exp.incompatibleTypes();
11871 return;
11873 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11874 return setError();
11876 result = exp;
11879 override void visit(LogicalExp exp)
11881 static if (LOGSEMANTIC)
11883 printf("LogicalExp::semantic() %s\n", exp.toChars());
11886 if (exp.type)
11888 result = exp;
11889 return;
11892 exp.setNoderefOperands();
11894 Expression e1x = exp.e1.expressionSemantic(sc);
11896 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
11897 if (e1x.op == EXP.type)
11898 e1x = resolveAliasThis(sc, e1x);
11900 e1x = resolveProperties(sc, e1x);
11901 e1x = e1x.toBoolean(sc);
11903 if (sc.flags & SCOPE.condition)
11905 /* If in static if, don't evaluate e2 if we don't have to.
11907 e1x = e1x.optimize(WANTvalue);
11908 if (e1x.toBool().hasValue(exp.op == EXP.orOr))
11910 if (sc.flags & SCOPE.Cfile)
11911 result = new IntegerExp(exp.op == EXP.orOr);
11912 else
11913 result = IntegerExp.createBool(exp.op == EXP.orOr);
11914 return;
11918 CtorFlow ctorflow = sc.ctorflow.clone();
11919 Expression e2x = exp.e2.expressionSemantic(sc);
11920 sc.merge(exp.loc, ctorflow);
11921 ctorflow.freeFieldinit();
11923 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
11924 if (e2x.op == EXP.type)
11925 e2x = resolveAliasThis(sc, e2x);
11927 e2x = resolveProperties(sc, e2x);
11929 auto f1 = checkNonAssignmentArrayOp(e1x);
11930 auto f2 = checkNonAssignmentArrayOp(e2x);
11931 if (f1 || f2)
11932 return setError();
11934 // Unless the right operand is 'void', the expression is converted to 'bool'.
11935 if (e2x.type.ty != Tvoid)
11936 e2x = e2x.toBoolean(sc);
11938 if (e2x.op == EXP.type || e2x.op == EXP.scope_)
11940 exp.error("`%s` is not an expression", exp.e2.toChars());
11941 return setError();
11943 if (e1x.op == EXP.error || e1x.type.ty == Tnoreturn)
11945 result = e1x;
11946 return;
11948 if (e2x.op == EXP.error)
11950 result = e2x;
11951 return;
11954 // The result type is 'bool', unless the right operand has type 'void'.
11955 if (e2x.type.ty == Tvoid)
11956 exp.type = Type.tvoid;
11957 else
11958 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
11960 exp.e1 = e1x;
11961 exp.e2 = e2x;
11962 result = exp;
11966 override void visit(CmpExp exp)
11968 static if (LOGSEMANTIC)
11970 printf("CmpExp::semantic('%s')\n", exp.toChars());
11972 if (exp.type)
11974 result = exp;
11975 return;
11978 exp.setNoderefOperands();
11980 if (Expression ex = binSemanticProp(exp, sc))
11982 result = ex;
11983 return;
11985 Type t1 = exp.e1.type.toBasetype();
11986 Type t2 = exp.e2.type.toBasetype();
11987 if (t1.ty == Tclass && exp.e2.op == EXP.null_ || t2.ty == Tclass && exp.e1.op == EXP.null_)
11989 exp.error("do not use `null` when comparing class types");
11990 return setError();
11994 EXP cmpop = exp.op;
11995 if (auto e = exp.op_overload(sc, &cmpop))
11997 if (!e.type.isscalar() && e.type.equals(exp.e1.type))
11999 exp.error("recursive `opCmp` expansion");
12000 return setError();
12002 if (e.op == EXP.call)
12005 if (t1.ty == Tclass && t2.ty == Tclass)
12007 // Lower to object.__cmp(e1, e2)
12008 Expression cl = new IdentifierExp(exp.loc, Id.empty);
12009 cl = new DotIdExp(exp.loc, cl, Id.object);
12010 cl = new DotIdExp(exp.loc, cl, Id.__cmp);
12011 cl = cl.expressionSemantic(sc);
12013 auto arguments = new Expressions();
12014 // Check if op_overload found a better match by calling e2.opCmp(e1)
12015 // If the operands were swapped, then the result must be reversed
12016 // e1.opCmp(e2) == -e2.opCmp(e1)
12017 // cmpop takes care of this
12018 if (exp.op == cmpop)
12020 arguments.push(exp.e1);
12021 arguments.push(exp.e2);
12023 else
12025 // Use better match found by op_overload
12026 arguments.push(exp.e2);
12027 arguments.push(exp.e1);
12030 cl = new CallExp(exp.loc, cl, arguments);
12031 cl = new CmpExp(cmpop, exp.loc, cl, new IntegerExp(0));
12032 result = cl.expressionSemantic(sc);
12033 return;
12036 e = new CmpExp(cmpop, exp.loc, e, IntegerExp.literal!0);
12037 e = e.expressionSemantic(sc);
12039 result = e;
12040 return;
12044 if (Expression ex = typeCombine(exp, sc))
12046 result = ex;
12047 return;
12050 auto f1 = checkNonAssignmentArrayOp(exp.e1);
12051 auto f2 = checkNonAssignmentArrayOp(exp.e2);
12052 if (f1 || f2)
12053 return setError();
12055 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
12057 // Special handling for array comparisons
12058 Expression arrayLowering = null;
12059 t1 = exp.e1.type.toBasetype();
12060 t2 = exp.e2.type.toBasetype();
12061 if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && (t2.ty == Tarray || t2.ty == Tsarray || t2.ty == Tpointer))
12063 Type t1next = t1.nextOf();
12064 Type t2next = t2.nextOf();
12065 if (t1next.implicitConvTo(t2next) < MATCH.constant && t2next.implicitConvTo(t1next) < MATCH.constant && (t1next.ty != Tvoid && t2next.ty != Tvoid))
12067 exp.error("array comparison type mismatch, `%s` vs `%s`", t1next.toChars(), t2next.toChars());
12068 return setError();
12071 if (sc.needsCodegen() &&
12072 (t1.ty == Tarray || t1.ty == Tsarray) &&
12073 (t2.ty == Tarray || t2.ty == Tsarray))
12075 if (!verifyHookExist(exp.loc, *sc, Id.__cmp, "comparing arrays"))
12076 return setError();
12078 // Lower to object.__cmp(e1, e2)
12079 Expression al = new IdentifierExp(exp.loc, Id.empty);
12080 al = new DotIdExp(exp.loc, al, Id.object);
12081 al = new DotIdExp(exp.loc, al, Id.__cmp);
12082 al = al.expressionSemantic(sc);
12084 auto arguments = new Expressions(2);
12085 (*arguments)[0] = exp.e1;
12086 (*arguments)[1] = exp.e2;
12088 al = new CallExp(exp.loc, al, arguments);
12089 al = new CmpExp(exp.op, exp.loc, al, IntegerExp.literal!0);
12091 arrayLowering = al;
12094 else if (t1.ty == Tstruct || t2.ty == Tstruct || (t1.ty == Tclass && t2.ty == Tclass))
12096 if (t2.ty == Tstruct)
12097 exp.error("need member function `opCmp()` for %s `%s` to compare", t2.toDsymbol(sc).kind(), t2.toChars());
12098 else
12099 exp.error("need member function `opCmp()` for %s `%s` to compare", t1.toDsymbol(sc).kind(), t1.toChars());
12100 return setError();
12102 else if (t1.iscomplex() || t2.iscomplex())
12104 exp.error("compare not defined for complex operands");
12105 return setError();
12107 else if (t1.ty == Taarray || t2.ty == Taarray)
12109 exp.error("`%s` is not defined for associative arrays", EXPtoString(exp.op).ptr);
12110 return setError();
12112 else if (!target.isVectorOpSupported(t1, exp.op, t2))
12114 result = exp.incompatibleTypes();
12115 return;
12117 else
12119 bool r1 = exp.e1.checkValue() || exp.e1.checkSharedAccess(sc);
12120 bool r2 = exp.e2.checkValue() || exp.e2.checkSharedAccess(sc);
12121 if (r1 || r2)
12122 return setError();
12125 //printf("CmpExp: %s, type = %s\n", e.toChars(), e.type.toChars());
12126 if (arrayLowering)
12128 arrayLowering = arrayLowering.expressionSemantic(sc);
12129 result = arrayLowering;
12130 return;
12133 if (auto tv = t1.isTypeVector())
12134 exp.type = tv.toBooleanVector();
12136 result = exp;
12137 return;
12140 override void visit(InExp exp)
12142 if (exp.type)
12144 result = exp;
12145 return;
12148 if (Expression ex = binSemanticProp(exp, sc))
12150 result = ex;
12151 return;
12153 Expression e = exp.op_overload(sc);
12154 if (e)
12156 result = e;
12157 return;
12160 Type t2b = exp.e2.type.toBasetype();
12161 switch (t2b.ty)
12163 case Taarray:
12165 TypeAArray ta = cast(TypeAArray)t2b;
12167 // Special handling for array keys
12168 if (!arrayTypeCompatibleWithoutCasting(exp.e1.type, ta.index))
12170 // Convert key to type of key
12171 exp.e1 = exp.e1.implicitCastTo(sc, ta.index);
12174 semanticTypeInfo(sc, ta.index);
12176 // Return type is pointer to value
12177 exp.type = ta.nextOf().pointerTo();
12178 break;
12181 case Terror:
12182 return setError();
12184 case Tarray, Tsarray:
12185 result = exp.incompatibleTypes();
12186 exp.errorSupplemental("`in` is only allowed on associative arrays");
12187 const(char)* slice = (t2b.ty == Tsarray) ? "[]" : "";
12188 exp.errorSupplemental("perhaps use `std.algorithm.find(%s, %s%s)` instead",
12189 exp.e1.toChars(), exp.e2.toChars(), slice);
12190 return;
12192 default:
12193 result = exp.incompatibleTypes();
12194 return;
12196 result = exp;
12199 override void visit(RemoveExp e)
12201 if (Expression ex = binSemantic(e, sc))
12203 result = ex;
12204 return;
12206 result = e;
12209 override void visit(EqualExp exp)
12211 //printf("EqualExp::semantic('%s')\n", exp.toChars());
12212 if (exp.type)
12214 result = exp;
12215 return;
12218 exp.setNoderefOperands();
12220 if (auto e = binSemanticProp(exp, sc))
12222 result = e;
12223 return;
12225 if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
12227 /* https://issues.dlang.org/show_bug.cgi?id=12520
12228 * empty tuples are represented as types so special cases are added
12229 * so that they can be compared for equality with tuples of values.
12231 static auto extractTypeTupAndExpTup(Expression e)
12233 static struct Result { bool ttEmpty; bool te; }
12234 auto tt = e.op == EXP.type ? e.isTypeExp().type.isTypeTuple() : null;
12235 return Result(tt && (!tt.arguments || !tt.arguments.length), e.isTupleExp() !is null);
12237 auto tups1 = extractTypeTupAndExpTup(exp.e1);
12238 auto tups2 = extractTypeTupAndExpTup(exp.e2);
12239 // AliasSeq!() == AliasSeq!(<at least a value>)
12240 if (tups1.ttEmpty && tups2.te)
12242 result = IntegerExp.createBool(exp.op != EXP.equal);
12243 return;
12245 // AliasSeq!(<at least a value>) == AliasSeq!()
12246 else if (tups1.te && tups2.ttEmpty)
12248 result = IntegerExp.createBool(exp.op != EXP.equal);
12249 return;
12251 // AliasSeq!() == AliasSeq!()
12252 else if (tups1.ttEmpty && tups2.ttEmpty)
12254 result = IntegerExp.createBool(exp.op == EXP.equal);
12255 return;
12257 // otherwise, two types are really not comparable
12258 result = exp.incompatibleTypes();
12259 return;
12263 auto t1 = exp.e1.type;
12264 auto t2 = exp.e2.type;
12265 if (t1.ty == Tenum && t2.ty == Tenum && !t1.equivalent(t2))
12266 exp.error("comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`",
12267 t1.toChars(), t2.toChars());
12270 /* Before checking for operator overloading, check to see if we're
12271 * comparing the addresses of two statics. If so, we can just see
12272 * if they are the same symbol.
12274 if (exp.e1.op == EXP.address && exp.e2.op == EXP.address)
12276 AddrExp ae1 = cast(AddrExp)exp.e1;
12277 AddrExp ae2 = cast(AddrExp)exp.e2;
12278 if (ae1.e1.op == EXP.variable && ae2.e1.op == EXP.variable)
12280 VarExp ve1 = cast(VarExp)ae1.e1;
12281 VarExp ve2 = cast(VarExp)ae2.e1;
12282 if (ve1.var == ve2.var)
12284 // They are the same, result is 'true' for ==, 'false' for !=
12285 result = IntegerExp.createBool(exp.op == EXP.equal);
12286 return;
12291 Type t1 = exp.e1.type.toBasetype();
12292 Type t2 = exp.e2.type.toBasetype();
12294 // Indicates whether the comparison of the 2 specified array types
12295 // requires an object.__equals() lowering.
12296 static bool needsDirectEq(Type t1, Type t2, Scope* sc)
12298 Type t1n = t1.nextOf().toBasetype();
12299 Type t2n = t2.nextOf().toBasetype();
12300 if ((t1n.ty.isSomeChar && t2n.ty.isSomeChar) ||
12301 (t1n.ty == Tvoid || t2n.ty == Tvoid))
12303 return false;
12305 if (t1n.constOf() != t2n.constOf())
12306 return true;
12308 Type t = t1n;
12309 while (t.toBasetype().nextOf())
12310 t = t.nextOf().toBasetype();
12311 if (auto ts = t.isTypeStruct())
12313 // semanticTypeInfo() makes sure hasIdentityEquals has been computed
12314 if (global.params.useTypeInfo && Type.dtypeinfo)
12315 semanticTypeInfo(sc, ts);
12317 return ts.sym.hasIdentityEquals; // has custom opEquals
12320 return false;
12323 if (auto e = exp.op_overload(sc))
12325 result = e;
12326 return;
12330 const isArrayComparison = (t1.ty == Tarray || t1.ty == Tsarray) &&
12331 (t2.ty == Tarray || t2.ty == Tsarray);
12332 const needsArrayLowering = isArrayComparison && needsDirectEq(t1, t2, sc);
12334 if (!needsArrayLowering)
12336 // https://issues.dlang.org/show_bug.cgi?id=23783
12337 if (exp.e1.checkSharedAccess(sc) || exp.e2.checkSharedAccess(sc))
12338 return setError();
12339 if (auto e = typeCombine(exp, sc))
12341 result = e;
12342 return;
12346 auto f1 = checkNonAssignmentArrayOp(exp.e1);
12347 auto f2 = checkNonAssignmentArrayOp(exp.e2);
12348 if (f1 || f2)
12349 return setError();
12351 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
12353 if (!isArrayComparison)
12355 if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
12357 // Cast both to complex
12358 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
12359 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80);
12363 // lower some array comparisons to object.__equals(e1, e2)
12364 if (needsArrayLowering || (t1.ty == Tarray && t2.ty == Tarray))
12366 //printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars());
12368 // https://issues.dlang.org/show_bug.cgi?id=22390
12369 // Equality comparison between array of noreturns simply lowers to length equality comparison
12370 if (t1.nextOf.isTypeNoreturn() && t2.nextOf.isTypeNoreturn())
12372 Expression exp_l1 = new DotIdExp(exp.e1.loc, exp.e1, Id.length);
12373 Expression exp_l2 = new DotIdExp(exp.e2.loc, exp.e2, Id.length);
12374 auto e = new EqualExp(EXP.equal, exp.loc, exp_l1, exp_l2);
12375 result = e.expressionSemantic(sc);
12376 return;
12379 if (!verifyHookExist(exp.loc, *sc, Id.__equals, "equal checks on arrays"))
12380 return setError();
12382 Expression __equals = new IdentifierExp(exp.loc, Id.empty);
12383 Identifier id = Identifier.idPool("__equals");
12384 __equals = new DotIdExp(exp.loc, __equals, Id.object);
12385 __equals = new DotIdExp(exp.loc, __equals, id);
12387 /* https://issues.dlang.org/show_bug.cgi?id=23674
12389 * Optimize before creating the call expression to the
12390 * druntime hook as the optimizer may output errors
12391 * that will get swallowed otherwise.
12393 exp.e1 = exp.e1.optimize(WANTvalue);
12394 exp.e2 = exp.e2.optimize(WANTvalue);
12396 auto arguments = new Expressions(2);
12397 (*arguments)[0] = exp.e1;
12398 (*arguments)[1] = exp.e2;
12400 __equals = new CallExp(exp.loc, __equals, arguments);
12401 if (exp.op == EXP.notEqual)
12403 __equals = new NotExp(exp.loc, __equals);
12405 __equals = __equals.trySemantic(sc); // for better error message
12406 if (!__equals)
12408 exp.error("incompatible types for array comparison: `%s` and `%s`",
12409 exp.e1.type.toChars(), exp.e2.type.toChars());
12410 __equals = ErrorExp.get();
12413 result = __equals;
12414 return;
12417 if (exp.e1.type.toBasetype().ty == Taarray)
12418 semanticTypeInfo(sc, exp.e1.type.toBasetype());
12421 if (!target.isVectorOpSupported(t1, exp.op, t2))
12423 result = exp.incompatibleTypes();
12424 return;
12427 if (auto tv = t1.isTypeVector())
12428 exp.type = tv.toBooleanVector();
12430 result = exp;
12433 override void visit(IdentityExp exp)
12435 if (exp.type)
12437 result = exp;
12438 return;
12441 exp.setNoderefOperands();
12443 if (auto e = binSemanticProp(exp, sc))
12445 result = e;
12446 return;
12449 if (auto e = typeCombine(exp, sc))
12451 result = e;
12452 return;
12455 auto f1 = checkNonAssignmentArrayOp(exp.e1);
12456 auto f2 = checkNonAssignmentArrayOp(exp.e2);
12457 if (f1 || f2)
12458 return setError();
12460 if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
12462 result = exp.incompatibleTypes();
12463 return;
12466 exp.type = Type.tbool;
12468 if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
12470 // Cast both to complex
12471 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
12472 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80);
12475 auto tb1 = exp.e1.type.toBasetype();
12476 auto tb2 = exp.e2.type.toBasetype();
12477 if (!target.isVectorOpSupported(tb1, exp.op, tb2))
12479 result = exp.incompatibleTypes();
12480 return;
12483 if (exp.e1.op == EXP.call)
12484 exp.e1 = (cast(CallExp)exp.e1).addDtorHook(sc);
12485 if (exp.e2.op == EXP.call)
12486 exp.e2 = (cast(CallExp)exp.e2).addDtorHook(sc);
12488 if (exp.e1.type.toBasetype().ty == Tsarray ||
12489 exp.e2.type.toBasetype().ty == Tsarray)
12490 exp.deprecation("identity comparison of static arrays "
12491 ~ "implicitly coerces them to slices, "
12492 ~ "which are compared by reference");
12494 result = exp;
12497 override void visit(CondExp exp)
12499 static if (LOGSEMANTIC)
12501 printf("CondExp::semantic('%s')\n", exp.toChars());
12503 if (exp.type)
12505 result = exp;
12506 return;
12509 if (auto die = exp.econd.isDotIdExp())
12510 die.noderef = true;
12512 Expression ec = exp.econd.expressionSemantic(sc);
12513 ec = resolveProperties(sc, ec);
12514 ec = ec.toBoolean(sc);
12516 CtorFlow ctorflow_root = sc.ctorflow.clone();
12517 Expression e1x = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
12518 e1x = resolveProperties(sc, e1x);
12520 CtorFlow ctorflow1 = sc.ctorflow;
12521 sc.ctorflow = ctorflow_root;
12522 Expression e2x = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
12523 e2x = resolveProperties(sc, e2x);
12525 sc.merge(exp.loc, ctorflow1);
12526 ctorflow1.freeFieldinit();
12528 if (ec.op == EXP.error)
12530 result = ec;
12531 return;
12533 if (ec.type == Type.terror)
12534 return setError();
12535 exp.econd = ec;
12537 if (e1x.op == EXP.error)
12539 result = e1x;
12540 return;
12542 if (e1x.type == Type.terror)
12543 return setError();
12544 exp.e1 = e1x;
12546 if (e2x.op == EXP.error)
12548 result = e2x;
12549 return;
12551 if (e2x.type == Type.terror)
12552 return setError();
12553 exp.e2 = e2x;
12555 auto f0 = checkNonAssignmentArrayOp(exp.econd);
12556 auto f1 = checkNonAssignmentArrayOp(exp.e1);
12557 auto f2 = checkNonAssignmentArrayOp(exp.e2);
12558 if (f0 || f1 || f2)
12559 return setError();
12561 Type t1 = exp.e1.type;
12562 Type t2 = exp.e2.type;
12564 // https://issues.dlang.org/show_bug.cgi?id=23767
12565 // `cast(void*) 0` should be treated as `null` so the ternary expression
12566 // gets the pointer type of the other branch
12567 if (sc.flags & SCOPE.Cfile)
12569 static void rewriteCNull(ref Expression e, ref Type t)
12571 if (!t.isTypePointer())
12572 return;
12573 if (auto ie = e.optimize(WANTvalue).isIntegerExp())
12575 if (ie.getInteger() == 0)
12577 e = new NullExp(e.loc, Type.tnull);
12578 t = Type.tnull;
12582 rewriteCNull(exp.e1, t1);
12583 rewriteCNull(exp.e2, t2);
12586 if (t1.ty == Tnoreturn)
12588 exp.type = t2;
12589 exp.e1 = specialNoreturnCast(exp.e1, exp.type);
12591 else if (t2.ty == Tnoreturn)
12593 exp.type = t1;
12594 exp.e2 = specialNoreturnCast(exp.e2, exp.type);
12596 // If either operand is void the result is void, we have to cast both
12597 // the expression to void so that we explicitly discard the expression
12598 // value if any
12599 // https://issues.dlang.org/show_bug.cgi?id=16598
12600 else if (t1.ty == Tvoid || t2.ty == Tvoid)
12602 exp.type = Type.tvoid;
12603 exp.e1 = exp.e1.castTo(sc, exp.type);
12604 exp.e2 = exp.e2.castTo(sc, exp.type);
12606 else if (t1 == t2)
12607 exp.type = t1;
12608 else
12610 if (Expression ex = typeCombine(exp, sc))
12612 result = ex;
12613 return;
12616 switch (exp.e1.type.toBasetype().ty)
12618 case Tcomplex32:
12619 case Tcomplex64:
12620 case Tcomplex80:
12621 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
12622 break;
12623 default:
12624 break;
12626 switch (exp.e2.type.toBasetype().ty)
12628 case Tcomplex32:
12629 case Tcomplex64:
12630 case Tcomplex80:
12631 exp.e1 = exp.e1.castTo(sc, exp.e2.type);
12632 break;
12633 default:
12634 break;
12636 if (exp.type.toBasetype().ty == Tarray)
12638 exp.e1 = exp.e1.castTo(sc, exp.type);
12639 exp.e2 = exp.e2.castTo(sc, exp.type);
12642 exp.type = exp.type.merge2();
12643 version (none)
12645 printf("res: %s\n", exp.type.toChars());
12646 printf("e1 : %s\n", exp.e1.type.toChars());
12647 printf("e2 : %s\n", exp.e2.type.toChars());
12650 /* https://issues.dlang.org/show_bug.cgi?id=14696
12651 * If either e1 or e2 contain temporaries which need dtor,
12652 * make them conditional.
12653 * Rewrite:
12654 * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2)
12655 * to:
12656 * (auto __cond = cond) ? (... __tmp1) : (... __tmp2)
12657 * and replace edtors of __tmp1 and __tmp2 with:
12658 * __tmp1.edtor --> __cond && __tmp1.dtor()
12659 * __tmp2.edtor --> __cond || __tmp2.dtor()
12661 exp.hookDtors(sc);
12663 result = exp;
12666 override void visit(GenericExp exp)
12668 static if (LOGSEMANTIC)
12670 printf("GenericExp::semantic('%s')\n", exp.toChars());
12672 // C11 6.5.1.1 Generic Selection
12674 auto ec = exp.cntlExp.expressionSemantic(sc).arrayFuncConv(sc);
12675 bool errors = ec.isErrorExp() !is null;
12676 auto tc = ec.type;
12678 auto types = (*exp.types)[];
12679 foreach (i, ref t; types)
12681 if (!t)
12682 continue; // `default:` case
12683 t = t.typeSemantic(ec.loc, sc);
12684 if (t.isTypeError())
12686 errors = true;
12687 continue;
12690 /* C11 6.5.1-2 duplicate check
12692 /* C11 distinguishes int, long, and long long. But D doesn't, so depending on the
12693 * C target, a long may have the same type as `int` in the D type system.
12694 * So, skip checks when this may be the case. Later pick the first match
12696 if (
12697 (t.ty == Tint32 || t.ty == Tuns32) && target.c.longsize == 4 ||
12698 (t.ty == Tint64 || t.ty == Tuns64) && target.c.longsize == 8 ||
12699 (t.ty == Tfloat64 || t.ty == Timaginary64 || t.ty == Tcomplex64) && target.c.long_doublesize == 8
12701 continue;
12703 foreach (t2; types[0 .. i])
12705 if (t2 && t2.equals(t))
12707 error(ec.loc, "generic association type `%s` can only appear once", t.toChars());
12708 errors = true;
12709 break;
12714 auto exps = (*exp.exps)[];
12715 foreach (ref e; exps)
12717 e = e.expressionSemantic(sc);
12718 if (e.isErrorExp())
12719 errors = true;
12722 if (errors)
12723 return setError();
12725 enum size_t None = ~0;
12726 size_t imatch = None;
12727 size_t idefault = None;
12728 foreach (const i, t; types)
12730 if (t)
12732 /* if tc is compatible with t, it's a match
12733 * C11 6.2.7 defines a compatible type as being the same type, including qualifiers
12735 if (tc.equals(t))
12737 assert(imatch == None);
12738 imatch = i;
12739 break; // pick first match
12742 else
12743 idefault = i; // multiple defaults are not allowed, and are caught by cparse
12746 if (imatch == None)
12747 imatch = idefault;
12748 if (imatch == None)
12750 error(exp.loc, "no compatible generic association type for controlling expression type `%s`", tc.toChars());
12751 return setError();
12754 result = exps[imatch];
12757 override void visit(FileInitExp e)
12759 //printf("FileInitExp::semantic()\n");
12760 e.type = Type.tstring;
12761 result = e;
12764 override void visit(LineInitExp e)
12766 e.type = Type.tint32;
12767 result = e;
12770 override void visit(ModuleInitExp e)
12772 //printf("ModuleInitExp::semantic()\n");
12773 e.type = Type.tstring;
12774 result = e;
12777 override void visit(FuncInitExp e)
12779 //printf("FuncInitExp::semantic()\n");
12780 e.type = Type.tstring;
12781 if (sc.func)
12783 result = e.resolveLoc(Loc.initial, sc);
12784 return;
12786 result = e;
12789 override void visit(PrettyFuncInitExp e)
12791 //printf("PrettyFuncInitExp::semantic()\n");
12792 e.type = Type.tstring;
12793 if (sc.func)
12795 result = e.resolveLoc(Loc.initial, sc);
12796 return;
12799 result = e;
12803 /**********************************
12804 * Try to run semantic routines.
12805 * If they fail, return NULL.
12807 Expression trySemantic(Expression exp, Scope* sc)
12809 //printf("+trySemantic(%s)\n", exp.toChars());
12810 uint errors = global.startGagging();
12811 Expression e = expressionSemantic(exp, sc);
12812 if (global.endGagging(errors))
12814 e = null;
12816 //printf("-trySemantic(%s)\n", exp.toChars());
12817 return e;
12820 /**************************
12821 * Helper function for easy error propagation.
12822 * If error occurs, returns ErrorExp. Otherwise returns NULL.
12824 Expression unaSemantic(UnaExp e, Scope* sc)
12826 static if (LOGSEMANTIC)
12828 printf("UnaExp::semantic('%s')\n", e.toChars());
12830 Expression e1x = e.e1.expressionSemantic(sc);
12831 if (e1x.op == EXP.error)
12832 return e1x;
12833 e.e1 = e1x;
12834 return null;
12837 /**************************
12838 * Helper function for easy error propagation.
12839 * If error occurs, returns ErrorExp. Otherwise returns NULL.
12841 Expression binSemantic(BinExp e, Scope* sc)
12843 static if (LOGSEMANTIC)
12845 printf("BinExp::semantic('%s')\n", e.toChars());
12847 Expression e1x = e.e1.expressionSemantic(sc);
12848 Expression e2x = e.e2.expressionSemantic(sc);
12850 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
12851 if (e1x.op == EXP.type)
12852 e1x = resolveAliasThis(sc, e1x);
12853 if (e2x.op == EXP.type)
12854 e2x = resolveAliasThis(sc, e2x);
12856 if (e1x.op == EXP.error)
12857 return e1x;
12858 if (e2x.op == EXP.error)
12859 return e2x;
12860 e.e1 = e1x;
12861 e.e2 = e2x;
12862 return null;
12865 Expression binSemanticProp(BinExp e, Scope* sc)
12867 if (Expression ex = binSemantic(e, sc))
12868 return ex;
12869 Expression e1x = resolveProperties(sc, e.e1);
12870 Expression e2x = resolveProperties(sc, e.e2);
12871 if (e1x.op == EXP.error)
12872 return e1x;
12873 if (e2x.op == EXP.error)
12874 return e2x;
12875 e.e1 = e1x;
12876 e.e2 = e2x;
12877 return null;
12880 // entrypoint for semantic ExpressionSemanticVisitor
12881 extern (C++) Expression expressionSemantic(Expression e, Scope* sc)
12883 scope v = new ExpressionSemanticVisitor(sc);
12884 e.accept(v);
12885 return v.result;
12888 private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc)
12890 //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars());
12891 if (Expression ex = unaSemantic(exp, sc))
12892 return ex;
12894 if (!(sc.flags & SCOPE.Cfile) && exp.ident == Id._mangleof)
12896 // symbol.mangleof
12898 // return mangleof as an Expression
12899 static Expression dotMangleof(const ref Loc loc, Scope* sc, Dsymbol ds)
12901 assert(ds);
12902 if (auto f = ds.isFuncDeclaration())
12904 if (f.checkForwardRef(loc))
12905 return ErrorExp.get();
12907 if (f.purityInprocess || f.safetyInprocess || f.nothrowInprocess || f.nogcInprocess)
12909 f.error(loc, "cannot retrieve its `.mangleof` while inferring attributes");
12910 return ErrorExp.get();
12913 OutBuffer buf;
12914 mangleToBuffer(ds, &buf);
12915 Expression e = new StringExp(loc, buf.extractSlice());
12916 return e.expressionSemantic(sc);
12919 Dsymbol ds;
12920 switch (exp.e1.op)
12922 case EXP.scope_: return dotMangleof(exp.loc, sc, exp.e1.isScopeExp().sds);
12923 case EXP.variable: return dotMangleof(exp.loc, sc, exp.e1.isVarExp().var);
12924 case EXP.dotVariable: return dotMangleof(exp.loc, sc, exp.e1.isDotVarExp().var);
12925 case EXP.overloadSet: return dotMangleof(exp.loc, sc, exp.e1.isOverExp().vars);
12926 case EXP.template_:
12928 TemplateExp te = exp.e1.isTemplateExp();
12929 return dotMangleof(exp.loc, sc, ds = te.fd ? te.fd.isDsymbol() : te.td);
12932 default:
12933 break;
12937 if (exp.e1.isVarExp() && exp.e1.type.toBasetype().isTypeSArray() && exp.ident == Id.length)
12939 // bypass checkPurity
12940 return exp.e1.type.dotExp(sc, exp.e1, exp.ident, cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref));
12943 if (!exp.e1.isDotExp())
12945 exp.e1 = resolvePropertiesX(sc, exp.e1);
12948 if (auto te = exp.e1.isTupleExp())
12950 if (exp.ident == Id.offsetof)
12952 /* 'distribute' the .offsetof to each of the tuple elements.
12954 auto exps = new Expressions(te.exps.length);
12955 foreach (i, e; (*te.exps)[])
12957 (*exps)[i] = new DotIdExp(e.loc, e, Id.offsetof);
12959 // Don't evaluate te.e0 in runtime
12960 Expression e = new TupleExp(exp.loc, null, exps);
12961 e = e.expressionSemantic(sc);
12962 return e;
12964 if (exp.ident == Id.length)
12966 // Don't evaluate te.e0 in runtime
12967 return new IntegerExp(exp.loc, te.exps.length, Type.tsize_t);
12971 // https://issues.dlang.org/show_bug.cgi?id=14416
12972 // Template has no built-in properties except for 'stringof'.
12973 if ((exp.e1.isDotTemplateExp() || exp.e1.isTemplateExp()) && exp.ident != Id.stringof)
12975 exp.error("template `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
12976 return ErrorExp.get();
12978 if (!exp.e1.type)
12980 exp.error("expression `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
12981 return ErrorExp.get();
12984 return exp;
12987 /******************************
12988 * Resolve properties, i.e. `e1.ident`, without seeing UFCS.
12989 * Params:
12990 * exp = expression to resolve
12991 * sc = context
12992 * gag = do not emit error messages, just return `null`
12993 * Returns:
12994 * resolved expression, null if error
12996 Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
12998 //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars());
13000 //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
13002 const cfile = (sc.flags & SCOPE.Cfile) != 0;
13004 /* Special case: rewrite this.id and super.id
13005 * to be classtype.id and baseclasstype.id
13006 * if we have no this pointer.
13008 if ((exp.e1.isThisExp() || exp.e1.isSuperExp()) && !hasThis(sc))
13010 if (AggregateDeclaration ad = sc.getStructClassScope())
13012 if (exp.e1.isThisExp())
13014 exp.e1 = new TypeExp(exp.e1.loc, ad.type);
13016 else
13018 if (auto cd = ad.isClassDeclaration())
13020 if (cd.baseClass)
13021 exp.e1 = new TypeExp(exp.e1.loc, cd.baseClass.type);
13028 Expression e = dotIdSemanticPropX(exp, sc);
13029 if (e != exp)
13030 return e;
13033 Expression eleft;
13034 Expression eright;
13035 if (auto de = exp.e1.isDotExp())
13037 eleft = de.e1;
13038 eright = de.e2;
13040 else
13042 eleft = null;
13043 eright = exp.e1;
13046 Type t1b = exp.e1.type.toBasetype();
13048 if (auto ie = eright.isScopeExp()) // also used for template alias's
13050 auto flags = SearchLocalsOnly;
13051 /* Disable access to another module's private imports.
13052 * The check for 'is sds our current module' is because
13053 * the current module should have access to its own imports.
13055 if (ie.sds.isModule() && ie.sds != sc._module)
13056 flags |= IgnorePrivateImports;
13057 if (sc.flags & SCOPE.ignoresymbolvisibility)
13058 flags |= IgnoreSymbolVisibility;
13059 Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags);
13060 /* Check for visibility before resolving aliases because public
13061 * aliases to private symbols are public.
13063 if (s && !(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc._module, s))
13065 s = null;
13067 if (s)
13069 auto p = s.isPackage();
13070 if (p && checkAccess(sc, p))
13072 s = null;
13075 if (s)
13077 // if 's' is a tuple variable, the tuple is returned.
13078 s = s.toAlias();
13080 exp.checkDeprecated(sc, s);
13081 exp.checkDisabled(sc, s);
13083 if (auto em = s.isEnumMember())
13085 return em.getVarExp(exp.loc, sc);
13087 if (auto v = s.isVarDeclaration())
13089 //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars());
13090 if (!v.type ||
13091 !v.type.deco && v.inuse)
13093 if (v.inuse)
13094 exp.error("circular reference to %s `%s`", v.kind(), v.toPrettyChars());
13095 else
13096 exp.error("forward reference to %s `%s`", v.kind(), v.toPrettyChars());
13097 return ErrorExp.get();
13099 if (v.type.isTypeError())
13100 return ErrorExp.get();
13102 if ((v.storage_class & STC.manifest) && v._init && !exp.wantsym)
13104 /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2().
13105 * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably
13106 * be reverted. `wantsym` is the hack to work around the problem.
13108 if (v.inuse)
13110 error(exp.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
13111 return ErrorExp.get();
13113 auto e = v.expandInitializer(exp.loc);
13114 v.inuse++;
13115 e = e.expressionSemantic(sc);
13116 v.inuse--;
13117 return e;
13120 Expression e;
13121 if (v.needThis())
13123 if (!eleft)
13124 eleft = new ThisExp(exp.loc);
13125 e = new DotVarExp(exp.loc, eleft, v);
13126 e = e.expressionSemantic(sc);
13128 else
13130 e = new VarExp(exp.loc, v);
13131 if (eleft)
13133 e = new CommaExp(exp.loc, eleft, e);
13134 e.type = v.type;
13137 e = e.deref();
13138 return e.expressionSemantic(sc);
13141 if (auto f = s.isFuncDeclaration())
13143 //printf("it's a function\n");
13144 if (!f.functionSemantic())
13145 return ErrorExp.get();
13146 Expression e;
13147 if (f.needThis())
13149 if (!eleft)
13150 eleft = new ThisExp(exp.loc);
13151 e = new DotVarExp(exp.loc, eleft, f, true);
13152 e = e.expressionSemantic(sc);
13154 else
13156 e = new VarExp(exp.loc, f, true);
13157 if (eleft)
13159 e = new CommaExp(exp.loc, eleft, e);
13160 e.type = f.type;
13163 return e;
13165 if (auto td = s.isTemplateDeclaration())
13167 Expression e;
13168 if (eleft)
13169 e = new DotTemplateExp(exp.loc, eleft, td);
13170 else
13171 e = new TemplateExp(exp.loc, td);
13172 e = e.expressionSemantic(sc);
13173 return e;
13175 if (OverDeclaration od = s.isOverDeclaration())
13177 Expression e = new VarExp(exp.loc, od, true);
13178 if (eleft)
13180 e = new CommaExp(exp.loc, eleft, e);
13181 e.type = Type.tvoid; // ambiguous type?
13183 return e.expressionSemantic(sc);
13185 if (auto o = s.isOverloadSet())
13187 //printf("'%s' is an overload set\n", o.toChars());
13188 return new OverExp(exp.loc, o);
13191 if (auto t = s.getType())
13193 return (new TypeExp(exp.loc, t)).expressionSemantic(sc);
13196 if (auto tup = s.isTupleDeclaration())
13198 if (eleft)
13200 Expression e = new DotVarExp(exp.loc, eleft, tup);
13201 e = e.expressionSemantic(sc);
13202 return e;
13204 Expression e = new TupleExp(exp.loc, tup);
13205 e = e.expressionSemantic(sc);
13206 return e;
13209 if (auto sds = s.isScopeDsymbol())
13211 //printf("it's a ScopeDsymbol %s\n", ident.toChars());
13212 Expression e = new ScopeExp(exp.loc, sds);
13213 e = e.expressionSemantic(sc);
13214 if (eleft)
13215 e = new DotExp(exp.loc, eleft, e);
13216 return e;
13219 if (auto imp = s.isImport())
13221 Expression se = new ScopeExp(exp.loc, imp.pkg);
13222 return se.expressionSemantic(sc);
13225 if (auto attr = s.isAttribDeclaration())
13227 if (auto sm = ie.sds.search(exp.loc, exp.ident, flags))
13229 auto es = new DsymbolExp(exp.loc, sm);
13230 return es;
13234 // BUG: handle other cases like in IdentifierExp::semantic()
13235 debug
13237 printf("s = %p '%s', kind = '%s'\n", s, s.toChars(), s.kind());
13239 assert(0);
13241 else if (exp.ident == Id.stringof)
13243 Expression e = new StringExp(exp.loc, ie.toString());
13244 e = e.expressionSemantic(sc);
13245 return e;
13247 if (ie.sds.isPackage() || ie.sds.isImport() || ie.sds.isModule())
13249 gag = false;
13251 if (gag)
13252 return null;
13253 s = ie.sds.search_correct(exp.ident);
13254 if (s && symbolIsVisible(sc, s))
13256 if (s.isPackage())
13257 exp.error("undefined identifier `%s` in %s `%s`, perhaps add `static import %s;`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars(), s.toPrettyChars());
13258 else
13259 exp.error("undefined identifier `%s` in %s `%s`, did you mean %s `%s`?", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars(), s.kind(), s.toChars());
13261 else
13262 exp.error("undefined identifier `%s` in %s `%s`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars());
13263 return ErrorExp.get();
13265 else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum &&
13267 exp.ident == Id.__sizeof ||
13268 exp.ident == Id.__xalignof ||
13269 !cfile &&
13270 (exp.ident == Id._mangleof ||
13271 exp.ident == Id.offsetof ||
13272 exp.ident == Id._init ||
13273 exp.ident == Id.stringof)
13276 Type t1bn = t1b.nextOf();
13277 if (gag)
13279 if (AggregateDeclaration ad = isAggregate(t1bn))
13281 if (!ad.members) // https://issues.dlang.org/show_bug.cgi?id=11312
13282 return null;
13286 /* Rewrite:
13287 * p.ident
13288 * as:
13289 * (*p).ident
13291 if (gag && t1bn.ty == Tvoid)
13292 return null;
13293 Expression e = new PtrExp(exp.loc, exp.e1);
13294 e = e.expressionSemantic(sc);
13295 const newFlag = cast(DotExpFlag) (gag * DotExpFlag.gag | exp.noderef * DotExpFlag.noDeref);
13296 return e.type.dotExp(sc, e, exp.ident, newFlag);
13298 else if (exp.ident == Id.__xalignof &&
13299 exp.e1.isVarExp() &&
13300 exp.e1.isVarExp().var.isVarDeclaration() &&
13301 !exp.e1.isVarExp().var.isVarDeclaration().alignment.isUnknown())
13303 // For `x.alignof` get the alignment of the variable, not the alignment of its type
13304 const explicitAlignment = exp.e1.isVarExp().var.isVarDeclaration().alignment;
13305 const naturalAlignment = exp.e1.type.alignsize();
13306 const actualAlignment = explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get();
13307 Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
13308 return e;
13310 else if ((exp.ident == Id.max || exp.ident == Id.min) &&
13311 exp.e1.isVarExp() &&
13312 exp.e1.isVarExp().var.isBitFieldDeclaration())
13314 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
13315 auto bf = exp.e1.isVarExp().var.isBitFieldDeclaration();
13316 return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type);
13318 else if ((exp.ident == Id.max || exp.ident == Id.min) &&
13319 exp.e1.isDotVarExp() &&
13320 exp.e1.isDotVarExp().var.isBitFieldDeclaration())
13322 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
13323 auto bf = exp.e1.isDotVarExp().var.isBitFieldDeclaration();
13324 return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type);
13326 else
13328 if (exp.e1.isTypeExp() || exp.e1.isTemplateExp())
13329 gag = false;
13331 const flag = cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref | gag * DotExpFlag.gag);
13333 Expression e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag);
13334 if (e)
13336 e = e.expressionSemantic(sc);
13338 return e;
13343 * Resolve `e1.ident!tiargs` without seeing UFCS.
13344 * Params:
13345 * exp = the `DotTemplateInstanceExp` to resolve
13346 * sc = the semantic scope
13347 * gag = stop "not a property" error and return `null`.
13348 * Returns:
13349 * `null` if error or not found, or the resolved expression.
13351 Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, bool gag)
13353 static if (LOGSEMANTIC)
13355 printf("DotTemplateInstanceExpY::semantic('%s')\n", exp.toChars());
13358 static Expression errorExp()
13360 return ErrorExp.get();
13363 Expression e1 = exp.e1;
13365 if (exp.ti.tempdecl && exp.ti.tempdecl.parent && exp.ti.tempdecl.parent.isTemplateMixin())
13367 // if 'ti.tempdecl' happens to be found in a mixin template don't lose that info
13368 // and do the symbol search in that context (Issue: 19476)
13369 auto tm = cast(TemplateMixin)exp.ti.tempdecl.parent;
13370 e1 = new DotExp(exp.e1.loc, exp.e1, new ScopeExp(tm.loc, tm));
13373 auto die = new DotIdExp(exp.loc, e1, exp.ti.name);
13375 Expression e = die.dotIdSemanticPropX(sc);
13376 if (e == die)
13378 exp.e1 = die.e1; // take back
13379 Type t1b = exp.e1.type.toBasetype();
13380 if (t1b.ty == Tarray || t1b.ty == Tsarray || t1b.ty == Taarray || t1b.ty == Tnull || (t1b.isTypeBasic() && t1b.ty != Tvoid))
13382 /* No built-in type has templatized properties, so do shortcut.
13383 * It is necessary in: 1024.max!"a < b"
13385 if (gag)
13386 return null;
13388 e = die.dotIdSemanticProp(sc, gag);
13389 if (gag)
13391 if (!e ||
13392 isDotOpDispatch(e))
13394 /* opDispatch!tiargs would be a function template that needs IFTI,
13395 * so it's not a template
13397 return null;
13401 assert(e);
13403 if (e.op == EXP.error)
13404 return e;
13405 if (DotVarExp dve = e.isDotVarExp())
13407 if (FuncDeclaration fd = dve.var.isFuncDeclaration())
13409 if (TemplateDeclaration td = fd.findTemplateDeclRoot())
13411 e = new DotTemplateExp(dve.loc, dve.e1, td);
13412 e = e.expressionSemantic(sc);
13415 else if (OverDeclaration od = dve.var.isOverDeclaration())
13417 exp.e1 = dve.e1; // pull semantic() result
13419 if (!exp.findTempDecl(sc))
13420 goto Lerr;
13421 if (exp.ti.needsTypeInference(sc))
13422 return exp;
13423 exp.ti.dsymbolSemantic(sc);
13424 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
13425 return errorExp();
13427 if (Declaration v = exp.ti.toAlias().isDeclaration())
13429 if (v.type && !v.type.deco)
13430 v.type = v.type.typeSemantic(v.loc, sc);
13431 return new DotVarExp(exp.loc, exp.e1, v)
13432 .expressionSemantic(sc);
13434 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
13435 .expressionSemantic(sc);
13438 else if (e.op == EXP.variable)
13440 VarExp ve = cast(VarExp)e;
13441 if (FuncDeclaration fd = ve.var.isFuncDeclaration())
13443 if (TemplateDeclaration td = fd.findTemplateDeclRoot())
13445 e = new TemplateExp(ve.loc, td)
13446 .expressionSemantic(sc);
13449 else if (OverDeclaration od = ve.var.isOverDeclaration())
13451 exp.ti.tempdecl = od;
13452 return new ScopeExp(exp.loc, exp.ti)
13453 .expressionSemantic(sc);
13457 if (DotTemplateExp dte = e.isDotTemplateExp())
13459 exp.e1 = dte.e1; // pull semantic() result
13461 exp.ti.tempdecl = dte.td;
13462 if (!exp.ti.semanticTiargs(sc))
13463 return errorExp();
13464 if (exp.ti.needsTypeInference(sc))
13465 return exp;
13466 exp.ti.dsymbolSemantic(sc);
13467 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
13468 return errorExp();
13470 if (Declaration v = exp.ti.toAlias().isDeclaration())
13472 return new DotVarExp(exp.loc, exp.e1, v)
13473 .expressionSemantic(sc);
13475 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
13476 .expressionSemantic(sc);
13478 else if (e.op == EXP.template_)
13480 exp.ti.tempdecl = (cast(TemplateExp)e).td;
13481 return new ScopeExp(exp.loc, exp.ti)
13482 .expressionSemantic(sc);
13484 else if (DotExp de = e.isDotExp())
13486 if (de.e2.op == EXP.overloadSet)
13488 if (!exp.findTempDecl(sc) || !exp.ti.semanticTiargs(sc))
13490 return errorExp();
13492 if (exp.ti.needsTypeInference(sc))
13493 return exp;
13494 exp.ti.dsymbolSemantic(sc);
13495 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
13496 return errorExp();
13498 if (Declaration v = exp.ti.toAlias().isDeclaration())
13500 if (v.type && !v.type.deco)
13501 v.type = v.type.typeSemantic(v.loc, sc);
13502 return new DotVarExp(exp.loc, exp.e1, v)
13503 .expressionSemantic(sc);
13505 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
13506 .expressionSemantic(sc);
13509 else if (OverExp oe = e.isOverExp())
13511 exp.ti.tempdecl = oe.vars;
13512 return new ScopeExp(exp.loc, exp.ti)
13513 .expressionSemantic(sc);
13516 Lerr:
13517 exp.error("`%s` isn't a template", e.toChars());
13518 return errorExp();
13521 /***************************************
13522 * If expression is shared, check that we can access it.
13523 * Give error message if not.
13525 * Params:
13526 * e = expression to check
13527 * sc = context
13528 * returnRef = Whether this expression is for a `return` statement
13529 * off a `ref` function, in which case a single level
13530 * of dereference is allowed (e.g. `shared(int)*`).
13531 * Returns:
13532 * true on error
13534 bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
13536 if (global.params.noSharedAccess != FeatureState.enabled ||
13537 !sc ||
13538 sc.intypeof ||
13539 sc.flags & SCOPE.ctfe)
13541 return false;
13544 //printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef);
13546 bool check(Expression e, bool allowRef)
13548 bool sharedError(Expression e)
13550 // https://dlang.org/phobos/core_atomic.html
13551 e.error("direct access to shared `%s` is not allowed, see `core.atomic`", e.toChars());
13552 return true;
13555 // Error by default
13556 bool visit(Expression e)
13558 // https://issues.dlang.org/show_bug.cgi?id=23639
13559 // Should be able to cast(shared)
13560 if (!e.isCastExp() && e.type.isShared())
13561 return sharedError(e);
13562 return false;
13565 bool visitNew(NewExp e)
13567 if (e.thisexp)
13568 check(e.thisexp, false);
13569 return false;
13572 bool visitVar(VarExp e)
13574 // https://issues.dlang.org/show_bug.cgi?id=20908
13575 // direct access to init symbols is ok as they
13576 // cannot be modified.
13577 if (e.var.isSymbolDeclaration())
13578 return false;
13580 // https://issues.dlang.org/show_bug.cgi?id=22626
13581 // Synchronized functions don't need to use core.atomic
13582 // when accessing `this`.
13583 if (sc.func && sc.func.isSynchronized())
13585 if (e.var.isThisDeclaration())
13586 return false;
13587 else
13588 return sharedError(e);
13590 else if (!allowRef && e.var.type.isShared())
13591 return sharedError(e);
13593 return false;
13596 bool visitAddr(AddrExp e)
13598 return check(e.e1, true);
13601 bool visitPtr(PtrExp e)
13603 if (!allowRef && e.type.isShared())
13604 return sharedError(e);
13606 if (e.e1.type.isShared())
13607 return sharedError(e);
13609 return check(e.e1, false);
13612 bool visitDotVar(DotVarExp e)
13614 //printf("dotvarexp = %s\n", e.toChars());
13615 if (e.type.isShared())
13617 if (e.e1.isThisExp())
13619 // https://issues.dlang.org/show_bug.cgi?id=22626
13620 if (sc.func && sc.func.isSynchronized())
13621 return false;
13623 // https://issues.dlang.org/show_bug.cgi?id=23790
13624 if (e.e1.type.isTypeStruct())
13625 return false;
13628 auto fd = e.var.isFuncDeclaration();
13629 const sharedFunc = fd && fd.type.isShared;
13630 if (!allowRef && !sharedFunc)
13631 return sharedError(e);
13633 // Allow using `DotVarExp` within value types
13634 if (e.e1.type.isTypeSArray() || e.e1.type.isTypeStruct())
13635 return check(e.e1, allowRef);
13637 // If we end up with a single `VarExp`, it might be a `ref` param
13638 // `shared ref T` param == `shared(T)*`.
13639 if (auto ve = e.e1.isVarExp())
13641 return check(e.e1, allowRef && (ve.var.storage_class & STC.ref_));
13644 return sharedError(e);
13647 return check(e.e1, false);
13650 bool visitIndex(IndexExp e)
13652 if (!allowRef && e.type.isShared())
13653 return sharedError(e);
13655 if (e.e1.type.isShared())
13656 return sharedError(e);
13658 return check(e.e1, false);
13661 bool visitComma(CommaExp e)
13663 // Cannot be `return ref` since we can't use the return,
13664 // but it's better to show that error than an unrelated `shared` one
13665 return check(e.e2, true);
13668 switch (e.op)
13670 default: return visit(e);
13672 // Those have no indirections / can be ignored
13673 case EXP.call:
13674 case EXP.error:
13675 case EXP.complex80:
13676 case EXP.int64:
13677 case EXP.null_: return false;
13679 case EXP.variable: return visitVar(e.isVarExp());
13680 case EXP.new_: return visitNew(e.isNewExp());
13681 case EXP.address: return visitAddr(e.isAddrExp());
13682 case EXP.star: return visitPtr(e.isPtrExp());
13683 case EXP.dotVariable: return visitDotVar(e.isDotVarExp());
13684 case EXP.index: return visitIndex(e.isIndexExp());
13688 return check(e, returnRef);
13693 /****************************************************
13694 * Determine if `exp`, which gets its address taken, can do so safely.
13695 * Params:
13696 * sc = context
13697 * exp = expression having its address taken
13698 * v = the variable getting its address taken
13699 * Returns:
13700 * `true` if ok, `false` for error
13702 bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
13704 //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars());
13705 if (v is null)
13706 return true;
13708 if (!v.canTakeAddressOf())
13710 exp.error("cannot take address of `%s`", exp.toChars());
13711 return false;
13713 if (sc.func && !sc.intypeof && !v.isDataseg())
13715 if (global.params.useDIP1000 != FeatureState.enabled &&
13716 !(v.storage_class & STC.temp) &&
13717 sc.setUnsafe(false, exp.loc, "cannot take address of local `%s` in `@safe` function `%s`", v, sc.func))
13719 return false;
13722 return true;
13725 /**************************************
13726 * This check ensures that the object in `exp` can have its address taken, or
13727 * issue a diagnostic error.
13728 * Params:
13729 * e = expression to check
13730 * sc = context
13731 * Returns:
13732 * true if the expression is addressable
13734 bool checkAddressable(Expression e, Scope* sc)
13736 Expression ex = e;
13737 while (true)
13739 switch (ex.op)
13741 case EXP.dotVariable:
13742 // https://issues.dlang.org/show_bug.cgi?id=22749
13743 // Error about taking address of any bit-field, regardless of
13744 // whether SCOPE.Cfile is set.
13745 if (auto bf = ex.isDotVarExp().var.isBitFieldDeclaration())
13747 e.error("cannot take address of bit-field `%s`", bf.toChars());
13748 return false;
13750 goto case EXP.cast_;
13752 case EXP.index:
13753 ex = ex.isBinExp().e1;
13754 continue;
13756 case EXP.address:
13757 case EXP.array:
13758 case EXP.cast_:
13759 ex = ex.isUnaExp().e1;
13760 continue;
13762 case EXP.variable:
13763 if (sc.flags & SCOPE.Cfile)
13765 // C11 6.5.3.2: A variable that has its address taken cannot be
13766 // stored in a register.
13767 // C11 6.3.2.1: An array that has its address computed with `[]`
13768 // or cast to an lvalue pointer cannot be stored in a register.
13769 if (ex.isVarExp().var.storage_class & STC.register)
13771 if (e.isIndexExp())
13772 e.error("cannot index through register variable `%s`", ex.toChars());
13773 else
13774 e.error("cannot take address of register variable `%s`", ex.toChars());
13775 return false;
13778 break;
13780 default:
13781 break;
13783 break;
13785 return true;
13789 /*******************************
13790 * Checks the attributes of a function.
13791 * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`)
13792 * and usage of `deprecated` and `@disabled`-ed symbols are checked.
13794 * Params:
13795 * exp = expression to check attributes for
13796 * sc = scope of the function
13797 * f = function to be checked
13798 * Returns: `true` if error occur.
13800 private bool checkFunctionAttributes(Expression exp, Scope* sc, FuncDeclaration f)
13802 with(exp)
13804 bool error = checkDisabled(sc, f);
13805 error |= checkDeprecated(sc, f);
13806 error |= checkPurity(sc, f);
13807 error |= checkSafety(sc, f);
13808 error |= checkNogc(sc, f);
13809 return error;
13813 /*******************************
13814 * Helper function for `getRightThis()`.
13815 * Gets `this` of the next outer aggregate.
13816 * Params:
13817 * loc = location to use for error messages
13818 * sc = context
13819 * s = the parent symbol of the existing `this`
13820 * ad = struct or class we need the correct `this` for
13821 * e1 = existing `this`
13822 * t = type of the existing `this`
13823 * var = the specific member of ad we're accessing
13824 * flag = if true, return `null` instead of throwing an error
13825 * Returns:
13826 * Expression representing the `this` for the var
13828 Expression getThisSkipNestedFuncs(const ref Loc loc, Scope* sc, Dsymbol s, AggregateDeclaration ad, Expression e1, Type t, Dsymbol var, bool flag = false)
13830 int n = 0;
13831 while (s && s.isFuncDeclaration())
13833 FuncDeclaration f = s.isFuncDeclaration();
13834 if (f.vthis)
13836 n++;
13837 e1 = new VarExp(loc, f.vthis);
13838 if (f.hasDualContext())
13840 // (*__this)[i]
13841 if (n > 1)
13842 e1 = e1.expressionSemantic(sc);
13843 e1 = new PtrExp(loc, e1);
13844 uint i = f.followInstantiationContext(ad);
13845 e1 = new IndexExp(loc, e1, new IntegerExp(i));
13846 s = f.toParentP(ad);
13847 continue;
13850 else
13852 if (flag)
13853 return null;
13854 e1.error("need `this` of type `%s` to access member `%s` from static function `%s`", ad.toChars(), var.toChars(), f.toChars());
13855 e1 = ErrorExp.get();
13856 return e1;
13858 s = s.toParent2();
13860 if (n > 1 || e1.op == EXP.index)
13861 e1 = e1.expressionSemantic(sc);
13862 if (s && e1.type.equivalent(Type.tvoidptr))
13864 if (auto sad = s.isAggregateDeclaration())
13866 Type ta = sad.handleType();
13867 if (ta.ty == Tstruct)
13868 ta = ta.pointerTo();
13869 e1.type = ta;
13872 e1.type = e1.type.addMod(t.mod);
13873 return e1;
13876 /*******************************
13877 * Make a dual-context container for use as a `this` argument.
13878 * Params:
13879 * loc = location to use for error messages
13880 * sc = current scope
13881 * fd = target function that will take the `this` argument
13882 * Returns:
13883 * Temporary closure variable.
13884 * Note:
13885 * The function `fd` is added to the nested references of the
13886 * newly created variable such that a closure is made for the variable when
13887 * the address of `fd` is taken.
13889 VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration fd)
13891 Type tthis2 = Type.tvoidptr.sarrayOf(2);
13892 VarDeclaration vthis2 = new VarDeclaration(loc, tthis2, Identifier.generateId("__this"), null);
13893 vthis2.storage_class |= STC.temp;
13894 vthis2.dsymbolSemantic(sc);
13895 vthis2.parent = sc.parent;
13896 // make it a closure var
13897 assert(sc.func);
13898 sc.func.closureVars.push(vthis2);
13899 // add `fd` to the nested refs
13900 vthis2.nestedrefs.push(fd);
13901 return vthis2;
13904 /*******************************
13905 * Make sure that the runtime hook `id` exists.
13906 * Params:
13907 * loc = location to use for error messages
13908 * sc = current scope
13909 * id = the hook identifier
13910 * description = what the hook does
13911 * module_ = what module the hook is located in
13912 * Returns:
13913 * a `bool` indicating if the hook is present.
13915 bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string description, Identifier module_ = Id.object)
13917 auto rootSymbol = sc.search(loc, Id.empty, null);
13918 if (auto moduleSymbol = rootSymbol.search(loc, module_))
13919 if (moduleSymbol.search(loc, id))
13920 return true;
13921 error(loc, "`%s.%s` not found. The current runtime does not support %.*s, or the runtime is corrupt.", module_.toChars(), id.toChars(), cast(int)description.length, description.ptr);
13922 return false;
13925 /***************************************
13926 * Fit elements[] to the corresponding types of the `sd`'s fields.
13928 * Params:
13929 * sd = the struct declaration
13930 * loc = location to use for error messages
13931 * sc = context
13932 * elements = explicit arguments used to construct object
13933 * stype = the constructed object type.
13934 * Returns:
13935 * false if any errors occur,
13936 * otherwise true and elements[] are rewritten for the output.
13938 private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions* elements, Type stype)
13940 if (!elements)
13941 return true;
13943 const nfields = sd.nonHiddenFields();
13944 size_t offset = 0;
13945 for (size_t i = 0; i < elements.length; i++)
13947 Expression e = (*elements)[i];
13948 if (!e)
13949 continue;
13951 e = resolveProperties(sc, e);
13952 if (i >= nfields)
13954 if (i < sd.fields.length && e.op == EXP.null_)
13956 // CTFE sometimes creates null as hidden pointer; we'll allow this.
13957 continue;
13959 .error(loc, "more initializers than fields (%llu) of `%s`", cast(ulong)nfields, sd.toChars());
13960 return false;
13962 VarDeclaration v = sd.fields[i];
13963 if (v.offset < offset)
13965 .error(loc, "overlapping initialization for `%s`", v.toChars());
13966 if (!sd.isUnionDeclaration())
13968 enum errorMsg = "`struct` initializers that contain anonymous unions" ~
13969 " must initialize only the first member of a `union`. All subsequent" ~
13970 " non-overlapping fields are default initialized";
13971 .errorSupplemental(loc, errorMsg);
13973 return false;
13975 const vsize = v.type.size();
13976 if (vsize == SIZE_INVALID)
13977 return false;
13978 offset = cast(uint)(v.offset + vsize);
13980 Type t = v.type;
13981 if (stype)
13982 t = t.addMod(stype.mod);
13983 Type origType = t;
13984 Type tb = t.toBasetype();
13986 const hasPointers = tb.hasPointers();
13987 if (hasPointers)
13989 if ((!stype.alignment.isDefault() && stype.alignment.get() < target.ptrsize ||
13990 (v.offset & (target.ptrsize - 1))) &&
13991 (sc.setUnsafe(false, loc,
13992 "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, v)))
13994 return false;
13998 /* Look for case of initializing a static array with a too-short
13999 * string literal, such as:
14000 * char[5] foo = "abc";
14001 * Allow this by doing an explicit cast, which will lengthen the string
14002 * literal.
14004 if (e.op == EXP.string_ && tb.ty == Tsarray)
14006 StringExp se = cast(StringExp)e;
14007 Type typeb = se.type.toBasetype();
14008 TY tynto = tb.nextOf().ty;
14009 if (!se.committed &&
14010 (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar &&
14011 se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger())
14013 e = se.castTo(sc, t);
14014 goto L1;
14018 while (!e.implicitConvTo(t) && tb.ty == Tsarray)
14020 /* Static array initialization, as in:
14021 * T[3][5] = e;
14023 t = tb.nextOf();
14024 tb = t.toBasetype();
14026 if (!e.implicitConvTo(t))
14027 t = origType; // restore type for better diagnostic
14029 e = e.implicitCastTo(sc, t);
14031 if (e.op == EXP.error)
14032 return false;
14034 (*elements)[i] = doCopyOrMove(sc, e);
14036 return true;
14041 * Returns `em` as a VariableExp
14042 * Params:
14043 * em = the EnumMember to wrap
14044 * loc = location of use of em
14045 * sc = scope of use of em
14046 * Returns:
14047 * VarExp referenceing `em` or ErrorExp if `em` if disabled/deprecated
14049 Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc)
14051 dsymbolSemantic(em, sc);
14052 if (em.errors)
14053 return ErrorExp.get();
14054 em.checkDisabled(loc, sc);
14056 if (em.depdecl && !em.depdecl._scope)
14057 em.depdecl._scope = sc;
14058 em.checkDeprecated(loc, sc);
14060 if (em.errors)
14061 return ErrorExp.get();
14062 Expression e = new VarExp(loc, em);
14063 e = e.expressionSemantic(sc);
14064 if (!(sc.flags & SCOPE.Cfile) && em.isCsymbol())
14066 /* C11 types them as int. But if in D file,
14067 * type qualified names as the enum
14069 e.type = em.parent.isEnumDeclaration().type;
14070 assert(e.type);
14072 return e;
14076 /*****************************
14077 * Try to treat `exp` as a boolean,
14078 * Params:
14079 * exp = the expression
14080 * sc = scope to evalute `exp` in
14081 * Returns:
14082 * Modified expression on success, ErrorExp on error
14084 Expression toBoolean(Expression exp, Scope* sc)
14086 switch(exp.op)
14088 case EXP.delete_:
14089 exp.error("`delete` does not give a boolean result");
14090 return ErrorExp.get();
14092 case EXP.comma:
14093 auto ce = exp.isCommaExp();
14094 auto ex2 = ce.e2.toBoolean(sc);
14095 if (ex2.op == EXP.error)
14096 return ex2;
14097 ce.e2 = ex2;
14098 ce.type = ce.e2.type;
14099 return ce;
14101 case EXP.assign:
14102 case EXP.construct:
14103 case EXP.blit:
14104 case EXP.loweredAssignExp:
14105 if (sc.flags & SCOPE.Cfile)
14106 return exp;
14107 // Things like:
14108 // if (a = b) ...
14109 // are usually mistakes.
14110 exp.error("assignment cannot be used as a condition, perhaps `==` was meant?");
14111 return ErrorExp.get();
14113 //LogicalExp
14114 case EXP.andAnd:
14115 case EXP.orOr:
14116 auto le = exp.isLogicalExp();
14117 auto ex2 = le.e2.toBoolean(sc);
14118 if (ex2.op == EXP.error)
14119 return ex2;
14120 le.e2 = ex2;
14121 return le;
14123 case EXP.question:
14124 auto ce = exp.isCondExp();
14125 auto ex1 = ce.e1.toBoolean(sc);
14126 auto ex2 = ce.e2.toBoolean(sc);
14127 if (ex1.op == EXP.error)
14128 return ex1;
14129 if (ex2.op == EXP.error)
14130 return ex2;
14131 ce.e1 = ex1;
14132 ce.e2 = ex2;
14133 return ce;
14136 default:
14137 // Default is 'yes' - do nothing
14138 Expression e = arrayFuncConv(exp, sc);
14139 Type t = e.type;
14140 Type tb = t.toBasetype();
14141 Type att = null;
14143 while (1)
14145 // Structs can be converted to bool using opCast(bool)()
14146 if (auto ts = tb.isTypeStruct())
14148 AggregateDeclaration ad = ts.sym;
14149 /* Don't really need to check for opCast first, but by doing so we
14150 * get better error messages if it isn't there.
14152 if (Dsymbol fd = search_function(ad, Id._cast))
14154 e = new CastExp(exp.loc, e, Type.tbool);
14155 e = e.expressionSemantic(sc);
14156 return e;
14159 // Forward to aliasthis.
14160 if (ad.aliasthis && !isRecursiveAliasThis(att, tb))
14162 e = resolveAliasThis(sc, e);
14163 t = e.type;
14164 tb = e.type.toBasetype();
14165 continue;
14168 break;
14171 if (!t.isBoolean())
14173 if (tb != Type.terror)
14174 exp.error("expression `%s` of type `%s` does not have a boolean value",
14175 exp.toChars(), t.toChars());
14176 return ErrorExp.get();
14178 return e;