d: Merge upstream dmd ff57fec515, druntime ff57fec515, phobos 17bafda79.
[official-gcc.git] / gcc / d / dmd / expressionsem.d
blobe6b90183b51196fcf74a2e3aff5e72000c44fe7f
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.errorsink;
45 import dmd.escape;
46 import dmd.expression;
47 import dmd.file_manager;
48 import dmd.func;
49 import dmd.globals;
50 import dmd.hdrgen;
51 import dmd.id;
52 import dmd.identifier;
53 import dmd.imphint;
54 import dmd.importc;
55 import dmd.init;
56 import dmd.initsem;
57 import dmd.inline;
58 import dmd.intrange;
59 import dmd.location;
60 import dmd.mtype;
61 import dmd.mustuse;
62 import dmd.nspace;
63 import dmd.objc;
64 import dmd.opover;
65 import dmd.optimize;
66 import dmd.parse;
67 import dmd.printast;
68 import dmd.postordervisitor;
69 import dmd.root.array;
70 import dmd.root.ctfloat;
71 import dmd.root.filename;
72 import dmd.common.outbuffer;
73 import dmd.rootobject;
74 import dmd.root.string;
75 import dmd.root.utf;
76 import dmd.semantic2;
77 import dmd.semantic3;
78 import dmd.sideeffect;
79 import dmd.safe;
80 import dmd.target;
81 import dmd.tokens;
82 import dmd.traits;
83 import dmd.typesem;
84 import dmd.typinf;
85 import dmd.utils;
86 import dmd.visitor;
88 enum LOGSEMANTIC = false;
90 /***********************************
91 * Determine if a `this` is needed to access `d`.
92 * Params:
93 * sc = context
94 * d = declaration to check
95 * Returns:
96 * true means a `this` is needed
98 private bool isNeedThisScope(Scope* sc, Declaration d)
100 if (sc.intypeof == 1)
101 return false;
103 AggregateDeclaration ad = d.isThis();
104 if (!ad)
105 return false;
106 //printf("d = %s, ad = %s\n", d.toChars(), ad.toChars());
108 for (Dsymbol s = sc.parent; s; s = s.toParentLocal())
110 //printf("\ts = %s %s, toParent2() = %p\n", s.kind(), s.toChars(), s.toParent2());
111 if (AggregateDeclaration ad2 = s.isAggregateDeclaration())
113 if (ad2 == ad)
114 return false;
115 else if (ad2.isNested())
116 continue;
117 else
118 return true;
120 if (FuncDeclaration f = s.isFuncDeclaration())
122 if (f.isMemberLocal())
123 break;
126 return true;
130 /********************************************************
131 * Perform semantic analysis and CTFE on expressions to produce
132 * a string.
133 * Params:
134 * buf = append generated string to buffer
135 * sc = context
136 * exps = array of Expressions
137 * Returns:
138 * true on error
140 bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps)
142 if (!exps)
143 return false;
145 foreach (ex; *exps)
147 if (!ex)
148 continue;
149 auto sc2 = sc.startCTFE();
150 sc2.tinst = null;
151 sc2.minst = null; // prevents emission of any instantiated templates to object file
152 auto e2 = ex.expressionSemantic(sc2);
153 auto e3 = resolveProperties(sc2, e2);
154 sc2.endCTFE();
156 // allowed to contain types as well as expressions
157 auto e4 = ctfeInterpretForPragmaMsg(e3);
158 if (!e4 || e4.op == EXP.error)
159 return true;
161 // expand tuple
162 if (auto te = e4.isTupleExp())
164 if (expressionsToString(buf, sc, te.exps))
165 return true;
166 continue;
168 // char literals exp `.toStringExp` return `null` but we cant override it
169 // because in most contexts we don't want the conversion to succeed.
170 IntegerExp ie = e4.isIntegerExp();
171 const ty = (ie && ie.type) ? ie.type.ty : Terror;
172 if (ty.isSomeChar)
174 auto tsa = new TypeSArray(ie.type, IntegerExp.literal!1);
175 e4 = new ArrayLiteralExp(ex.loc, tsa, ie);
178 if (StringExp se = e4.toStringExp())
179 buf.writestring(se.toUTF8(sc).peekString());
180 else
181 buf.writestring(e4.toString());
183 return false;
186 /*****************************************
187 * Determine if `this` is available by walking up the enclosing
188 * scopes until a function is found.
190 * Params:
191 * sc = where to start looking for the enclosing function
192 * Returns:
193 * Found function if it satisfies `isThis()`, otherwise `null`
195 FuncDeclaration hasThis(Scope* sc)
197 //printf("hasThis()\n");
198 Dsymbol p = sc.parent;
199 while (p && p.isTemplateMixin())
200 p = p.parent;
201 FuncDeclaration fdthis = p ? p.isFuncDeclaration() : null;
202 //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis.toChars() : "");
204 // Go upwards until we find the enclosing member function
205 FuncDeclaration fd = fdthis;
206 while (1)
208 if (!fd)
210 return null;
212 if (!fd.isNested() || fd.isThis() || (fd.hasDualContext() && fd.isMember2()))
213 break;
215 Dsymbol parent = fd.parent;
216 while (1)
218 if (!parent)
219 return null;
220 TemplateInstance ti = parent.isTemplateInstance();
221 if (ti)
222 parent = ti.parent;
223 else
224 break;
226 fd = parent.isFuncDeclaration();
229 if (!fd.isThis() && !(fd.hasDualContext() && fd.isMember2()))
231 return null;
234 assert(fd.vthis);
235 return fd;
239 extern (D) bool findTempDecl(DotTemplateInstanceExp exp, Scope* sc)
241 auto ti = exp.ti;
242 auto e1 = exp.e1;
243 static if (LOGSEMANTIC)
245 printf("DotTemplateInstanceExp::findTempDecl('%s')\n", exp.toChars());
247 if (ti.tempdecl)
248 return true;
250 Expression e = new DotIdExp(exp.loc, e1, ti.name);
251 e = e.expressionSemantic(sc);
252 if (e.op == EXP.dot)
253 e = (cast(DotExp)e).e2;
255 Dsymbol s = null;
256 switch (e.op)
258 case EXP.overloadSet:
259 s = (cast(OverExp)e).vars;
260 break;
262 case EXP.dotTemplateDeclaration:
263 s = (cast(DotTemplateExp)e).td;
264 break;
266 case EXP.scope_:
267 s = (cast(ScopeExp)e).sds;
268 break;
270 case EXP.dotVariable:
271 s = (cast(DotVarExp)e).var;
272 break;
274 case EXP.variable:
275 s = (cast(VarExp)e).var;
276 break;
278 default:
279 return false;
281 return ti.updateTempDecl(sc, s);
284 /***********************************************************
285 * Resolve `exp` as a compile-time known string.
286 * Params:
287 * sc = scope
288 * exp = Expression which expected as a string
289 * s = What the string is expected for, will be used in error diagnostic.
290 * Returns:
291 * String literal, or `null` if error happens.
293 StringExp semanticString(Scope *sc, Expression exp, const char* s)
295 sc = sc.startCTFE();
296 exp = exp.expressionSemantic(sc);
297 exp = resolveProperties(sc, exp);
298 sc = sc.endCTFE();
300 if (exp.op == EXP.error)
301 return null;
303 auto e = exp;
304 if (exp.type.isString())
306 e = e.ctfeInterpret();
307 if (e.op == EXP.error)
308 return null;
311 auto se = e.toStringExp();
312 if (!se)
314 error(exp.loc, "`string` expected for %s, not `(%s)` of type `%s`",
315 s, exp.toChars(), exp.type.toChars());
316 return null;
318 return se;
321 /****************************************
322 * Convert string to char[].
324 StringExp toUTF8(StringExp se, Scope* sc)
326 if (se.sz != 1)
328 // Convert to UTF-8 string
329 se.committed = false;
330 Expression e = castTo(se, sc, Type.tchar.arrayOf());
331 e = e.optimize(WANTvalue);
332 auto result = e.isStringExp();
333 assert(result.sz == 1);
334 return result;
336 return se;
339 private Expression reorderSettingAAElem(BinExp exp, Scope* sc)
341 BinExp be = exp;
343 auto ie = be.e1.isIndexExp();
344 if (!ie)
345 return be;
346 if (ie.e1.type.toBasetype().ty != Taarray)
347 return be;
349 /* Fix evaluation order of setting AA element
350 * https://issues.dlang.org/show_bug.cgi?id=3825
351 * Rewrite:
352 * aa[k1][k2][k3] op= val;
353 * as:
354 * auto ref __aatmp = aa;
355 * auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3;
356 * auto ref __aaval = val;
357 * __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval; // assignment
360 Expression e0;
361 while (1)
363 Expression de;
364 ie.e2 = extractSideEffect(sc, "__aakey", de, ie.e2);
365 e0 = Expression.combine(de, e0);
367 auto ie1 = ie.e1.isIndexExp();
368 if (!ie1 ||
369 ie1.e1.type.toBasetype().ty != Taarray)
371 break;
373 ie = ie1;
375 assert(ie.e1.type.toBasetype().ty == Taarray);
377 Expression de;
378 ie.e1 = extractSideEffect(sc, "__aatmp", de, ie.e1);
379 e0 = Expression.combine(de, e0);
381 be.e2 = extractSideEffect(sc, "__aaval", e0, be.e2, true);
383 //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars());
384 return Expression.combine(e0, be);
388 private Expression checkOpAssignTypes(BinExp binExp, Scope* sc)
390 auto e1 = binExp.e1;
391 auto e2 = binExp.e2;
392 auto op = binExp.op;
393 auto type = binExp.type;
394 auto loc = binExp.loc;
396 // At that point t1 and t2 are the merged types. type is the original type of the lhs.
397 Type t1 = e1.type;
398 Type t2 = e2.type;
400 // T opAssign floating yields a floating. Prevent truncating conversions (float to int).
401 // See https://issues.dlang.org/show_bug.cgi?id=3841.
402 // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ?
403 if (op == EXP.addAssign || op == EXP.minAssign ||
404 op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign ||
405 op == EXP.powAssign)
407 if ((type.isintegral() && t2.isfloating()))
409 warning(loc, "`%s %s %s` is performing truncating conversion", type.toChars(), EXPtoString(op).ptr, t2.toChars());
413 // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
414 if (op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign)
416 // Any multiplication by an imaginary or complex number yields a complex result.
417 // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
418 const(char)* opstr = EXPtoString(op).ptr;
419 if (t1.isreal() && t2.iscomplex())
421 error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
422 return ErrorExp.get();
424 else if (t1.isimaginary() && t2.iscomplex())
426 error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
427 return ErrorExp.get();
429 else if ((t1.isreal() || t1.isimaginary()) && t2.isimaginary())
431 error(loc, "`%s %s %s` is an undefined operation", t1.toChars(), opstr, t2.toChars());
432 return ErrorExp.get();
436 // generate an error if this is a nonsensical += or -=, eg real += imaginary
437 if (op == EXP.addAssign || op == EXP.minAssign)
439 // Addition or subtraction of a real and an imaginary is a complex result.
440 // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
441 if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex())))
443 error(loc, "`%s %s %s` is undefined (result is complex)", t1.toChars(), EXPtoString(op).ptr, t2.toChars());
444 return ErrorExp.get();
446 if (type.isreal() || type.isimaginary())
448 assert(global.errors || t2.isfloating());
449 e2 = e2.castTo(sc, t1);
452 if (op == EXP.mulAssign)
454 if (t2.isfloating())
456 if (t1.isreal())
458 if (t2.isimaginary() || t2.iscomplex())
460 e2 = e2.castTo(sc, t1);
463 else if (t1.isimaginary())
465 if (t2.isimaginary() || t2.iscomplex())
467 switch (t1.ty)
469 case Timaginary32:
470 t2 = Type.tfloat32;
471 break;
473 case Timaginary64:
474 t2 = Type.tfloat64;
475 break;
477 case Timaginary80:
478 t2 = Type.tfloat80;
479 break;
481 default:
482 assert(0);
484 e2 = e2.castTo(sc, t2);
489 else if (op == EXP.divAssign)
491 if (t2.isimaginary())
493 if (t1.isreal())
495 // x/iv = i(-x/v)
496 // Therefore, the result is 0
497 e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1));
498 e2.type = t1;
499 Expression e = new AssignExp(loc, e1, e2);
500 e.type = t1;
501 return e;
503 else if (t1.isimaginary())
505 Type t3;
506 switch (t1.ty)
508 case Timaginary32:
509 t3 = Type.tfloat32;
510 break;
512 case Timaginary64:
513 t3 = Type.tfloat64;
514 break;
516 case Timaginary80:
517 t3 = Type.tfloat80;
518 break;
520 default:
521 assert(0);
523 e2 = e2.castTo(sc, t3);
524 Expression e = new AssignExp(loc, e1, e2);
525 e.type = t1;
526 return e;
530 else if (op == EXP.modAssign)
532 if (t2.iscomplex())
534 error(loc, "cannot perform modulo complex arithmetic");
535 return ErrorExp.get();
538 return binExp;
541 private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue)
543 Expression e0;
544 Expression e1 = Expression.extractLast(ue.e1, e0);
545 // https://issues.dlang.org/show_bug.cgi?id=12585
546 // Extract the side effect part if ue.e1 is comma.
548 if ((sc.flags & SCOPE.ctfe) ? hasSideEffect(e1) : !isTrivialExp(e1)) // match logic in extractSideEffect()
550 /* Even if opDollar is needed, 'e1' should be evaluate only once. So
551 * Rewrite:
552 * e1.opIndex( ... use of $ ... )
553 * e1.opSlice( ... use of $ ... )
554 * as:
555 * (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...)
556 * (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
558 e1 = extractSideEffect(sc, "__dop", e0, e1, false);
559 assert(e1.isVarExp());
560 e1.isVarExp().var.storage_class |= STC.exptemp; // lifetime limited to expression
562 ue.e1 = e1;
563 return e0;
566 /**************************************
567 * Runs semantic on ae.arguments. Declares temporary variables
568 * if '$' was used.
570 Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0)
572 assert(!ae.lengthVar);
573 *pe0 = null;
574 AggregateDeclaration ad = isAggregate(ae.e1.type);
575 Dsymbol slice = search_function(ad, Id.slice);
576 //printf("slice = %s %s\n", slice.kind(), slice.toChars());
577 foreach (i, e; *ae.arguments)
579 if (i == 0)
580 *pe0 = extractOpDollarSideEffect(sc, ae);
582 if (e.op == EXP.interval && !(slice && slice.isTemplateDeclaration()))
584 Lfallback:
585 if (ae.arguments.length == 1)
586 return null;
587 error(ae.loc, "multi-dimensional slicing requires template `opSlice`");
588 return ErrorExp.get();
590 //printf("[%d] e = %s\n", i, e.toChars());
592 // Create scope for '$' variable for this dimension
593 auto sym = new ArrayScopeSymbol(sc, ae);
594 sym.parent = sc.scopesym;
595 sc = sc.push(sym);
596 ae.lengthVar = null; // Create it only if required
597 ae.currentDimension = i; // Dimension for $, if required
599 e = e.expressionSemantic(sc);
600 e = resolveProperties(sc, e);
602 if (ae.lengthVar && sc.func)
604 // If $ was used, declare it now
605 Expression de = new DeclarationExp(ae.loc, ae.lengthVar);
606 de = de.expressionSemantic(sc);
607 *pe0 = Expression.combine(*pe0, de);
609 sc = sc.pop();
611 if (auto ie = e.isIntervalExp())
613 auto tiargs = new Objects();
614 Expression edim = new IntegerExp(ae.loc, i, Type.tsize_t);
615 edim = edim.expressionSemantic(sc);
616 tiargs.push(edim);
618 auto fargs = new Expressions(2);
619 (*fargs)[0] = ie.lwr;
620 (*fargs)[1] = ie.upr;
622 uint xerrors = global.startGagging();
623 sc = sc.push();
624 FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, ArgumentList(fargs), FuncResolveFlag.quiet);
625 sc = sc.pop();
626 global.endGagging(xerrors);
627 if (!fslice)
628 goto Lfallback;
630 e = new DotTemplateInstanceExp(ae.loc, ae.e1, slice.ident, tiargs);
631 e = new CallExp(ae.loc, e, fargs);
632 e = e.expressionSemantic(sc);
635 if (!e.type)
637 error(ae.loc, "`%s` has no value", e.toChars());
638 e = ErrorExp.get();
640 if (e.op == EXP.error)
641 return e;
643 (*ae.arguments)[i] = e;
645 return ae;
648 /**************************************
649 * Runs semantic on se.lwr and se.upr. Declares a temporary variable
650 * if '$' was used.
651 * Returns:
652 * ae, or ErrorExp if errors occurred
654 Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* pe0)
656 //assert(!ae.lengthVar);
657 if (!ie)
658 return ae;
660 VarDeclaration lengthVar = ae.lengthVar;
661 bool errors = false;
663 // create scope for '$'
664 auto sym = new ArrayScopeSymbol(sc, ae);
665 sym.parent = sc.scopesym;
666 sc = sc.push(sym);
668 Expression sem(Expression e)
670 e = e.expressionSemantic(sc);
671 e = resolveProperties(sc, e);
672 if (!e.type)
674 error(ae.loc, "`%s` has no value", e.toChars());
675 errors = true;
677 return e;
680 ie.lwr = sem(ie.lwr);
681 ie.upr = sem(ie.upr);
683 if (ie.lwr.isErrorExp() || ie.upr.isErrorExp())
684 errors = true;
686 if (lengthVar != ae.lengthVar && sc.func)
688 // If $ was used, declare it now
689 Expression de = new DeclarationExp(ae.loc, ae.lengthVar);
690 de = de.expressionSemantic(sc);
691 *pe0 = Expression.combine(*pe0, de);
694 sc = sc.pop();
696 return errors ? ErrorExp.get() : ae;
699 /******************************
700 * Perform semantic() on an array of Expressions.
702 extern(D) bool arrayExpressionSemantic(
703 Expression[] exps, Scope* sc, bool preserveErrors = false)
705 bool err = false;
706 foreach (ref e; exps)
708 if (e is null) continue;
709 auto e2 = e.expressionSemantic(sc);
710 if (e2.op == EXP.error)
711 err = true;
712 if (preserveErrors || e2.op != EXP.error)
713 e = e2;
715 return err;
718 /************************************************
719 * Handle the postblit call on lvalue, or the move of rvalue.
721 * Params:
722 * sc = the scope where the expression is encountered
723 * e = the expression the needs to be moved or copied (source)
724 * t = if the struct defines a copy constructor, the type of the destination
726 * Returns:
727 * The expression that copy constructs or moves the value.
729 extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t = null)
731 if (auto ce = e.isCondExp())
733 ce.e1 = doCopyOrMove(sc, ce.e1);
734 ce.e2 = doCopyOrMove(sc, ce.e2);
736 else
738 e = e.isLvalue() ? callCpCtor(sc, e, t) : valueNoDtor(e);
740 return e;
743 /*********************************************
744 * If e is an instance of a struct, and that struct has a copy constructor,
745 * rewrite e as:
746 * (tmp = e),tmp
747 * Input:
748 * sc = just used to specify the scope of created temporary variable
749 * destinationType = the type of the object on which the copy constructor is called;
750 * may be null if the struct defines a postblit
752 private Expression callCpCtor(Scope* sc, Expression e, Type destinationType)
754 if (auto ts = e.type.baseElemOf().isTypeStruct())
756 StructDeclaration sd = ts.sym;
757 if (sd.postblit || sd.hasCopyCtor)
759 /* Create a variable tmp, and replace the argument e with:
760 * (tmp = e),tmp
761 * and let AssignExp() handle the construction.
762 * This is not the most efficient, ideally tmp would be constructed
763 * directly onto the stack.
765 auto tmp = copyToTemp(STC.rvalue, "__copytmp", e);
766 if (sd.hasCopyCtor && destinationType)
768 // https://issues.dlang.org/show_bug.cgi?id=22619
769 // If the destination type is inout we can preserve it
770 // only if inside an inout function; if we are not inside
771 // an inout function, then we will preserve the type of
772 // the source
773 if (destinationType.hasWild && !(sc.func.storage_class & STC.wild))
774 tmp.type = e.type;
775 else
776 tmp.type = destinationType;
778 tmp.storage_class |= STC.nodtor;
779 tmp.dsymbolSemantic(sc);
780 Expression de = new DeclarationExp(e.loc, tmp);
781 Expression ve = new VarExp(e.loc, tmp);
782 de.type = Type.tvoid;
783 ve.type = e.type;
784 return Expression.combine(de, ve);
787 return e;
790 /************************************************
791 * If we want the value of this expression, but do not want to call
792 * the destructor on it.
794 Expression valueNoDtor(Expression e)
796 auto ex = lastComma(e);
798 if (auto ce = ex.isCallExp())
800 /* The struct value returned from the function is transferred
801 * so do not call the destructor on it.
802 * Recognize:
803 * ((S _ctmp = S.init), _ctmp).this(...)
804 * and make sure the destructor is not called on _ctmp
805 * BUG: if ex is a CommaExp, we should go down the right side.
807 if (auto dve = ce.e1.isDotVarExp())
809 if (dve.var.isCtorDeclaration())
811 // It's a constructor call
812 if (auto comma = dve.e1.isCommaExp())
814 if (auto ve = comma.e2.isVarExp())
816 VarDeclaration ctmp = ve.var.isVarDeclaration();
817 if (ctmp)
819 ctmp.storage_class |= STC.nodtor;
820 assert(!ce.isLvalue());
827 else if (auto ve = ex.isVarExp())
829 auto vtmp = ve.var.isVarDeclaration();
830 if (vtmp && (vtmp.storage_class & STC.rvalue))
832 vtmp.storage_class |= STC.nodtor;
835 return e;
839 Checks if `exp` contains a direct access to a `noreturn`
840 variable. If that is the case, an `assert(0)` expression
841 is generated and returned. This function should be called
842 only after semantic analysis has been performed on `exp`.
844 Params:
845 exp = expression that is checked
847 Returns:
848 An `assert(0)` expression if `exp` contains a `noreturn`
849 variable access, `exp` otherwise.
852 Expression checkNoreturnVarAccess(Expression exp)
854 assert(exp.type);
856 Expression result = exp;
857 if (exp.type.isTypeNoreturn() && !exp.isAssertExp() &&
858 !exp.isThrowExp() && !exp.isCallExp())
860 auto msg = new StringExp(exp.loc, "Accessed expression of type `noreturn`");
861 msg.type = Type.tstring;
862 result = new AssertExp(exp.loc, IntegerExp.literal!0, msg);
863 result.type = exp.type;
866 return result;
869 /******************************
870 * Find symbol in accordance with the UFCS name look up rule
872 private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
874 //printf("searchUFCS(ident = %s)\n", ident.toChars());
875 Loc loc = ue.loc;
877 // TODO: merge with Scope.search.searchScopes()
878 Dsymbol searchScopes(int flags)
880 Dsymbol s = null;
881 for (Scope* scx = sc; scx; scx = scx.enclosing)
883 if (!scx.scopesym)
884 continue;
885 if (scx.scopesym.isModule())
886 flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
887 s = scx.scopesym.search(loc, ident, flags);
888 if (s)
890 // overload set contains only module scope symbols.
891 if (s.isOverloadSet())
892 break;
893 // selective/renamed imports also be picked up
894 if (AliasDeclaration ad = s.isAliasDeclaration())
896 if (ad._import)
897 break;
899 // See only module scope symbols for UFCS target.
900 Dsymbol p = s.toParent2();
901 if (p && p.isModule())
902 break;
904 s = null;
906 // Stop when we hit a module, but keep going if that is not just under the global scope
907 if (scx.scopesym.isModule() && !(scx.enclosing && !scx.enclosing.enclosing))
908 break;
910 return s;
913 int flags = 0;
914 Dsymbol s;
916 if (sc.flags & SCOPE.ignoresymbolvisibility)
917 flags |= IgnoreSymbolVisibility;
919 // First look in local scopes
920 s = searchScopes(flags | SearchLocalsOnly);
921 if (!s)
923 // Second look in imported modules
924 s = searchScopes(flags | SearchImportsOnly);
927 if (!s)
928 return ue.e1.type.getProperty(sc, loc, ident, 0, ue.e1);
930 FuncDeclaration f = s.isFuncDeclaration();
931 if (f)
933 TemplateDeclaration td = getFuncTemplateDecl(f);
934 if (td)
936 if (td.overroot)
937 td = td.overroot;
938 s = td;
942 if (auto dti = ue.isDotTemplateInstanceExp())
944 // https://issues.dlang.org/show_bug.cgi?id=23968
945 // Typically, deprecated alias declarations are caught
946 // when `TemplateInstance.findTempDecl` is called,
947 // however, in this case the tempdecl field is updated
948 // therefore `findTempDecl` will return immediately
949 // and not get the chance to issue the deprecation.
950 if (s.isAliasDeclaration())
951 s.checkDeprecated(ue.loc, sc);
953 auto ti = new TemplateInstance(loc, s.ident, dti.ti.tiargs);
954 if (!ti.updateTempDecl(sc, s))
955 return ErrorExp.get();
956 return new ScopeExp(loc, ti);
958 else
960 //printf("-searchUFCS() %s\n", s.toChars());
961 return new DsymbolExp(loc, s);
965 /******************************
966 * check e is exp.opDispatch!(tiargs) or not
967 * It's used to switch to UFCS the semantic analysis path
969 private bool isDotOpDispatch(Expression e)
971 if (auto dtie = e.isDotTemplateInstanceExp())
972 return dtie.ti.name == Id.opDispatch;
973 return false;
976 private void hookDtors(CondExp ce, Scope* sc)
978 extern (C++) final class DtorVisitor : StoppableVisitor
980 alias visit = typeof(super).visit;
981 public:
982 Scope* sc;
983 CondExp ce;
984 VarDeclaration vcond;
985 bool isThen;
987 extern (D) this(Scope* sc, CondExp ce) @safe
989 this.sc = sc;
990 this.ce = ce;
993 override void visit(Expression e)
995 //printf("(e = %s)\n", e.toChars());
998 override void visit(DeclarationExp e)
1000 auto v = e.declaration.isVarDeclaration();
1001 if (v && !v.isDataseg())
1003 if (v._init)
1005 if (auto ei = v._init.isExpInitializer())
1006 walkPostorder(ei.exp, this);
1009 if (v.edtor)
1010 walkPostorder(v.edtor, this);
1012 if (v.needsScopeDtor())
1014 if (!vcond)
1016 vcond = copyToTemp(STC.volatile_ | STC.const_, "__cond", ce.econd);
1017 vcond.dsymbolSemantic(sc);
1019 Expression de = new DeclarationExp(ce.econd.loc, vcond);
1020 de = de.expressionSemantic(sc);
1022 Expression ve = new VarExp(ce.econd.loc, vcond);
1023 ce.econd = Expression.combine(de, ve);
1026 //printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
1027 Expression ve = new VarExp(vcond.loc, vcond);
1028 if (isThen)
1029 v.edtor = new LogicalExp(v.edtor.loc, EXP.andAnd, ve, v.edtor);
1030 else
1031 v.edtor = new LogicalExp(v.edtor.loc, EXP.orOr, ve, v.edtor);
1032 v.edtor = v.edtor.expressionSemantic(sc);
1033 //printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
1039 scope DtorVisitor v = new DtorVisitor(sc, ce);
1040 //printf("+%s\n", toChars());
1041 v.isThen = true;
1042 walkPostorder(ce.e1, v);
1043 v.isThen = false;
1044 walkPostorder(ce.e2, v);
1045 //printf("-%s\n", toChars());
1049 /******************************
1050 * Pull out callable entity with UFCS.
1052 private Expression resolveUFCS(Scope* sc, CallExp ce)
1054 Loc loc = ce.loc;
1055 Expression eleft;
1056 Expression e;
1058 if (auto die = ce.e1.isDotIdExp())
1060 Identifier ident = die.ident;
1062 Expression ex = die.dotIdSemanticPropX(sc);
1063 if (ex != die)
1065 ce.e1 = ex;
1066 return null;
1068 eleft = die.e1;
1070 Type t = eleft.type.toBasetype();
1071 if (t.ty == Tarray || t.ty == Tsarray || t.ty == Tnull || (t.isTypeBasic() && t.ty != Tvoid))
1073 /* Built-in types and arrays have no callable properties, so do shortcut.
1074 * It is necessary in: e.init()
1077 else if (t.ty == Taarray)
1079 if (ident == Id.remove)
1081 /* Transform:
1082 * aa.remove(arg) into delete aa[arg]
1084 if (!ce.arguments || ce.arguments.length != 1)
1086 error(ce.loc, "expected key as argument to `aa.remove()`");
1087 return ErrorExp.get();
1089 if (!eleft.type.isMutable())
1091 error(ce.loc, "cannot remove key from `%s` associative array `%s`", MODtoChars(t.mod), eleft.toChars());
1092 return ErrorExp.get();
1094 Expression key = (*ce.arguments)[0];
1095 key = key.expressionSemantic(sc);
1096 key = resolveProperties(sc, key);
1098 TypeAArray taa = t.isTypeAArray();
1099 key = key.implicitCastTo(sc, taa.index);
1101 if (key.checkValue() || key.checkSharedAccess(sc))
1102 return ErrorExp.get();
1104 semanticTypeInfo(sc, taa.index);
1106 return new RemoveExp(loc, eleft, key);
1109 else
1111 if (Expression ey = die.dotIdSemanticProp(sc, 1))
1113 if (ey.op == EXP.error)
1114 return ey;
1115 ce.e1 = ey;
1116 if (isDotOpDispatch(ey))
1118 // even opDispatch and UFCS must have valid arguments,
1119 // so now that we've seen indication of a problem,
1120 // check them for issues.
1121 Expressions* originalArguments = Expression.arraySyntaxCopy(ce.arguments);
1123 uint errors = global.startGagging();
1124 e = ce.expressionSemantic(sc);
1125 if (!global.endGagging(errors))
1126 return e;
1128 if (arrayExpressionSemantic(originalArguments.peekSlice(), sc))
1129 return ErrorExp.get();
1131 /* fall down to UFCS */
1133 else
1134 return null;
1138 /* https://issues.dlang.org/show_bug.cgi?id=13953
1140 * If a struct has an alias this to an associative array
1141 * and remove is used on a struct instance, we have to
1142 * check first if there is a remove function that can be called
1143 * on the struct. If not we must check the alias this.
1145 * struct A
1147 * string[string] a;
1148 * alias a this;
1151 * void fun()
1153 * A s;
1154 * s.remove("foo");
1157 const errors = global.startGagging();
1158 e = searchUFCS(sc, die, ident);
1159 // if there were any errors and the identifier was remove
1160 if (global.endGagging(errors))
1162 if (ident == Id.remove)
1164 // check alias this
1165 Expression alias_e = resolveAliasThis(sc, die.e1, 1);
1166 if (alias_e && alias_e != die.e1)
1168 die.e1 = alias_e;
1169 CallExp ce2 = ce.syntaxCopy();
1170 ce2.e1 = die;
1171 e = ce2.isCallExp().trySemantic(sc);
1172 if (e)
1173 return e;
1176 // if alias this did not work out, print the initial errors
1177 searchUFCS(sc, die, ident);
1180 else if (auto dti = ce.e1.isDotTemplateInstanceExp())
1182 if (Expression ey = dti.dotTemplateSemanticProp(sc, DotExpFlag.gag))
1184 ce.e1 = ey;
1185 return null;
1187 eleft = dti.e1;
1188 e = searchUFCS(sc, dti, dti.ti.name);
1190 else
1191 return null;
1193 // Rewrite
1194 ce.e1 = e;
1195 if (!ce.arguments)
1196 ce.arguments = new Expressions();
1197 ce.arguments.shift(eleft);
1198 if (!ce.names)
1199 ce.names = new Identifiers();
1200 ce.names.shift(null);
1201 ce.isUfcsRewrite = true;
1202 return null;
1205 int expandAliasThisTuples(Expressions* exps, size_t starti = 0)
1207 if (!exps || exps.length == 0)
1208 return -1;
1210 for (size_t u = starti; u < exps.length; u++)
1212 Expression exp = (*exps)[u];
1213 if (TupleDeclaration td = exp.isAliasThisTuple)
1215 exps.remove(u);
1216 size_t i;
1217 td.foreachVar((s)
1219 auto d = s.isDeclaration();
1220 auto e = new DotVarExp(exp.loc, exp, d);
1221 assert(d.type);
1222 e.type = d.type;
1223 exps.insert(u + i, e);
1224 ++i;
1226 version (none)
1228 printf("expansion ->\n");
1229 foreach (e; exps)
1231 printf("\texps[%d] e = %s %s\n", i, EXPtoString(e.op), e.toChars());
1234 return cast(int)u;
1237 return -1;
1240 /******************************
1241 * Pull out property with UFCS.
1243 private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2 = null)
1245 Loc loc = e1.loc;
1246 Expression eleft;
1247 Expression e;
1249 if (auto die = e1.isDotIdExp())
1251 eleft = die.e1;
1252 e = searchUFCS(sc, die, die.ident);
1254 else if (auto dti = e1.isDotTemplateInstanceExp())
1256 eleft = dti.e1;
1257 e = searchUFCS(sc, dti, dti.ti.name);
1259 else
1260 return null;
1262 if (e is null)
1263 return null;
1265 // Rewrite
1266 if (e2)
1268 // run semantic without gagging
1269 e2 = e2.expressionSemantic(sc);
1271 /* f(e1) = e2
1273 Expression ex = e.copy();
1274 auto a1 = new Expressions(1);
1275 (*a1)[0] = eleft;
1276 ex = new CallExp(loc, ex, a1);
1277 auto e1PassSemantic = ex.trySemantic(sc);
1279 /* f(e1, e2)
1281 auto a2 = new Expressions(2);
1282 (*a2)[0] = eleft;
1283 (*a2)[1] = e2;
1284 e = new CallExp(loc, e, a2);
1285 e = e.trySemantic(sc);
1286 if (!e1PassSemantic && !e)
1288 /* https://issues.dlang.org/show_bug.cgi?id=20448
1290 * If both versions have failed to pass semantic,
1291 * f(e1) = e2 gets priority in error printing
1292 * because f might be a templated function that
1293 * failed to instantiate and we have to print
1294 * the instantiation errors.
1296 return e1.expressionSemantic(sc);
1298 else if (ex && !e)
1300 ex = new AssignExp(loc, ex, e2);
1301 return ex.expressionSemantic(sc);
1303 else
1305 // strict setter prints errors if fails
1306 e = e.expressionSemantic(sc);
1308 return e;
1310 else
1312 /* f(e1)
1314 auto arguments = new Expressions(1);
1315 (*arguments)[0] = eleft;
1316 e = new CallExp(loc, e, arguments);
1318 // https://issues.dlang.org/show_bug.cgi?id=24017
1319 if (sc.flags & SCOPE.debug_)
1320 e.isCallExp().inDebugStatement = true;
1322 e = e.expressionSemantic(sc);
1323 return e;
1327 /******************************
1328 * If e1 is a property function (template), resolve it.
1330 Expression resolvePropertiesOnly(Scope* sc, Expression e1)
1332 //printf("e1 = %s %s\n", Token.toChars(e1.op), e1.toChars());
1334 Expression handleOverloadSet(OverloadSet os)
1336 assert(os);
1337 foreach (s; os.a)
1339 auto fd = s.isFuncDeclaration();
1340 auto td = s.isTemplateDeclaration();
1341 if (fd)
1343 if (fd.type.isTypeFunction().isproperty)
1344 return resolveProperties(sc, e1);
1346 else if (td && td.onemember && (fd = td.onemember.isFuncDeclaration()) !is null)
1348 if (fd.type.isTypeFunction().isproperty ||
1349 (fd.storage_class2 & STC.property) ||
1350 (td._scope.stc & STC.property))
1351 return resolveProperties(sc, e1);
1354 return e1;
1357 Expression handleTemplateDecl(TemplateDeclaration td)
1359 assert(td);
1360 if (td.onemember)
1362 if (auto fd = td.onemember.isFuncDeclaration())
1364 if (fd.type.isTypeFunction().isproperty ||
1365 (fd.storage_class2 & STC.property) ||
1366 (td._scope.stc & STC.property))
1367 return resolveProperties(sc, e1);
1370 return e1;
1373 Expression handleFuncDecl(FuncDeclaration fd)
1375 assert(fd);
1376 if (fd.type.isTypeFunction().isproperty)
1377 return resolveProperties(sc, e1);
1378 return e1;
1381 if (auto de = e1.isDotExp())
1383 if (auto os = de.e2.isOverExp())
1384 return handleOverloadSet(os.vars);
1386 else if (auto oe = e1.isOverExp())
1387 return handleOverloadSet(oe.vars);
1388 else if (auto dti = e1.isDotTemplateInstanceExp())
1390 if (dti.ti.tempdecl)
1391 if (auto td = dti.ti.tempdecl.isTemplateDeclaration())
1392 return handleTemplateDecl(td);
1394 else if (auto dte = e1.isDotTemplateExp())
1395 return handleTemplateDecl(dte.td);
1396 else if (auto se = e1.isScopeExp())
1398 Dsymbol s = se.sds;
1399 TemplateInstance ti = s.isTemplateInstance();
1400 if (ti && !ti.semanticRun && ti.tempdecl)
1401 if (auto td = ti.tempdecl.isTemplateDeclaration())
1402 return handleTemplateDecl(td);
1404 else if (auto et = e1.isTemplateExp())
1405 return handleTemplateDecl(et.td);
1406 else if (e1.isDotVarExp() && e1.type.isTypeFunction())
1408 DotVarExp dve = e1.isDotVarExp();
1409 return handleFuncDecl(dve.var.isFuncDeclaration());
1411 else if (e1.isVarExp() && e1.type && e1.type.isTypeFunction() && (sc.intypeof || !e1.isVarExp().var.needThis()))
1412 return handleFuncDecl(e1.isVarExp().var.isFuncDeclaration());
1413 return e1;
1416 /****************************************
1417 * Turn symbol `s` into the expression it represents.
1419 * Params:
1420 * s = symbol to resolve
1421 * loc = location of use of `s`
1422 * sc = context
1423 * hasOverloads = applies if `s` represents a function.
1424 * true means it's overloaded and will be resolved later,
1425 * false means it's the exact function symbol.
1426 * Returns:
1427 * `s` turned into an expression, `ErrorExp` if an error occurred
1429 Expression symbolToExp(Dsymbol s, const ref Loc loc, Scope *sc, bool hasOverloads)
1431 static if (LOGSEMANTIC)
1433 printf("DsymbolExp::resolve(%s %s)\n", s.kind(), s.toChars());
1436 Lagain:
1437 Expression e;
1439 //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars());
1440 //printf("s = '%s', s.kind = '%s'\n", s.toChars(), s.kind());
1441 Dsymbol olds = s;
1442 Declaration d = s.isDeclaration();
1443 if (d && (d.storage_class & STC.templateparameter))
1445 s = s.toAlias();
1447 else
1449 // functions are checked after overloading
1450 // templates are checked after matching constraints
1451 if (!s.isFuncDeclaration() && !s.isTemplateDeclaration())
1453 s.checkDeprecated(loc, sc);
1454 if (d)
1455 d.checkDisabled(loc, sc);
1458 // https://issues.dlang.org/show_bug.cgi?id=12023
1459 // if 's' is a tuple variable, the tuple is returned.
1460 s = s.toAlias();
1462 //printf("s = '%s', s.kind = '%s', s.needThis() = %p\n", s.toChars(), s.kind(), s.needThis());
1463 if (s != olds && !s.isFuncDeclaration() && !s.isTemplateDeclaration())
1465 s.checkDeprecated(loc, sc);
1466 if (d)
1467 d.checkDisabled(loc, sc);
1470 if (auto sd = s.isDeclaration())
1472 if (sd.isSystem())
1474 if (sc.setUnsafePreview(global.params.systemVariables, false, loc,
1475 "cannot access `@system` variable `%s` in @safe code", sd))
1477 if (auto v = sd.isVarDeclaration())
1479 if (v.systemInferred)
1480 errorSupplemental(v.loc, "`%s` is inferred to be `@system` from its initializer here", v.toChars());
1481 else
1482 errorSupplemental(v.loc, "`%s` is declared here", v.toChars());
1484 return ErrorExp.get();
1490 if (auto em = s.isEnumMember())
1492 return em.getVarExp(loc, sc);
1494 if (auto v = s.isVarDeclaration())
1496 //printf("Identifier '%s' is a variable, type '%s'\n", s.toChars(), v.type.toChars());
1497 if (sc.intypeof == 1 && !v.inuse)
1498 v.dsymbolSemantic(sc);
1499 if (!v.type || // during variable type inference
1500 !v.type.deco && v.inuse) // during variable type semantic
1502 if (v.inuse) // variable type depends on the variable itself
1503 error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
1504 else // variable type cannot be determined
1505 error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
1506 return ErrorExp.get();
1508 if (v.type.ty == Terror)
1509 return ErrorExp.get();
1511 if ((v.storage_class & STC.manifest) && v._init)
1513 if (v.inuse)
1515 error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
1516 return ErrorExp.get();
1518 e = v.expandInitializer(loc);
1519 v.inuse++;
1520 e = e.expressionSemantic(sc);
1521 v.inuse--;
1522 return e;
1525 // We need to run semantics to correctly set 'STC.field' if it is a member variable
1526 // that could be forward referenced. This is needed for 'v.needThis()' to work
1527 if (v.isThis())
1528 v.dsymbolSemantic(sc);
1530 // Change the ancestor lambdas to delegate before hasThis(sc) call.
1531 if (v.checkNestedReference(sc, loc))
1532 return ErrorExp.get();
1534 if (v.needThis() && hasThis(sc))
1535 e = new DotVarExp(loc, new ThisExp(loc), v);
1536 else
1537 e = new VarExp(loc, v);
1538 e = e.expressionSemantic(sc);
1539 return e;
1541 if (auto fld = s.isFuncLiteralDeclaration())
1543 //printf("'%s' is a function literal\n", fld.toChars());
1544 e = new FuncExp(loc, fld);
1545 return e.expressionSemantic(sc);
1547 if (auto f = s.isFuncDeclaration())
1549 f = f.toAliasFunc();
1550 if (!f.functionSemantic())
1551 return ErrorExp.get();
1553 if (!hasOverloads && f.checkForwardRef(loc))
1554 return ErrorExp.get();
1556 auto fd = s.isFuncDeclaration();
1557 fd.type = f.type;
1558 return new VarExp(loc, fd, hasOverloads);
1560 if (OverDeclaration od = s.isOverDeclaration())
1562 e = new VarExp(loc, od, true);
1563 e.type = Type.tvoid;
1564 return e;
1566 if (OverloadSet o = s.isOverloadSet())
1568 //printf("'%s' is an overload set\n", o.toChars());
1569 return new OverExp(loc, o);
1572 if (Import imp = s.isImport())
1574 if (!imp.pkg)
1576 .error(loc, "forward reference of import `%s`", imp.toChars());
1577 return ErrorExp.get();
1579 auto ie = new ScopeExp(loc, imp.pkg);
1580 return ie.expressionSemantic(sc);
1582 if (Package pkg = s.isPackage())
1584 auto ie = new ScopeExp(loc, pkg);
1585 return ie.expressionSemantic(sc);
1587 if (Module mod = s.isModule())
1589 auto ie = new ScopeExp(loc, mod);
1590 return ie.expressionSemantic(sc);
1592 if (Nspace ns = s.isNspace())
1594 auto ie = new ScopeExp(loc, ns);
1595 return ie.expressionSemantic(sc);
1598 if (Type t = s.getType())
1600 return (new TypeExp(loc, t)).expressionSemantic(sc);
1603 if (TupleDeclaration tup = s.isTupleDeclaration())
1605 if (tup.needThis() && hasThis(sc))
1606 e = new DotVarExp(loc, new ThisExp(loc), tup);
1607 else
1608 e = new TupleExp(loc, tup);
1609 e = e.expressionSemantic(sc);
1610 return e;
1613 if (TemplateInstance ti = s.isTemplateInstance())
1615 ti.dsymbolSemantic(sc);
1616 if (!ti.inst || ti.errors)
1617 return ErrorExp.get();
1618 s = ti.toAlias();
1619 if (!s.isTemplateInstance())
1620 goto Lagain;
1621 e = new ScopeExp(loc, ti);
1622 e = e.expressionSemantic(sc);
1623 return e;
1625 if (TemplateDeclaration td = s.isTemplateDeclaration())
1627 Dsymbol p = td.toParentLocal();
1628 FuncDeclaration fdthis = hasThis(sc);
1629 AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null;
1630 if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0)
1632 e = new DotTemplateExp(loc, new ThisExp(loc), td);
1634 else
1635 e = new TemplateExp(loc, td);
1636 e = e.expressionSemantic(sc);
1637 return e;
1640 .error(loc, "%s `%s` is not a variable", s.kind(), s.toChars());
1641 return ErrorExp.get();
1644 /*************************************************************
1645 * Given var, get the
1646 * right `this` pointer if var is in an outer class, but our
1647 * existing `this` pointer is in an inner class.
1648 * Params:
1649 * loc = location to use for error messages
1650 * sc = context
1651 * ad = struct or class we need the correct `this` for
1652 * e1 = existing `this`
1653 * var = the specific member of ad we're accessing
1654 * flag = if true, return `null` instead of throwing an error
1655 * Returns:
1656 * Expression representing the `this` for the var
1658 private Expression getRightThis(const ref Loc loc, Scope* sc, AggregateDeclaration ad, Expression e1, Dsymbol var, int flag = 0)
1660 //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars());
1662 Type t = e1.type.toBasetype();
1663 //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars());
1665 if (e1.op == EXP.objcClassReference)
1667 // We already have an Objective-C class reference, just use that as 'this'.
1668 return e1;
1670 else if (ad && ad.isClassDeclaration && ad.isClassDeclaration.classKind == ClassKind.objc &&
1671 var.isFuncDeclaration && var.isFuncDeclaration.isStatic &&
1672 var.isFuncDeclaration.objc.selector)
1674 auto cls = ad.isClassDeclaration();
1675 auto classObj = new ObjcClassReferenceExp(e1.loc, cls);
1676 classObj.type = objc.getRuntimeMetaclass(cls).getType();
1677 return classObj;
1680 /* Access of a member which is a template parameter in dual-scope scenario
1681 * class A { inc(alias m)() { ++m; } } // `m` needs `this` of `B`
1682 * class B {int m; inc() { new A().inc!m(); } }
1684 if (e1.op == EXP.this_)
1686 FuncDeclaration f = hasThis(sc);
1687 if (f && f.hasDualContext())
1689 if (f.followInstantiationContext(ad))
1691 e1 = new VarExp(loc, f.vthis);
1692 e1 = new PtrExp(loc, e1);
1693 e1 = new IndexExp(loc, e1, IntegerExp.literal!1);
1694 e1 = getThisSkipNestedFuncs(loc, sc, f.toParent2(), ad, e1, t, var);
1695 if (e1.op == EXP.error)
1696 return e1;
1697 goto L1;
1702 /* If e1 is not the 'this' pointer for ad
1704 if (ad &&
1705 !(t.isTypePointer() && t.nextOf().isTypeStruct() && t.nextOf().isTypeStruct().sym == ad) &&
1706 !(t.isTypeStruct() && t.isTypeStruct().sym == ad))
1708 ClassDeclaration cd = ad.isClassDeclaration();
1709 ClassDeclaration tcd = t.isClassHandle();
1711 /* e1 is the right this if ad is a base class of e1
1713 if (!cd || !tcd || !(tcd == cd || cd.isBaseOf(tcd, null)))
1715 /* Only classes can be inner classes with an 'outer'
1716 * member pointing to the enclosing class instance
1718 if (tcd && tcd.isNested())
1720 /* e1 is the 'this' pointer for an inner class: tcd.
1721 * Rewrite it as the 'this' pointer for the outer class.
1723 auto vthis = tcd.followInstantiationContext(ad) ? tcd.vthis2 : tcd.vthis;
1724 e1 = new DotVarExp(loc, e1, vthis);
1725 e1.type = vthis.type;
1726 e1.type = e1.type.addMod(t.mod);
1727 // Do not call ensureStaticLinkTo()
1728 //e1 = e1.semantic(sc);
1730 // Skip up over nested functions, and get the enclosing
1731 // class type.
1732 e1 = getThisSkipNestedFuncs(loc, sc, tcd.toParentP(ad), ad, e1, t, var);
1733 if (e1.op == EXP.error)
1734 return e1;
1735 goto L1;
1738 /* Can't find a path from e1 to ad
1740 if (flag)
1741 return null;
1742 error(e1.loc, "`this` for `%s` needs to be type `%s` not type `%s`", var.toChars(), ad.toChars(), t.toChars());
1743 return ErrorExp.get();
1746 return e1;
1750 * Check whether `outerFunc` and `calledFunc` have the same `this`.
1751 * If `calledFunc` is the member of a base class of the class that contains
1752 * `outerFunc` we consider that they have the same this.
1754 * This function is used to test whether `this` needs to be prepended to
1755 * a function call or function symbol. For example:
1757 * struct X
1759 * void gun() {}
1761 * struct A
1763 * void fun() {}
1764 * void sun()
1766 * fun();
1767 * X.gun(); // error
1771 * When `fun` is called, `outerfunc` = `sun` and `calledFunc = `fun`.
1772 * `sun` is a member of `A` and `fun` is also a member of `A`, therefore
1773 * `this` can be prepended to `fun`. When `gun` is called (it will result
1774 * in an error, but that is not relevant here), which is a member of `X`,
1775 * no `this` is needed because the outer function does not have the same
1776 * `this` as `gun`.
1778 * Returns:
1779 * `true` if outerFunc and calledFunc may use the same `this` pointer.
1780 * `false` otherwise.
1782 private bool haveSameThis(FuncDeclaration outerFunc, FuncDeclaration calledFunc)
1784 // https://issues.dlang.org/show_bug.cgi?id=24013
1785 // traits(getOverloads) inserts an alias to select the overload.
1786 // When searching for the right this we need to use the aliased
1787 // overload/function, not the alias.
1788 outerFunc = outerFunc.toAliasFunc();
1789 calledFunc = calledFunc.toAliasFunc();
1791 auto thisAd = outerFunc.isMemberLocal();
1792 if (!thisAd)
1793 return false;
1795 auto requiredAd = calledFunc.isMemberLocal();
1796 if (!requiredAd)
1797 return false;
1799 if (thisAd == requiredAd)
1800 return true;
1802 // if outerfunc is the member of a nested aggregate, then let
1803 // getRightThis take care of this.
1804 if (thisAd.isNested())
1805 return true;
1807 // outerfunc is the member of a base class that contains calledFunc,
1808 // then we consider that they have the same this.
1809 auto cd = requiredAd.isClassDeclaration();
1810 if (!cd)
1811 return false;
1813 if (cd.isBaseOf2(thisAd.isClassDeclaration()))
1814 return true;
1816 return false;
1819 /*********************************************
1820 * Calling function f.
1821 * Check the purity, i.e. if we're in a pure function
1822 * we can only call other pure functions.
1823 * Returns true if error occurs.
1825 private bool checkPurity(FuncDeclaration f, const ref Loc loc, Scope* sc)
1827 if (!sc.func)
1828 return false;
1829 if (sc.func == f)
1830 return false;
1831 if (sc.intypeof == 1)
1832 return false;
1833 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1834 return false;
1836 // If the call has a pure parent, then the called func must be pure.
1837 if (!f.isPure() && checkImpure(sc, loc, null, f))
1839 error(loc, "`pure` %s `%s` cannot call impure %s `%s`",
1840 sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
1841 f.toPrettyChars());
1843 if (!f.isDtorDeclaration())
1844 errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.pure_);
1846 f.checkOverriddenDtor(sc, loc, dd => dd.type.toTypeFunction().purity != PURE.impure, "impure");
1847 return true;
1849 return false;
1853 * Checks whether `f` is a generated `DtorDeclaration` that hides a user-defined one
1854 * which passes `check` while `f` doesn't (e.g. when the user defined dtor is pure but
1855 * the generated dtor is not).
1856 * In that case the method will identify and print all members causing the attribute
1857 * missmatch.
1859 * Params:
1860 * f = potential `DtorDeclaration`
1861 * sc = scope
1862 * loc = location
1863 * check = current check (e.g. whether it's pure)
1864 * checkName = the kind of check (e.g. `"pure"`)
1866 void checkOverriddenDtor(FuncDeclaration f, Scope* sc, const ref Loc loc,
1867 scope bool function(DtorDeclaration) check, const string checkName)
1869 auto dd = f.isDtorDeclaration();
1870 if (!dd || !dd.isGenerated())
1871 return;
1873 // DtorDeclaration without parents should fail at an earlier stage
1874 auto ad = cast(AggregateDeclaration) f.toParent2();
1875 assert(ad);
1877 if (ad.userDtors.length)
1879 if (!check(ad.userDtors[0])) // doesn't match check (e.g. is impure as well)
1880 return;
1882 // Sanity check
1883 assert(!check(ad.fieldDtor));
1886 dd.loc.errorSupplemental("%s`%s.~this` is %.*s because of the following field's destructors:",
1887 dd.isGenerated() ? "generated " : "".ptr,
1888 ad.toChars,
1889 cast(int) checkName.length, checkName.ptr);
1891 // Search for the offending fields
1892 foreach (field; ad.fields)
1894 // Only structs may define automatically called destructors
1895 auto ts = field.type.isTypeStruct();
1896 if (!ts)
1898 // But they might be part of a static array
1899 auto ta = field.type.isTypeSArray();
1900 if (!ta)
1901 continue;
1903 ts = ta.baseElemOf().isTypeStruct();
1904 if (!ts)
1905 continue;
1908 auto fieldSym = ts.toDsymbol(sc);
1909 assert(fieldSym); // Resolving ts must succeed because missing defs. should error before
1911 auto fieldSd = fieldSym.isStructDeclaration();
1912 assert(fieldSd); // ts is a TypeStruct, this would imply a malformed ASR
1914 if (fieldSd.dtor && !check(fieldSd.dtor))
1916 field.loc.errorSupplemental(" - %s %s", field.type.toChars(), field.toChars());
1918 if (fieldSd.dtor.isGenerated())
1919 fieldSd.dtor.checkOverriddenDtor(sc, loc, check, checkName);
1920 else
1921 fieldSd.dtor.loc.errorSupplemental(" %.*s `%s.~this` is declared here",
1922 cast(int) checkName.length, checkName.ptr, fieldSd.toChars());
1927 /*******************************************
1928 * Accessing variable v.
1929 * Check for purity and safety violations.
1930 * Returns true if error occurs.
1932 private bool checkPurity(VarDeclaration v, const ref Loc loc, Scope* sc)
1934 //printf("v = %s %s\n", v.type.toChars(), v.toChars());
1935 /* Look for purity and safety violations when accessing variable v
1936 * from current function.
1938 if (!sc.func)
1939 return false;
1940 if (sc.intypeof == 1)
1941 return false; // allow violations inside typeof(expression)
1942 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1943 return false; // allow violations inside compile-time evaluated expressions and debug conditionals
1944 if (v.ident == Id.ctfe)
1945 return false; // magic variable never violates pure and safe
1946 if (v.isImmutable())
1947 return false; // always safe and pure to access immutables...
1948 if (v.isConst() && !v.isReference() && (v.isDataseg() || v.isParameter()) && v.type.implicitConvTo(v.type.immutableOf()))
1949 return false; // or const global/parameter values which have no mutable indirections
1950 if (v.storage_class & STC.manifest)
1951 return false; // ...or manifest constants
1953 // accessing empty structs is pure
1954 // https://issues.dlang.org/show_bug.cgi?id=18694
1955 // https://issues.dlang.org/show_bug.cgi?id=21464
1956 // https://issues.dlang.org/show_bug.cgi?id=23589
1957 if (v.type.ty == Tstruct)
1959 StructDeclaration sd = (cast(TypeStruct)v.type).sym;
1960 if (sd.members) // not opaque
1962 if (sd.semanticRun >= PASS.semanticdone)
1963 sd.determineSize(v.loc);
1964 if (sd.hasNoFields)
1965 return false;
1969 bool err = false;
1970 if (v.isDataseg())
1972 // https://issues.dlang.org/show_bug.cgi?id=7533
1973 // Accessing implicit generated __gate is pure.
1974 if (v.ident == Id.gate)
1975 return false;
1977 if (checkImpure(sc, loc, "`pure` %s `%s` cannot access mutable static data `%s`", v))
1979 error(loc, "`pure` %s `%s` cannot access mutable static data `%s`",
1980 sc.func.kind(), sc.func.toPrettyChars(), v.toChars());
1981 err = true;
1984 else
1986 /* Given:
1987 * void f() {
1988 * int fx;
1989 * pure void g() {
1990 * int gx;
1991 * /+pure+/ void h() {
1992 * int hx;
1993 * /+pure+/ void i() { }
1997 * i() can modify hx and gx but not fx
2000 Dsymbol vparent = v.toParent2();
2001 for (Dsymbol s = sc.func; !err && s; s = s.toParentP(vparent))
2003 if (s == vparent)
2004 break;
2006 if (AggregateDeclaration ad = s.isAggregateDeclaration())
2008 if (ad.isNested())
2009 continue;
2010 break;
2012 FuncDeclaration ff = s.isFuncDeclaration();
2013 if (!ff)
2014 break;
2015 if (ff.isNested() || ff.isThis())
2017 if (ff.type.isImmutable() ||
2018 ff.type.isShared() && !MODimplicitConv(ff.type.mod, v.type.mod))
2020 OutBuffer ffbuf;
2021 OutBuffer vbuf;
2022 MODMatchToBuffer(&ffbuf, ff.type.mod, v.type.mod);
2023 MODMatchToBuffer(&vbuf, v.type.mod, ff.type.mod);
2024 error(loc, "%s%s `%s` cannot access %sdata `%s`",
2025 ffbuf.peekChars(), ff.kind(), ff.toPrettyChars(), vbuf.peekChars(), v.toChars());
2026 err = true;
2027 break;
2029 continue;
2031 break;
2035 /* Do not allow safe functions to access __gshared data
2037 if (v.storage_class & STC.gshared)
2039 if (sc.setUnsafe(false, loc,
2040 "`@safe` function `%s` cannot access `__gshared` data `%s`", sc.func, v))
2042 err = true;
2046 return err;
2050 Check if sc.func is impure or can be made impure.
2051 Returns true on error, i.e. if sc.func is pure and cannot be made impure.
2053 private bool checkImpure(Scope* sc, Loc loc, const(char)* fmt, RootObject arg0)
2055 return sc.func && (isRootTraitsCompilesScope(sc)
2056 ? sc.func.isPureBypassingInference() >= PURE.weak
2057 : sc.func.setImpure(loc, fmt, arg0));
2060 /*********************************************
2061 * Calling function f.
2062 * Check the safety, i.e. if we're in a @safe function
2063 * we can only call @safe or @trusted functions.
2064 * Returns true if error occurs.
2066 private bool checkSafety(FuncDeclaration f, ref Loc loc, Scope* sc)
2068 if (sc.func == f)
2069 return false;
2070 if (sc.intypeof == 1)
2071 return false;
2072 if (sc.flags & SCOPE.debug_)
2073 return false;
2074 if ((sc.flags & SCOPE.ctfe) && sc.func)
2075 return false;
2077 if (!sc.func)
2079 if (sc.varDecl && !f.safetyInprocess && !f.isSafe() && !f.isTrusted())
2081 if (sc.varDecl.storage_class & STC.safe)
2083 error(loc, "`@safe` variable `%s` cannot be initialized by calling `@system` function `%s`",
2084 sc.varDecl.toChars(), f.toChars());
2085 return true;
2087 else
2089 sc.varDecl.storage_class |= STC.system;
2090 sc.varDecl.systemInferred = true;
2093 return false;
2096 if (!f.isSafe() && !f.isTrusted())
2098 if (isRootTraitsCompilesScope(sc) ? sc.func.isSafeBypassingInference() : sc.func.setUnsafeCall(f))
2100 if (!loc.isValid()) // e.g. implicitly generated dtor
2101 loc = sc.func.loc;
2103 const prettyChars = f.toPrettyChars();
2104 error(loc, "`@safe` %s `%s` cannot call `@system` %s `%s`",
2105 sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
2106 prettyChars);
2107 if (!f.isDtorDeclaration)
2108 errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.safe);
2109 .errorSupplemental(f.loc, "`%s` is declared here", prettyChars);
2111 f.checkOverriddenDtor(sc, loc, dd => dd.type.toTypeFunction().trust > TRUST.system, "@system");
2113 return true;
2116 else if (f.isSafe() && f.safetyViolation)
2118 // for dip1000 by default transition, print deprecations for calling functions that will become `@system`
2119 if (sc.func.isSafeBypassingInference())
2121 .deprecation(loc, "`@safe` function `%s` calling `%s`", sc.func.toChars(), f.toChars());
2122 errorSupplementalInferredAttr(f, 10, true, STC.safe);
2124 else if (!sc.func.safetyViolation)
2126 import dmd.func : AttributeViolation;
2127 sc.func.safetyViolation = new AttributeViolation(loc, null, f, null, null);
2130 return false;
2133 /*********************************************
2134 * Calling function f.
2135 * Check the @nogc-ness, i.e. if we're in a @nogc function
2136 * we can only call other @nogc functions.
2137 * Returns true if error occurs.
2139 private bool checkNogc(FuncDeclaration f, ref Loc loc, Scope* sc)
2141 if (!sc.func)
2142 return false;
2143 if (sc.func == f)
2144 return false;
2145 if (sc.intypeof == 1)
2146 return false;
2147 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
2148 return false;
2149 /* The original expressions (`new S(...)` or `new S[...]``) will be
2150 * verified instead. This is to keep errors related to the original code
2151 * and not the lowering.
2153 if (f.ident == Id._d_newitemT || f.ident == Id._d_newarrayT || f.ident == Id._d_newarraymTX)
2154 return false;
2156 if (!f.isNogc())
2158 if (isRootTraitsCompilesScope(sc) ? sc.func.isNogcBypassingInference() : sc.func.setGCCall(f))
2160 if (loc.linnum == 0) // e.g. implicitly generated dtor
2161 loc = sc.func.loc;
2163 // Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)),
2164 // so don't print anything to avoid double error messages.
2165 if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT
2166 || f.ident == Id._d_arrayappendT || f.ident == Id._d_arrayappendcTX
2167 || f.ident == Id._d_arraycatnTX || f.ident == Id._d_newclassT))
2169 error(loc, "`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
2170 sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars());
2172 if (!f.isDtorDeclaration)
2173 f.errorSupplementalInferredAttr(/*max depth*/ 10, /*deprecation*/ false, STC.nogc);
2176 f.checkOverriddenDtor(sc, loc, dd => dd.type.toTypeFunction().isnogc, "non-@nogc");
2178 return true;
2181 return false;
2184 /********************************************
2185 * Check that the postblit is callable if t is an array of structs.
2186 * Returns true if error happens.
2188 private bool checkPostblit(Type t, ref Loc loc, Scope* sc)
2190 if (auto ts = t.baseElemOf().isTypeStruct())
2192 if (global.params.useTypeInfo && Type.dtypeinfo)
2194 // https://issues.dlang.org/show_bug.cgi?id=11395
2195 // Require TypeInfo generation for array concatenation
2196 semanticTypeInfo(sc, t);
2199 StructDeclaration sd = ts.sym;
2200 if (sd.postblit)
2202 if (sd.postblit.checkDisabled(loc, sc))
2203 return true;
2205 //checkDeprecated(sc, sd.postblit); // necessary?
2206 sd.postblit.checkPurity(loc, sc);
2207 sd.postblit.checkSafety(loc, sc);
2208 sd.postblit.checkNogc(loc, sc);
2209 //checkAccess(sd, loc, sc, sd.postblit); // necessary?
2210 return false;
2213 return false;
2216 /***************************************
2217 * Pull out any properties.
2219 private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null, BinExp saveAtts = null)
2221 //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null);
2222 Loc loc = e1.loc;
2224 OverloadSet os;
2225 Dsymbol s;
2226 Objects* tiargs;
2227 Type tthis;
2228 if (auto de = e1.isDotExp())
2230 if (auto oe = de.e2.isOverExp())
2232 tiargs = null;
2233 tthis = de.e1.type;
2234 os = oe.vars;
2235 goto Los;
2238 else if (e1.isOverExp())
2240 tiargs = null;
2241 tthis = null;
2242 os = e1.isOverExp().vars;
2243 Los:
2244 assert(os);
2245 FuncDeclaration fd = null;
2246 if (e2)
2248 e2 = e2.expressionSemantic(sc);
2249 if (e2.op == EXP.error)
2250 return ErrorExp.get();
2251 e2 = resolveProperties(sc, e2);
2253 Expressions* a = new Expressions();
2254 a.push(e2);
2256 for (size_t i = 0; i < os.a.length; i++)
2258 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(a), FuncResolveFlag.quiet))
2260 if (f.errors)
2261 return ErrorExp.get();
2262 fd = f;
2263 assert(fd.type.ty == Tfunction);
2266 if (fd)
2268 Expression e = new CallExp(loc, e1, e2);
2269 return e.expressionSemantic(sc);
2273 for (size_t i = 0; i < os.a.length; i++)
2275 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet))
2277 if (f.errors)
2278 return ErrorExp.get();
2279 fd = f;
2280 assert(fd.type.ty == Tfunction);
2281 auto tf = fd.type.isTypeFunction();
2282 if (!tf.isref && e2)
2284 error(loc, "%s is not an lvalue", e1.toChars());
2285 return ErrorExp.get();
2289 if (fd)
2291 Expression e = new CallExp(loc, e1);
2292 if (e2)
2294 e = new AssignExp(loc, e, e2);
2295 if (saveAtts)
2297 (cast(BinExp)e).att1 = saveAtts.att1;
2298 (cast(BinExp)e).att2 = saveAtts.att2;
2301 return e.expressionSemantic(sc);
2304 if (e2)
2305 goto Leprop;
2307 else if (auto dti = e1.isDotTemplateInstanceExp())
2309 if (!dti.findTempDecl(sc))
2310 goto Leprop;
2311 if (!dti.ti.semanticTiargs(sc))
2312 goto Leprop;
2313 tiargs = dti.ti.tiargs;
2314 tthis = dti.e1.type;
2315 if ((os = dti.ti.tempdecl.isOverloadSet()) !is null)
2316 goto Los;
2317 if ((s = dti.ti.tempdecl) !is null)
2318 goto Lfd;
2320 else if (auto dte = e1.isDotTemplateExp())
2322 s = dte.td;
2323 tiargs = null;
2324 tthis = dte.e1.type;
2325 goto Lfd;
2327 else if (auto se = e1.isScopeExp())
2329 s = se.sds;
2330 TemplateInstance ti = s.isTemplateInstance();
2331 if (ti && !ti.semanticRun && ti.tempdecl)
2333 //assert(ti.needsTypeInference(sc));
2334 if (!ti.semanticTiargs(sc))
2335 goto Leprop;
2336 tiargs = ti.tiargs;
2337 tthis = null;
2338 if ((os = ti.tempdecl.isOverloadSet()) !is null)
2339 goto Los;
2340 if ((s = ti.tempdecl) !is null)
2341 goto Lfd;
2344 else if (auto te = e1.isTemplateExp())
2346 s = te.td;
2347 tiargs = null;
2348 tthis = null;
2349 goto Lfd;
2351 else if (e1.isDotVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isDotVarExp().var.isOverDeclaration()))
2353 DotVarExp dve = e1.isDotVarExp();
2354 s = dve.var;
2355 tiargs = null;
2356 tthis = dve.e1.type;
2357 goto Lfd;
2359 else if (sc && sc.flags & SCOPE.Cfile && e1.isVarExp() && !e2)
2361 // ImportC: do not implicitly call function if no ( ) are present
2363 else if (e1.isVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isVarExp().var.isOverDeclaration()))
2365 s = e1.isVarExp().var;
2366 tiargs = null;
2367 tthis = null;
2368 Lfd:
2369 assert(s);
2370 if (e2)
2372 e2 = e2.expressionSemantic(sc);
2373 if (e2.op == EXP.error)
2374 return ErrorExp.get();
2375 e2 = resolveProperties(sc, e2);
2377 Expressions* a = new Expressions();
2378 a.push(e2);
2380 FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(a), FuncResolveFlag.quiet);
2381 if (fd && fd.type)
2383 if (fd.errors)
2384 return ErrorExp.get();
2385 assert(fd.type.ty == Tfunction);
2386 Expression e = new CallExp(loc, e1, e2);
2387 return e.expressionSemantic(sc);
2391 FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet);
2392 if (fd && fd.type)
2394 if (fd.errors)
2395 return ErrorExp.get();
2396 TypeFunction tf = fd.type.isTypeFunction();
2397 if (!e2 || tf.isref)
2399 Expression e = new CallExp(loc, e1);
2400 if (e2)
2402 e = new AssignExp(loc, e, e2);
2403 if (saveAtts)
2405 (cast(BinExp)e).att1 = saveAtts.att1;
2406 (cast(BinExp)e).att2 = saveAtts.att2;
2409 return e.expressionSemantic(sc);
2413 if (FuncDeclaration fd = s.isFuncDeclaration())
2415 // Keep better diagnostic message for invalid property usage of functions
2416 assert(fd.type.ty == Tfunction);
2417 Expression e = new CallExp(loc, e1, e2);
2418 return e.expressionSemantic(sc);
2420 if (e2)
2421 goto Leprop;
2423 if (auto ve = e1.isVarExp())
2425 if (auto v = ve.var.isVarDeclaration())
2427 if (v.checkPurity(ve.loc, sc))
2428 return ErrorExp.get();
2431 if (e2)
2432 return null;
2434 if (e1.type && !e1.isTypeExp()) // function type is not a property
2436 /* Look for e1 being a lazy parameter; rewrite as delegate call
2437 * only if the symbol wasn't already treated as a delegate
2439 auto ve = e1.isVarExp();
2440 if (ve && ve.var.storage_class & STC.lazy_ && !ve.delegateWasExtracted)
2442 Expression e = new CallExp(loc, e1);
2443 return e.expressionSemantic(sc);
2445 else if (e1.isDotVarExp())
2447 // Check for reading overlapped pointer field in @safe code.
2448 if (checkUnsafeAccess(sc, e1, true, true))
2449 return ErrorExp.get();
2451 else if (auto ce = e1.isCallExp())
2453 // Check for reading overlapped pointer field in @safe code.
2454 if (checkUnsafeAccess(sc, ce.e1, true, true))
2455 return ErrorExp.get();
2459 if (!e1.type)
2461 error(loc, "cannot resolve type for %s", e1.toChars());
2462 e1 = ErrorExp.get();
2464 return e1;
2466 Leprop:
2467 error(loc, "not a property %s", e1.toChars());
2468 return ErrorExp.get();
2471 private bool checkRightThis(Expression e, Scope* sc)
2473 if (e.op == EXP.error)
2474 return true;
2475 if (e.op == EXP.variable && e.type.ty != Terror)
2477 VarExp ve = cast(VarExp)e;
2478 if (isNeedThisScope(sc, ve.var))
2480 //printf("checkRightThis sc.intypeof = %d, ad = %p, func = %p, fdthis = %p\n",
2481 // sc.intypeof, sc.getStructClassScope(), func, fdthis);
2482 auto t = ve.var.isThis();
2483 assert(t);
2484 error(e.loc, "accessing non-static variable `%s` requires an instance of `%s`", ve.var.toChars(), t.toChars());
2485 return true;
2488 return false;
2491 extern (C++) Expression resolveProperties(Scope* sc, Expression e)
2493 //printf("resolveProperties(%s)\n", e.toChars());
2494 e = resolvePropertiesX(sc, e);
2495 if (e.checkRightThis(sc))
2496 return ErrorExp.get();
2497 return e;
2500 /****************************************
2501 * The common type is determined by applying ?: to each pair.
2502 * Output:
2503 * exps[] properties resolved, implicitly cast to common type, rewritten in place
2504 * Returns:
2505 * The common type, or `null` if an error has occured
2507 private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
2509 /* Still have a problem with:
2510 * ubyte[][] = [ cast(ubyte[])"hello", [1]];
2511 * which works if the array literal is initialized top down with the ubyte[][]
2512 * type, but fails with this function doing bottom up typing.
2515 //printf("arrayExpressionToCommonType()\n");
2516 scope IntegerExp integerexp = IntegerExp.literal!0;
2517 scope CondExp condexp = new CondExp(Loc.initial, integerexp, null, null);
2519 Type t0 = null;
2520 Expression e0 = null;
2521 bool foundType;
2523 for (size_t i = 0; i < exps.length; i++)
2525 Expression e = exps[i];
2526 if (!e)
2527 continue;
2529 e = resolveProperties(sc, e);
2530 if (!e.type)
2532 error(e.loc, "`%s` has no value", e.toChars());
2533 t0 = Type.terror;
2534 continue;
2536 if (e.op == EXP.type)
2538 foundType = true; // do not break immediately, there might be more errors
2539 e.checkValue(); // report an error "type T has no value"
2540 t0 = Type.terror;
2541 continue;
2543 if (e.type.ty == Tvoid)
2545 // void expressions do not concur to the determination of the common
2546 // type.
2547 continue;
2549 if (checkNonAssignmentArrayOp(e))
2551 t0 = Type.terror;
2552 continue;
2555 e = doCopyOrMove(sc, e);
2557 if (!foundType && t0 && !t0.equals(e.type))
2559 /* This applies ?: to merge the types. It's backwards;
2560 * ?: should call this function to merge types.
2562 condexp.type = null;
2563 condexp.e1 = e0;
2564 condexp.e2 = e;
2565 condexp.loc = e.loc;
2566 Expression ex = condexp.expressionSemantic(sc);
2567 if (ex.op == EXP.error)
2568 e = ex;
2569 else
2571 // Convert to common type
2572 exps[i] = condexp.e1.castTo(sc, condexp.type);
2573 e = condexp.e2.castTo(sc, condexp.type);
2576 e0 = e;
2577 t0 = e.type;
2578 if (e.op != EXP.error)
2579 exps[i] = e;
2582 // [] is typed as void[]
2583 if (!t0)
2584 return Type.tvoid;
2586 // It's an error, don't do the cast
2587 if (t0.ty == Terror)
2588 return null;
2590 for (size_t i = 0; i < exps.length; i++)
2592 Expression e = exps[i];
2593 if (!e)
2594 continue;
2596 e = e.implicitCastTo(sc, t0);
2597 if (e.op == EXP.error)
2599 /* https://issues.dlang.org/show_bug.cgi?id=13024
2600 * a workaround for the bug in typeMerge -
2601 * it should paint e1 and e2 by deduced common type,
2602 * but doesn't in this particular case.
2604 return null;
2606 exps[i] = e;
2608 return t0;
2611 private Expression opAssignToOp(const ref Loc loc, EXP op, Expression e1, Expression e2) @safe
2613 Expression e;
2614 switch (op)
2616 case EXP.addAssign:
2617 e = new AddExp(loc, e1, e2);
2618 break;
2620 case EXP.minAssign:
2621 e = new MinExp(loc, e1, e2);
2622 break;
2624 case EXP.mulAssign:
2625 e = new MulExp(loc, e1, e2);
2626 break;
2628 case EXP.divAssign:
2629 e = new DivExp(loc, e1, e2);
2630 break;
2632 case EXP.modAssign:
2633 e = new ModExp(loc, e1, e2);
2634 break;
2636 case EXP.andAssign:
2637 e = new AndExp(loc, e1, e2);
2638 break;
2640 case EXP.orAssign:
2641 e = new OrExp(loc, e1, e2);
2642 break;
2644 case EXP.xorAssign:
2645 e = new XorExp(loc, e1, e2);
2646 break;
2648 case EXP.leftShiftAssign:
2649 e = new ShlExp(loc, e1, e2);
2650 break;
2652 case EXP.rightShiftAssign:
2653 e = new ShrExp(loc, e1, e2);
2654 break;
2656 case EXP.unsignedRightShiftAssign:
2657 e = new UshrExp(loc, e1, e2);
2658 break;
2660 default:
2661 assert(0);
2663 return e;
2666 /*********************
2667 * Rewrite:
2668 * array.length op= e2
2670 private Expression rewriteOpAssign(BinExp exp)
2672 ArrayLengthExp ale = exp.e1.isArrayLengthExp();
2673 if (ale.e1.isVarExp())
2675 // array.length = array.length op e2
2676 Expression e = opAssignToOp(exp.loc, exp.op, ale, exp.e2);
2677 e = new AssignExp(exp.loc, ale.syntaxCopy(), e);
2678 return e;
2680 else
2682 // (ref tmp = array;), tmp.length = tmp.length op e2
2683 auto tmp = copyToTemp(STC.ref_, "__arraylength", ale.e1);
2684 Expression e1 = new ArrayLengthExp(ale.loc, new VarExp(ale.loc, tmp));
2685 Expression elvalue = e1.syntaxCopy();
2686 Expression e = opAssignToOp(exp.loc, exp.op, e1, exp.e2);
2687 e = new AssignExp(exp.loc, elvalue, e);
2688 e = new CommaExp(exp.loc, new DeclarationExp(ale.loc, tmp), e);
2689 return e;
2693 /****************************************
2694 * Preprocess arguments to function.
2696 * Tuples in argumentList get expanded, properties resolved, rewritten in place
2698 * Params:
2699 * sc = scope
2700 * argumentList = arguments to function
2701 * reportErrors = whether or not to report errors here. Some callers are not
2702 * checking actual function params, so they'll do their own error reporting
2703 * Returns:
2704 * `true` when a semantic error occurred
2706 private bool preFunctionParameters(Scope* sc, ArgumentList argumentList, const bool reportErrors = true)
2708 Expressions* exps = argumentList.arguments;
2709 bool err = false;
2710 if (exps)
2712 expandTuples(exps, argumentList.names);
2714 for (size_t i = 0; i < exps.length; i++)
2716 Expression arg = (*exps)[i];
2717 arg = resolveProperties(sc, arg);
2718 arg = arg.arrayFuncConv(sc);
2719 if (arg.op == EXP.type)
2721 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
2722 arg = resolveAliasThis(sc, arg);
2724 if (arg.op == EXP.type)
2726 if (reportErrors)
2728 error(arg.loc, "cannot pass type `%s` as a function argument", arg.toChars());
2729 arg = ErrorExp.get();
2731 err = true;
2734 else if (arg.type.toBasetype().ty == Tfunction)
2736 if (reportErrors)
2738 error(arg.loc, "cannot pass function `%s` as a function argument", arg.toChars());
2739 arg = ErrorExp.get();
2741 err = true;
2743 else if (checkNonAssignmentArrayOp(arg))
2745 arg = ErrorExp.get();
2746 err = true;
2748 (*exps)[i] = arg;
2751 return err;
2754 /********************************************
2755 * Issue an error if default construction is disabled for type t.
2756 * Default construction is required for arrays and 'out' parameters.
2757 * Returns:
2758 * true an error was issued
2760 private bool checkDefCtor(Loc loc, Type t)
2762 if (auto ts = t.baseElemOf().isTypeStruct())
2764 StructDeclaration sd = ts.sym;
2765 if (sd.noDefaultCtor)
2767 .error(loc, "%s `%s` default construction is disabled", sd.kind, sd.toPrettyChars);
2768 return true;
2771 return false;
2774 /****************************************
2775 * Now that we know the exact type of the function we're calling,
2776 * the arguments[] need to be adjusted:
2777 * 1. implicitly convert argument to the corresponding parameter type
2778 * 2. add default arguments for any missing arguments
2779 * 3. do default promotions on arguments corresponding to ...
2780 * 4. add hidden _arguments[] argument
2781 * 5. call copy constructor for struct value arguments
2782 * Params:
2783 * loc = location of function call
2784 * sc = context
2785 * tf = type of the function
2786 * ethis = `this` argument, `null` if none or not known
2787 * tthis = type of `this` argument, `null` if no `this` argument
2788 * argumentsList = array of actual arguments to function call
2789 * fd = the function being called, `null` if called indirectly
2790 * prettype = set to return type of function
2791 * peprefix = set to expression to execute before `arguments[]` are evaluated, `null` if none
2792 * Returns:
2793 * true errors happened
2795 private bool functionParameters(const ref Loc loc, Scope* sc,
2796 TypeFunction tf, Expression ethis, Type tthis, ArgumentList argumentList, FuncDeclaration fd,
2797 Type* prettype, Expression* peprefix)
2799 Expressions* arguments = argumentList.arguments;
2800 //printf("functionParameters() %s\n", fd ? fd.toChars() : "");
2801 assert(arguments);
2802 assert(fd || tf.next);
2803 const size_t nparams = tf.parameterList.length;
2804 const olderrors = global.errors;
2805 bool err = false;
2806 Expression eprefix = null;
2807 *peprefix = null;
2809 if (argumentList.names)
2811 const(char)* msg = null;
2812 auto resolvedArgs = tf.resolveNamedArgs(argumentList, &msg);
2813 if (!resolvedArgs)
2815 // while errors are usually already caught by `tf.callMatch`,
2816 // this can happen when calling `typeof(freefunc)`
2817 if (msg)
2818 error(loc, "%s", msg);
2819 return true;
2821 // note: the argument list should be mutated with named arguments / default arguments,
2822 // so we can't simply change the pointer like `arguments = resolvedArgs;`
2823 arguments.setDim(0);
2824 arguments.pushSlice((*resolvedArgs)[]);
2826 size_t nargs = arguments ? arguments.length : 0;
2828 if (nargs > nparams && tf.parameterList.varargs == VarArg.none)
2830 error(loc, "expected %llu arguments, not %llu for non-variadic function type `%s`", cast(ulong)nparams, cast(ulong)nargs, tf.toChars());
2831 return true;
2834 // If inferring return type, and semantic3() needs to be run if not already run
2835 if (!tf.next && fd.inferRetType)
2837 fd.functionSemantic();
2839 else if (fd && fd.parent)
2841 TemplateInstance ti = fd.parent.isTemplateInstance();
2842 if (ti && ti.tempdecl)
2844 fd.functionSemantic3();
2848 /* If calling a pragma(inline, true) function,
2849 * set flag to later scan for inlines.
2851 if (fd && fd.inlining == PINLINE.always)
2853 if (sc._module)
2854 sc._module.hasAlwaysInlines = true;
2855 if (sc.func)
2856 sc.func.hasAlwaysInlines = true;
2859 const isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration();
2861 const size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams)
2863 /* If the function return type has wildcards in it, we'll need to figure out the actual type
2864 * based on the actual argument types.
2865 * Start with the `this` argument, later on merge into wildmatch the mod bits of the rest
2866 * of the arguments.
2868 MOD wildmatch = (tthis && !isCtorCall) ? tthis.Type.deduceWild(tf, false) : 0;
2870 bool done = false;
2871 foreach (const i; 0 .. n)
2873 Expression arg = (i < nargs) ? (*arguments)[i] : null;
2875 if (i < nparams)
2877 bool errorArgs()
2879 error(loc, "expected %llu function arguments, not %llu", cast(ulong)nparams, cast(ulong)nargs);
2880 return true;
2883 Parameter p = tf.parameterList[i];
2885 if (!arg)
2887 if (!p.defaultArg)
2889 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams)
2890 goto L2;
2891 return errorArgs();
2893 arg = p.defaultArg;
2894 if (!arg.type)
2895 arg = arg.expressionSemantic(sc);
2896 arg = inlineCopy(arg, sc);
2897 // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
2898 arg = arg.resolveLoc(loc, sc);
2899 if (i >= nargs)
2901 arguments.push(arg);
2902 nargs++;
2904 else
2905 (*arguments)[i] = arg;
2907 else
2909 if (arg.isDefaultInitExp())
2911 arg = arg.resolveLoc(loc, sc);
2912 (*arguments)[i] = arg;
2917 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams) // https://dlang.org/spec/function.html#variadic
2919 //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars());
2921 MATCH m;
2922 if ((m = arg.implicitConvTo(p.type)) > MATCH.nomatch)
2924 if (p.type.nextOf() && arg.implicitConvTo(p.type.nextOf()) >= m)
2925 goto L2;
2926 else if (nargs != nparams)
2927 return errorArgs();
2928 goto L1;
2932 Type tb = p.type.toBasetype();
2933 switch (tb.ty)
2935 case Tsarray:
2936 case Tarray:
2938 /* Create a static array variable v of type arg.type:
2939 * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
2941 * The array literal in the initializer of the hidden variable
2942 * is now optimized.
2943 * https://issues.dlang.org/show_bug.cgi?id=2356
2945 Type tbn = (cast(TypeArray)tb).next; // array element type
2946 Type tret = p.isLazyArray();
2948 auto elements = new Expressions(nargs - i);
2949 foreach (u; 0 .. elements.length)
2951 Expression a = (*arguments)[i + u];
2952 if (tret && a.implicitConvTo(tret))
2954 // p is a lazy array of delegates, tret is return type of the delegates
2955 a = a.implicitCastTo(sc, tret)
2956 .optimize(WANTvalue)
2957 .toDelegate(tret, sc);
2959 else
2960 a = a.implicitCastTo(sc, tbn);
2961 a = a.addDtorHook(sc);
2962 (*elements)[u] = a;
2964 // https://issues.dlang.org/show_bug.cgi?id=14395
2965 // Convert to a static array literal, or its slice.
2966 arg = new ArrayLiteralExp(loc, tbn.sarrayOf(nargs - i), elements);
2967 if (tb.ty == Tarray)
2969 arg = new SliceExp(loc, arg, null, null);
2970 arg.type = p.type;
2972 break;
2974 case Tclass:
2976 /* Set arg to be:
2977 * new Tclass(arg0, arg1, ..., argn)
2979 auto args = new Expressions(nargs - i);
2980 foreach (u; i .. nargs)
2981 (*args)[u - i] = (*arguments)[u];
2982 arg = new NewExp(loc, null, p.type, args);
2983 break;
2985 default:
2986 if (!arg)
2988 error(loc, "not enough arguments");
2989 return true;
2991 break;
2993 arg = arg.expressionSemantic(sc);
2994 //printf("\targ = '%s'\n", arg.toChars());
2995 arguments.setDim(i + 1);
2996 (*arguments)[i] = arg;
2997 nargs = i + 1;
2998 done = true;
3002 if (!(p.isLazy() && p.type.ty == Tvoid))
3004 if (ubyte wm = arg.type.deduceWild(p.type, p.isReference()))
3006 wildmatch = wildmatch ? MODmerge(wildmatch, wm) : wm;
3007 //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p.type.toChars(), arg.type.toChars(), wm, wildmatch);
3011 if (done)
3012 break;
3014 if ((wildmatch == MODFlags.mutable || wildmatch == MODFlags.immutable_) &&
3015 tf.next && tf.next.hasWild() &&
3016 (tf.isref || !tf.next.implicitConvTo(tf.next.immutableOf())))
3018 bool errorInout(MOD wildmatch)
3020 const(char)* s = wildmatch == MODFlags.mutable ? "mutable" : MODtoChars(wildmatch);
3021 error(loc, "modify `inout` to `%s` is not allowed inside `inout` function", s);
3022 return true;
3025 if (fd)
3027 /* If the called function may return the reference to
3028 * outer inout data, it should be rejected.
3030 * void foo(ref inout(int) x) {
3031 * ref inout(int) bar(inout(int)) { return x; }
3032 * struct S {
3033 * ref inout(int) bar() inout { return x; }
3034 * ref inout(int) baz(alias a)() inout { return x; }
3036 * bar(int.init) = 1; // bad!
3037 * S().bar() = 1; // bad!
3039 * void test() {
3040 * int a;
3041 * auto s = foo(a);
3042 * s.baz!a() = 1; // bad!
3046 bool checkEnclosingWild(Dsymbol s)
3048 bool checkWild(Dsymbol s)
3050 if (!s)
3051 return false;
3052 if (auto ad = s.isAggregateDeclaration())
3054 if (ad.isNested())
3055 return checkEnclosingWild(s);
3057 else if (auto ff = s.isFuncDeclaration())
3059 if (ff.type.isTypeFunction().iswild)
3060 return errorInout(wildmatch);
3062 if (ff.isNested() || ff.isThis())
3063 return checkEnclosingWild(s);
3065 return false;
3068 Dsymbol ctx0 = s.toParent2();
3069 Dsymbol ctx1 = s.toParentLocal();
3070 if (checkWild(ctx0))
3071 return true;
3072 if (ctx0 != ctx1)
3073 return checkWild(ctx1);
3074 return false;
3076 if ((fd.isThis() || fd.isNested()) && checkEnclosingWild(fd))
3077 return true;
3079 else if (tf.isWild())
3080 return errorInout(wildmatch);
3083 Expression firstArg = null;
3084 final switch (returnParamDest(tf, tthis))
3086 case ReturnParamDest.returnVal:
3087 break;
3088 case ReturnParamDest.firstArg:
3089 firstArg = nargs > 0 ? (*arguments)[0] : null;
3090 break;
3091 case ReturnParamDest.this_:
3092 firstArg = ethis;
3093 break;
3096 assert(nargs >= nparams);
3097 foreach (const i, arg; (*arguments)[0 .. nargs])
3099 assert(arg);
3100 if (i < nparams)
3102 Parameter p = tf.parameterList[i];
3103 Type targ = arg.type; // keep original type for isCopyable() because alias this
3104 // resolution may hide an uncopyable type
3106 if (!(p.isLazy() && p.type.ty == Tvoid))
3108 Type tprm = p.type.hasWild()
3109 ? p.type.substWildTo(wildmatch)
3110 : p.type;
3112 const hasCopyCtor = arg.type.isTypeStruct() && arg.type.isTypeStruct().sym.hasCopyCtor;
3113 const typesMatch = arg.type.mutableOf().unSharedOf().equals(tprm.mutableOf().unSharedOf());
3114 if (!((hasCopyCtor && typesMatch) || tprm.equals(arg.type)))
3116 //printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars());
3117 arg = arg.implicitCastTo(sc, tprm);
3118 arg = arg.optimize(WANTvalue, p.isReference());
3122 // Support passing rvalue to `in` parameters
3123 if ((p.storageClass & (STC.in_ | STC.ref_)) == (STC.in_ | STC.ref_))
3125 if (!arg.isLvalue())
3127 auto v = copyToTemp(STC.exptemp, "__rvalue", arg);
3128 Expression ev = new DeclarationExp(arg.loc, v);
3129 ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
3130 arg = ev.expressionSemantic(sc);
3132 arg = arg.toLvalue(sc, "create `in` parameter from");
3134 // Look for mutable misaligned pointer, etc., in @safe mode
3135 err |= checkUnsafeAccess(sc, arg, false, true);
3137 else if (p.storageClass & STC.ref_)
3139 if (global.params.rvalueRefParam == FeatureState.enabled &&
3140 !arg.isLvalue() &&
3141 targ.isCopyable())
3142 { /* allow rvalues to be passed to ref parameters by copying
3143 * them to a temp, then pass the temp as the argument
3145 auto v = copyToTemp(0, "__rvalue", arg);
3146 Expression ev = new DeclarationExp(arg.loc, v);
3147 ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
3148 arg = ev.expressionSemantic(sc);
3150 arg = arg.toLvalue(sc, "create `ref` parameter from");
3152 // Look for mutable misaligned pointer, etc., in @safe mode
3153 err |= checkUnsafeAccess(sc, arg, false, true);
3155 else if (p.storageClass & STC.out_)
3157 Type t = arg.type;
3158 if (!t.isMutable() || !t.isAssignable()) // check blit assignable
3160 error(arg.loc, "cannot modify struct `%s` with immutable members", arg.toChars());
3161 err = true;
3163 else
3165 // Look for misaligned pointer, etc., in @safe mode
3166 err |= checkUnsafeAccess(sc, arg, false, true);
3167 err |= checkDefCtor(arg.loc, t); // t must be default constructible
3169 arg = arg.toLvalue(sc, "create `out` parameter from");
3171 else if (p.isLazy())
3173 // Convert lazy argument to a delegate
3174 auto t = (p.type.ty == Tvoid) ? p.type : arg.type;
3175 arg = toDelegate(arg, t, sc);
3177 //printf("arg: %s\n", arg.toChars());
3178 //printf("type: %s\n", arg.type.toChars());
3179 //printf("param: %s\n", p.toChars());
3181 const indirect = (fd is null) || (fd.isVirtual() && !fd.isFinal());
3182 const pStc = tf.parameterStorageClass(tthis, p, fd ? &fd.outerVars : null, indirect);
3184 if (firstArg && (pStc & STC.return_))
3186 /* Argument value can be assigned to firstArg.
3187 * Check arg to see if it matters.
3189 err |= checkParamArgumentReturn(sc, firstArg, arg, p, false);
3191 // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along
3192 // as lazy parameters to the next function, but that isn't escaping.
3193 // The arguments of `_d_arraycatnTX` are already handled in
3194 // expressionsem.d, via `checkNewEscape`. Without `-dip1000`, the
3195 // check does not return an error, so the lowering of `a ~ b` to
3196 // `_d_arraycatnTX(a, b)` still occurs.
3197 else if (!(pStc & STC.lazy_) && (!fd || fd.ident != Id._d_arraycatnTX))
3199 /* Argument value can escape from the called function.
3200 * Check arg to see if it matters.
3202 VarDeclaration vPar = fd ? (fd.parameters ? (*fd.parameters)[i] : null) : null;
3203 err |= checkParamArgumentEscape(sc, fd, p.ident, vPar, cast(STC) pStc, arg, false, false);
3206 // Turning heap allocations into stack allocations is dangerous without dip1000, since `scope` inference
3207 // may be unreliable when scope violations only manifest as deprecation warnings.
3208 // However, existing `@nogc` code may rely on it, so still do it when the parameter is explicitly marked `scope`
3209 const explicitScope = p.isLazy() ||
3210 ((p.storageClass & STC.scope_) && !(p.storageClass & STC.scopeinferred));
3211 if ((pStc & (STC.scope_ | STC.lazy_)) &&
3212 ((sc.useDIP1000 == FeatureState.enabled) || explicitScope) &&
3213 !(pStc & STC.return_))
3215 /* Argument value cannot escape from the called function.
3217 Expression a = arg;
3218 if (auto ce = a.isCastExp())
3219 a = ce.e1;
3221 ArrayLiteralExp ale;
3222 if (p.type.toBasetype().ty == Tarray &&
3223 (ale = a.isArrayLiteralExp()) !is null && ale.elements && ale.elements.length > 0)
3225 // allocate the array literal as temporary static array on the stack
3226 ale.type = ale.type.nextOf().sarrayOf(ale.elements.length);
3227 auto tmp = copyToTemp(0, "__arrayliteral_on_stack", ale);
3228 tmp.storage_class |= STC.exptemp;
3229 auto declareTmp = new DeclarationExp(ale.loc, tmp);
3230 auto castToSlice = new CastExp(ale.loc, new VarExp(ale.loc, tmp),
3231 p.type.substWildTo(MODFlags.mutable));
3232 arg = CommaExp.combine(declareTmp, castToSlice);
3233 arg = arg.expressionSemantic(sc);
3235 else if (auto fe = a.isFuncExp())
3237 /* Function literals can only appear once, so if this
3238 * appearance was scoped, there cannot be any others.
3240 fe.fd.tookAddressOf = 0;
3242 else if (auto de = a.isDelegateExp())
3244 /* For passing a delegate to a scoped parameter,
3245 * this doesn't count as taking the address of it.
3246 * We only worry about 'escaping' references to the function.
3248 if (auto ve = de.e1.isVarExp())
3250 if (auto f = ve.var.isFuncDeclaration())
3252 if (f.tookAddressOf)
3253 --f.tookAddressOf;
3254 //printf("--tookAddressOf = %d\n", f.tookAddressOf);
3259 if (!p.isReference())
3260 err |= arg.checkSharedAccess(sc);
3262 arg = arg.optimize(WANTvalue, p.isReference());
3264 else
3266 // These will be the trailing ... arguments
3267 // If not D linkage, do promotions
3268 if (tf.linkage != LINK.d)
3270 // Promote bytes, words, etc., to ints
3271 arg = integralPromotions(arg, sc);
3273 // Promote floats to doubles
3274 switch (arg.type.ty)
3276 case Tfloat32:
3277 arg = arg.castTo(sc, Type.tfloat64);
3278 break;
3280 case Timaginary32:
3281 arg = arg.castTo(sc, Type.timaginary64);
3282 break;
3284 default:
3285 break;
3287 if (tf.parameterList.varargs == VarArg.variadic ||
3288 tf.parameterList.varargs == VarArg.KRvariadic)
3290 const(char)* p = tf.linkage == LINK.c ? "extern(C)" : "extern(C++)";
3291 if (arg.type.ty == Tarray)
3293 error(arg.loc, "cannot pass dynamic arrays to `%s` vararg functions", p);
3294 err = true;
3296 if (arg.type.ty == Tsarray)
3298 error(arg.loc, "cannot pass static arrays to `%s` vararg functions", p);
3299 err = true;
3304 // Do not allow types that need destructors or copy constructors.
3305 if (arg.type.needsDestruction())
3307 error(arg.loc, "cannot pass types that need destruction as variadic arguments");
3308 err = true;
3310 if (arg.type.needsCopyOrPostblit())
3312 error(arg.loc, "cannot pass types with postblits or copy constructors as variadic arguments");
3313 err = true;
3316 // Convert static arrays to dynamic arrays
3317 // BUG: I don't think this is right for D2
3318 Type tb = arg.type.toBasetype();
3319 if (auto ts = tb.isTypeSArray())
3321 Type ta = ts.next.arrayOf();
3322 if (ts.size(arg.loc) == 0)
3323 arg = new NullExp(arg.loc, ta);
3324 else
3325 arg = arg.castTo(sc, ta);
3327 if (tb.ty == Tstruct)
3329 //arg = callCpCtor(sc, arg);
3331 // Give error for overloaded function addresses
3332 if (auto se = arg.isSymOffExp())
3334 if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique())
3336 error(arg.loc, "function `%s` is overloaded", arg.toChars());
3337 err = true;
3340 err |= arg.checkValue();
3341 err |= arg.checkSharedAccess(sc);
3342 err |= checkParamArgumentEscape(sc, fd, Id.dotdotdot, null, cast(STC) tf.parameterList.stc, arg, false, false);
3343 arg = arg.optimize(WANTvalue);
3345 (*arguments)[i] = arg;
3348 /* If calling C scanf(), printf(), or any variants, check the format string against the arguments
3350 const isVa_list = tf.parameterList.varargs == VarArg.none;
3351 if (fd && fd.printf)
3353 if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp())
3355 checkPrintfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list, sc.eSink);
3358 else if (fd && fd.scanf)
3360 if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp())
3362 checkScanfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list, sc.eSink);
3365 else
3367 // TODO: not checking the "v" functions yet (for those, check format string only, not args)
3370 /* Remaining problems:
3371 * 1. value structs (or static arrays of them) that need to be copy constructed
3372 * 2. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
3373 * function gets called.
3374 * 3. value structs need to be destructed after the function call for platforms where the caller destroys the arguments.
3375 * Those are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
3376 * up properly. Pushing arguments on the stack then cannot fail.
3379 /* Does Problem (3) apply?
3381 const bool callerDestroysArgs = !target.isCalleeDestroyingArgs(tf);
3383 /* Compute indices of last throwing argument and first arg needing destruction.
3384 * Used to not set up destructors unless an arg needs destruction on a throw
3385 * in a later argument.
3387 ptrdiff_t lastthrow = -1; // last argument that may throw
3388 ptrdiff_t firstdtor = -1; // first argument that needs destruction
3389 ptrdiff_t lastdtor = -1; // last argument that needs destruction
3390 for (ptrdiff_t i = 0; i != nargs; i++)
3392 Expression arg = (*arguments)[i];
3393 if (canThrow(arg, sc.func, null))
3394 lastthrow = i;
3395 if (arg.type.needsDestruction())
3397 Parameter p = (i >= nparams ? null : tf.parameterList[i]);
3398 if (!(p && (p.isLazy() || p.isReference())))
3400 if (firstdtor == -1)
3401 firstdtor = i;
3402 lastdtor = i;
3407 /* Do we need 'eprefix' for problems 2 or 3?
3409 const bool needsPrefix = callerDestroysArgs
3410 ? firstdtor >= 0 // true if any argument needs destruction
3411 : firstdtor >= 0 && lastthrow >= 0 &&
3412 (lastthrow - firstdtor) > 0; // last throw after first destruction
3413 const ptrdiff_t lastPrefix = callerDestroysArgs
3414 ? lastdtor // up to last argument requiring destruction
3415 : lastthrow; // up to last potentially throwing argument
3417 /* Problem 3: initialize 'eprefix' by declaring the gate
3419 VarDeclaration gate;
3420 if (needsPrefix && !callerDestroysArgs)
3422 // eprefix => bool __gate [= false]
3423 Identifier idtmp = Identifier.generateId("__gate");
3424 gate = new VarDeclaration(loc, Type.tbool, idtmp, null);
3425 gate.storage_class |= STC.temp | STC.ctfe | STC.volatile_;
3426 gate.dsymbolSemantic(sc);
3428 auto ae = new DeclarationExp(loc, gate);
3429 eprefix = ae.expressionSemantic(sc);
3432 for (ptrdiff_t i = 0; i != nargs; i++)
3434 Expression arg = (*arguments)[i];
3435 //printf("arg[%d]: %s\n", cast(int)i, arg.toChars());
3437 Parameter parameter = (i >= nparams ? null : tf.parameterList[i]);
3438 const bool isRef = parameter && parameter.isReference();
3439 const bool isLazy = parameter && parameter.isLazy();
3441 /* Skip lazy parameters
3443 if (isLazy)
3444 continue;
3446 /* Do we have 'eprefix' and aren't past 'lastPrefix' yet?
3447 * Then declare a temporary variable for this arg and append that declaration
3448 * to 'eprefix', which will implicitly take care of potential problem 1) for
3449 * this arg.
3450 * 'eprefix' will therefore finally contain all args up to and including 'lastPrefix',
3451 * excluding all lazy parameters.
3453 if (needsPrefix && (lastPrefix - i) >= 0)
3455 const bool needsDtor = !isRef && arg.type.needsDestruction() &&
3456 // Problem 3: last throwing arg doesn't require dtor patching
3457 (callerDestroysArgs || i != lastPrefix);
3459 /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
3461 auto tmp = copyToTemp(
3462 (parameter ? parameter.storageClass : tf.parameterList.stc) & (STC.scope_),
3463 needsDtor ? "__pfx" : "__pfy",
3464 !isRef ? arg : arg.addressOf());
3465 tmp.dsymbolSemantic(sc);
3467 if (callerDestroysArgs)
3469 /* Problem 4: Normal temporary, destructed after the call
3471 if (needsDtor)
3472 tmp.isArgDtorVar = true; // mark it so that the backend passes it by ref to the function being called
3474 else
3476 /* Problem 2: Modify the destructor so it only runs if gate==false,
3477 * i.e., only if there was a throw while constructing the args
3479 if (!needsDtor)
3481 if (tmp.edtor)
3483 assert(i == lastPrefix);
3484 tmp.edtor = null;
3487 else
3489 // edtor => (__gate || edtor)
3490 assert(tmp.edtor);
3491 Expression e = tmp.edtor;
3492 e = new LogicalExp(e.loc, EXP.orOr, new VarExp(e.loc, gate), e);
3493 tmp.edtor = e.expressionSemantic(sc);
3494 //printf("edtor: %s\n", tmp.edtor.toChars());
3498 // eprefix => (eprefix, auto __pfx/y = arg)
3499 auto ae = new DeclarationExp(loc, tmp);
3500 eprefix = Expression.combine(eprefix, ae.expressionSemantic(sc));
3502 // arg => __pfx/y
3503 arg = new VarExp(loc, tmp);
3504 arg = arg.expressionSemantic(sc);
3505 if (isRef)
3507 arg = new PtrExp(loc, arg);
3508 arg = arg.expressionSemantic(sc);
3511 /* Problem 2: Last throwing arg?
3512 * Then finalize eprefix => (eprefix, gate = true), i.e., disable the
3513 * dtors right after constructing the last throwing arg.
3514 * From now on, the callee will take care of destructing the args because
3515 * the args are implicitly moved into function parameters.
3517 if (!callerDestroysArgs && i == lastPrefix)
3519 auto e = new AssignExp(gate.loc, new VarExp(gate.loc, gate), IntegerExp.createBool(true));
3520 eprefix = Expression.combine(eprefix, e.expressionSemantic(sc));
3523 else // not part of 'eprefix'
3525 /* Handle problem 1) by calling the copy constructor for value structs
3526 * (or static arrays of them) if appropriate.
3528 Type tv = arg.type.baseElemOf();
3529 if (!isRef && tv.ty == Tstruct)
3530 arg = doCopyOrMove(sc, arg, parameter ? parameter.type : null);
3533 (*arguments)[i] = arg;
3536 //if (eprefix) printf("eprefix: %s\n", eprefix.toChars());
3538 /* Test compliance with DIP1021 Argument Ownership and Function Calls
3540 if (global.params.useDIP1021 && (tf.trust == TRUST.safe || tf.trust == TRUST.default_) ||
3541 tf.islive)
3542 err |= checkMutableArguments(sc, fd, tf, ethis, arguments, false);
3544 // If D linkage and variadic, add _arguments[] as first argument
3545 if (tf.isDstyleVariadic())
3547 assert(arguments.length >= nparams);
3549 auto args = new Parameters(arguments.length - nparams);
3550 for (size_t i = 0; i < arguments.length - nparams; i++)
3552 Expression earg = (*arguments)[nparams + i];
3553 auto arg = new Parameter(earg.loc, STC.in_, earg.type, null, null, null);
3554 (*args)[i] = arg;
3556 auto tup = new TypeTuple(args);
3557 Expression e = (new TypeidExp(loc, tup)).expressionSemantic(sc);
3558 arguments.insert(0, e);
3561 /* Determine function return type: tret
3563 Type tret = tf.next;
3564 if (isCtorCall)
3566 //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd.toChars(), fd.type.toChars(),
3567 // wildmatch, tf.isWild(), fd.isReturnIsolated());
3568 if (!tthis)
3570 assert(sc.intypeof || global.errors);
3571 tthis = fd.isThis().type.addMod(fd.type.mod);
3573 if (tf.isWild() && !fd.isReturnIsolated())
3575 if (wildmatch)
3576 tret = tret.substWildTo(wildmatch);
3577 int offset;
3578 if (!tret.implicitConvTo(tthis) && !(MODimplicitConv(tret.mod, tthis.mod) && tret.isBaseOf(tthis, &offset) && offset == 0))
3580 const(char)* s1 = tret.isNaked() ? " mutable" : tret.modToChars();
3581 const(char)* s2 = tthis.isNaked() ? " mutable" : tthis.modToChars();
3582 .error(loc, "`inout` constructor `%s` creates%s object, not%s", fd.toPrettyChars(), s1, s2);
3583 err = true;
3586 tret = tthis;
3588 else if (wildmatch && tret)
3590 /* Adjust function return type based on wildmatch
3592 //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret.toChars());
3593 tret = tret.substWildTo(wildmatch);
3596 *prettype = tret;
3597 *peprefix = eprefix;
3598 return (err || olderrors != global.errors);
3602 * Determines whether a symbol represents a module or package
3603 * (Used as a helper for is(type == module) and is(type == package))
3605 * Params:
3606 * sym = the symbol to be checked
3608 * Returns:
3609 * the symbol which `sym` represents (or `null` if it doesn't represent a `Package`)
3611 Package resolveIsPackage(Dsymbol sym)
3613 Package pkg;
3614 if (Import imp = sym.isImport())
3616 if (imp.pkg is null)
3618 .error(sym.loc, "internal compiler error: unable to process forward-referenced import `%s`",
3619 imp.toChars());
3620 assert(0);
3622 pkg = imp.pkg;
3624 else if (auto mod = sym.isModule())
3625 pkg = mod.isPackageFile ? mod.pkg : sym.isPackage();
3626 else
3627 pkg = sym.isPackage();
3628 if (pkg)
3629 pkg.resolvePKGunknown();
3630 return pkg;
3634 private extern (C++) final class ExpressionSemanticVisitor : Visitor
3636 alias visit = Visitor.visit;
3638 Scope* sc;
3639 Expression result;
3641 this(Scope* sc) scope @safe
3643 this.sc = sc;
3646 private void setError()
3648 result = ErrorExp.get();
3651 private void needThisError(Loc loc, FuncDeclaration f)
3653 auto t = f.isThis();
3654 assert(t);
3655 .error(loc, "calling non-static function `%s` requires an instance of type `%s`", f.toChars(), t.toChars());
3656 setError();
3659 /**************************
3660 * Semantically analyze Expression.
3661 * Determine types, fold constants, etc.
3663 override void visit(Expression e)
3665 static if (LOGSEMANTIC)
3667 printf("Expression::semantic() %s\n", e.toChars());
3669 if (e.type)
3670 e.type = e.type.typeSemantic(e.loc, sc);
3671 else
3672 e.type = Type.tvoid;
3673 result = e;
3676 override void visit(IntegerExp e)
3678 assert(e.type);
3679 if (e.type.ty == Terror)
3680 return setError();
3682 assert(e.type.deco);
3683 e.setInteger(e.getInteger());
3684 result = e;
3687 override void visit(RealExp e)
3689 if (!e.type)
3690 e.type = Type.tfloat64;
3691 else if (e.type.isimaginary && sc.flags & SCOPE.Cfile)
3693 /* Convert to core.stdc.config.complex
3695 Type t = getComplexLibraryType(e.loc, sc, e.type.ty);
3696 if (t.ty == Terror)
3697 return setError();
3699 Type tf;
3700 switch (e.type.ty)
3702 case Timaginary32: tf = Type.tfloat32; break;
3703 case Timaginary64: tf = Type.tfloat64; break;
3704 case Timaginary80: tf = Type.tfloat80; break;
3705 default:
3706 assert(0);
3709 /* Construct ts{re : 0.0, im : e}
3711 TypeStruct ts = t.isTypeStruct;
3712 Expressions* elements = new Expressions(2);
3713 (*elements)[0] = new RealExp(e.loc, CTFloat.zero, tf);
3714 (*elements)[1] = new RealExp(e.loc, e.toImaginary(), tf);
3715 Expression sle = new StructLiteralExp(e.loc, ts.sym, elements);
3716 result = sle.expressionSemantic(sc);
3717 return;
3719 else
3720 e.type = e.type.typeSemantic(e.loc, sc);
3721 result = e;
3724 override void visit(ComplexExp e)
3726 if (!e.type)
3727 e.type = Type.tcomplex80;
3728 else
3729 e.type = e.type.typeSemantic(e.loc, sc);
3730 result = e;
3733 override void visit(IdentifierExp exp)
3735 static if (LOGSEMANTIC)
3737 printf("IdentifierExp::semantic('%s')\n", exp.ident.toChars());
3739 if (exp.type) // This is used as the dummy expression
3741 result = exp;
3742 return;
3745 Dsymbol scopesym;
3746 Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym);
3747 if (s)
3749 if (s.errors)
3750 return setError();
3752 Expression e;
3754 /* See if the symbol was a member of an enclosing 'with'
3756 WithScopeSymbol withsym = scopesym.isWithScopeSymbol();
3757 if (withsym && withsym.withstate.wthis && symbolIsVisible(sc, s))
3759 /* Disallow shadowing
3761 // First find the scope of the with
3762 Scope* scwith = sc;
3763 while (scwith.scopesym != scopesym)
3765 scwith = scwith.enclosing;
3766 assert(scwith);
3768 // Look at enclosing scopes for symbols with the same name,
3769 // in the same function
3770 for (Scope* scx = scwith; scx && scx.func == scwith.func; scx = scx.enclosing)
3772 Dsymbol s2;
3773 if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2)
3775 error(exp.loc, "with symbol `%s` is shadowing local symbol `%s`", s.toPrettyChars(), s2.toPrettyChars());
3776 return setError();
3779 s = s.toAlias();
3781 // Same as wthis.ident
3782 // TODO: DotIdExp.semantic will find 'ident' from 'wthis' again.
3783 // The redudancy should be removed.
3784 e = new VarExp(exp.loc, withsym.withstate.wthis);
3785 e = new DotIdExp(exp.loc, e, exp.ident);
3786 e = e.expressionSemantic(sc);
3788 else
3790 if (withsym)
3792 if (withsym.withstate.exp.type.ty != Tvoid)
3794 // 'with (exp)' is a type expression
3795 // or 's' is not visible there (for error message)
3796 e = new TypeExp(exp.loc, withsym.withstate.exp.type);
3798 else
3800 // 'with (exp)' is a Package/Module
3801 e = withsym.withstate.exp;
3803 e = new DotIdExp(exp.loc, e, exp.ident);
3804 result = e.expressionSemantic(sc);
3805 return;
3808 /* If f is really a function template,
3809 * then replace f with the function template declaration.
3811 FuncDeclaration f = s.isFuncDeclaration();
3812 if (f)
3814 TemplateDeclaration td = getFuncTemplateDecl(f);
3815 if (td)
3817 if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
3818 td = td.overroot; // then get the start
3819 e = new TemplateExp(exp.loc, td, f);
3820 e = e.expressionSemantic(sc);
3821 result = e;
3822 return;
3826 if (global.params.fixAliasThis)
3828 ExpressionDsymbol expDsym = scopesym.isExpressionDsymbol();
3829 if (expDsym)
3831 //printf("expDsym = %s\n", expDsym.exp.toChars());
3832 result = expDsym.exp.expressionSemantic(sc);
3833 return;
3836 // Haven't done overload resolution yet, so pass 1
3837 e = symbolToExp(s, exp.loc, sc, true);
3839 result = e;
3840 return;
3843 if (!global.params.fixAliasThis && hasThis(sc))
3845 for (AggregateDeclaration ad = sc.getStructClassScope(); ad;)
3847 if (ad.aliasthis)
3849 Expression e;
3850 e = new ThisExp(exp.loc);
3851 e = new DotIdExp(exp.loc, e, ad.aliasthis.ident);
3852 e = new DotIdExp(exp.loc, e, exp.ident);
3853 e = e.trySemantic(sc);
3854 if (e)
3856 result = e;
3857 return;
3861 auto cd = ad.isClassDeclaration();
3862 if (cd && cd.baseClass && cd.baseClass != ClassDeclaration.object)
3864 ad = cd.baseClass;
3865 continue;
3867 break;
3871 if (exp.ident == Id.ctfe)
3873 if (sc.flags & SCOPE.ctfe)
3875 error(exp.loc, "variable `__ctfe` cannot be read at compile time");
3876 return setError();
3879 // Create the magic __ctfe bool variable
3880 auto vd = new VarDeclaration(exp.loc, Type.tbool, Id.ctfe, null);
3881 vd.storage_class |= STC.temp;
3882 vd.semanticRun = PASS.semanticdone;
3883 Expression e = new VarExp(exp.loc, vd);
3884 e = e.expressionSemantic(sc);
3885 result = e;
3886 return;
3889 // If we've reached this point and are inside a with() scope then we may
3890 // try one last attempt by checking whether the 'wthis' object supports
3891 // dynamic dispatching via opDispatch.
3892 // This is done by rewriting this expression as wthis.ident.
3893 // The innermost with() scope of the hierarchy to satisfy the condition
3894 // above wins.
3895 // https://issues.dlang.org/show_bug.cgi?id=6400
3896 for (Scope* sc2 = sc; sc2; sc2 = sc2.enclosing)
3898 if (!sc2.scopesym)
3899 continue;
3901 if (auto ss = sc2.scopesym.isWithScopeSymbol())
3903 if (ss.withstate.wthis)
3905 Expression e;
3906 e = new VarExp(exp.loc, ss.withstate.wthis);
3907 e = new DotIdExp(exp.loc, e, exp.ident);
3908 e = e.trySemantic(sc);
3909 if (e)
3911 result = e;
3912 return;
3915 // Try Type.opDispatch (so the static version)
3916 else if (ss.withstate.exp && ss.withstate.exp.op == EXP.type)
3918 if (Type t = ss.withstate.exp.isTypeExp().type)
3920 Expression e;
3921 e = new TypeExp(exp.loc, t);
3922 e = new DotIdExp(exp.loc, e, exp.ident);
3923 e = e.trySemantic(sc);
3924 if (e)
3926 result = e;
3927 return;
3934 /* Look for what user might have meant
3936 if (const n = importHint(exp.ident.toString()))
3937 error(exp.loc, "`%s` is not defined, perhaps `import %.*s;` is needed?", exp.ident.toChars(), cast(int)n.length, n.ptr);
3938 else if (auto s2 = sc.search_correct(exp.ident))
3939 error(exp.loc, "undefined identifier `%s`, did you mean %s `%s`?", exp.ident.toChars(), s2.kind(), s2.toChars());
3940 else if (const p = Scope.search_correct_C(exp.ident))
3941 error(exp.loc, "undefined identifier `%s`, did you mean `%s`?", exp.ident.toChars(), p);
3942 else if (exp.ident == Id.dollar)
3943 error(exp.loc, "undefined identifier `$`");
3944 else
3945 error(exp.loc, "undefined identifier `%s`", exp.ident.toChars());
3947 result = ErrorExp.get();
3950 override void visit(DsymbolExp e)
3952 result = symbolToExp(e.s, e.loc, sc, e.hasOverloads);
3955 override void visit(ThisExp e)
3957 static if (LOGSEMANTIC)
3959 printf("ThisExp::semantic()\n");
3961 if (e.type)
3963 result = e;
3964 return;
3967 FuncDeclaration fd = hasThis(sc); // fd is the uplevel function with the 'this' variable
3968 AggregateDeclaration ad;
3970 /* Special case for typeof(this) and typeof(super) since both
3971 * should work even if they are not inside a non-static member function
3973 if (!fd && sc.intypeof == 1)
3975 // Find enclosing struct or class
3976 for (Dsymbol s = sc.getStructClassScope(); 1; s = s.parent)
3978 if (!s)
3980 error(e.loc, "`%s` is not in a class or struct scope", e.toChars());
3981 return setError();
3983 ClassDeclaration cd = s.isClassDeclaration();
3984 if (cd)
3986 e.type = cd.type;
3987 result = e;
3988 return;
3990 StructDeclaration sd = s.isStructDeclaration();
3991 if (sd)
3993 e.type = sd.type;
3994 result = e;
3995 return;
3999 if (!fd)
4001 error(e.loc, "`this` is only defined in non-static member functions, not `%s`", sc.parent.toChars());
4002 return setError();
4005 assert(fd.vthis);
4006 e.var = fd.vthis;
4007 assert(e.var.parent);
4008 ad = fd.isMemberLocal();
4009 if (!ad)
4010 ad = fd.isMember2();
4011 assert(ad);
4012 e.type = ad.type.addMod(e.var.type.mod);
4014 if (e.var.checkNestedReference(sc, e.loc))
4015 return setError();
4017 result = e;
4020 override void visit(SuperExp e)
4022 static if (LOGSEMANTIC)
4024 printf("SuperExp::semantic('%s')\n", e.toChars());
4026 if (e.type)
4028 result = e;
4029 return;
4032 FuncDeclaration fd = hasThis(sc);
4033 ClassDeclaration cd;
4034 Dsymbol s;
4036 /* Special case for typeof(this) and typeof(super) since both
4037 * should work even if they are not inside a non-static member function
4039 if (!fd && sc.intypeof == 1)
4041 // Find enclosing class
4042 for (s = sc.getStructClassScope(); 1; s = s.parent)
4044 if (!s)
4046 error(e.loc, "`%s` is not in a class scope", e.toChars());
4047 return setError();
4049 cd = s.isClassDeclaration();
4050 if (cd)
4052 cd = cd.baseClass;
4053 if (!cd)
4055 error(e.loc, "class `%s` has no `super`", s.toChars());
4056 return setError();
4058 e.type = cd.type;
4059 result = e;
4060 return;
4064 if (!fd)
4065 goto Lerr;
4067 e.var = fd.vthis;
4068 assert(e.var && e.var.parent);
4070 s = fd.toParentDecl();
4071 if (s.isTemplateDeclaration()) // allow inside template constraint
4072 s = s.toParent();
4073 assert(s);
4074 cd = s.isClassDeclaration();
4075 //printf("parent is %s %s\n", fd.toParent().kind(), fd.toParent().toChars());
4076 if (!cd)
4077 goto Lerr;
4078 if (!cd.baseClass)
4080 error(e.loc, "no base class for `%s`", cd.toChars());
4081 e.type = cd.type.addMod(e.var.type.mod);
4083 else
4085 e.type = cd.baseClass.type;
4086 e.type = e.type.castMod(e.var.type.mod);
4089 if (e.var.checkNestedReference(sc, e.loc))
4090 return setError();
4092 result = e;
4093 return;
4095 Lerr:
4096 error(e.loc, "`super` is only allowed in non-static class member functions");
4097 result = ErrorExp.get();
4100 override void visit(NullExp e)
4102 static if (LOGSEMANTIC)
4104 printf("NullExp::semantic('%s')\n", e.toChars());
4106 // NULL is the same as (void *)0
4107 if (e.type)
4109 result = e;
4110 return;
4112 e.type = Type.tnull;
4113 result = e;
4116 override void visit(StringExp e)
4118 static if (LOGSEMANTIC)
4120 printf("StringExp::semantic() %s\n", e.toChars());
4122 if (e.type)
4124 result = e;
4125 return;
4128 OutBuffer buffer;
4129 size_t newlen = 0;
4130 size_t u;
4131 dchar c;
4133 switch (e.postfix)
4135 case 'd':
4136 for (u = 0; u < e.len;)
4138 if (const p = utf_decodeChar(e.peekString(), u, c))
4140 error(e.loc, "%.*s", cast(int)p.length, p.ptr);
4141 return setError();
4143 else
4145 buffer.write4(c);
4146 newlen++;
4149 buffer.write4(0);
4150 e.setData(buffer.extractData(), newlen, 4);
4151 if (sc && sc.flags & SCOPE.Cfile)
4152 e.type = Type.tuns32.sarrayOf(e.len + 1);
4153 else
4154 e.type = Type.tdchar.immutableOf().arrayOf();
4155 e.committed = true;
4156 break;
4158 case 'w':
4159 for (u = 0; u < e.len;)
4161 if (const p = utf_decodeChar(e.peekString(), u, c))
4163 error(e.loc, "%.*s", cast(int)p.length, p.ptr);
4164 return setError();
4166 else
4168 buffer.writeUTF16(c);
4169 newlen++;
4170 if (c >= 0x10000)
4171 newlen++;
4174 buffer.writeUTF16(0);
4175 e.setData(buffer.extractData(), newlen, 2);
4176 if (sc && sc.flags & SCOPE.Cfile)
4177 e.type = Type.tuns16.sarrayOf(e.len + 1);
4178 else
4179 e.type = Type.twchar.immutableOf().arrayOf();
4180 e.committed = true;
4181 break;
4183 case 'c':
4184 e.committed = true;
4185 goto default;
4187 default:
4188 if (sc && sc.flags & SCOPE.Cfile)
4189 e.type = Type.tchar.sarrayOf(e.len + 1);
4190 else
4191 e.type = Type.tchar.immutableOf().arrayOf();
4192 break;
4194 e.type = e.type.typeSemantic(e.loc, sc);
4195 //type = type.immutableOf();
4196 //printf("type = %s\n", type.toChars());
4198 result = e;
4201 override void visit(TupleExp exp)
4203 static if (LOGSEMANTIC)
4205 printf("+TupleExp::semantic(%s)\n", exp.toChars());
4207 if (exp.type)
4209 result = exp;
4210 return;
4213 if (exp.e0)
4214 exp.e0 = exp.e0.expressionSemantic(sc);
4216 // Run semantic() on each argument
4217 bool err = false;
4218 for (size_t i = 0; i < exp.exps.length; i++)
4220 Expression e = (*exp.exps)[i];
4221 e = e.expressionSemantic(sc);
4222 if (!e.type)
4224 error(exp.loc, "`%s` has no value", e.toChars());
4225 err = true;
4227 else if (e.op == EXP.error)
4228 err = true;
4229 else
4230 (*exp.exps)[i] = e;
4232 if (err)
4233 return setError();
4235 expandTuples(exp.exps);
4237 exp.type = new TypeTuple(exp.exps);
4238 exp.type = exp.type.typeSemantic(exp.loc, sc);
4239 //printf("-TupleExp::semantic(%s)\n", toChars());
4240 result = exp;
4243 override void visit(ArrayLiteralExp e)
4245 static if (LOGSEMANTIC)
4247 printf("ArrayLiteralExp::semantic('%s')\n", e.toChars());
4249 if (e.type)
4251 result = e;
4252 return;
4255 /* Perhaps an empty array literal [ ] should be rewritten as null?
4258 if (e.basis)
4259 e.basis = e.basis.expressionSemantic(sc);
4260 if (arrayExpressionSemantic(e.elements.peekSlice(), sc) || (e.basis && e.basis.op == EXP.error))
4261 return setError();
4263 expandTuples(e.elements);
4265 if (e.basis)
4266 e.elements.push(e.basis);
4267 Type t0 = arrayExpressionToCommonType(sc, *e.elements);
4268 if (e.basis)
4269 e.basis = e.elements.pop();
4270 if (t0 is null)
4271 return setError();
4273 e.type = t0.arrayOf();
4274 e.type = e.type.typeSemantic(e.loc, sc);
4276 /* Disallow array literals of type void being used.
4278 if (e.elements.length > 0 && t0.ty == Tvoid)
4280 error(e.loc, "`%s` of type `%s` has no value", e.toChars(), e.type.toChars());
4281 return setError();
4284 if (global.params.useTypeInfo && Type.dtypeinfo)
4285 semanticTypeInfo(sc, e.type);
4287 result = e;
4290 override void visit(AssocArrayLiteralExp e)
4292 static if (LOGSEMANTIC)
4294 printf("AssocArrayLiteralExp::semantic('%s')\n", e.toChars());
4296 if (e.type)
4298 result = e;
4299 return;
4302 // Run semantic() on each element
4303 bool err_keys = arrayExpressionSemantic(e.keys.peekSlice(), sc);
4304 bool err_vals = arrayExpressionSemantic(e.values.peekSlice(), sc);
4305 if (err_keys || err_vals)
4306 return setError();
4308 expandTuples(e.keys);
4309 expandTuples(e.values);
4310 if (e.keys.length != e.values.length)
4312 error(e.loc, "number of keys is %llu, must match number of values %llu",
4313 cast(ulong) e.keys.length, cast(ulong) e.values.length);
4314 return setError();
4317 Type tkey = arrayExpressionToCommonType(sc, *e.keys);
4318 Type tvalue = arrayExpressionToCommonType(sc, *e.values);
4319 if (tkey is null || tvalue is null)
4320 return setError();
4322 e.type = new TypeAArray(tvalue, tkey);
4323 e.type = e.type.typeSemantic(e.loc, sc);
4325 semanticTypeInfo(sc, e.type);
4327 if (checkAssocArrayLiteralEscape(sc, e, false))
4328 return setError();
4330 result = e;
4333 override void visit(StructLiteralExp e)
4335 static if (LOGSEMANTIC)
4337 printf("StructLiteralExp::semantic('%s')\n", e.toChars());
4339 if (e.type)
4341 result = e;
4342 return;
4345 e.sd.size(e.loc);
4346 if (e.sd.sizeok != Sizeok.done)
4347 return setError();
4349 // run semantic() on each element
4350 if (arrayExpressionSemantic(e.elements.peekSlice(), sc))
4351 return setError();
4353 expandTuples(e.elements);
4355 /* Fit elements[] to the corresponding type of field[].
4357 if (!e.sd.fit(e.loc, sc, e.elements, e.stype))
4358 return setError();
4360 /* Fill out remainder of elements[] with default initializers for fields[]
4362 if (!e.sd.fill(e.loc, *e.elements, false))
4364 /* An error in the initializer needs to be recorded as an error
4365 * in the enclosing function or template, since the initializer
4366 * will be part of the stuct declaration.
4368 global.increaseErrorCount();
4369 return setError();
4372 if (checkFrameAccess(e.loc, sc, e.sd, e.elements.length))
4373 return setError();
4375 e.type = e.stype ? e.stype : e.sd.type;
4376 result = e;
4379 override void visit(CompoundLiteralExp cle)
4381 static if (LOGSEMANTIC)
4383 printf("CompoundLiteralExp::semantic('%s')\n", cle.toChars());
4385 Type t = cle.type.typeSemantic(cle.loc, sc);
4386 auto init = initializerSemantic(cle.initializer, sc, t, INITnointerpret);
4387 auto e = initializerToExpression(init, t, (sc.flags & SCOPE.Cfile) != 0);
4388 if (!e)
4390 error(cle.loc, "cannot convert initializer `%s` to expression", init.toChars());
4391 return setError();
4393 result = e;
4394 return;
4397 override void visit(TypeExp exp)
4399 if (exp.type.ty == Terror)
4400 return setError();
4402 //printf("TypeExp::semantic(%s)\n", exp.type.toChars());
4403 Expression e;
4404 Type t;
4405 Dsymbol s;
4407 dmd.typesem.resolve(exp.type, exp.loc, sc, e, t, s, true);
4408 if (e)
4410 // `(Type)` is actually `(var)` so if `(var)` is a member requiring `this`
4411 // then rewrite as `(this.var)` in case it would be followed by a DotVar
4412 // to fix https://issues.dlang.org/show_bug.cgi?id=9490
4413 VarExp ve = e.isVarExp();
4414 if (ve && ve.var && exp.parens && !ve.var.isStatic() && !(sc.stc & STC.static_) &&
4415 sc.func && sc.func.needThis && ve.var.isMember2())
4417 // printf("apply fix for bugzilla issue 9490: add `this.` to `%s`...\n", e.toChars());
4418 e = new DotVarExp(exp.loc, new ThisExp(exp.loc), ve.var, false);
4420 //printf("e = %s %s\n", Token.toChars(e.op), e.toChars());
4421 e = e.expressionSemantic(sc);
4423 else if (t)
4425 //printf("t = %d %s\n", t.ty, t.toChars());
4426 exp.type = t.typeSemantic(exp.loc, sc);
4427 e = exp;
4429 else if (s)
4431 //printf("s = %s %s\n", s.kind(), s.toChars());
4432 e = symbolToExp(s, exp.loc, sc, true);
4434 else
4435 assert(0);
4437 exp.type.checkComplexTransition(exp.loc, sc);
4439 result = e;
4442 override void visit(ScopeExp exp)
4444 static if (LOGSEMANTIC)
4446 printf("+ScopeExp::semantic(%p '%s')\n", exp, exp.toChars());
4448 if (exp.type)
4450 result = exp;
4451 return;
4454 ScopeDsymbol sds2 = exp.sds;
4455 TemplateInstance ti = sds2.isTemplateInstance();
4456 while (ti)
4458 WithScopeSymbol withsym;
4459 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc))
4460 return setError();
4461 if (withsym && withsym.withstate.wthis)
4463 Expression e = new VarExp(exp.loc, withsym.withstate.wthis);
4464 e = new DotTemplateInstanceExp(exp.loc, e, ti);
4465 result = e.expressionSemantic(sc);
4466 return;
4468 if (ti.needsTypeInference(sc))
4470 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
4472 Dsymbol p = td.toParentLocal();
4473 FuncDeclaration fdthis = hasThis(sc);
4474 AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null;
4475 if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0)
4477 Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti);
4478 result = e.expressionSemantic(sc);
4479 return;
4482 else if (OverloadSet os = ti.tempdecl.isOverloadSet())
4484 FuncDeclaration fdthis = hasThis(sc);
4485 AggregateDeclaration ad = os.parent.isAggregateDeclaration();
4486 if (fdthis && ad && fdthis.isMemberLocal() == ad)
4488 Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti);
4489 result = e.expressionSemantic(sc);
4490 return;
4493 // ti is an instance which requires IFTI.
4494 exp.sds = ti;
4495 exp.type = Type.tvoid;
4496 result = exp;
4497 return;
4499 ti.dsymbolSemantic(sc);
4500 if (!ti.inst || ti.errors)
4501 return setError();
4503 Dsymbol s = ti.toAlias();
4504 if (s == ti)
4506 exp.sds = ti;
4507 exp.type = Type.tvoid;
4508 result = exp;
4509 return;
4511 sds2 = s.isScopeDsymbol();
4512 if (sds2)
4514 ti = sds2.isTemplateInstance();
4515 //printf("+ sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
4516 continue;
4519 if (auto v = s.isVarDeclaration())
4521 if (!v.type)
4523 error(exp.loc, "forward reference of %s `%s`", v.kind(), v.toChars());
4524 return setError();
4526 if ((v.storage_class & STC.manifest) && v._init)
4528 /* When an instance that will be converted to a constant exists,
4529 * the instance representation "foo!tiargs" is treated like a
4530 * variable name, and its recursive appearance check (note that
4531 * it's equivalent with a recursive instantiation of foo) is done
4532 * separately from the circular initialization check for the
4533 * eponymous enum variable declaration.
4535 * template foo(T) {
4536 * enum bool foo = foo; // recursive definition check (v.inuse)
4538 * template bar(T) {
4539 * enum bool bar = bar!T; // recursive instantiation check (ti.inuse)
4542 if (ti.inuse)
4544 error(exp.loc, "recursive expansion of %s `%s`", ti.kind(), ti.toPrettyChars());
4545 return setError();
4547 v.checkDeprecated(exp.loc, sc);
4548 auto e = v.expandInitializer(exp.loc);
4549 ti.inuse++;
4550 e = e.expressionSemantic(sc);
4551 ti.inuse--;
4552 result = e;
4553 return;
4557 //printf("s = %s, '%s'\n", s.kind(), s.toChars());
4558 auto e = symbolToExp(s, exp.loc, sc, true);
4559 //printf("-1ScopeExp::semantic()\n");
4560 result = e;
4561 return;
4564 //printf("sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
4565 //printf("\tparent = '%s'\n", sds2.parent.toChars());
4566 sds2.dsymbolSemantic(sc);
4568 // (Aggregate|Enum)Declaration
4569 if (auto t = sds2.getType())
4571 result = (new TypeExp(exp.loc, t)).expressionSemantic(sc);
4572 return;
4575 if (auto td = sds2.isTemplateDeclaration())
4577 result = (new TemplateExp(exp.loc, td)).expressionSemantic(sc);
4578 return;
4581 exp.sds = sds2;
4582 exp.type = Type.tvoid;
4583 //printf("-2ScopeExp::semantic() %s\n", toChars());
4584 result = exp;
4588 * Sets the `lowering` field of a `NewExp` to a call to `_d_newitemT` unless
4589 * compiling with `-betterC` or within `__traits(compiles)`.
4591 * Params:
4592 * ne = the `NewExp` to lower
4594 private void tryLowerToNewItem(NewExp ne)
4596 if (!global.params.useGC || !sc.needsCodegen())
4597 return;
4599 auto hook = global.params.tracegc ? Id._d_newitemTTrace : Id._d_newitemT;
4600 if (!verifyHookExist(ne.loc, *sc, hook, "new struct"))
4601 return;
4603 /* Lower the memory allocation and initialization of `new T()` to
4604 * `_d_newitemT!T()`.
4606 Expression id = new IdentifierExp(ne.loc, Id.empty);
4607 id = new DotIdExp(ne.loc, id, Id.object);
4608 auto tiargs = new Objects();
4610 * Remove `inout`, `const`, `immutable` and `shared` to reduce the
4611 * number of generated `_d_newitemT` instances.
4613 auto t = ne.type.nextOf.unqualify(MODFlags.wild | MODFlags.const_ |
4614 MODFlags.immutable_ | MODFlags.shared_);
4615 tiargs.push(t);
4616 id = new DotTemplateInstanceExp(ne.loc, id, hook, tiargs);
4618 auto arguments = new Expressions();
4619 if (global.params.tracegc)
4621 auto funcname = (sc.callsc && sc.callsc.func) ?
4622 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
4623 arguments.push(new StringExp(ne.loc, ne.loc.filename.toDString()));
4624 arguments.push(new IntegerExp(ne.loc, ne.loc.linnum, Type.tint32));
4625 arguments.push(new StringExp(ne.loc, funcname.toDString()));
4627 id = new CallExp(ne.loc, id, arguments);
4629 ne.lowering = id.expressionSemantic(sc);
4632 override void visit(NewExp exp)
4634 static if (LOGSEMANTIC)
4636 printf("NewExp::semantic() %s\n", exp.toChars());
4637 if (exp.thisexp)
4638 printf("\tthisexp = %s\n", exp.thisexp.toChars());
4639 printf("\tnewtype: %s\n", exp.newtype.toChars());
4641 if (exp.type) // if semantic() already run
4643 result = exp;
4644 return;
4647 //for error messages if the argument in [] is not convertible to size_t
4648 const originalNewtype = exp.newtype;
4650 // https://issues.dlang.org/show_bug.cgi?id=11581
4651 // With the syntax `new T[edim]` or `thisexp.new T[edim]`,
4652 // T should be analyzed first and edim should go into arguments iff it's
4653 // not a tuple.
4654 Expression edim = null;
4655 if (!exp.arguments && exp.newtype.isTypeSArray())
4657 auto ts = exp.newtype.isTypeSArray();
4658 // check `new Value[Key]`
4659 ts.dim = ts.dim.expressionSemantic(sc);
4660 if (ts.dim.op == EXP.type)
4662 exp.newtype = new TypeAArray(ts.next, ts.dim.isTypeExp().type);
4664 else
4666 edim = ts.dim;
4667 exp.newtype = ts.next;
4671 ClassDeclaration cdthis = null;
4672 if (exp.thisexp)
4674 exp.thisexp = exp.thisexp.expressionSemantic(sc);
4675 if (exp.thisexp.op == EXP.error)
4676 return setError();
4678 cdthis = exp.thisexp.type.isClassHandle();
4679 if (!cdthis)
4681 error(exp.loc, "`this` for nested class must be a class type, not `%s`", exp.thisexp.type.toChars());
4682 return setError();
4685 sc = sc.push(cdthis);
4686 exp.type = exp.newtype.typeSemantic(exp.loc, sc);
4687 sc = sc.pop();
4689 else
4691 exp.type = exp.newtype.typeSemantic(exp.loc, sc);
4693 if (exp.type.ty == Terror)
4694 return setError();
4696 if (edim)
4698 if (exp.type.toBasetype().ty == Ttuple)
4700 // --> new T[edim]
4701 exp.type = new TypeSArray(exp.type, edim);
4702 exp.type = exp.type.typeSemantic(exp.loc, sc);
4703 if (exp.type.ty == Terror)
4704 return setError();
4706 else
4708 // --> new T[](edim)
4709 exp.arguments = new Expressions();
4710 exp.arguments.push(edim);
4711 exp.type = exp.type.arrayOf();
4715 exp.newtype = exp.type; // in case type gets cast to something else
4716 Type tb = exp.type.toBasetype();
4717 //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco);
4718 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc))
4720 return setError();
4722 if (preFunctionParameters(sc, exp.argumentList))
4724 return setError();
4727 if (exp.thisexp && tb.ty != Tclass)
4729 error(exp.loc, "`.new` is only for allocating nested classes, not `%s`", tb.toChars());
4730 return setError();
4733 const size_t nargs = exp.arguments ? exp.arguments.length : 0;
4734 Expression newprefix = null;
4736 if (auto tc = tb.isTypeClass())
4738 auto cd = tc.sym;
4739 if (cd.errors)
4740 return setError();
4741 cd.size(exp.loc);
4742 if (cd.sizeok != Sizeok.done)
4743 return setError();
4744 if (!cd.ctor)
4745 cd.ctor = cd.searchCtor();
4746 if (cd.noDefaultCtor && !nargs && !cd.defaultCtor)
4748 error(exp.loc, "default construction is disabled for type `%s`", cd.type.toChars());
4749 return setError();
4752 if (cd.isInterfaceDeclaration())
4754 error(exp.loc, "cannot create instance of interface `%s`", cd.toChars());
4755 return setError();
4758 if (cd.isAbstract())
4760 error(exp.loc, "cannot create instance of abstract class `%s`", cd.toChars());
4761 errorSupplemental(cd.loc, "class `%s` is declared here", cd.toChars());
4762 for (size_t i = 0; i < cd.vtbl.length; i++)
4764 FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration();
4765 if (fd && fd.isAbstract())
4767 errorSupplemental(fd.loc, "function `%s` is not implemented",
4768 fd.toFullSignature());
4771 return setError();
4773 // checkDeprecated() is already done in newtype.typeSemantic().
4775 if (cd.isNested())
4777 /* We need a 'this' pointer for the nested class.
4778 * Ensure we have the right one.
4780 Dsymbol s = cd.toParentLocal();
4782 //printf("cd isNested, parent = %s '%s'\n", s.kind(), s.toPrettyChars());
4783 if (auto cdn = s.isClassDeclaration())
4785 if (!cdthis)
4787 void noReferenceToOuterClass()
4789 if (cd.isAnonymous)
4790 error(exp.loc, "cannot construct anonymous nested class because no implicit `this` reference to outer class is available");
4791 else
4792 error(exp.loc, "cannot construct nested class `%s` because no implicit `this` reference to outer class `%s` is available",
4793 cd.toChars(), cdn.toChars());
4794 return setError();
4797 if (!sc.hasThis)
4798 return noReferenceToOuterClass();
4800 // Supply an implicit 'this' and try again
4801 exp.thisexp = new ThisExp(exp.loc);
4802 for (Dsymbol sp = sc.parent; 1; sp = sp.toParentLocal())
4804 if (!sp)
4805 return noReferenceToOuterClass();
4806 ClassDeclaration cdp = sp.isClassDeclaration();
4807 if (!cdp)
4808 continue;
4809 if (cdp == cdn || cdn.isBaseOf(cdp, null))
4810 break;
4811 // Add a '.outer' and try again
4812 exp.thisexp = new DotIdExp(exp.loc, exp.thisexp, Id.outer);
4815 exp.thisexp = exp.thisexp.expressionSemantic(sc);
4816 if (exp.thisexp.op == EXP.error)
4817 return setError();
4818 cdthis = exp.thisexp.type.isClassHandle();
4820 if (cdthis != cdn && !cdn.isBaseOf(cdthis, null))
4822 //printf("cdthis = %s\n", cdthis.toChars());
4823 error(exp.loc, "`this` for nested class must be of type `%s`, not `%s`",
4824 cdn.toChars(), exp.thisexp.type.toChars());
4825 return setError();
4827 if (!MODimplicitConv(exp.thisexp.type.mod, exp.newtype.mod))
4829 error(exp.loc, "nested type `%s` should have the same or weaker constancy as enclosing type `%s`",
4830 exp.newtype.toChars(), exp.thisexp.type.toChars());
4831 return setError();
4834 else if (exp.thisexp)
4836 error(exp.loc, "`.new` is only for allocating nested classes");
4837 return setError();
4839 else if (auto fdn = s.isFuncDeclaration())
4841 // make sure the parent context fdn of cd is reachable from sc
4842 if (!ensureStaticLinkTo(sc.parent, fdn))
4844 error(exp.loc, "outer function context of `%s` is needed to `new` nested class `%s`",
4845 fdn.toPrettyChars(), cd.toPrettyChars());
4846 return setError();
4849 else
4850 assert(0);
4852 else if (exp.thisexp)
4854 error(exp.loc, "`.new` is only for allocating nested classes");
4855 return setError();
4858 if (cd.vthis2)
4860 if (AggregateDeclaration ad2 = cd.isMember2())
4862 Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
4863 if (te.op != EXP.error)
4864 te = getRightThis(exp.loc, sc, ad2, te, cd);
4865 if (te.op == EXP.error)
4867 error(exp.loc, "need `this` of type `%s` needed to `new` nested class `%s`", ad2.toChars(), cd.toChars());
4868 return setError();
4873 if (cd.disableNew && !exp.onstack)
4875 error(exp.loc, "cannot allocate `class %s` with `new` because it is annotated with `@disable new()`",
4876 originalNewtype.toChars());
4877 return setError();
4880 if (cd.ctor)
4882 FuncDeclaration f = resolveFuncCall(exp.loc, sc, cd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard);
4883 if (!f || f.errors)
4884 return setError();
4886 checkFunctionAttributes(exp, sc, f);
4887 checkAccess(cd, exp.loc, sc, f);
4889 TypeFunction tf = f.type.isTypeFunction();
4890 if (!exp.arguments)
4891 exp.arguments = new Expressions();
4892 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix))
4893 return setError();
4895 exp.member = f.isCtorDeclaration();
4896 assert(exp.member);
4898 else
4900 if (nargs)
4902 error(exp.loc, "no constructor for `%s`", cd.toChars());
4903 return setError();
4906 // https://issues.dlang.org/show_bug.cgi?id=19941
4907 // Run semantic on all field initializers to resolve any forward
4908 // references. This is the same as done for structs in sd.fill().
4909 for (ClassDeclaration c = cd; c; c = c.baseClass)
4911 foreach (v; c.fields)
4913 if (v.inuse || v._scope is null || v._init is null ||
4914 v._init.isVoidInitializer() || v.semanticRun >= PASS.semantic2done)
4915 continue;
4916 v.inuse++;
4917 v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret);
4918 import dmd.semantic2 : lowerStaticAAs;
4919 lowerStaticAAs(v, sc);
4920 v.inuse--;
4925 // When using `@nogc` exception handling, lower `throw new E(args)` to
4926 // `throw (__tmp = _d_newThrowable!E(), __tmp.__ctor(args), __tmp)`.
4927 if (global.params.ehnogc && exp.thrownew &&
4928 !cd.isCOMclass() && !cd.isCPPclass())
4930 assert(cd.ctor);
4932 Expression id = new IdentifierExp(exp.loc, Id.empty);
4933 id = new DotIdExp(exp.loc, id, Id.object);
4935 auto tiargs = new Objects();
4936 tiargs.push(exp.newtype);
4937 id = new DotTemplateInstanceExp(exp.loc, id, Id._d_newThrowable, tiargs);
4938 id = new CallExp(exp.loc, id).expressionSemantic(sc);
4940 Expression idVal;
4941 Expression tmp = extractSideEffect(sc, "__tmpThrowable", idVal, id, true);
4942 // auto castTmp = new CastExp(exp.loc, tmp, exp.type);
4944 auto ctor = new DotIdExp(exp.loc, tmp, Id.ctor).expressionSemantic(sc);
4945 auto ctorCall = new CallExp(exp.loc, ctor, exp.arguments);
4947 id = Expression.combine(idVal, exp.argprefix).expressionSemantic(sc);
4948 id = Expression.combine(id, ctorCall).expressionSemantic(sc);
4949 // id = Expression.combine(id, castTmp).expressionSemantic(sc);
4951 result = id.expressionSemantic(sc);
4952 return;
4954 else if (sc.needsCodegen() && // interpreter doesn't need this lowered
4955 !exp.onstack && !exp.type.isscope()) // these won't use the GC
4957 /* replace `new T(arguments)` with `core.lifetime._d_newclassT!T(arguments)`
4958 * or `_d_newclassTTrace`
4960 auto hook = global.params.tracegc ? Id._d_newclassTTrace : Id._d_newclassT;
4961 if (!verifyHookExist(exp.loc, *sc, hook, "new class"))
4962 return setError();
4964 Expression id = new IdentifierExp(exp.loc, Id.empty);
4965 id = new DotIdExp(exp.loc, id, Id.object);
4967 auto tiargs = new Objects();
4968 auto t = exp.newtype.unqualify(MODFlags.wild); // remove `inout`
4969 tiargs.push(t);
4970 id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs);
4971 auto arguments = new Expressions();
4972 if (global.params.tracegc)
4974 auto funcname = (sc.callsc && sc.callsc.func) ?
4975 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
4976 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
4977 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
4978 arguments.push(new StringExp(exp.loc, funcname.toDString()));
4980 id = new CallExp(exp.loc, id, arguments);
4982 exp.lowering = id.expressionSemantic(sc);
4985 else if (auto ts = tb.isTypeStruct())
4987 auto sd = ts.sym;
4988 sd.size(exp.loc);
4989 if (sd.sizeok != Sizeok.done)
4990 return setError();
4991 if (!sd.ctor)
4992 sd.ctor = sd.searchCtor();
4993 if (sd.noDefaultCtor && !nargs)
4995 error(exp.loc, "default construction is disabled for type `%s`", sd.type.toChars());
4996 return setError();
4998 // checkDeprecated() is already done in newtype.typeSemantic().
5000 if (sd.disableNew)
5002 error(exp.loc, "cannot allocate `struct %s` with `new` because it is annotated with `@disable new()`",
5003 originalNewtype.toChars());
5004 return setError();
5007 // https://issues.dlang.org/show_bug.cgi?id=22639
5008 // If the new expression has arguments, we either should call a
5009 // regular constructor of a copy constructor if the first argument
5010 // is the same type as the struct
5011 if (nargs && (sd.hasRegularCtor() || (sd.ctor && (*exp.arguments)[0].type.mutableOf() == sd.type.mutableOf())))
5013 FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard);
5014 if (!f || f.errors)
5015 return setError();
5017 checkFunctionAttributes(exp, sc, f);
5018 checkAccess(sd, exp.loc, sc, f);
5020 TypeFunction tf = f.type.isTypeFunction();
5021 if (!exp.arguments)
5022 exp.arguments = new Expressions();
5023 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix))
5024 return setError();
5026 exp.member = f.isCtorDeclaration();
5027 assert(exp.member);
5029 if (checkFrameAccess(exp.loc, sc, sd, sd.fields.length))
5030 return setError();
5032 else
5034 if (exp.names)
5036 exp.arguments = resolveStructLiteralNamedArgs(sd, exp.type, sc, exp.loc,
5037 exp.names ? (*exp.names)[] : null,
5038 (size_t i, Type t) => (*exp.arguments)[i],
5039 i => (*exp.arguments)[i].loc
5041 if (!exp.arguments)
5042 return setError();
5044 else if (!exp.arguments)
5046 exp.arguments = new Expressions();
5049 if (!sd.fit(exp.loc, sc, exp.arguments, tb))
5050 return setError();
5052 if (!sd.fill(exp.loc, *exp.arguments, false))
5053 return setError();
5055 if (checkFrameAccess(exp.loc, sc, sd, exp.arguments ? exp.arguments.length : 0))
5056 return setError();
5058 /* Since a `new` allocation may escape, check each of the arguments for escaping
5060 foreach (arg; *exp.arguments)
5062 if (arg && checkNewEscape(sc, arg, false))
5063 return setError();
5067 exp.type = exp.type.pointerTo();
5068 tryLowerToNewItem(exp);
5070 else if (tb.ty == Tarray)
5072 if (!nargs)
5074 // https://issues.dlang.org/show_bug.cgi?id=20422
5075 // Without this check the compiler would give a misleading error
5076 error(exp.loc, "missing length argument for array");
5077 return setError();
5080 Type tn = tb.nextOf().baseElemOf();
5081 Dsymbol s = tn.toDsymbol(sc);
5082 AggregateDeclaration ad = s ? s.isAggregateDeclaration() : null;
5083 if (ad && ad.noDefaultCtor)
5085 error(exp.loc, "default construction is disabled for type `%s`", tb.nextOf().toChars());
5086 return setError();
5088 for (size_t i = 0; i < nargs; i++)
5090 if (tb.ty != Tarray)
5092 error(exp.loc, "too many arguments for array");
5093 return setError();
5096 Expression arg = (*exp.arguments)[i];
5097 if (exp.names && (*exp.names)[i])
5099 error(exp.loc, "no named argument `%s` allowed for array dimension", (*exp.names)[i].toChars());
5100 return setError();
5103 arg = resolveProperties(sc, arg);
5104 arg = arg.implicitCastTo(sc, Type.tsize_t);
5105 if (arg.op == EXP.error)
5106 return setError();
5107 arg = arg.optimize(WANTvalue);
5108 if (arg.op == EXP.int64 && (target.isLP64 ?
5109 cast(sinteger_t)arg.toInteger() : cast(int)arg.toInteger()) < 0)
5111 error(exp.loc, "negative array dimension `%s`", (*exp.arguments)[i].toChars());
5112 return setError();
5114 (*exp.arguments)[i] = arg;
5115 tb = tb.isTypeDArray().next.toBasetype();
5118 if (global.params.betterC || !sc.needsCodegen())
5119 goto LskipNewArrayLowering;
5121 /* Class types may inherit base classes that have errors.
5122 * This may leak errors from the base class to the derived one
5123 * and then to the hook. Semantic analysis is performed eagerly
5124 * to a void this.
5126 if (auto tc = exp.type.nextOf.isTypeClass())
5128 tc.sym.dsymbolSemantic(sc);
5129 if (tc.sym.errors)
5130 goto LskipNewArrayLowering;
5133 if (nargs == 1)
5135 auto hook = global.params.tracegc ? Id._d_newarrayTTrace : Id._d_newarrayT;
5136 if (!verifyHookExist(exp.loc, *sc, hook, "new array"))
5137 goto LskipNewArrayLowering;
5139 /* Lower the memory allocation and initialization of `new T[n]`
5140 * to `_d_newarrayT!T(n)`.
5142 Expression lowering = new IdentifierExp(exp.loc, Id.empty);
5143 lowering = new DotIdExp(exp.loc, lowering, Id.object);
5144 auto tiargs = new Objects();
5145 /* Remove `inout`, `const`, `immutable` and `shared` to reduce
5146 * the number of generated `_d_newarrayT` instances.
5148 const isShared = exp.type.nextOf.isShared();
5149 auto t = exp.type.nextOf.unqualify(MODFlags.wild | MODFlags.const_ |
5150 MODFlags.immutable_ | MODFlags.shared_);
5151 tiargs.push(t);
5152 lowering = new DotTemplateInstanceExp(exp.loc, lowering, hook, tiargs);
5154 auto arguments = new Expressions();
5155 if (global.params.tracegc)
5157 auto funcname = (sc.callsc && sc.callsc.func) ?
5158 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
5159 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
5160 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
5161 arguments.push(new StringExp(exp.loc, funcname.toDString()));
5163 arguments.push((*exp.arguments)[0]);
5164 arguments.push(new IntegerExp(exp.loc, isShared, Type.tbool));
5166 lowering = new CallExp(exp.loc, lowering, arguments);
5167 exp.lowering = lowering.expressionSemantic(sc);
5169 else
5171 auto hook = global.params.tracegc ? Id._d_newarraymTXTrace : Id._d_newarraymTX;
5172 if (!verifyHookExist(exp.loc, *sc, hook, "new multi-dimensional array"))
5173 goto LskipNewArrayLowering;
5175 /* Lower the memory allocation and initialization of `new T[][]...[](n1, n2, ...)`
5176 * to `_d_newarraymTX!(T[][]...[], T)([n1, n2, ...])`.
5178 Expression lowering = new IdentifierExp(exp.loc, Id.empty);
5179 lowering = new DotIdExp(exp.loc, lowering, Id.object);
5181 auto tbn = exp.type.nextOf();
5182 while (tbn.ty == Tarray)
5183 tbn = tbn.nextOf();
5184 auto unqualTbn = tbn.unqualify(MODFlags.wild | MODFlags.const_ |
5185 MODFlags.immutable_ | MODFlags.shared_);
5187 auto tiargs = new Objects();
5188 tiargs.push(exp.type);
5189 tiargs.push(unqualTbn);
5190 lowering = new DotTemplateInstanceExp(exp.loc, lowering, hook, tiargs);
5192 auto arguments = new Expressions();
5193 if (global.params.tracegc)
5195 auto funcname = (sc.callsc && sc.callsc.func) ?
5196 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
5197 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
5198 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
5199 arguments.push(new StringExp(exp.loc, funcname.toDString()));
5202 arguments.push(new ArrayLiteralExp(exp.loc, Type.tsize_t.sarrayOf(nargs), exp.arguments));
5203 arguments.push(new IntegerExp(exp.loc, tbn.isShared(), Type.tbool));
5205 lowering = new CallExp(exp.loc, lowering, arguments);
5206 exp.lowering = lowering.expressionSemantic(sc);
5209 else if (tb.isscalar())
5211 if (!nargs)
5214 else if (nargs == 1)
5216 if (exp.names && (*exp.names)[0])
5218 error(exp.loc, "no named argument `%s` allowed for scalar", (*exp.names)[0].toChars());
5219 return setError();
5221 Expression e = (*exp.arguments)[0];
5222 e = e.implicitCastTo(sc, tb);
5223 (*exp.arguments)[0] = e;
5225 else
5227 error(exp.loc, "more than one argument for construction of `%s`", exp.type.toChars());
5228 return setError();
5231 exp.type = exp.type.pointerTo();
5232 tryLowerToNewItem(exp);
5234 else if (tb.ty == Taarray)
5236 // e.g. `new Alias(args)`
5237 if (nargs)
5239 error(exp.loc, "`new` cannot take arguments for an associative array");
5240 return setError();
5243 else
5245 error(exp.loc, "cannot create a `%s` with `new`", exp.type.toChars());
5246 return setError();
5249 LskipNewArrayLowering:
5250 //printf("NewExp: '%s'\n", toChars());
5251 //printf("NewExp:type '%s'\n", type.toChars());
5252 semanticTypeInfo(sc, exp.type);
5254 if (newprefix)
5256 result = Expression.combine(newprefix, exp);
5257 return;
5259 result = exp;
5262 override void visit(NewAnonClassExp e)
5264 static if (LOGSEMANTIC)
5266 printf("NewAnonClassExp::semantic() %s\n", e.toChars());
5267 //printf("thisexp = %p\n", thisexp);
5268 //printf("type: %s\n", type.toChars());
5271 Expression d = new DeclarationExp(e.loc, e.cd);
5272 sc = sc.push(); // just create new scope
5273 sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
5274 d = d.expressionSemantic(sc);
5275 sc = sc.pop();
5277 if (!e.cd.errors && sc.intypeof && !sc.parent.inNonRoot())
5279 ScopeDsymbol sds = sc.tinst ? cast(ScopeDsymbol)sc.tinst : sc._module;
5280 if (!sds.members)
5281 sds.members = new Dsymbols();
5282 sds.members.push(e.cd);
5285 Expression n = new NewExp(e.loc, e.thisexp, e.cd.type, e.arguments);
5287 Expression c = new CommaExp(e.loc, d, n);
5288 result = c.expressionSemantic(sc);
5291 override void visit(SymOffExp e)
5293 static if (LOGSEMANTIC)
5295 printf("SymOffExp::semantic('%s')\n", e.toChars());
5297 //var.dsymbolSemantic(sc);
5298 if (!e.type)
5299 e.type = e.var.type.pointerTo();
5301 if (auto v = e.var.isVarDeclaration())
5303 if (v.checkNestedReference(sc, e.loc))
5304 return setError();
5306 else if (auto f = e.var.isFuncDeclaration())
5308 if (f.checkNestedReference(sc, e.loc))
5309 return setError();
5312 result = e;
5315 override void visit(VarExp e)
5317 static if (LOGSEMANTIC)
5319 printf("VarExp::semantic(%s)\n", e.toChars());
5322 auto vd = e.var.isVarDeclaration();
5323 auto fd = e.var.isFuncDeclaration();
5325 if (fd)
5327 //printf("L%d fd = %s\n", __LINE__, f.toChars());
5328 if (!fd.functionSemantic())
5329 return setError();
5332 if (!e.type)
5333 e.type = e.var.type;
5334 if (e.type && !e.type.deco)
5336 auto decl = e.var.isDeclaration();
5337 if (decl)
5338 decl.inuse++;
5339 e.type = e.type.typeSemantic(e.loc, sc);
5340 if (decl)
5341 decl.inuse--;
5344 /* Fix for 1161 doesn't work because it causes visibility
5345 * problems when instantiating imported templates passing private
5346 * variables as alias template parameters.
5348 //checkAccess(loc, sc, NULL, var);
5350 if (vd)
5352 if (vd.checkNestedReference(sc, e.loc))
5353 return setError();
5355 // https://issues.dlang.org/show_bug.cgi?id=12025
5356 // If the variable is not actually used in runtime code,
5357 // the purity violation error is redundant.
5358 //checkPurity(sc, vd);
5360 else if (fd)
5362 // TODO: If fd isn't yet resolved its overload, the checkNestedReference
5363 // call would cause incorrect validation.
5364 // Maybe here should be moved in CallExp, or AddrExp for functions.
5365 if (fd.checkNestedReference(sc, e.loc))
5366 return setError();
5368 else if (auto od = e.var.isOverDeclaration())
5370 e.type = Type.tvoid; // ambiguous type?
5373 result = e;
5376 private void genIdent(FuncExp exp, Scope* sc)
5378 if (exp.fd.ident == Id.empty)
5380 const(char)[] s;
5381 if (exp.fd.fes)
5382 s = "__foreachbody";
5383 else if (exp.fd.tok == TOK.reserved)
5384 s = "__lambda";
5385 else if (exp.fd.tok == TOK.delegate_)
5386 s = "__dgliteral";
5387 else
5388 s = "__funcliteral";
5390 DsymbolTable symtab;
5391 if (FuncDeclaration func = sc.parent.isFuncDeclaration())
5393 if (func.localsymtab is null)
5395 // Inside template constraint, symtab is not set yet.
5396 // Initialize it lazily.
5397 func.localsymtab = new DsymbolTable();
5399 symtab = func.localsymtab;
5401 else
5403 ScopeDsymbol sds = sc.parent.isScopeDsymbol();
5404 if (!sds.symtab)
5406 // Inside template constraint, symtab may not be set yet.
5407 // Initialize it lazily.
5408 assert(sds.isTemplateInstance());
5409 sds.symtab = new DsymbolTable();
5411 symtab = sds.symtab;
5413 assert(symtab);
5414 Identifier id = Identifier.generateId(s, symtab.length() + 1);
5415 exp.fd.ident = id;
5416 if (exp.td)
5417 exp.td.ident = id;
5418 symtab.insert(exp.td ? cast(Dsymbol)exp.td : cast(Dsymbol)exp.fd);
5422 override void visit(FuncExp exp)
5424 static if (LOGSEMANTIC)
5426 printf("FuncExp::semantic(%s)\n", exp.toChars());
5427 if (exp.fd.treq)
5428 printf(" treq = %s\n", exp.fd.treq.toChars());
5431 if (exp.type)
5433 result = exp;
5434 return;
5437 Expression e = exp;
5438 uint olderrors;
5440 sc = sc.push(); // just create new scope
5441 sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
5442 sc.visibility = Visibility(Visibility.Kind.public_); // https://issues.dlang.org/show_bug.cgi?id=12506
5444 /* fd.treq might be incomplete type,
5445 * so should not semantic it.
5446 * void foo(T)(T delegate(int) dg){}
5447 * foo(a=>a); // in IFTI, treq == T delegate(int)
5449 //if (fd.treq)
5450 // fd.treq = fd.treq.dsymbolSemantic(loc, sc);
5452 genIdent(exp, sc);
5454 // Set target of return type inference
5455 if (exp.fd.treq && !exp.fd.type.nextOf())
5457 TypeFunction tfv = null;
5458 if (exp.fd.treq.ty == Tdelegate || exp.fd.treq.isPtrToFunction())
5459 tfv = cast(TypeFunction)exp.fd.treq.nextOf();
5460 if (tfv)
5462 TypeFunction tfl = cast(TypeFunction)exp.fd.type;
5463 tfl.next = tfv.nextOf();
5467 //printf("td = %p, treq = %p\n", td, fd.treq);
5468 if (exp.td)
5470 assert(exp.td.parameters && exp.td.parameters.length);
5471 exp.td.dsymbolSemantic(sc);
5472 exp.type = Type.tvoid; // temporary type
5474 if (exp.fd.treq) // defer type determination
5476 FuncExp fe;
5477 if (exp.matchType(exp.fd.treq, sc, &fe, sc.eSink) > MATCH.nomatch)
5478 e = fe;
5479 else
5480 e = ErrorExp.get();
5482 goto Ldone;
5485 olderrors = global.errors;
5486 exp.fd.dsymbolSemantic(sc);
5487 if (olderrors == global.errors)
5489 exp.fd.semantic2(sc);
5490 if (olderrors == global.errors)
5491 exp.fd.semantic3(sc);
5493 if (olderrors != global.errors)
5495 if (exp.fd.type && exp.fd.type.ty == Tfunction && !exp.fd.type.nextOf())
5496 (cast(TypeFunction)exp.fd.type).next = Type.terror;
5497 e = ErrorExp.get();
5498 goto Ldone;
5501 // Type is a "delegate to" or "pointer to" the function literal
5502 if ((exp.fd.isNested() && exp.fd.tok == TOK.delegate_) || (exp.tok == TOK.reserved && exp.fd.treq && exp.fd.treq.ty == Tdelegate))
5504 // https://issues.dlang.org/show_bug.cgi?id=22686
5505 // if the delegate return type is an error
5506 // abort semantic of the FuncExp and propagate
5507 // the error
5508 if (exp.fd.type.isTypeError())
5510 e = ErrorExp.get();
5511 goto Ldone;
5513 exp.type = new TypeDelegate(exp.fd.type.isTypeFunction());
5514 exp.type = exp.type.typeSemantic(exp.loc, sc);
5516 exp.fd.tok = TOK.delegate_;
5518 else
5520 exp.type = new TypePointer(exp.fd.type);
5521 exp.type = exp.type.typeSemantic(exp.loc, sc);
5522 //type = fd.type.pointerTo();
5524 /* A lambda expression deduced to function pointer might become
5525 * to a delegate literal implicitly.
5527 * auto foo(void function() fp) { return 1; }
5528 * assert(foo({}) == 1);
5530 * So, should keep fd.tok == TOK.reserve if fd.treq == NULL.
5532 if (exp.fd.treq && exp.fd.treq.ty == Tpointer)
5534 // change to non-nested
5535 exp.fd.tok = TOK.function_;
5536 exp.fd.vthis = null;
5539 exp.fd.tookAddressOf++;
5541 Ldone:
5542 sc = sc.pop();
5543 result = e;
5547 * Perform semantic analysis on function literals
5549 * Test the following construct:
5550 * ---
5551 * (x, y, z) { return x + y + z; }(42, 84, 1992);
5552 * ---
5554 Expression callExpSemantic(FuncExp exp, Scope* sc, Expressions* arguments)
5556 if ((!exp.type || exp.type == Type.tvoid) && exp.td && arguments && arguments.length)
5558 for (size_t k = 0; k < arguments.length; k++)
5560 Expression checkarg = (*arguments)[k];
5561 if (checkarg.op == EXP.error)
5562 return checkarg;
5565 genIdent(exp, sc);
5567 assert(exp.td.parameters && exp.td.parameters.length);
5568 exp.td.dsymbolSemantic(sc);
5570 TypeFunction tfl = cast(TypeFunction)exp.fd.type;
5571 size_t dim = tfl.parameterList.length;
5572 if (arguments.length < dim)
5574 // Default arguments are always typed, so they don't need inference.
5575 Parameter p = tfl.parameterList[arguments.length];
5576 if (p.defaultArg)
5577 dim = arguments.length;
5580 if ((tfl.parameterList.varargs == VarArg.none && arguments.length > dim) ||
5581 arguments.length < dim)
5583 OutBuffer buf;
5584 foreach (idx, ref arg; *arguments)
5585 buf.printf("%s%s", (idx ? ", ".ptr : "".ptr), arg.type.toChars());
5586 error(exp.loc, "function literal `%s%s` is not callable using argument types `(%s)`",
5587 exp.fd.toChars(), parametersTypeToChars(tfl.parameterList),
5588 buf.peekChars());
5589 errorSupplemental(exp.loc, "too %s arguments, expected %d, got %d",
5590 arguments.length < dim ? "few".ptr : "many".ptr,
5591 cast(int)dim, cast(int)arguments.length);
5592 return ErrorExp.get();
5595 auto tiargs = new Objects();
5596 tiargs.reserve(exp.td.parameters.length);
5598 for (size_t i = 0; i < exp.td.parameters.length; i++)
5600 TemplateParameter tp = (*exp.td.parameters)[i];
5601 assert(dim <= tfl.parameterList.length);
5602 foreach (u, p; tfl.parameterList)
5604 if (u == dim)
5605 break;
5607 if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident)
5609 Expression e = (*arguments)[u];
5610 tiargs.push(e.type);
5611 break;
5616 auto ti = new TemplateInstance(exp.loc, exp.td, tiargs);
5617 return (new ScopeExp(exp.loc, ti)).expressionSemantic(sc);
5619 return exp.expressionSemantic(sc);
5622 override void visit(CallExp exp)
5624 static if (LOGSEMANTIC)
5626 printf("CallExp::semantic() %s\n", exp.toChars());
5628 if (exp.type)
5630 result = exp;
5631 return; // semantic() already run
5634 Objects* tiargs = null; // initial list of template arguments
5635 Expression ethis = null;
5636 Type tthis = null;
5637 Expression e1org = exp.e1;
5639 if (auto ce = exp.e1.isCommaExp())
5641 /* Rewrite (a,b)(args) as (a,(b(args)))
5643 exp.e1 = ce.e2;
5644 ce.e2 = exp;
5645 result = ce.expressionSemantic(sc);
5646 return;
5648 if (DelegateExp de = exp.e1.isDelegateExp())
5650 exp.e1 = new DotVarExp(de.loc, de.e1, de.func, de.hasOverloads);
5651 visit(exp);
5652 return;
5654 if (FuncExp fe = exp.e1.isFuncExp())
5656 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
5657 preFunctionParameters(sc, exp.argumentList))
5658 return setError();
5660 // Run e1 semantic even if arguments have any errors
5661 exp.e1 = callExpSemantic(fe, sc, exp.arguments);
5662 if (exp.e1.op == EXP.error)
5664 result = exp.e1;
5665 return;
5668 if (sc.flags & SCOPE.Cfile)
5670 /* See if need to rewrite the AST because of cast/call ambiguity
5672 if (auto e = castCallAmbiguity(exp, sc))
5674 result = expressionSemantic(e, sc);
5675 return;
5679 if (Expression ex = resolveUFCS(sc, exp))
5681 result = ex;
5682 return;
5685 /* This recognizes:
5686 * foo!(tiargs)(funcargs)
5688 if (ScopeExp se = exp.e1.isScopeExp())
5690 TemplateInstance ti = se.sds.isTemplateInstance();
5691 if (ti)
5693 /* Attempt to instantiate ti. If that works, go with it.
5694 * If not, go with partial explicit specialization.
5696 WithScopeSymbol withsym;
5697 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc))
5698 return setError();
5699 if (withsym && withsym.withstate.wthis)
5701 exp.e1 = new VarExp(exp.e1.loc, withsym.withstate.wthis);
5702 exp.e1 = new DotTemplateInstanceExp(exp.e1.loc, exp.e1, ti);
5703 goto Ldotti;
5705 if (ti.needsTypeInference(sc, 1))
5707 /* Go with partial explicit specialization
5709 tiargs = ti.tiargs;
5710 assert(ti.tempdecl);
5711 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
5712 exp.e1 = new TemplateExp(exp.loc, td);
5713 else if (OverDeclaration od = ti.tempdecl.isOverDeclaration())
5714 exp.e1 = new VarExp(exp.loc, od);
5715 else
5716 exp.e1 = new OverExp(exp.loc, ti.tempdecl.isOverloadSet());
5718 else
5720 Expression e1x = exp.e1.expressionSemantic(sc);
5721 if (e1x.op == EXP.error)
5723 result = e1x;
5724 return;
5726 exp.e1 = e1x;
5731 /* This recognizes:
5732 * expr.foo!(tiargs)(funcargs)
5734 Ldotti:
5735 if (DotTemplateInstanceExp se = exp.e1.isDotTemplateInstanceExp())
5737 TemplateInstance ti = se.ti;
5739 /* Attempt to instantiate ti. If that works, go with it.
5740 * If not, go with partial explicit specialization.
5742 if (!se.findTempDecl(sc) || !ti.semanticTiargs(sc))
5743 return setError();
5744 if (ti.needsTypeInference(sc, 1))
5746 /* Go with partial explicit specialization
5748 tiargs = ti.tiargs;
5749 assert(ti.tempdecl);
5750 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
5751 exp.e1 = new DotTemplateExp(exp.loc, se.e1, td);
5752 else if (OverDeclaration od = ti.tempdecl.isOverDeclaration())
5754 exp.e1 = new DotVarExp(exp.loc, se.e1, od, true);
5756 else
5757 exp.e1 = new DotExp(exp.loc, se.e1, new OverExp(exp.loc, ti.tempdecl.isOverloadSet()));
5759 else
5761 Expression e1x = exp.e1.expressionSemantic(sc);
5762 if (e1x.op == EXP.error)
5764 result = e1x;
5765 return;
5767 exp.e1 = e1x;
5772 Type att = null;
5773 Lagain:
5774 //printf("Lagain: %s\n", toChars());
5775 exp.f = null;
5776 if (exp.e1.op == EXP.this_ || exp.e1.op == EXP.super_)
5778 // semantic() run later for these
5780 else
5782 if (DotIdExp die = exp.e1.isDotIdExp())
5784 exp.e1 = die.expressionSemantic(sc);
5785 /* Look for e1 having been rewritten to expr.opDispatch!(string)
5786 * We handle such earlier, so go back.
5787 * Note that in the rewrite, we carefully did not run semantic() on e1
5789 if (exp.e1.op == EXP.dotTemplateInstance)
5791 goto Ldotti;
5794 else
5796 __gshared int nest;
5797 if (++nest > global.recursionLimit)
5799 error(exp.loc, "recursive evaluation of `%s`", exp.toChars());
5800 --nest;
5801 return setError();
5803 Expression ex = unaSemantic(exp, sc);
5804 --nest;
5805 if (ex)
5807 result = ex;
5808 return;
5812 /* Look for e1 being a lazy parameter
5814 if (VarExp ve = exp.e1.isVarExp())
5816 if (ve.var.storage_class & STC.lazy_)
5818 // lazy parameters can be called without violating purity and safety
5819 Type tw = ve.var.type;
5820 Type tc = ve.var.type.substWildTo(MODFlags.const_);
5821 auto tf = new TypeFunction(ParameterList(), tc, LINK.d, STC.safe | STC.pure_);
5822 (tf = cast(TypeFunction)tf.typeSemantic(exp.loc, sc)).next = tw; // hack for bug7757
5823 auto t = new TypeDelegate(tf);
5824 ve.type = t.typeSemantic(exp.loc, sc);
5826 VarDeclaration v = ve.var.isVarDeclaration();
5827 if (v && v.checkPurity(ve.loc, sc))
5828 return setError();
5831 if (exp.e1.op == EXP.symbolOffset && (cast(SymOffExp)exp.e1).hasOverloads)
5833 SymOffExp se = cast(SymOffExp)exp.e1;
5834 exp.e1 = new VarExp(se.loc, se.var, true);
5835 exp.e1 = exp.e1.expressionSemantic(sc);
5837 else if (DotExp de = exp.e1.isDotExp())
5839 if (de.e2.op == EXP.overloadSet)
5841 ethis = de.e1;
5842 tthis = de.e1.type;
5843 exp.e1 = de.e2;
5846 else if (exp.e1.op == EXP.star && exp.e1.type.ty == Tfunction)
5848 // Rewrite (*fp)(arguments) to fp(arguments)
5849 exp.e1 = (cast(PtrExp)exp.e1).e1;
5851 else if (exp.e1.op == EXP.type && (sc && sc.flags & SCOPE.Cfile))
5853 const numArgs = exp.arguments ? exp.arguments.length : 0;
5855 /* Ambiguous cases arise from CParser where there is not enough
5856 * information to determine if we have a function call or declaration.
5857 * type-name ( identifier ) ;
5858 * identifier ( identifier ) ;
5859 * If exp.e1 is a type-name, then this is a declaration. C11 does not
5860 * have type construction syntax, so don't convert this to a cast().
5862 if (numArgs == 1)
5864 Expression arg = (*exp.arguments)[0];
5865 if (auto ie = (*exp.arguments)[0].isIdentifierExp())
5867 TypeExp te = cast(TypeExp)exp.e1;
5868 auto initializer = new VoidInitializer(ie.loc);
5869 Dsymbol s = new VarDeclaration(ie.loc, te.type, ie.ident, initializer);
5870 auto decls = new Dsymbols(1);
5871 (*decls)[0] = s;
5872 s = new LinkDeclaration(s.loc, LINK.c, decls);
5873 result = new DeclarationExp(exp.loc, s);
5874 result = result.expressionSemantic(sc);
5876 else
5878 error(arg.loc, "identifier or `(` expected");
5879 result = ErrorExp.get();
5881 return;
5883 error(exp.loc, "identifier or `(` expected before `)`");
5884 result = ErrorExp.get();
5885 return;
5889 Type t1 = exp.e1.type ? exp.e1.type.toBasetype() : null;
5891 if (exp.e1.op == EXP.error)
5893 result = exp.e1;
5894 return;
5896 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
5897 preFunctionParameters(sc, exp.argumentList))
5898 return setError();
5900 // Check for call operator overload
5901 if (t1)
5903 if (t1.ty == Tstruct)
5905 auto sd = (cast(TypeStruct)t1).sym;
5906 sd.size(exp.loc); // Resolve forward references to construct object
5907 if (sd.sizeok != Sizeok.done)
5908 return setError();
5909 if (!sd.ctor)
5910 sd.ctor = sd.searchCtor();
5911 /* If `sd.ctor` is a generated copy constructor, this means that it
5912 is the single constructor that this struct has. In order to not
5913 disable default construction, the ctor is nullified. The side effect
5914 of this is that the generated copy constructor cannot be called
5915 explicitly, but that is ok, because when calling a constructor the
5916 default constructor should have priority over the generated copy
5917 constructor.
5919 if (sd.ctor)
5921 auto ctor = sd.ctor.isCtorDeclaration();
5922 if (ctor && ctor.isCpCtor && ctor.isGenerated())
5923 sd.ctor = null;
5926 // First look for constructor
5927 if (exp.e1.op == EXP.type && sd.ctor)
5929 if (!sd.noDefaultCtor && !(exp.arguments && exp.arguments.length))
5930 goto Lx;
5932 /* https://issues.dlang.org/show_bug.cgi?id=20695
5933 If all constructors are copy constructors, then
5934 try default construction.
5936 if (!sd.hasRegularCtor &&
5937 // https://issues.dlang.org/show_bug.cgi?id=22639
5938 // we might still have a copy constructor that could be called
5939 (*exp.arguments)[0].type.mutableOf != sd.type.mutableOf())
5940 goto Lx;
5942 auto sle = new StructLiteralExp(exp.loc, sd, null, exp.e1.type);
5943 if (!sd.fill(exp.loc, *sle.elements, true))
5944 return setError();
5945 if (checkFrameAccess(exp.loc, sc, sd, sle.elements.length))
5946 return setError();
5948 // https://issues.dlang.org/show_bug.cgi?id=14556
5949 // Set concrete type to avoid further redundant semantic().
5950 sle.type = exp.e1.type;
5952 /* Constructor takes a mutable object, so don't use
5953 * the immutable initializer symbol.
5955 sle.useStaticInit = false;
5957 Expression e = sle;
5958 if (auto cf = sd.ctor.isCtorDeclaration())
5960 e = new DotVarExp(exp.loc, e, cf, true);
5962 else if (auto td = sd.ctor.isTemplateDeclaration())
5964 e = new DotIdExp(exp.loc, e, td.ident);
5966 else if (auto os = sd.ctor.isOverloadSet())
5968 e = new DotExp(exp.loc, e, new OverExp(exp.loc, os));
5970 else
5971 assert(0);
5972 e = new CallExp(exp.loc, e, exp.arguments, exp.names);
5973 e = e.expressionSemantic(sc);
5974 result = e;
5975 return;
5977 // No constructor, look for overload of opCall
5978 if (search_function(sd, Id.call))
5979 goto L1;
5980 // overload of opCall, therefore it's a call
5981 if (exp.e1.op != EXP.type)
5983 if (sd.aliasthis && !isRecursiveAliasThis(att, exp.e1.type))
5985 exp.e1 = resolveAliasThis(sc, exp.e1);
5986 goto Lagain;
5988 error(exp.loc, "%s `%s` does not overload ()", sd.kind(), sd.toChars());
5989 return setError();
5992 /* It's a struct literal
5995 Expressions* resolvedArgs = exp.arguments;
5996 if (exp.names)
5998 resolvedArgs = resolveStructLiteralNamedArgs(sd, exp.e1.type, sc, exp.loc,
5999 (*exp.names)[],
6000 (size_t i, Type t) => (*exp.arguments)[i],
6001 i => (*exp.arguments)[i].loc
6003 if (!resolvedArgs)
6005 result = ErrorExp.get();
6006 return;
6010 Expression e = new StructLiteralExp(exp.loc, sd, resolvedArgs, exp.e1.type);
6011 e = e.expressionSemantic(sc);
6012 result = e;
6013 return;
6015 else if (t1.ty == Tclass)
6018 // Rewrite as e1.call(arguments)
6019 Expression e = new DotIdExp(exp.loc, exp.e1, Id.call);
6020 e = new CallExp(exp.loc, e, exp.arguments, exp.names);
6021 e = e.expressionSemantic(sc);
6022 result = e;
6023 return;
6025 else if (exp.e1.op == EXP.type && t1.isscalar())
6027 Expression e;
6029 // Make sure to use the enum type itself rather than its
6030 // base type
6031 // https://issues.dlang.org/show_bug.cgi?id=16346
6032 if (exp.e1.type.ty == Tenum)
6034 t1 = exp.e1.type;
6037 if (!exp.arguments || exp.arguments.length == 0)
6039 e = t1.defaultInitLiteral(exp.loc);
6041 else if (exp.arguments.length == 1)
6043 e = (*exp.arguments)[0];
6044 e = e.implicitCastTo(sc, t1);
6045 e = new CastExp(exp.loc, e, t1);
6047 else
6049 error(exp.loc, "more than one argument for construction of `%s`", t1.toChars());
6050 return setError();
6052 e = e.expressionSemantic(sc);
6053 result = e;
6054 return;
6058 FuncDeclaration resolveOverloadSet(Loc loc, Scope* sc,
6059 OverloadSet os, Objects* tiargs, Type tthis, ArgumentList argumentList)
6061 FuncDeclaration f = null;
6062 foreach (s; os.a)
6064 if (tiargs && s.isFuncDeclaration())
6065 continue;
6066 if (auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, argumentList, FuncResolveFlag.quiet))
6068 if (f2.errors)
6069 return null;
6070 if (f)
6072 /* Match in more than one overload set,
6073 * even if one is a 'better' match than the other.
6075 if (f.isCsymbol() && f2.isCsymbol())
6077 /* C has global name space, so just pick one, such as f.
6078 * If f and f2 are not compatible, that's how C rolls.
6081 else
6082 ScopeDsymbol.multiplyDefined(loc, f, f2); // issue error
6084 else
6085 f = f2;
6088 if (!f)
6090 .error(loc, "no overload matches for `%s`", exp.toChars());
6091 errorSupplemental(loc, "Candidates are:");
6092 foreach (s; os.a)
6094 overloadApply(s, (ds){
6095 if (auto fd = ds.isFuncDeclaration())
6096 .errorSupplemental(ds.loc, "%s%s", fd.toChars(),
6097 fd.type.toTypeFunction().parameterList.parametersTypeToChars());
6098 else
6099 .errorSupplemental(ds.loc, "%s", ds.toChars());
6100 return 0;
6104 else if (f.errors)
6105 f = null;
6106 return f;
6109 bool isSuper = false;
6110 if (exp.e1.op == EXP.dotVariable && t1.ty == Tfunction || exp.e1.op == EXP.dotTemplateDeclaration)
6112 UnaExp ue = cast(UnaExp)exp.e1;
6114 Expression ue1old = ue.e1; // need for 'right this' check
6115 DotVarExp dve;
6116 DotTemplateExp dte;
6117 Dsymbol s;
6118 if (exp.e1.op == EXP.dotVariable)
6120 dve = cast(DotVarExp)exp.e1;
6121 dte = null;
6122 s = dve.var;
6123 tiargs = null;
6125 else
6127 dve = null;
6128 dte = cast(DotTemplateExp)exp.e1;
6129 s = dte.td;
6132 // Do overload resolution
6133 exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, ue.e1.type, exp.argumentList, FuncResolveFlag.standard);
6134 if (!exp.f || exp.f.errors || exp.f.type.ty == Terror)
6135 return setError();
6137 if (exp.f.interfaceVirtual)
6139 /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent
6141 auto b = exp.f.interfaceVirtual;
6142 auto ad2 = b.sym;
6143 ue.e1 = ue.e1.castTo(sc, ad2.type.addMod(ue.e1.type.mod));
6144 ue.e1 = ue.e1.expressionSemantic(sc);
6145 auto vi = exp.f.findVtblIndex(&ad2.vtbl, cast(int)ad2.vtbl.length);
6146 assert(vi >= 0);
6147 exp.f = ad2.vtbl[vi].isFuncDeclaration();
6148 assert(exp.f);
6150 if (exp.f.needThis())
6152 AggregateDeclaration ad = exp.f.isMemberLocal();
6153 ue.e1 = getRightThis(exp.loc, sc, ad, ue.e1, exp.f);
6154 if (ue.e1.op == EXP.error)
6156 result = ue.e1;
6157 return;
6159 ethis = ue.e1;
6160 tthis = ue.e1.type;
6161 if (!(exp.f.type.ty == Tfunction && (cast(TypeFunction)exp.f.type).isScopeQual))
6163 if (checkParamArgumentEscape(sc, exp.f, Id.This, exp.f.vthis, STC.undefined_, ethis, false, false))
6164 return setError();
6168 /* Cannot call public functions from inside invariant
6169 * (because then the invariant would have infinite recursion)
6171 if (sc.func && sc.func.isInvariantDeclaration() && ue.e1.op == EXP.this_ && exp.f.addPostInvariant())
6173 error(exp.loc, "cannot call `public`/`export` function `%s` from invariant", exp.f.toChars());
6174 return setError();
6177 if (!exp.ignoreAttributes)
6178 checkFunctionAttributes(exp, sc, exp.f);
6180 // Cut-down version of checkAccess() that doesn't use the "most visible" version of exp.f.
6181 // We've already selected an overload here.
6182 const parent = exp.f.toParent();
6183 if (parent && parent.isTemplateInstance())
6185 // already a deprecation
6187 else if (!checkSymbolAccess(sc, exp.f))
6189 error(exp.loc, "%s `%s` of type `%s` is not accessible from module `%s`",
6190 exp.f.kind(), exp.f.toPrettyChars(), exp.f.type.toChars(), sc._module.toChars);
6191 return setError();
6194 if (!exp.f.needThis())
6196 exp.e1 = Expression.combine(ue.e1, new VarExp(exp.loc, exp.f, false));
6198 else
6200 if (ue1old.checkRightThis(sc))
6201 return setError();
6202 if (exp.e1.op == EXP.dotVariable)
6204 dve.var = exp.f;
6205 exp.e1.type = exp.f.type;
6207 else
6209 exp.e1 = new DotVarExp(exp.loc, dte.e1, exp.f, false);
6210 exp.e1 = exp.e1.expressionSemantic(sc);
6211 if (exp.e1.op == EXP.error)
6212 return setError();
6213 ue = cast(UnaExp)exp.e1;
6215 version (none)
6217 printf("ue.e1 = %s\n", ue.e1.toChars());
6218 printf("f = %s\n", exp.f.toChars());
6219 printf("t1 = %s\n", t1.toChars());
6220 printf("e1 = %s\n", exp.e1.toChars());
6221 printf("e1.type = %s\n", exp.e1.type.toChars());
6224 // See if we need to adjust the 'this' pointer
6225 AggregateDeclaration ad = exp.f.isThis();
6226 ClassDeclaration cd = ue.e1.type.isClassHandle();
6227 if (ad && cd && ad.isClassDeclaration())
6229 if (ue.e1.op == EXP.dotType)
6231 ue.e1 = (cast(DotTypeExp)ue.e1).e1;
6232 exp.directcall = true;
6234 else if (ue.e1.op == EXP.super_)
6235 exp.directcall = true;
6236 else if ((cd.storage_class & STC.final_) != 0) // https://issues.dlang.org/show_bug.cgi?id=14211
6237 exp.directcall = true;
6239 if (ad != cd)
6241 ue.e1 = ue.e1.castTo(sc, ad.type.addMod(ue.e1.type.mod));
6242 ue.e1 = ue.e1.expressionSemantic(sc);
6246 // If we've got a pointer to a function then deference it
6247 // https://issues.dlang.org/show_bug.cgi?id=16483
6248 if (exp.e1.type.isPtrToFunction())
6250 Expression e = new PtrExp(exp.loc, exp.e1);
6251 e.type = exp.e1.type.nextOf();
6252 exp.e1 = e;
6254 t1 = exp.e1.type;
6256 else if (exp.e1.op == EXP.super_ || exp.e1.op == EXP.this_)
6258 auto ad = sc.func ? sc.func.isThis() : null;
6259 auto cd = ad ? ad.isClassDeclaration() : null;
6261 isSuper = exp.e1.op == EXP.super_;
6262 if (isSuper)
6264 // Base class constructor call
6265 if (!cd || !cd.baseClass || !sc.func.isCtorDeclaration())
6267 error(exp.loc, "super class constructor call must be in a constructor");
6268 return setError();
6270 if (!cd.baseClass.ctor)
6272 error(exp.loc, "no super class constructor for `%s`", cd.baseClass.toChars());
6273 return setError();
6276 else
6278 // `this` call expression must be inside a
6279 // constructor
6280 if (!ad || !sc.func.isCtorDeclaration())
6282 error(exp.loc, "constructor call must be in a constructor");
6283 return setError();
6286 // https://issues.dlang.org/show_bug.cgi?id=18719
6287 // If `exp` is a call expression to another constructor
6288 // then it means that all struct/class fields will be
6289 // initialized after this call.
6290 foreach (ref field; sc.ctorflow.fieldinit)
6292 field.csx |= CSX.this_ctor;
6296 if (!sc.intypeof && !(sc.ctorflow.callSuper & CSX.halt))
6298 if (sc.inLoop || sc.ctorflow.callSuper & CSX.label)
6299 error(exp.loc, "constructor calls not allowed in loops or after labels");
6300 if (sc.ctorflow.callSuper & (CSX.super_ctor | CSX.this_ctor))
6301 error(exp.loc, "multiple constructor calls");
6302 if ((sc.ctorflow.callSuper & CSX.return_) && !(sc.ctorflow.callSuper & CSX.any_ctor))
6303 error(exp.loc, "an earlier `return` statement skips constructor");
6304 sc.ctorflow.callSuper |= CSX.any_ctor | (isSuper ? CSX.super_ctor : CSX.this_ctor);
6307 tthis = ad.type.addMod(sc.func.type.mod);
6308 auto ctor = isSuper ? cd.baseClass.ctor : ad.ctor;
6309 if (auto os = ctor.isOverloadSet())
6310 exp.f = resolveOverloadSet(exp.loc, sc, os, null, tthis, exp.argumentList);
6311 else
6312 exp.f = resolveFuncCall(exp.loc, sc, ctor, null, tthis, exp.argumentList, FuncResolveFlag.standard);
6314 if (!exp.f || exp.f.errors)
6315 return setError();
6317 checkFunctionAttributes(exp, sc, exp.f);
6318 checkAccess(exp.loc, sc, null, exp.f);
6320 exp.e1 = new DotVarExp(exp.e1.loc, exp.e1, exp.f, false);
6321 exp.e1 = exp.e1.expressionSemantic(sc);
6322 // https://issues.dlang.org/show_bug.cgi?id=21095
6323 if (exp.e1.op == EXP.error)
6324 return setError();
6325 t1 = exp.e1.type;
6327 // BUG: this should really be done by checking the static
6328 // call graph
6329 if (exp.f == sc.func)
6331 error(exp.loc, "cyclic constructor call");
6332 return setError();
6335 else if (auto oe = exp.e1.isOverExp())
6337 exp.f = resolveOverloadSet(exp.loc, sc, oe.vars, tiargs, tthis, exp.argumentList);
6338 if (!exp.f)
6339 return setError();
6340 if (ethis)
6341 exp.e1 = new DotVarExp(exp.loc, ethis, exp.f, false);
6342 else
6343 exp.e1 = new VarExp(exp.loc, exp.f, false);
6344 goto Lagain;
6346 else if (!t1)
6348 error(exp.loc, "function expected before `()`, not `%s`", exp.e1.toChars());
6349 return setError();
6351 else if (t1.ty == Terror)
6353 return setError();
6355 else if (t1.ty != Tfunction)
6357 TypeFunction tf;
6358 const(char)* p;
6359 Dsymbol s;
6360 exp.f = null;
6361 if (auto fe = exp.e1.isFuncExp())
6363 // function literal that direct called is always inferred.
6364 assert(fe.fd);
6365 exp.f = fe.fd;
6366 tf = cast(TypeFunction)exp.f.type;
6367 p = "function literal";
6369 else if (t1.ty == Tdelegate)
6371 TypeDelegate td = cast(TypeDelegate)t1;
6372 assert(td.next.ty == Tfunction);
6373 tf = cast(TypeFunction)td.next;
6374 p = "delegate";
6376 else if (auto tfx = t1.isPtrToFunction())
6378 tf = tfx;
6379 p = "function pointer";
6381 else if (exp.e1.op == EXP.dotVariable && (cast(DotVarExp)exp.e1).var.isOverDeclaration())
6383 DotVarExp dve = cast(DotVarExp)exp.e1;
6384 exp.f = resolveFuncCall(exp.loc, sc, dve.var, tiargs, dve.e1.type, exp.argumentList, FuncResolveFlag.overloadOnly);
6385 if (!exp.f)
6386 return setError();
6387 if (exp.f.needThis())
6389 dve.var = exp.f;
6390 dve.type = exp.f.type;
6391 dve.hasOverloads = false;
6392 goto Lagain;
6394 exp.e1 = new VarExp(dve.loc, exp.f, false);
6395 Expression e = new CommaExp(exp.loc, dve.e1, exp);
6396 result = e.expressionSemantic(sc);
6397 return;
6399 else if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.isOverDeclaration())
6401 s = (cast(VarExp)exp.e1).var;
6402 goto L2;
6404 else if (exp.e1.op == EXP.template_)
6406 s = (cast(TemplateExp)exp.e1).td;
6408 exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, null, exp.argumentList,
6409 exp.isUfcsRewrite ? FuncResolveFlag.ufcs : FuncResolveFlag.standard);
6410 if (!exp.f || exp.f.errors)
6411 return setError();
6412 if (exp.f.needThis())
6414 if (hasThis(sc))
6416 // Supply an implicit 'this', as in
6417 // this.ident
6418 exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), exp.f, false);
6419 goto Lagain;
6421 else if (isNeedThisScope(sc, exp.f))
6423 return needThisError(exp.loc, exp.f);
6426 exp.e1 = new VarExp(exp.e1.loc, exp.f, false);
6427 goto Lagain;
6429 else
6431 error(exp.loc, "function expected before `()`, not `%s` of type `%s`", exp.e1.toChars(), exp.e1.type.toChars());
6432 return setError();
6435 const(char)* failMessage;
6436 if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc))
6438 OutBuffer buf;
6439 buf.writeByte('(');
6440 argExpTypesToCBuffer(buf, exp.arguments);
6441 buf.writeByte(')');
6442 if (tthis)
6443 tthis.modToBuffer(buf);
6445 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
6446 .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`",
6447 p, exp.e1.toChars(), parametersTypeToChars(tf.parameterList), buf.peekChars());
6448 if (failMessage)
6449 errorSupplemental(exp.loc, "%s", failMessage);
6450 return setError();
6452 // Purity and safety check should run after testing arguments matching
6453 if (exp.f)
6455 exp.f.checkPurity(exp.loc, sc);
6456 exp.f.checkSafety(exp.loc, sc);
6457 exp.f.checkNogc(exp.loc, sc);
6458 if (exp.f.checkNestedReference(sc, exp.loc))
6459 return setError();
6461 else if (sc.func && sc.intypeof != 1 && !(sc.flags & (SCOPE.ctfe | SCOPE.debug_)))
6463 bool err = false;
6464 if (!tf.purity && sc.func.setImpure(exp.loc, "`pure` %s `%s` cannot call impure `%s`", exp.e1))
6466 error(exp.loc, "`pure` %s `%s` cannot call impure %s `%s`",
6467 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
6468 err = true;
6470 if (!tf.isnogc && sc.func.setGC(exp.loc, "`@nogc` %s `%s` cannot call non-@nogc `%s`", exp.e1))
6472 error(exp.loc, "`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
6473 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
6474 err = true;
6476 if (tf.trust <= TRUST.system && sc.setUnsafe(true, exp.loc,
6477 "`@safe` function `%s` cannot call `@system` `%s`", sc.func, exp.e1))
6479 error(exp.loc, "`@safe` %s `%s` cannot call `@system` %s `%s`",
6480 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
6481 err = true;
6483 if (err)
6484 return setError();
6487 if (t1.ty == Tpointer)
6489 Expression e = new PtrExp(exp.loc, exp.e1);
6490 e.type = tf;
6491 exp.e1 = e;
6493 t1 = tf;
6495 else if (VarExp ve = exp.e1.isVarExp())
6497 // Do overload resolution
6498 exp.f = ve.var.isFuncDeclaration();
6499 assert(exp.f);
6500 tiargs = null;
6502 if (exp.f.overnext)
6503 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.overloadOnly);
6504 else
6506 exp.f = exp.f.toAliasFunc();
6507 TypeFunction tf = cast(TypeFunction)exp.f.type;
6508 const(char)* failMessage;
6509 if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc))
6511 OutBuffer buf;
6512 buf.writeByte('(');
6513 argExpTypesToCBuffer(buf, exp.arguments);
6514 buf.writeByte(')');
6516 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
6517 if (exp.isUfcsRewrite)
6519 const arg = (*exp.argumentList.arguments)[0];
6520 .error(exp.loc, "no property `%s` for `%s` of type `%s`", exp.f.ident.toChars(), arg.toChars(), arg.type.toChars());
6521 .errorSupplemental(exp.loc, "the following error occured while looking for a UFCS match");
6524 .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`",
6525 exp.f.kind(), exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList), buf.peekChars());
6526 if (failMessage)
6527 errorSupplemental(exp.loc, "%s", failMessage);
6528 exp.f = null;
6531 if (!exp.f || exp.f.errors)
6532 return setError();
6534 if (exp.f.needThis())
6536 // Change the ancestor lambdas to delegate before hasThis(sc) call.
6537 if (exp.f.checkNestedReference(sc, exp.loc))
6538 return setError();
6540 auto memberFunc = hasThis(sc);
6541 if (memberFunc && haveSameThis(memberFunc, exp.f))
6543 // Supply an implicit 'this', as in
6544 // this.ident
6545 exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), ve.var);
6546 // Note: we cannot use f directly, because further overload resolution
6547 // through the supplied 'this' may cause different result.
6548 goto Lagain;
6550 else if (isNeedThisScope(sc, exp.f))
6552 // At this point it is possible that `exp.f` had an ambiguity error that was
6553 // silenced because the previous call to `resolveFuncCall` was done using
6554 // `FuncResolveFlag.overloadOnly`. To make sure that a proper error message
6555 // is printed, redo the call with `FuncResolveFlag.standard`.
6557 // https://issues.dlang.org/show_bug.cgi?id=22157
6558 if (exp.f.overnext)
6559 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.standard);
6561 if (!exp.f || exp.f.errors)
6562 return setError();
6564 // If no error is printed, it means that `f` is the single matching overload
6565 // and it needs `this`.
6566 return needThisError(exp.loc, exp.f);
6570 checkFunctionAttributes(exp, sc, exp.f);
6571 checkAccess(exp.loc, sc, null, exp.f);
6572 if (exp.f.checkNestedReference(sc, exp.loc))
6573 return setError();
6575 ethis = null;
6576 tthis = null;
6578 if (ve.hasOverloads)
6580 exp.e1 = new VarExp(ve.loc, exp.f, false);
6581 exp.e1.type = exp.f.type;
6583 t1 = exp.f.type;
6585 assert(t1.ty == Tfunction);
6587 Expression argprefix;
6588 if (!exp.arguments)
6589 exp.arguments = new Expressions();
6590 if (functionParameters(exp.loc, sc, cast(TypeFunction)t1, ethis, tthis, exp.argumentList, exp.f, &exp.type, &argprefix))
6591 return setError();
6593 if (!exp.type)
6595 exp.e1 = e1org; // https://issues.dlang.org/show_bug.cgi?id=10922
6596 // avoid recursive expression printing
6597 error(exp.loc, "forward reference to inferred return type of function call `%s`", exp.toChars());
6598 return setError();
6601 if (exp.f && exp.f.tintro)
6603 Type t = exp.type;
6604 int offset = 0;
6605 TypeFunction tf = cast(TypeFunction)exp.f.tintro;
6606 if (tf.next.isBaseOf(t, &offset) && offset)
6608 exp.type = tf.next;
6609 result = Expression.combine(argprefix, exp.castTo(sc, t));
6610 return;
6614 // Handle the case of a direct lambda call
6615 if (exp.f && exp.f.isFuncLiteralDeclaration() && sc.func && !sc.intypeof)
6617 exp.f.tookAddressOf = 0;
6620 result = Expression.combine(argprefix, exp);
6622 if (isSuper)
6624 auto ad = sc.func ? sc.func.isThis() : null;
6625 auto cd = ad ? ad.isClassDeclaration() : null;
6626 if (cd && cd.classKind == ClassKind.cpp && exp.f && !exp.f.fbody)
6628 // if super is defined in C++, it sets the vtable pointer to the base class
6629 // so we have to restore it, but still return 'this' from super() call:
6630 // (auto __vptrTmp = this.__vptr, auto __superTmp = super()), (this.__vptr = __vptrTmp, __superTmp)
6631 Loc loc = exp.loc;
6633 auto vptr = new DotIdExp(loc, new ThisExp(loc), Id.__vptr);
6634 auto vptrTmpDecl = copyToTemp(0, "__vptrTmp", vptr);
6635 auto declareVptrTmp = new DeclarationExp(loc, vptrTmpDecl);
6637 auto superTmpDecl = copyToTemp(0, "__superTmp", result);
6638 auto declareSuperTmp = new DeclarationExp(loc, superTmpDecl);
6640 auto declareTmps = new CommaExp(loc, declareVptrTmp, declareSuperTmp);
6642 auto restoreVptr = new AssignExp(loc, vptr.syntaxCopy(), new VarExp(loc, vptrTmpDecl));
6644 Expression e = new CommaExp(loc, declareTmps, new CommaExp(loc, restoreVptr, new VarExp(loc, superTmpDecl)));
6645 result = e.expressionSemantic(sc);
6649 // `super.fun()` with fun being abstract and unimplemented
6650 auto supDotFun = exp.e1.isDotVarExp();
6651 if (supDotFun && supDotFun.e1.isSuperExp() && exp.f && exp.f.isAbstract() && !exp.f.fbody)
6653 error(exp.loc, "call to unimplemented abstract function `%s`", exp.f.toFullSignature());
6654 errorSupplemental(exp.loc, "declared here: %s", exp.f.loc.toChars());
6657 // declare dual-context container
6658 if (exp.f && exp.f.hasDualContext() && !sc.intypeof && sc.func)
6660 // check access to second `this`
6661 if (AggregateDeclaration ad2 = exp.f.isMember2())
6663 Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
6664 if (te.op != EXP.error)
6665 te = getRightThis(exp.loc, sc, ad2, te, exp.f);
6666 if (te.op == EXP.error)
6668 error(exp.loc, "need `this` of type `%s` to call function `%s`", ad2.toChars(), exp.f.toChars());
6669 return setError();
6672 exp.vthis2 = makeThis2Argument(exp.loc, sc, exp.f);
6673 Expression de = new DeclarationExp(exp.loc, exp.vthis2);
6674 result = Expression.combine(de, result);
6675 result = result.expressionSemantic(sc);
6679 override void visit(DeclarationExp e)
6681 if (e.type)
6683 result = e;
6684 return;
6686 static if (LOGSEMANTIC)
6688 printf("DeclarationExp::semantic() %s\n", e.toChars());
6691 uint olderrors = global.errors;
6693 /* This is here to support extern(linkage) declaration,
6694 * where the extern(linkage) winds up being an AttribDeclaration
6695 * wrapper.
6697 Dsymbol s = e.declaration;
6699 while (1)
6701 AttribDeclaration ad = s.isAttribDeclaration();
6702 if (ad)
6704 if (ad.decl && ad.decl.length == 1)
6706 s = (*ad.decl)[0];
6707 continue;
6710 break;
6713 //printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc);
6714 // Insert into both local scope and function scope.
6715 // Must be unique in both.
6716 if (s.ident)
6718 VarDeclaration v = s.isVarDeclaration();
6719 if (v)
6721 if (sc.flags & SCOPE.Cfile)
6723 /* Do semantic() on the type before inserting v into the symbol table
6725 if (!v.originalType)
6726 v.originalType = v.type.syntaxCopy();
6727 Scope* sc2 = sc.push();
6728 sc2.stc |= v.storage_class & STC.FUNCATTR;
6729 sc2.linkage = LINK.c; // account for the extern(C) in front of the declaration
6730 v.inuse++;
6731 v.type = v.type.typeSemantic(v.loc, sc2);
6732 v.inuse--;
6733 sc2.pop();
6735 else
6737 /* Do semantic() on initializer first so this will be illegal:
6738 * int a = a;
6740 e.declaration.dsymbolSemantic(sc);
6741 s.parent = sc.parent;
6745 if (!sc.insert(s))
6747 auto conflict = sc.search(Loc.initial, s.ident, null);
6748 error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
6749 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
6750 conflict.kind(), conflict.toChars());
6751 return setError();
6754 if (v && (sc.flags & SCOPE.Cfile))
6756 /* Do semantic() on initializer last so this will be legal:
6757 * int a = a;
6759 e.declaration.dsymbolSemantic(sc);
6760 s.parent = sc.parent;
6763 if (sc.func)
6765 // https://issues.dlang.org/show_bug.cgi?id=11720
6766 if ((s.isFuncDeclaration() ||
6767 s.isAggregateDeclaration() ||
6768 s.isEnumDeclaration() ||
6769 s.isTemplateDeclaration() ||
6771 ) && !sc.func.localsymtab.insert(s))
6773 // Get the previous symbol
6774 Dsymbol originalSymbol = sc.func.localsymtab.lookup(s.ident);
6776 // Perturb the name mangling so that the symbols can co-exist
6777 // instead of colliding
6778 s.localNum = cast(ushort)(originalSymbol.localNum + 1);
6779 // 65535 should be enough for anyone
6780 if (!s.localNum)
6782 error(e.loc, "more than 65535 symbols with name `%s` generated", s.ident.toChars());
6783 return setError();
6786 // Replace originalSymbol with s, which updates the localCount
6787 sc.func.localsymtab.update(s);
6789 // The mangling change only works for D mangling
6792 if (!(sc.flags & SCOPE.Cfile))
6794 /* https://issues.dlang.org/show_bug.cgi?id=21272
6795 * If we are in a foreach body we need to extract the
6796 * function containing the foreach
6798 FuncDeclaration fes_enclosing_func;
6799 if (sc.func && sc.func.fes)
6800 fes_enclosing_func = sc.enclosing.enclosing.func;
6802 // Disallow shadowing
6803 for (Scope* scx = sc.enclosing; scx && (scx.func == sc.func || (fes_enclosing_func && scx.func == fes_enclosing_func)); scx = scx.enclosing)
6805 Dsymbol s2;
6806 if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2)
6808 // allow STC.local symbols to be shadowed
6809 // TODO: not really an optimal design
6810 auto decl = s2.isDeclaration();
6811 if (!decl || !(decl.storage_class & STC.local))
6813 if (sc.func.fes)
6815 deprecation(e.loc, "%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
6817 else
6819 error(e.loc, "%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
6820 return setError();
6828 if (!s.isVarDeclaration())
6830 Scope* sc2 = sc;
6831 if (sc2.stc & (STC.pure_ | STC.nothrow_ | STC.nogc))
6832 sc2 = sc.push();
6833 sc2.stc &= ~(STC.pure_ | STC.nothrow_ | STC.nogc);
6834 e.declaration.dsymbolSemantic(sc2);
6835 if (sc2 != sc)
6836 sc2.pop();
6837 s.parent = sc.parent;
6839 if (global.errors == olderrors)
6841 e.declaration.semantic2(sc);
6842 if (global.errors == olderrors)
6844 e.declaration.semantic3(sc);
6847 // todo: error in declaration should be propagated.
6849 e.type = Type.tvoid;
6850 result = e;
6853 override void visit(TypeidExp exp)
6855 static if (LOGSEMANTIC)
6857 printf("TypeidExp::semantic() %s\n", exp.toChars());
6859 Type ta = isType(exp.obj);
6860 Expression ea = isExpression(exp.obj);
6861 Dsymbol sa = isDsymbol(exp.obj);
6862 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
6864 if (ta)
6866 dmd.typesem.resolve(ta, exp.loc, sc, ea, ta, sa, true);
6869 if (ea)
6871 if (auto sym = getDsymbol(ea))
6872 ea = symbolToExp(sym, exp.loc, sc, false);
6873 else
6874 ea = ea.expressionSemantic(sc);
6875 ea = resolveProperties(sc, ea);
6876 ta = ea.type;
6877 if (ea.op == EXP.type)
6878 ea = null;
6881 if (!ta)
6883 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
6884 error(exp.loc, "no type for `typeid(%s)`", ea ? ea.toChars() : (sa ? sa.toChars() : ""));
6885 return setError();
6888 ta.checkComplexTransition(exp.loc, sc);
6890 Expression e;
6891 auto tb = ta.toBasetype();
6892 if (ea && tb.ty == Tclass)
6894 if (tb.toDsymbol(sc).isClassDeclaration().classKind == ClassKind.cpp)
6896 error(exp.loc, "runtime type information is not supported for `extern(C++)` classes");
6897 e = ErrorExp.get();
6899 else if (!Type.typeinfoclass)
6901 error(exp.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
6902 e = ErrorExp.get();
6904 else
6906 /* Get the dynamic type, which is .classinfo
6908 ea = ea.expressionSemantic(sc);
6909 e = new TypeidExp(ea.loc, ea);
6910 e.type = Type.typeinfoclass.type;
6913 else if (ta.ty == Terror)
6915 e = ErrorExp.get();
6917 else
6919 // Handle this in the glue layer
6920 e = new TypeidExp(exp.loc, ta);
6922 bool genObjCode = true;
6924 // https://issues.dlang.org/show_bug.cgi?id=23650
6925 // We generate object code for typeinfo, required
6926 // by typeid, only if in non-speculative context
6927 if (sc.flags & SCOPE.compile)
6929 genObjCode = false;
6932 e.type = getTypeInfoType(exp.loc, ta, sc, genObjCode);
6933 semanticTypeInfo(sc, ta);
6935 if (ea)
6937 e = new CommaExp(exp.loc, ea, e); // execute ea
6938 e = e.expressionSemantic(sc);
6941 result = e;
6944 override void visit(TraitsExp e)
6946 result = semanticTraits(e, sc);
6949 override void visit(HaltExp e)
6951 static if (LOGSEMANTIC)
6953 printf("HaltExp::semantic()\n");
6955 e.type = Type.tnoreturn;
6956 result = e;
6959 override void visit(IsExp e)
6961 /* is(targ id tok tspec)
6962 * is(targ id : tok2)
6963 * is(targ id == tok2)
6965 Type tded = null;
6967 void yes()
6969 //printf("yes\n");
6970 if (!e.id)
6972 result = IntegerExp.createBool(true);
6973 return;
6976 Dsymbol s;
6977 Tuple tup = isTuple(tded);
6978 if (tup)
6979 s = new TupleDeclaration(e.loc, e.id, &tup.objects);
6980 else
6981 s = new AliasDeclaration(e.loc, e.id, tded);
6982 s.dsymbolSemantic(sc);
6984 /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there.
6985 * More investigation is needed.
6987 if (!tup && !sc.insert(s))
6989 auto conflict = sc.search(Loc.initial, s.ident, null);
6990 error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
6991 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
6992 conflict.kind(), conflict.toChars());
6995 unSpeculative(sc, s);
6997 result = IntegerExp.createBool(true);
6999 void no()
7001 result = IntegerExp.createBool(false);
7002 //printf("no\n");
7005 static if (LOGSEMANTIC)
7007 printf("IsExp::semantic(%s)\n", e.toChars());
7009 if (e.id && !(sc.flags & SCOPE.condition))
7011 error(e.loc, "can only declare type aliases within `static if` conditionals or `static assert`s");
7012 return setError();
7015 if (e.tok2 == TOK.package_ || e.tok2 == TOK.module_) // These is() expressions are special because they can work on modules, not just types.
7017 const oldErrors = global.startGagging();
7018 Dsymbol sym = e.targ.toDsymbol(sc);
7019 global.endGagging(oldErrors);
7021 if (sym is null)
7022 return no();
7023 Package p = resolveIsPackage(sym);
7024 if (p is null)
7025 return no();
7026 if (e.tok2 == TOK.package_ && p.isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module.
7027 return no();
7028 else if(e.tok2 == TOK.module_ && !(p.isModule() || p.isPackageMod()))
7029 return no();
7030 tded = e.targ;
7031 return yes();
7035 Scope* sc2 = sc.copy(); // keep sc.flags
7036 sc2.tinst = null;
7037 sc2.minst = null;
7038 sc2.flags |= SCOPE.fullinst;
7039 Type t = e.targ.trySemantic(e.loc, sc2);
7040 sc2.pop();
7041 if (!t) // errors, so condition is false
7042 return no();
7043 e.targ = t;
7046 if (e.tok2 != TOK.reserved)
7048 switch (e.tok2)
7050 case TOK.struct_:
7051 if (e.targ.ty != Tstruct)
7052 return no();
7053 if ((cast(TypeStruct)e.targ).sym.isUnionDeclaration())
7054 return no();
7055 tded = e.targ;
7056 break;
7058 case TOK.union_:
7059 if (e.targ.ty != Tstruct)
7060 return no();
7061 if (!(cast(TypeStruct)e.targ).sym.isUnionDeclaration())
7062 return no();
7063 tded = e.targ;
7064 break;
7066 case TOK.class_:
7067 if (e.targ.ty != Tclass)
7068 return no();
7069 if ((cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
7070 return no();
7071 tded = e.targ;
7072 break;
7074 case TOK.interface_:
7075 if (e.targ.ty != Tclass)
7076 return no();
7077 if (!(cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
7078 return no();
7079 tded = e.targ;
7080 break;
7082 case TOK.const_:
7083 if (!e.targ.isConst())
7084 return no();
7085 tded = e.targ;
7086 break;
7088 case TOK.immutable_:
7089 if (!e.targ.isImmutable())
7090 return no();
7091 tded = e.targ;
7092 break;
7094 case TOK.shared_:
7095 if (!e.targ.isShared())
7096 return no();
7097 tded = e.targ;
7098 break;
7100 case TOK.inout_:
7101 if (!e.targ.isWild())
7102 return no();
7103 tded = e.targ;
7104 break;
7106 case TOK.super_:
7107 // If class or interface, get the base class and interfaces
7108 if (e.targ.ty != Tclass)
7109 return no();
7110 else
7112 ClassDeclaration cd = (cast(TypeClass)e.targ).sym;
7113 auto args = new Parameters();
7114 args.reserve(cd.baseclasses.length);
7115 if (cd.semanticRun < PASS.semanticdone)
7116 cd.dsymbolSemantic(null);
7117 for (size_t i = 0; i < cd.baseclasses.length; i++)
7119 BaseClass* b = (*cd.baseclasses)[i];
7120 args.push(new Parameter(Loc.initial, STC.in_, b.type, null, null, null));
7122 tded = new TypeTuple(args);
7124 break;
7126 case TOK.enum_:
7127 if (e.targ.ty != Tenum)
7128 return no();
7129 if (e.id)
7130 tded = (cast(TypeEnum)e.targ).sym.getMemtype(e.loc);
7131 else
7132 tded = e.targ;
7134 if (tded.ty == Terror)
7135 return setError();
7136 break;
7138 case TOK.delegate_:
7139 if (e.targ.ty != Tdelegate)
7140 return no();
7141 tded = (cast(TypeDelegate)e.targ).next; // the underlying function type
7142 break;
7144 case TOK.function_:
7145 if (e.targ.ty != Tfunction)
7146 return no();
7147 goto case;
7148 case TOK.parameters:
7150 if (auto tf = e.targ.isFunction_Delegate_PtrToFunction())
7151 tded = tf;
7152 else
7153 return no();
7155 /* Generate tuple from function parameter types.
7157 auto args = new Parameters();
7158 foreach (i, arg; tded.isTypeFunction().parameterList)
7160 assert(arg && arg.type);
7161 /* If one of the default arguments was an error,
7162 don't return an invalid tuple
7164 if (e.tok2 == TOK.parameters && arg.defaultArg && arg.defaultArg.op == EXP.error)
7165 return setError();
7166 args.push(new Parameter(arg.loc, arg.storageClass, arg.type, (e.tok2 == TOK.parameters) ? arg.ident : null, (e.tok2 == TOK.parameters) ? arg.defaultArg : null, arg.userAttribDecl));
7168 tded = new TypeTuple(args);
7169 break;
7171 case TOK.return_:
7172 /* Get the 'return type' for the function,
7173 * delegate, or pointer to function.
7175 if (auto tf = e.targ.isFunction_Delegate_PtrToFunction())
7176 tded = tf.next;
7177 else
7178 return no();
7179 break;
7181 case TOK.argumentTypes:
7182 /* Generate a type tuple of the equivalent types used to determine if a
7183 * function argument of this type can be passed in registers.
7184 * The results of this are highly platform dependent, and intended
7185 * primarly for use in implementing va_arg().
7187 tded = target.toArgTypes(e.targ);
7188 if (!tded)
7189 return no();
7190 // not valid for a parameter
7191 break;
7193 case TOK.vector:
7194 if (e.targ.ty != Tvector)
7195 return no();
7196 tded = (cast(TypeVector)e.targ).basetype;
7197 break;
7199 default:
7200 assert(0);
7203 // https://issues.dlang.org/show_bug.cgi?id=18753
7204 if (tded)
7205 return yes();
7206 return no();
7208 else if (e.tspec && !e.id && !(e.parameters && e.parameters.length))
7210 /* Evaluate to true if targ matches tspec
7211 * is(targ == tspec)
7212 * is(targ : tspec)
7214 e.tspec = e.tspec.typeSemantic(e.loc, sc);
7215 //printf("targ = %s, %s\n", e.targ.toChars(), e.targ.deco);
7216 //printf("tspec = %s, %s\n", e.tspec.toChars(), e.tspec.deco);
7218 if (e.tok == TOK.colon)
7220 // current scope is itself deprecated, or deprecations are not errors
7221 const bool deprecationAllowed = sc.isDeprecated
7222 || global.params.useDeprecated != DiagnosticReporting.error;
7223 const bool preventAliasThis = e.targ.hasDeprecatedAliasThis && !deprecationAllowed;
7225 if (preventAliasThis && e.targ.ty == Tstruct)
7227 if ((cast(TypeStruct) e.targ).implicitConvToWithoutAliasThis(e.tspec))
7228 return yes();
7229 else
7230 return no();
7232 else if (preventAliasThis && e.targ.ty == Tclass)
7234 if ((cast(TypeClass) e.targ).implicitConvToWithoutAliasThis(e.tspec))
7235 return yes();
7236 else
7237 return no();
7239 else if (e.targ.implicitConvTo(e.tspec))
7240 return yes();
7241 else
7242 return no();
7244 else /* == */
7246 if (e.targ.equals(e.tspec))
7247 return yes();
7248 else
7249 return no();
7252 else if (e.tspec)
7254 /* Evaluate to true if targ matches tspec.
7255 * If true, declare id as an alias for the specialized type.
7256 * is(targ == tspec, tpl)
7257 * is(targ : tspec, tpl)
7258 * is(targ id == tspec)
7259 * is(targ id : tspec)
7260 * is(targ id == tspec, tpl)
7261 * is(targ id : tspec, tpl)
7263 Identifier tid = e.id ? e.id : Identifier.generateId("__isexp_id");
7264 e.parameters.insert(0, new TemplateTypeParameter(e.loc, tid, null, null));
7266 Objects dedtypes = Objects(e.parameters.length);
7267 dedtypes.zero();
7269 MATCH m = deduceType(e.targ, sc, e.tspec, e.parameters, &dedtypes, null, 0, e.tok == TOK.equal);
7271 if (m == MATCH.nomatch || (m != MATCH.exact && e.tok == TOK.equal))
7273 return no();
7275 else
7277 tded = cast(Type)dedtypes[0];
7278 if (!tded)
7279 tded = e.targ;
7280 Objects tiargs = Objects(1);
7281 tiargs[0] = e.targ;
7283 /* Declare trailing parameters
7285 for (size_t i = 1; i < e.parameters.length; i++)
7287 TemplateParameter tp = (*e.parameters)[i];
7288 Declaration s = null;
7290 m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, &dedtypes, &s);
7291 if (m == MATCH.nomatch)
7292 return no();
7293 s.dsymbolSemantic(sc);
7294 if (!sc.insert(s))
7296 auto conflict = sc.search(Loc.initial, s.ident, null);
7297 error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
7298 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
7299 conflict.kind(), conflict.toChars());
7302 unSpeculative(sc, s);
7304 return yes();
7307 else if (e.id)
7309 /* Declare id as an alias for type targ. Evaluate to true
7310 * is(targ id)
7312 tded = e.targ;
7314 return yes();
7317 override void visit(BinAssignExp exp)
7319 if (exp.type)
7321 result = exp;
7322 return;
7325 Expression e = exp.op_overload(sc);
7326 if (e)
7328 result = e;
7329 return;
7332 if (exp.e1.op == EXP.arrayLength)
7334 // arr.length op= e2;
7335 e = rewriteOpAssign(exp);
7336 e = e.expressionSemantic(sc);
7337 result = e;
7338 return;
7340 if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
7342 if (checkNonAssignmentArrayOp(exp.e1))
7343 return setError();
7345 if (exp.e1.op == EXP.slice)
7346 (cast(SliceExp)exp.e1).arrayop = true;
7348 // T[] op= ...
7349 if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
7351 // T[] op= T
7352 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
7354 else if (Expression ex = typeCombine(exp, sc))
7356 result = ex;
7357 return;
7359 exp.type = exp.e1.type;
7360 result = arrayOp(exp, sc);
7361 return;
7364 exp.e1 = exp.e1.expressionSemantic(sc);
7365 exp.e1 = exp.e1.modifiableLvalue(sc);
7366 exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
7367 exp.type = exp.e1.type;
7369 if (auto ad = isAggregate(exp.e1.type))
7371 if (const s = search_function(ad, Id.opOpAssign))
7373 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());
7374 return setError();
7377 if (exp.e1.checkScalar() ||
7378 exp.e1.checkReadModifyWrite(exp.op, exp.e2) ||
7379 exp.e1.checkSharedAccess(sc))
7380 return setError();
7382 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);
7383 int bitwise = (exp.op == EXP.andAssign || exp.op == EXP.orAssign || exp.op == EXP.xorAssign);
7384 int shift = (exp.op == EXP.leftShiftAssign || exp.op == EXP.rightShiftAssign || exp.op == EXP.unsignedRightShiftAssign);
7386 if (bitwise && exp.type.toBasetype().ty == Tbool)
7387 exp.e2 = exp.e2.implicitCastTo(sc, exp.type);
7388 else if (exp.checkNoBool())
7389 return setError();
7391 if ((exp.op == EXP.addAssign || exp.op == EXP.minAssign) && exp.e1.type.toBasetype().ty == Tpointer && exp.e2.type.toBasetype().isintegral())
7393 result = scaleFactor(exp, sc);
7394 return;
7397 if (Expression ex = typeCombine(exp, sc))
7399 result = ex;
7400 return;
7403 if (arith && (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)))
7404 return setError();
7405 if ((bitwise || shift) && (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)))
7406 return setError();
7408 if (shift)
7410 if (exp.e2.type.toBasetype().ty != Tvector)
7411 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
7414 if (!target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
7416 result = exp.incompatibleTypes();
7417 return;
7420 if (exp.e1.op == EXP.error || exp.e2.op == EXP.error)
7421 return setError();
7423 e = exp.checkOpAssignTypes(sc);
7424 if (e.op == EXP.error)
7426 result = e;
7427 return;
7430 assert(e.op == EXP.assign || e == exp);
7431 result = (cast(BinExp)e).reorderSettingAAElem(sc);
7434 private Expression compileIt(MixinExp exp)
7436 OutBuffer buf;
7437 if (expressionsToString(buf, sc, exp.exps))
7438 return null;
7440 uint errors = global.errors;
7441 const len = buf.length;
7442 const str = buf.extractChars()[0 .. len];
7443 const bool doUnittests = global.params.parsingUnittestsRequired();
7444 auto loc = adjustLocForMixin(str, exp.loc, global.params.mixinOut);
7445 scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
7446 p.transitionIn = global.params.v.vin;
7447 p.nextToken();
7448 //printf("p.loc.linnum = %d\n", p.loc.linnum);
7450 Expression e = p.parseExpression();
7451 if (global.errors != errors)
7452 return null;
7454 if (p.token.value != TOK.endOfFile)
7456 error(e.loc, "unexpected token `%s` after %s expression",
7457 p.token.toChars(), EXPtoString(e.op).ptr);
7458 errorSupplemental(e.loc, "while parsing string mixin expression `%s`",
7459 str.ptr);
7460 return null;
7462 return e;
7465 override void visit(MixinExp exp)
7467 /* https://dlang.org/spec/expression.html#mixin_expressions
7470 static if (LOGSEMANTIC)
7472 printf("MixinExp::semantic('%s')\n", exp.toChars());
7475 auto e = compileIt(exp);
7476 if (!e)
7477 return setError();
7478 result = e.expressionSemantic(sc);
7481 override void visit(ImportExp e)
7483 static if (LOGSEMANTIC)
7485 printf("ImportExp::semantic('%s')\n", e.toChars());
7488 auto se = semanticString(sc, e.e1, "file name argument");
7489 if (!se)
7490 return setError();
7491 se = se.toUTF8(sc);
7493 auto namez = se.toStringz();
7494 if (!global.filePath)
7496 error(e.loc, "need `-J` switch to import text file `%s`", namez.ptr);
7497 return setError();
7500 /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
7501 * ('Path Traversal') attacks.
7502 * https://cwe.mitre.org/data/definitions/22.html
7505 if (FileName.absolute(namez))
7507 error(e.loc, "absolute path is not allowed in import expression: `%s`", se.toChars());
7508 return setError();
7511 auto idxReserved = FileName.findReservedChar(namez);
7512 if (idxReserved != size_t.max)
7514 error(e.loc, "`%s` is not a valid filename on this platform", se.toChars());
7515 errorSupplemental(e.loc, "Character `'%c'` is reserved and cannot be used", namez[idxReserved]);
7516 return setError();
7519 if (FileName.refersToParentDir(namez))
7521 error(e.loc, "path refers to parent (`..`) directory: `%s`", se.toChars());
7522 return setError();
7525 auto resolvedNamez = FileName.searchPath(global.filePath, namez, false);
7526 if (!resolvedNamez)
7528 error(e.loc, "file `%s` cannot be found or not in a path specified with `-J`", se.toChars());
7529 errorSupplemental(e.loc, "Path(s) searched (as provided by `-J`):");
7530 foreach (idx, path; *global.filePath)
7532 const attr = FileName.exists(path);
7533 const(char)* err = attr == 2 ? "" :
7534 (attr == 1 ? " (not a directory)" : " (path not found)");
7535 errorSupplemental(e.loc, "[%llu]: `%s`%s", cast(ulong)idx, path, err);
7537 return setError();
7540 sc._module.contentImportedFiles.push(resolvedNamez.ptr);
7541 if (global.params.v.verbose)
7543 const slice = se.peekString();
7544 message("file %.*s\t(%s)", cast(int)slice.length, slice.ptr, resolvedNamez.ptr);
7546 if (global.params.moduleDeps.buffer !is null)
7548 OutBuffer* ob = global.params.moduleDeps.buffer;
7549 Module imod = sc._module;
7551 if (!global.params.moduleDeps.name)
7552 ob.writestring("depsFile ");
7553 ob.writestring(imod.toPrettyChars());
7554 ob.writestring(" (");
7555 escapePath(ob, imod.srcfile.toChars());
7556 ob.writestring(") : ");
7557 if (global.params.moduleDeps.name)
7558 ob.writestring("string : ");
7559 ob.write(se.peekString());
7560 ob.writestring(" (");
7561 escapePath(ob, resolvedNamez.ptr);
7562 ob.writestring(")");
7563 ob.writenl();
7565 if (global.params.makeDeps.doOutput)
7567 global.params.makeDeps.files.push(resolvedNamez.ptr);
7571 auto fileName = FileName(resolvedNamez);
7572 if (auto fmResult = global.fileManager.lookup(fileName))
7574 se = new StringExp(e.loc, fmResult);
7576 else
7578 error(e.loc, "cannot read file `%s`", resolvedNamez.ptr);
7579 return setError();
7582 result = se.expressionSemantic(sc);
7585 override void visit(AssertExp exp)
7587 // https://dlang.org/spec/expression.html#assert_expressions
7588 static if (LOGSEMANTIC)
7590 printf("AssertExp::semantic('%s')\n", exp.toChars());
7593 const generateMsg = !exp.msg &&
7594 sc.needsCodegen() && // let ctfe interpreter handle the error message
7595 global.params.checkAction == CHECKACTION.context &&
7596 global.params.useAssert == CHECKENABLE.on &&
7597 !((exp.e1.isIntegerExp() && (exp.e1.toInteger() == 0)) ||
7598 exp.e1.isNullExp());
7599 Expression temporariesPrefix;
7601 if (generateMsg)
7602 // no message - use assert expression as msg
7604 if (!verifyHookExist(exp.loc, *sc, Id._d_assert_fail, "generating assert messages"))
7605 return setError();
7609 auto a = e1, b = e2;
7610 assert(a == b, _d_assert_fail!"=="(a, b));
7615 Stores the result of an operand expression into a temporary
7616 if necessary, e.g. if it is an impure fuction call containing side
7617 effects as in https://issues.dlang.org/show_bug.cgi?id=20114
7619 Params:
7620 op = an expression which may require a temporary (added to
7621 `temporariesPrefix`: `auto tmp = op`) and will be replaced
7622 by `tmp` if necessary
7624 Returns: (possibly replaced) `op`
7626 Expression maybePromoteToTmp(ref Expression op)
7628 // https://issues.dlang.org/show_bug.cgi?id=20989
7629 // Flag that _d_assert_fail will never dereference `array.ptr` to avoid safety
7630 // errors for `assert(!array.ptr)` => `_d_assert_fail!"!"(array.ptr)`
7632 auto die = op.isDotIdExp();
7633 if (die && die.ident == Id.ptr)
7634 die.noderef = true;
7637 op = op.expressionSemantic(sc);
7638 op = resolveProperties(sc, op);
7640 // Detect assert's using static operator overloads (e.g. `"var" in environment`)
7641 if (auto te = op.isTypeExp())
7643 // Replace the TypeExp with it's textual representation
7644 // Including "..." in the error message isn't quite right but
7645 // proper solutions require more drastic changes, e.g. directly
7646 // using miniFormat and combine instead of calling _d_assert_fail
7647 auto name = new StringExp(te.loc, te.toString());
7648 return name.expressionSemantic(sc);
7651 // Create a temporary for expressions with side effects
7652 // Defensively assume that function calls may have side effects even
7653 // though it's not detected by hasSideEffect (e.g. `debug puts("Hello")` )
7654 // Rewriting CallExp's also avoids some issues with the inliner/debug generation
7655 if (op.hasSideEffect(true))
7657 // Don't create an invalid temporary for void-expressions
7658 // Further semantic will issue an appropriate error
7659 if (op.type.ty == Tvoid)
7660 return op;
7662 // https://issues.dlang.org/show_bug.cgi?id=21590
7663 // Don't create unnecessary temporaries and detect `assert(a = b)`
7664 if (op.isAssignExp() || op.isBinAssignExp())
7666 auto left = (cast(BinExp) op).e1;
7668 // Find leftmost expression to handle other rewrites,
7669 // e.g. --(++a) => a += 1 -= 1
7670 while (left.isAssignExp() || left.isBinAssignExp())
7671 left = (cast(BinExp) left).e1;
7673 // Only use the assignee if it's a variable and skip
7674 // other lvalues (e.g. ref's returned by functions)
7675 if (left.isVarExp())
7676 return left;
7678 // Sanity check that `op` can be converted to boolean
7679 // But don't raise errors for assignments enclosed in another expression
7680 if (op is exp.e1)
7681 op.toBoolean(sc);
7684 // Tuples with side-effects already receive a temporary during semantic
7685 if (op.type.isTypeTuple())
7687 auto te = op.isTupleExp();
7688 assert(te);
7690 // Create a new tuple without the associated temporary
7691 auto res = new TupleExp(op.loc, te.exps);
7692 return res.expressionSemantic(sc);
7695 const stc = op.isLvalue() ? STC.ref_ : 0;
7696 auto tmp = copyToTemp(stc, "__assertOp", op);
7697 tmp.dsymbolSemantic(sc);
7699 auto decl = new DeclarationExp(op.loc, tmp);
7700 temporariesPrefix = Expression.combine(temporariesPrefix, decl);
7702 op = new VarExp(op.loc, tmp);
7703 op = op.expressionSemantic(sc);
7705 return op;
7708 // if the assert condition is a mixin expression, try to compile it
7709 if (auto ce = exp.e1.isMixinExp())
7711 if (auto e1 = compileIt(ce))
7712 exp.e1 = e1;
7715 Expressions* es;
7716 Objects* tiargs;
7717 Loc loc = exp.e1.loc;
7719 const op = exp.e1.op;
7720 bool isEqualsCallExpression;
7721 if (const callExp = exp.e1.isCallExp())
7723 // https://issues.dlang.org/show_bug.cgi?id=20331
7724 // callExp.f may be null if the assert contains a call to
7725 // a function pointer or literal
7726 if (const callExpFunc = callExp.f)
7728 const callExpIdent = callExpFunc.ident;
7729 isEqualsCallExpression = callExpIdent == Id.__equals ||
7730 callExpIdent == Id.eq;
7733 if (op == EXP.equal || op == EXP.notEqual ||
7734 op == EXP.lessThan || op == EXP.greaterThan ||
7735 op == EXP.lessOrEqual || op == EXP.greaterOrEqual ||
7736 op == EXP.identity || op == EXP.notIdentity ||
7737 op == EXP.in_ ||
7738 isEqualsCallExpression)
7740 es = new Expressions(3);
7741 tiargs = new Objects(1);
7743 if (isEqualsCallExpression)
7745 auto callExp = cast(CallExp) exp.e1;
7746 auto args = callExp.arguments;
7748 // structs with opEquals get rewritten to a DotVarExp:
7749 // a.opEquals(b)
7750 // https://issues.dlang.org/show_bug.cgi?id=20100
7751 if (args.length == 1)
7753 auto dv = callExp.e1.isDotVarExp();
7754 assert(dv);
7756 // runtime args
7757 (*es)[1] = maybePromoteToTmp(dv.e1);
7758 (*es)[2] = maybePromoteToTmp((*args)[0]);
7760 else
7762 // runtime args
7763 (*es)[1] = maybePromoteToTmp((*args)[0]);
7764 (*es)[2] = maybePromoteToTmp((*args)[1]);
7767 else
7769 auto binExp = cast(EqualExp) exp.e1;
7771 // runtime args
7772 (*es)[1] = maybePromoteToTmp(binExp.e1);
7773 (*es)[2] = maybePromoteToTmp(binExp.e2);
7776 // template args
7777 Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : EXPtoString(exp.e1.op));
7778 comp = comp.expressionSemantic(sc);
7779 (*es)[0] = comp;
7780 (*tiargs)[0] = (*es)[1].type;
7783 // Format exp.e1 before any additional boolean conversion
7784 // Ignore &&/|| because "assert(...) failed" is more informative than "false != true"
7785 else if (op != EXP.andAnd && op != EXP.orOr)
7787 es = new Expressions(2);
7788 tiargs = new Objects(1);
7790 if (auto ne = exp.e1.isNotExp())
7792 // Fetch the (potential non-bool) expression and fold
7793 // (n) negations into (n % 2) negations, e.g. !!a => a
7794 for (bool neg = true; ; neg = !neg)
7796 if (auto ne2 = ne.e1.isNotExp())
7797 ne = ne2;
7798 else
7800 (*es)[0] = new StringExp(loc, neg ? "!" : "");
7801 (*es)[1] = maybePromoteToTmp(ne.e1);
7802 break;
7806 else
7807 { // Simply format exp.e1
7808 (*es)[0] = new StringExp(loc, "");
7809 (*es)[1] = maybePromoteToTmp(exp.e1);
7812 (*tiargs)[0] = (*es)[1].type;
7814 // Passing __ctfe to auto ref infers ref and aborts compilation:
7815 // "cannot modify compiler-generated variable __ctfe"
7816 auto ve = (*es)[1].isVarExp();
7817 if (ve && ve.var.ident == Id.ctfe)
7819 exp.msg = new StringExp(loc, "assert(__ctfe) failed!");
7820 goto LSkip;
7823 else
7825 OutBuffer buf;
7826 buf.printf("`%s` failed", exp.toChars());
7827 exp.msg = new StringExp(Loc.initial, buf.extractSlice());
7828 goto LSkip;
7831 Expression __assertFail = new IdentifierExp(exp.loc, Id.empty);
7832 auto assertFail = new DotIdExp(loc, __assertFail, Id.object);
7834 auto dt = new DotTemplateInstanceExp(loc, assertFail, Id._d_assert_fail, tiargs);
7835 auto ec = CallExp.create(loc, dt, es);
7836 exp.msg = ec;
7839 LSkip:
7840 if (Expression ex = unaSemantic(exp, sc))
7842 result = ex;
7843 return;
7846 exp.e1 = resolveProperties(sc, exp.e1);
7847 // BUG: see if we can do compile time elimination of the Assert
7848 exp.e1 = exp.e1.optimize(WANTvalue);
7849 exp.e1 = exp.e1.toBoolean(sc);
7851 if (exp.e1.op == EXP.error)
7853 result = exp.e1;
7854 return;
7857 if (exp.msg)
7859 exp.msg = expressionSemantic(exp.msg, sc);
7860 exp.msg = resolveProperties(sc, exp.msg);
7861 exp.msg = exp.msg.implicitCastTo(sc, Type.tchar.constOf().arrayOf());
7862 exp.msg = exp.msg.optimize(WANTvalue);
7863 checkParamArgumentEscape(sc, null, null, null, STC.undefined_, exp.msg, true, false);
7866 if (exp.msg && exp.msg.op == EXP.error)
7868 result = exp.msg;
7869 return;
7872 auto f1 = checkNonAssignmentArrayOp(exp.e1);
7873 auto f2 = exp.msg && checkNonAssignmentArrayOp(exp.msg);
7874 if (f1 || f2)
7875 return setError();
7877 if (exp.e1.toBool().hasValue(false))
7879 /* This is an `assert(0)` which means halt program execution
7881 FuncDeclaration fd = sc.parent.isFuncDeclaration();
7882 if (fd)
7883 fd.hasReturnExp |= 4;
7884 sc.ctorflow.orCSX(CSX.halt);
7886 if (global.params.useAssert == CHECKENABLE.off)
7888 Expression e = new HaltExp(exp.loc);
7889 e = e.expressionSemantic(sc);
7890 result = e;
7891 return;
7894 // Only override the type when it isn't already some flavour of noreturn,
7895 // e.g. when this assert was generated by defaultInitLiteral
7896 if (!exp.type || !exp.type.isTypeNoreturn())
7897 exp.type = Type.tnoreturn;
7899 else
7900 exp.type = Type.tvoid;
7902 result = !temporariesPrefix
7903 ? exp
7904 : Expression.combine(temporariesPrefix, exp).expressionSemantic(sc);
7907 override void visit(ThrowExp te)
7909 import dmd.statementsem;
7911 if (throwSemantic(te.loc, te.e1, sc))
7912 result = te;
7913 else
7914 setError();
7917 override void visit(DotIdExp exp)
7919 static if (LOGSEMANTIC)
7921 printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars());
7922 //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op));
7925 if (sc.flags & SCOPE.Cfile)
7927 /* See if need to rewrite the AST because of cast/call ambiguity
7929 if (auto e = castCallAmbiguity(exp, sc))
7931 result = expressionSemantic(e, sc);
7932 return;
7935 if (exp.arrow) // ImportC only
7936 exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
7938 if (exp.ident == Id.__xalignof && exp.e1.isTypeExp())
7940 // C11 6.5.3 says _Alignof only applies to types
7941 Expression e;
7942 Type t;
7943 Dsymbol s;
7944 dmd.typesem.resolve(exp.e1.type, exp.e1.loc, sc, e, t, s, true);
7945 if (e)
7947 error(exp.e1.loc, "argument to `_Alignof` must be a type");
7948 return setError();
7950 else if (t)
7952 // Note similarity to getProperty() implementation of __xalignof
7953 const explicitAlignment = t.alignment();
7954 const naturalAlignment = t.alignsize();
7955 const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get());
7956 result = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
7958 else if (s)
7960 error(exp.e1.loc, "argument to `_Alignof` must be a type");
7961 return setError();
7963 else
7964 assert(0);
7965 return;
7968 if (exp.ident != Id.__sizeof)
7970 result = fieldLookup(exp.e1, sc, exp.ident, exp.arrow);
7971 return;
7975 Expression e = exp.dotIdSemanticProp(sc, 1);
7977 if (e && isDotOpDispatch(e))
7979 auto ode = e;
7980 uint errors = global.startGagging();
7981 e = resolvePropertiesX(sc, e);
7982 // Any error or if 'e' is not resolved, go to UFCS
7983 if (global.endGagging(errors) || e is ode)
7984 e = null; /* fall down to UFCS */
7985 else
7987 result = e;
7988 return;
7991 if (!e) // if failed to find the property
7993 /* If ident is not a valid property, rewrite:
7994 * e1.ident
7995 * as:
7996 * .ident(e1)
7998 e = resolveUFCSProperties(sc, exp);
8000 result = e;
8003 override void visit(DotTemplateExp e)
8005 if (e.type)
8007 result = e;
8008 return;
8010 if (Expression ex = unaSemantic(e, sc))
8012 result = ex;
8013 return;
8015 // 'void' like TemplateExp
8016 e.type = Type.tvoid;
8017 result = e;
8020 override void visit(DotVarExp exp)
8022 static if (LOGSEMANTIC)
8024 printf("DotVarExp::semantic('%s')\n", exp.toChars());
8026 if (exp.type)
8028 result = exp;
8029 return;
8032 exp.var = exp.var.toAlias().isDeclaration();
8034 exp.e1 = exp.e1.expressionSemantic(sc);
8036 if (auto tup = exp.var.isTupleDeclaration())
8038 /* Replace:
8039 * e1.tuple(a, b, c)
8040 * with:
8041 * tuple(e1.a, e1.b, e1.c)
8043 Expression e0;
8044 Expression ev = sc.func ? extractSideEffect(sc, "__tup", e0, exp.e1) : exp.e1;
8046 auto exps = new Expressions();
8047 exps.reserve(tup.objects.length);
8048 for (size_t i = 0; i < tup.objects.length; i++)
8050 RootObject o = (*tup.objects)[i];
8051 Expression e;
8052 Declaration var;
8053 switch (o.dyncast()) with (DYNCAST)
8055 case expression:
8056 e = cast(Expression)o;
8057 if (auto se = e.isDsymbolExp())
8058 var = se.s.isDeclaration();
8059 else if (auto ve = e.isVarExp())
8060 if (!ve.var.isFuncDeclaration())
8061 // Exempt functions for backwards compatibility reasons.
8062 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
8063 var = ve.var;
8064 break;
8065 case dsymbol:
8066 Dsymbol s = cast(Dsymbol) o;
8067 Declaration d = s.isDeclaration();
8068 if (!d || d.isFuncDeclaration())
8069 // Exempt functions for backwards compatibility reasons.
8070 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
8071 e = new DsymbolExp(exp.loc, s);
8072 else
8073 var = d;
8074 break;
8075 case type:
8076 e = new TypeExp(exp.loc, cast(Type)o);
8077 break;
8078 default:
8079 error(exp.loc, "`%s` is not an expression", o.toChars());
8080 return setError();
8082 if (var)
8083 e = new DotVarExp(exp.loc, ev, var);
8084 exps.push(e);
8087 Expression e = new TupleExp(exp.loc, e0, exps);
8088 e = e.expressionSemantic(sc);
8089 result = e;
8090 return;
8092 else if (auto ad = exp.var.isAliasDeclaration())
8094 if (auto t = ad.getType())
8096 result = new TypeExp(exp.loc, t).expressionSemantic(sc);
8097 return;
8101 exp.e1 = exp.e1.addDtorHook(sc);
8103 Type t1 = exp.e1.type;
8105 if (FuncDeclaration fd = exp.var.isFuncDeclaration())
8107 // for functions, do checks after overload resolution
8108 if (!fd.functionSemantic())
8109 return setError();
8111 /* https://issues.dlang.org/show_bug.cgi?id=13843
8112 * If fd obviously has no overloads, we should
8113 * normalize AST, and it will give a chance to wrap fd with FuncExp.
8115 if ((fd.isNested() && !fd.isThis()) || fd.isFuncLiteralDeclaration())
8117 // (e1, fd)
8118 auto e = symbolToExp(fd, exp.loc, sc, false);
8119 result = Expression.combine(exp.e1, e);
8120 return;
8123 exp.type = fd.type;
8124 assert(exp.type);
8126 else if (OverDeclaration od = exp.var.isOverDeclaration())
8128 exp.type = Type.tvoid; // ambiguous type?
8130 else
8132 exp.type = exp.var.type;
8133 if (!exp.type && global.errors) // var is goofed up, just return error.
8134 return setError();
8135 assert(exp.type);
8137 if (t1.ty == Tpointer)
8138 t1 = t1.nextOf();
8140 exp.type = exp.type.addMod(t1.mod);
8142 // https://issues.dlang.org/show_bug.cgi?id=23109
8143 // Run semantic on the DotVarExp type
8144 if (auto handle = exp.type.isClassHandle())
8146 if (handle.semanticRun < PASS.semanticdone && !handle.isBaseInfoComplete())
8147 handle.dsymbolSemantic(null);
8150 Dsymbol vparent = exp.var.toParent();
8151 AggregateDeclaration ad = vparent ? vparent.isAggregateDeclaration() : null;
8152 if (Expression e1x = getRightThis(exp.loc, sc, ad, exp.e1, exp.var, 1))
8153 exp.e1 = e1x;
8154 else
8156 /* Later checkRightThis will report correct error for invalid field variable access.
8158 Expression e = new VarExp(exp.loc, exp.var);
8159 e = e.expressionSemantic(sc);
8160 result = e;
8161 return;
8163 checkAccess(exp.loc, sc, exp.e1, exp.var);
8165 VarDeclaration v = exp.var.isVarDeclaration();
8166 if (v && (v.isDataseg() || (v.storage_class & STC.manifest)))
8168 Expression e = expandVar(WANTvalue, v);
8169 if (e)
8171 result = e;
8172 return;
8176 if (v && (v.isDataseg() || // fix https://issues.dlang.org/show_bug.cgi?id=8238
8177 (!v.needThis() && v.semanticRun > PASS.initial))) // fix https://issues.dlang.org/show_bug.cgi?id=17258
8179 // (e1, v)
8180 checkAccess(exp.loc, sc, exp.e1, v);
8181 Expression e = new VarExp(exp.loc, v);
8182 e = new CommaExp(exp.loc, exp.e1, e);
8183 e = e.expressionSemantic(sc);
8184 result = e;
8185 return;
8188 //printf("-DotVarExp::semantic('%s')\n", toChars());
8189 result = exp;
8192 override void visit(DotTemplateInstanceExp exp)
8194 static if (LOGSEMANTIC)
8196 printf("DotTemplateInstanceExp::semantic('%s')\n", exp.toChars());
8198 if (exp.type)
8200 result = exp;
8201 return;
8203 // Indicate we need to resolve by UFCS.
8204 Expression e = exp.dotTemplateSemanticProp(sc, DotExpFlag.gag);
8205 if (!e)
8206 e = resolveUFCSProperties(sc, exp);
8207 if (e is exp)
8208 e.type = Type.tvoid; // Unresolved type, because it needs inference
8209 result = e;
8212 override void visit(DelegateExp e)
8214 static if (LOGSEMANTIC)
8216 printf("DelegateExp::semantic('%s')\n", e.toChars());
8218 if (e.type)
8220 result = e;
8221 return;
8224 e.e1 = e.e1.expressionSemantic(sc);
8226 e.type = new TypeDelegate(e.func.type.isTypeFunction());
8227 e.type = e.type.typeSemantic(e.loc, sc);
8229 FuncDeclaration f = e.func.toAliasFunc();
8230 AggregateDeclaration ad = f.isMemberLocal();
8231 if (f.needThis())
8232 e.e1 = getRightThis(e.loc, sc, ad, e.e1, f);
8234 if (f.type.ty == Tfunction)
8236 TypeFunction tf = cast(TypeFunction)f.type;
8237 if (!MODmethodConv(e.e1.type.mod, f.type.mod))
8239 OutBuffer thisBuf, funcBuf;
8240 MODMatchToBuffer(&thisBuf, e.e1.type.mod, tf.mod);
8241 MODMatchToBuffer(&funcBuf, tf.mod, e.e1.type.mod);
8242 error(e.loc, "%smethod `%s` is not callable using a %s`%s`",
8243 funcBuf.peekChars(), f.toPrettyChars(), thisBuf.peekChars(), e.e1.toChars());
8244 return setError();
8247 if (ad && ad.isClassDeclaration() && ad.type != e.e1.type)
8249 // A downcast is required for interfaces
8250 // https://issues.dlang.org/show_bug.cgi?id=3706
8251 e.e1 = new CastExp(e.loc, e.e1, ad.type);
8252 e.e1 = e.e1.expressionSemantic(sc);
8254 result = e;
8255 // declare dual-context container
8256 if (f.hasDualContext() && !sc.intypeof && sc.func)
8258 // check access to second `this`
8259 if (AggregateDeclaration ad2 = f.isMember2())
8261 Expression te = new ThisExp(e.loc).expressionSemantic(sc);
8262 if (te.op != EXP.error)
8263 te = getRightThis(e.loc, sc, ad2, te, f);
8264 if (te.op == EXP.error)
8266 error(e.loc, "need `this` of type `%s` to make delegate from function `%s`", ad2.toChars(), f.toChars());
8267 return setError();
8270 VarDeclaration vthis2 = makeThis2Argument(e.loc, sc, f);
8271 e.vthis2 = vthis2;
8272 Expression de = new DeclarationExp(e.loc, vthis2);
8273 result = Expression.combine(de, result);
8274 result = result.expressionSemantic(sc);
8278 override void visit(DotTypeExp exp)
8280 static if (LOGSEMANTIC)
8282 printf("DotTypeExp::semantic('%s')\n", exp.toChars());
8284 if (exp.type)
8286 result = exp;
8287 return;
8290 if (auto e = unaSemantic(exp, sc))
8292 result = e;
8293 return;
8296 exp.type = exp.sym.getType().addMod(exp.e1.type.mod);
8297 result = exp;
8300 override void visit(AddrExp exp)
8302 static if (LOGSEMANTIC)
8304 printf("AddrExp::semantic('%s')\n", exp.toChars());
8306 if (exp.type)
8308 result = exp;
8309 return;
8312 if (Expression ex = unaSemantic(exp, sc))
8314 result = ex;
8315 return;
8318 if (sc.flags & SCOPE.Cfile)
8320 /* Special handling for &"string"/&(T[]){0, 1}
8321 * since C regards string/array literals as lvalues
8323 auto e = exp.e1;
8324 if(e.isStringExp() || e.isArrayLiteralExp())
8326 e.type = typeSemantic(e.type, Loc.initial, sc);
8327 // if type is already a pointer exp is an illegal expression of the form `&(&"")`
8328 if (!e.type.isTypePointer())
8330 e.type = e.type.pointerTo();
8331 result = e;
8332 return;
8334 else
8336 // `toLvalue` call further below is upon exp.e1, omitting & from the error message
8337 exp.toLvalue(sc, "take address of");
8338 return setError();
8343 int wasCond = exp.e1.op == EXP.question;
8345 if (exp.e1.op == EXP.dotTemplateInstance)
8347 DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)exp.e1;
8348 TemplateInstance ti = dti.ti;
8350 //assert(ti.needsTypeInference(sc));
8351 ti.dsymbolSemantic(sc);
8352 if (!ti.inst || ti.errors) // if template failed to expand
8353 return setError();
8355 Dsymbol s = ti.toAlias();
8356 FuncDeclaration f = s.isFuncDeclaration();
8357 if (f)
8359 exp.e1 = new DotVarExp(exp.e1.loc, dti.e1, f);
8360 exp.e1 = exp.e1.expressionSemantic(sc);
8364 else if (exp.e1.op == EXP.scope_)
8366 TemplateInstance ti = (cast(ScopeExp)exp.e1).sds.isTemplateInstance();
8367 if (ti)
8369 //assert(ti.needsTypeInference(sc));
8370 ti.dsymbolSemantic(sc);
8371 if (!ti.inst || ti.errors) // if template failed to expand
8372 return setError();
8374 Dsymbol s = ti.toAlias();
8375 FuncDeclaration f = s.isFuncDeclaration();
8376 if (f)
8378 exp.e1 = new VarExp(exp.e1.loc, f);
8379 exp.e1 = exp.e1.expressionSemantic(sc);
8383 /* https://issues.dlang.org/show_bug.cgi?id=809
8385 * If the address of a lazy variable is taken,
8386 * the expression is rewritten so that the type
8387 * of it is the delegate type. This means that
8388 * the symbol is not going to represent a call
8389 * to the delegate anymore, but rather, the
8390 * actual symbol.
8392 if (auto ve = exp.e1.isVarExp())
8394 if (ve.var.storage_class & STC.lazy_)
8396 exp.e1 = exp.e1.expressionSemantic(sc);
8397 exp.e1 = resolveProperties(sc, exp.e1);
8398 if (auto callExp = exp.e1.isCallExp())
8400 if (callExp.e1.type.toBasetype().ty == Tdelegate)
8402 /* https://issues.dlang.org/show_bug.cgi?id=20551
8404 * Cannot take address of lazy parameter in @safe code
8405 * because it might end up being a pointer to undefined
8406 * memory.
8408 if (1)
8410 if (sc.setUnsafe(false, exp.loc,
8411 "cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve, sc.func))
8413 setError();
8414 return;
8417 VarExp ve2 = callExp.e1.isVarExp();
8418 ve2.delegateWasExtracted = true;
8419 ve2.var.storage_class |= STC.scope_;
8420 result = ve2;
8421 return;
8427 exp.e1 = exp.e1.toLvalue(sc, "take address of");
8428 if (exp.e1.op == EXP.error)
8430 result = exp.e1;
8431 return;
8433 if (checkNonAssignmentArrayOp(exp.e1))
8434 return setError();
8436 if (!exp.e1.type)
8438 error(exp.loc, "cannot take address of `%s`", exp.e1.toChars());
8439 return setError();
8441 if (!checkAddressable(exp, sc))
8442 return setError();
8444 bool hasOverloads;
8445 if (auto f = isFuncAddress(exp, &hasOverloads))
8447 if (!hasOverloads && f.checkForwardRef(exp.loc))
8448 return setError();
8450 else if (!exp.e1.type.deco)
8452 // try to resolve the type
8453 exp.e1.type = exp.e1.type.typeSemantic(exp.e1.loc, sc);
8454 if (!exp.e1.type.deco) // still couldn't resolve it
8456 if (auto ve = exp.e1.isVarExp())
8458 Declaration d = ve.var;
8459 error(exp.loc, "forward reference to %s `%s`", d.kind(), d.toChars());
8461 else
8462 error(exp.loc, "forward reference to type `%s` of expression `%s`", exp.e1.type.toChars(), exp.e1.toChars());
8463 return setError();
8467 exp.type = exp.e1.type.pointerTo();
8469 // See if this should really be a delegate
8470 if (exp.e1.op == EXP.dotVariable)
8472 DotVarExp dve = cast(DotVarExp)exp.e1;
8473 FuncDeclaration f = dve.var.isFuncDeclaration();
8474 if (f)
8476 f = f.toAliasFunc(); // FIXME, should see overloads
8477 // https://issues.dlang.org/show_bug.cgi?id=1983
8478 if (!dve.hasOverloads)
8479 f.tookAddressOf++;
8481 Expression e;
8482 if (f.needThis())
8483 e = new DelegateExp(exp.loc, dve.e1, f, dve.hasOverloads);
8484 else // It is a function pointer. Convert &v.f() --> (v, &V.f())
8485 e = new CommaExp(exp.loc, dve.e1, new AddrExp(exp.loc, new VarExp(exp.loc, f, dve.hasOverloads)));
8486 e = e.expressionSemantic(sc);
8487 result = e;
8488 return;
8491 // Look for misaligned pointer in @safe mode
8492 if (checkUnsafeAccess(sc, dve, !exp.type.isMutable(), true))
8493 return setError();
8495 else if (exp.e1.op == EXP.variable)
8497 VarExp ve = cast(VarExp)exp.e1;
8498 VarDeclaration v = ve.var.isVarDeclaration();
8499 if (v)
8501 if (!checkAddressVar(sc, exp.e1, v))
8502 return setError();
8504 v.checkPurity(ve.loc, sc);
8506 FuncDeclaration f = ve.var.isFuncDeclaration();
8507 if (f)
8509 /* Because nested functions cannot be overloaded,
8510 * mark here that we took its address because castTo()
8511 * may not be called with an exact match.
8513 * https://issues.dlang.org/show_bug.cgi?id=19285 :
8514 * We also need to make sure we aren't inside a typeof. Ideally the compiler
8515 * would do typeof(...) semantic analysis speculatively then collect information
8516 * about what it used rather than relying on what are effectively semantically-global
8517 * variables but it doesn't.
8519 if (!sc.isFromSpeculativeSemanticContext() && (!ve.hasOverloads || (f.isNested() && !f.needThis())))
8521 // TODO: Refactor to use a proper interface that can keep track of causes.
8522 f.tookAddressOf++;
8525 if (f.isNested() && !f.needThis())
8527 if (f.isFuncLiteralDeclaration())
8529 if (!f.FuncDeclaration.isNested())
8531 /* Supply a 'null' for a this pointer if no this is available
8533 Expression e = new DelegateExp(exp.loc, new NullExp(exp.loc, Type.tnull), f, ve.hasOverloads);
8534 e = e.expressionSemantic(sc);
8535 result = e;
8536 return;
8539 Expression e = new DelegateExp(exp.loc, exp.e1, f, ve.hasOverloads);
8540 e = e.expressionSemantic(sc);
8541 result = e;
8542 return;
8544 if (f.needThis())
8546 auto memberFunc = hasThis(sc);
8547 if (memberFunc && haveSameThis(memberFunc, f))
8549 /* Should probably supply 'this' after overload resolution,
8550 * not before.
8552 Expression ethis = new ThisExp(exp.loc);
8553 Expression e = new DelegateExp(exp.loc, ethis, f, ve.hasOverloads);
8554 e = e.expressionSemantic(sc);
8555 result = e;
8556 return;
8558 if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_))
8560 sc.setUnsafe(false, exp.loc,
8561 "`this` reference necessary to take address of member `%s` in `@safe` function `%s`",
8562 f, sc.func);
8567 else if (exp.e1.op == EXP.index)
8569 /* For:
8570 * int[3] a;
8571 * &a[i]
8572 * check 'a' the same as for a regular variable
8574 if (VarDeclaration v = expToVariable(exp.e1))
8576 v.checkPurity(exp.e1.loc, sc);
8579 else if (wasCond)
8581 /* a ? b : c was transformed to *(a ? &b : &c), but we still
8582 * need to do safety checks
8584 assert(exp.e1.op == EXP.star);
8585 PtrExp pe = cast(PtrExp)exp.e1;
8586 assert(pe.e1.op == EXP.question);
8587 CondExp ce = cast(CondExp)pe.e1;
8588 assert(ce.e1.op == EXP.address);
8589 assert(ce.e2.op == EXP.address);
8591 // Re-run semantic on the address expressions only
8592 ce.e1.type = null;
8593 ce.e1 = ce.e1.expressionSemantic(sc);
8594 ce.e2.type = null;
8595 ce.e2 = ce.e2.expressionSemantic(sc);
8597 result = exp.optimize(WANTvalue);
8600 override void visit(PtrExp exp)
8602 static if (LOGSEMANTIC)
8604 printf("PtrExp::semantic('%s')\n", exp.toChars());
8606 if (exp.type)
8608 result = exp;
8609 return;
8612 Expression e = exp.op_overload(sc);
8613 if (e)
8615 result = e;
8616 return;
8619 exp.e1 = exp.e1.arrayFuncConv(sc);
8621 Type tb = exp.e1.type.toBasetype();
8622 switch (tb.ty)
8624 case Tpointer:
8625 exp.type = (cast(TypePointer)tb).next;
8626 break;
8628 case Tsarray:
8629 case Tarray:
8630 if (isNonAssignmentArrayOp(exp.e1))
8631 goto default;
8632 error(exp.loc, "using `*` on an array is no longer supported; use `*(%s).ptr` instead", exp.e1.toChars());
8633 exp.type = (cast(TypeArray)tb).next;
8634 exp.e1 = exp.e1.castTo(sc, exp.type.pointerTo());
8635 break;
8637 case Terror:
8638 return setError();
8640 case Tnull:
8641 exp.type = Type.tnoreturn; // typeof(*null) is bottom type
8642 break;
8644 default:
8645 error(exp.loc, "can only `*` a pointer, not a `%s`", exp.e1.type.toChars());
8646 goto case Terror;
8649 if (sc.flags & SCOPE.Cfile && exp.type && exp.type.toBasetype().ty == Tvoid)
8651 // https://issues.dlang.org/show_bug.cgi?id=23752
8652 // `&*((void*)(0))` is allowed in C
8653 result = exp;
8654 return;
8657 if (exp.checkValue())
8658 return setError();
8660 result = exp;
8663 override void visit(NegExp exp)
8665 static if (LOGSEMANTIC)
8667 printf("NegExp::semantic('%s')\n", exp.toChars());
8669 if (exp.type)
8671 result = exp;
8672 return;
8675 Expression e = exp.op_overload(sc);
8676 if (e)
8678 result = e;
8679 return;
8682 fix16997(sc, exp);
8683 exp.type = exp.e1.type;
8684 Type tb = exp.type.toBasetype();
8685 if (tb.ty == Tarray || tb.ty == Tsarray)
8687 if (!isArrayOpValid(exp.e1))
8689 result = arrayOpInvalidError(exp);
8690 return;
8692 result = exp;
8693 return;
8695 if (!target.isVectorOpSupported(tb, exp.op))
8697 result = exp.incompatibleTypes();
8698 return;
8700 if (exp.e1.checkNoBool())
8701 return setError();
8702 if (exp.e1.checkArithmetic(exp.op) ||
8703 exp.e1.checkSharedAccess(sc))
8704 return setError();
8706 result = exp;
8709 override void visit(UAddExp exp)
8711 static if (LOGSEMANTIC)
8713 printf("UAddExp::semantic('%s')\n", exp.toChars());
8715 assert(!exp.type);
8717 Expression e = exp.op_overload(sc);
8718 if (e)
8720 result = e;
8721 return;
8724 fix16997(sc, exp);
8725 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op))
8727 result = exp.incompatibleTypes();
8728 return;
8730 if (exp.e1.checkNoBool())
8731 return setError();
8732 if (exp.e1.checkArithmetic(exp.op))
8733 return setError();
8734 if (exp.e1.checkSharedAccess(sc))
8735 return setError();
8737 result = exp.e1;
8740 override void visit(ComExp exp)
8742 if (exp.type)
8744 result = exp;
8745 return;
8748 Expression e = exp.op_overload(sc);
8749 if (e)
8751 result = e;
8752 return;
8755 fix16997(sc, exp);
8756 exp.type = exp.e1.type;
8757 Type tb = exp.type.toBasetype();
8758 if (tb.ty == Tarray || tb.ty == Tsarray)
8760 if (!isArrayOpValid(exp.e1))
8762 result = arrayOpInvalidError(exp);
8763 return;
8765 result = exp;
8766 return;
8768 if (!target.isVectorOpSupported(tb, exp.op))
8770 result = exp.incompatibleTypes();
8771 return;
8773 if (exp.e1.checkNoBool())
8774 return setError();
8775 if (exp.e1.checkIntegral() ||
8776 exp.e1.checkSharedAccess(sc))
8777 return setError();
8779 result = exp;
8782 override void visit(NotExp e)
8784 if (e.type)
8786 result = e;
8787 return;
8790 e.setNoderefOperand();
8792 // Note there is no operator overload
8793 if (Expression ex = unaSemantic(e, sc))
8795 result = ex;
8796 return;
8799 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
8800 if (e.e1.op == EXP.type)
8801 e.e1 = resolveAliasThis(sc, e.e1);
8803 e.e1 = resolveProperties(sc, e.e1);
8804 e.e1 = e.e1.toBoolean(sc);
8805 if (e.e1.type == Type.terror)
8807 result = e.e1;
8808 return;
8811 if (!target.isVectorOpSupported(e.e1.type.toBasetype(), e.op))
8813 result = e.incompatibleTypes();
8815 // https://issues.dlang.org/show_bug.cgi?id=13910
8816 // Today NotExp can take an array as its operand.
8817 if (checkNonAssignmentArrayOp(e.e1))
8818 return setError();
8820 e.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
8821 result = e;
8824 override void visit(DeleteExp exp)
8826 // @@@DEPRECATED_2.109@@@
8827 // 1. Deprecated since 2.079
8828 // 2. Error since 2.099
8829 // 3. Removal of keyword, "delete" can be used for other identities
8830 if (!exp.isRAII)
8832 error(exp.loc, "the `delete` keyword is obsolete");
8833 errorSupplemental(exp.loc, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead");
8834 return setError();
8837 Expression e = exp;
8839 if (Expression ex = unaSemantic(exp, sc))
8841 result = ex;
8842 return;
8844 exp.e1 = resolveProperties(sc, exp.e1);
8845 exp.e1 = exp.e1.modifiableLvalue(sc);
8846 if (exp.e1.op == EXP.error)
8848 result = exp.e1;
8849 return;
8851 exp.type = Type.tvoid;
8853 Type tb = exp.e1.type.toBasetype();
8855 /* Now that `delete` in user code is an error, we only get here when
8856 * `isRAII` has been set to true for the deletion of a `scope class`. */
8857 if (tb.ty != Tclass)
8859 error(exp.loc, "cannot delete type `%s`", exp.e1.type.toChars());
8860 return setError();
8863 ClassDeclaration cd = (cast(TypeClass)tb).sym;
8864 if (cd.isCOMinterface())
8866 /* Because COM classes are deleted by IUnknown.Release()
8868 error(exp.loc, "cannot `delete` instance of COM interface `%s`", cd.toChars());
8869 return setError();
8872 bool err = false;
8873 if (cd.dtor)
8875 err |= !cd.dtor.functionSemantic();
8876 err |= cd.dtor.checkPurity(exp.loc, sc);
8877 err |= cd.dtor.checkSafety(exp.loc, sc);
8878 err |= cd.dtor.checkNogc(exp.loc, sc);
8880 if (err)
8881 return setError();
8883 result = e;
8886 override void visit(CastExp exp)
8888 static if (LOGSEMANTIC)
8890 printf("CastExp::semantic('%s')\n", exp.toChars());
8892 //static int x; assert(++x < 10);
8893 if (exp.type)
8895 result = exp;
8896 return;
8899 if ((sc && sc.flags & SCOPE.Cfile) &&
8900 exp.to && (exp.to.ty == Tident || exp.to.ty == Tsarray) &&
8901 (exp.e1.op == EXP.address || exp.e1.op == EXP.star ||
8902 exp.e1.op == EXP.uadd || exp.e1.op == EXP.negate))
8904 /* Ambiguous cases arise from CParser if type-name is just an identifier.
8905 * ( identifier ) cast-expression
8906 * ( identifier [expression]) cast-expression
8907 * If we determine that `identifier` is a variable, and cast-expression
8908 * is one of the unary operators (& * + -), then rewrite this cast
8909 * as a binary expression.
8911 Loc loc = exp.loc;
8912 Type t;
8913 Expression e;
8914 Dsymbol s;
8915 exp.to.resolve(loc, sc, e, t, s);
8916 if (e !is null)
8918 if (auto ex = exp.e1.isAddrExp()) // (ident) &exp -> (ident & exp)
8919 result = new AndExp(loc, e, ex.e1);
8920 else if (auto ex = exp.e1.isPtrExp()) // (ident) *exp -> (ident * exp)
8921 result = new MulExp(loc, e, ex.e1);
8922 else if (auto ex = exp.e1.isUAddExp()) // (ident) +exp -> (ident + exp)
8923 result = new AddExp(loc, e, ex.e1);
8924 else if (auto ex = exp.e1.isNegExp()) // (ident) -exp -> (ident - exp)
8925 result = new MinExp(loc, e, ex.e1);
8927 assert(result);
8928 result = result.expressionSemantic(sc);
8929 return;
8933 if (exp.to)
8935 exp.to = exp.to.typeSemantic(exp.loc, sc);
8936 if (exp.to == Type.terror)
8937 return setError();
8939 if (!exp.to.hasPointers())
8940 exp.setNoderefOperand();
8942 // When e1 is a template lambda, this cast may instantiate it with
8943 // the type 'to'.
8944 exp.e1 = inferType(exp.e1, exp.to);
8947 if (auto e = unaSemantic(exp, sc))
8949 result = e;
8950 return;
8953 if (exp.to && !exp.to.isTypeSArray() && !exp.to.isTypeFunction())
8954 exp.e1 = exp.e1.arrayFuncConv(sc);
8956 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
8957 if (exp.e1.op == EXP.type)
8958 exp.e1 = resolveAliasThis(sc, exp.e1);
8960 auto e1x = resolveProperties(sc, exp.e1);
8961 if (e1x.op == EXP.error)
8963 result = e1x;
8964 return;
8966 if (e1x.checkType())
8967 return setError();
8968 exp.e1 = e1x;
8970 if (!exp.e1.type)
8972 error(exp.loc, "cannot cast `%s`", exp.e1.toChars());
8973 return setError();
8976 // https://issues.dlang.org/show_bug.cgi?id=19954
8977 if (exp.e1.type.ty == Ttuple)
8979 if (exp.to)
8981 if (TypeTuple tt = exp.to.isTypeTuple())
8983 if (exp.e1.type.implicitConvTo(tt))
8985 result = exp.e1.castTo(sc, tt);
8986 return;
8990 TupleExp te = exp.e1.isTupleExp();
8991 if (te.exps.length == 1)
8992 exp.e1 = (*te.exps)[0];
8995 // only allow S(x) rewrite if cast specified S explicitly.
8996 // See https://issues.dlang.org/show_bug.cgi?id=18545
8997 const bool allowImplicitConstruction = exp.to !is null;
8999 if (!exp.to) // Handle cast(const) and cast(immutable), etc.
9001 exp.to = exp.e1.type.castMod(exp.mod);
9002 exp.to = exp.to.typeSemantic(exp.loc, sc);
9004 if (exp.to == Type.terror)
9005 return setError();
9008 if (exp.to.ty == Ttuple)
9010 error(exp.loc, "cannot cast `%s` of type `%s` to type sequence `%s`", exp.e1.toChars(), exp.e1.type.toChars(), exp.to.toChars());
9011 return setError();
9014 // cast(void) is used to mark e1 as unused, so it is safe
9015 if (exp.to.ty == Tvoid)
9017 exp.type = exp.to;
9018 result = exp;
9019 return;
9022 if (!exp.to.equals(exp.e1.type) && exp.mod == cast(ubyte)~0)
9024 if (Expression e = exp.op_overload(sc))
9026 result = e.implicitCastTo(sc, exp.to);
9027 return;
9031 Type t1b = exp.e1.type.toBasetype();
9032 Type tob = exp.to.toBasetype();
9034 if (allowImplicitConstruction && tob.ty == Tstruct && !tob.equals(t1b))
9036 /* Look to replace:
9037 * cast(S)t
9038 * with:
9039 * S(t)
9042 // Rewrite as to.call(e1)
9043 Expression e = new TypeExp(exp.loc, exp.to);
9044 e = new CallExp(exp.loc, e, exp.e1);
9045 e = e.trySemantic(sc);
9046 if (e)
9048 result = e;
9049 return;
9053 if (!t1b.equals(tob) && (t1b.ty == Tarray || t1b.ty == Tsarray))
9055 if (checkNonAssignmentArrayOp(exp.e1))
9056 return setError();
9059 Expression ex = exp.e1.castTo(sc, exp.to);
9060 if (ex.op == EXP.error)
9062 result = ex;
9063 return;
9066 // Check for unsafe casts
9067 if (!isSafeCast(ex, t1b, tob))
9069 if (sc.setUnsafe(false, exp.loc, "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to))
9071 return setError();
9075 // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built
9076 // to handle certain casts. Those casts which `object.__ArrayCast` does not support are filtered out.
9077 // See `e2ir.toElemCast` for other types of casts. If `object.__ArrayCast` is improved to support more
9078 // casts these conditions and potentially some logic in `e2ir.toElemCast` can be removed.
9079 if (tob.ty == Tarray)
9081 // https://issues.dlang.org/show_bug.cgi?id=19840
9082 if (auto ad = isAggregate(t1b))
9084 if (ad.aliasthis)
9086 Expression e = resolveAliasThis(sc, exp.e1);
9087 e = new CastExp(exp.loc, e, exp.to);
9088 result = e.expressionSemantic(sc);
9089 return;
9093 if(t1b.ty == Tarray && exp.e1.op != EXP.arrayLiteral && sc.needsCodegen())
9095 auto tFrom = t1b.nextOf();
9096 auto tTo = tob.nextOf();
9098 // https://issues.dlang.org/show_bug.cgi?id=20130
9099 if (exp.e1.op != EXP.string_ || !ex.isStringExp)
9101 const uint fromSize = cast(uint)tFrom.size();
9102 const uint toSize = cast(uint)tTo.size();
9103 if (fromSize == SIZE_INVALID || toSize == SIZE_INVALID)
9104 return setError();
9106 // If array element sizes do not match, we must adjust the dimensions
9107 if (fromSize != toSize)
9109 if (!verifyHookExist(exp.loc, *sc, Id.__ArrayCast, "casting array of structs"))
9110 return setError();
9112 // A runtime check is needed in case arrays don't line up. That check should
9113 // be done in the implementation of `object.__ArrayCast`
9114 if (toSize == 0 || (fromSize % toSize) != 0)
9116 // lower to `object.__ArrayCast!(TFrom, TTo)(from)`
9118 // fully qualify as `object.__ArrayCast`
9119 Expression id = new IdentifierExp(exp.loc, Id.empty);
9120 auto dotid = new DotIdExp(exp.loc, id, Id.object);
9122 auto tiargs = new Objects();
9123 tiargs.push(tFrom);
9124 tiargs.push(tTo);
9125 auto dt = new DotTemplateInstanceExp(exp.loc, dotid, Id.__ArrayCast, tiargs);
9127 auto arguments = new Expressions();
9128 arguments.push(exp.e1);
9129 Expression ce = new CallExp(exp.loc, dt, arguments);
9131 result = expressionSemantic(ce, sc);
9132 return;
9139 if (sc && sc.flags & SCOPE.Cfile)
9141 /* C11 6.5.4-5: A cast does not yield an lvalue.
9142 * So ensure that castTo does not strip away the cast so that this
9143 * can be enforced in other semantic visitor methods.
9145 if (!ex.isCastExp())
9147 ex = new CastExp(exp.loc, ex, exp.to);
9148 ex.type = exp.to;
9151 result = ex;
9154 override void visit(VectorExp exp)
9156 static if (LOGSEMANTIC)
9158 printf("VectorExp::semantic('%s')\n", exp.toChars());
9160 if (exp.type)
9162 result = exp;
9163 return;
9166 exp.e1 = exp.e1.expressionSemantic(sc);
9167 exp.type = exp.to.typeSemantic(exp.loc, sc);
9168 if (exp.e1.op == EXP.error || exp.type.ty == Terror)
9170 result = exp.e1;
9171 return;
9174 Type tb = exp.type.toBasetype();
9175 assert(tb.ty == Tvector);
9176 TypeVector tv = cast(TypeVector)tb;
9177 Type te = tv.elementType();
9178 exp.dim = cast(int)(tv.size(exp.loc) / te.size(exp.loc));
9180 bool checkElem(Expression elem)
9182 if (elem.isConst() == 1)
9183 return false;
9185 error(exp.loc, "constant expression expected, not `%s`", elem.toChars());
9186 return true;
9189 exp.e1 = exp.e1.optimize(WANTvalue);
9190 bool res;
9191 if (exp.e1.op == EXP.arrayLiteral)
9193 foreach (i; 0 .. exp.dim)
9195 // Do not stop on first error - check all AST nodes even if error found
9196 res |= checkElem(exp.e1.isArrayLiteralExp()[i]);
9199 else if (exp.e1.type.ty == Tvoid)
9200 checkElem(exp.e1);
9202 result = res ? ErrorExp.get() : exp;
9205 override void visit(VectorArrayExp e)
9207 static if (LOGSEMANTIC)
9209 printf("VectorArrayExp::semantic('%s')\n", e.toChars());
9211 if (!e.type)
9213 unaSemantic(e, sc);
9214 e.e1 = resolveProperties(sc, e.e1);
9216 if (e.e1.op == EXP.error)
9218 result = e.e1;
9219 return;
9221 assert(e.e1.type.ty == Tvector);
9222 e.type = e.e1.type.isTypeVector().basetype;
9224 result = e;
9227 override void visit(SliceExp exp)
9229 static if (LOGSEMANTIC)
9231 printf("SliceExp::semantic('%s')\n", exp.toChars());
9233 if (exp.type)
9235 result = exp;
9236 return;
9239 // operator overloading should be handled in ArrayExp already.
9240 if (Expression ex = unaSemantic(exp, sc))
9242 result = ex;
9243 return;
9245 exp.e1 = resolveProperties(sc, exp.e1);
9246 if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
9248 if (exp.lwr || exp.upr)
9250 error(exp.loc, "cannot slice type `%s`", exp.e1.toChars());
9251 return setError();
9253 Expression e = new TypeExp(exp.loc, exp.e1.type.arrayOf());
9254 result = e.expressionSemantic(sc);
9255 return;
9257 if (!exp.lwr && !exp.upr)
9259 if (exp.e1.op == EXP.arrayLiteral)
9261 // Convert [a,b,c][] to [a,b,c]
9262 Type t1b = exp.e1.type.toBasetype();
9263 Expression e = exp.e1;
9264 if (t1b.ty == Tsarray)
9266 e = e.copy();
9267 e.type = t1b.nextOf().arrayOf();
9269 result = e;
9270 return;
9272 if (exp.e1.op == EXP.slice)
9274 // Convert e[][] to e[]
9275 SliceExp se = cast(SliceExp)exp.e1;
9276 if (!se.lwr && !se.upr)
9278 result = se;
9279 return;
9282 if (isArrayOpOperand(exp.e1))
9284 // Convert (a[]+b[])[] to a[]+b[]
9285 result = exp.e1;
9286 return;
9289 if (exp.e1.op == EXP.error)
9291 result = exp.e1;
9292 return;
9294 if (exp.e1.type.ty == Terror)
9295 return setError();
9297 Type t1b = exp.e1.type.toBasetype();
9298 if (auto tp = t1b.isTypePointer())
9300 if (t1b.isPtrToFunction())
9302 error(exp.loc, "cannot slice function pointer `%s`", exp.e1.toChars());
9303 return setError();
9305 if (!exp.lwr || !exp.upr)
9307 error(exp.loc, "upper and lower bounds are needed to slice a pointer");
9308 if (auto ad = isAggregate(tp.next.toBasetype()))
9310 auto s = search_function(ad, Id.index);
9311 if (!s) s = search_function(ad, Id.slice);
9312 if (s)
9314 auto fd = s.isFuncDeclaration();
9315 if ((fd && !fd.getParameterList().length) || s.isTemplateDeclaration())
9317 errorSupplemental(exp.loc,
9318 "pointer `%s` points to an aggregate that defines an `%s`, perhaps you meant `(*%s)[]`",
9319 exp.e1.toChars(),
9320 s.ident.toChars(),
9321 exp.e1.toChars()
9328 return setError();
9330 if (sc.setUnsafe(false, exp.loc, "pointer slicing not allowed in safe functions"))
9331 return setError();
9333 else if (t1b.ty == Tarray)
9336 else if (t1b.ty == Tsarray)
9339 else if (t1b.ty == Ttuple)
9341 if (!exp.lwr && !exp.upr)
9343 result = exp.e1;
9344 return;
9346 if (!exp.lwr || !exp.upr)
9348 error(exp.loc, "need upper and lower bound to slice a sequence");
9349 return setError();
9352 else if (t1b.ty == Tvector && exp.e1.isLvalue())
9354 // Convert e1 to corresponding static array
9355 TypeVector tv1 = cast(TypeVector)t1b;
9356 t1b = tv1.basetype;
9357 t1b = t1b.castMod(tv1.mod);
9358 exp.e1.type = t1b;
9360 else
9362 error(exp.loc, "`%s` cannot be sliced with `[]`", t1b.ty == Tvoid ? exp.e1.toChars() : t1b.toChars());
9363 return setError();
9366 /* Run semantic on lwr and upr.
9368 Scope* scx = sc;
9369 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
9371 // Create scope for 'length' variable
9372 ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
9373 sym.parent = sc.scopesym;
9374 sc = sc.push(sym);
9376 if (exp.lwr)
9378 if (t1b.ty == Ttuple)
9379 sc = sc.startCTFE();
9380 exp.lwr = exp.lwr.expressionSemantic(sc);
9381 exp.lwr = resolveProperties(sc, exp.lwr);
9382 if (t1b.ty == Ttuple)
9383 sc = sc.endCTFE();
9384 exp.lwr = exp.lwr.implicitCastTo(sc, Type.tsize_t);
9386 if (exp.upr)
9388 if (t1b.ty == Ttuple)
9389 sc = sc.startCTFE();
9390 exp.upr = exp.upr.expressionSemantic(sc);
9391 exp.upr = resolveProperties(sc, exp.upr);
9392 if (t1b.ty == Ttuple)
9393 sc = sc.endCTFE();
9394 exp.upr = exp.upr.implicitCastTo(sc, Type.tsize_t);
9396 if (sc != scx)
9397 sc = sc.pop();
9398 if (exp.lwr && exp.lwr.type == Type.terror || exp.upr && exp.upr.type == Type.terror)
9399 return setError();
9401 if (t1b.ty == Ttuple)
9403 exp.lwr = exp.lwr.ctfeInterpret();
9404 exp.upr = exp.upr.ctfeInterpret();
9405 uinteger_t i1 = exp.lwr.toUInteger();
9406 uinteger_t i2 = exp.upr.toUInteger();
9408 TupleExp te;
9409 TypeTuple tup;
9410 size_t length;
9411 if (exp.e1.op == EXP.tuple) // slicing an expression tuple
9413 te = cast(TupleExp)exp.e1;
9414 tup = null;
9415 length = te.exps.length;
9417 else if (exp.e1.op == EXP.type) // slicing a type tuple
9419 te = null;
9420 tup = cast(TypeTuple)t1b;
9421 length = Parameter.dim(tup.arguments);
9423 else
9424 assert(0);
9426 if (i2 < i1 || length < i2)
9428 error(exp.loc, "string slice `[%llu .. %llu]` is out of bounds", i1, i2);
9429 return setError();
9432 size_t j1 = cast(size_t)i1;
9433 size_t j2 = cast(size_t)i2;
9434 Expression e;
9435 if (exp.e1.op == EXP.tuple)
9437 auto exps = new Expressions(j2 - j1);
9438 for (size_t i = 0; i < j2 - j1; i++)
9440 (*exps)[i] = (*te.exps)[j1 + i];
9442 e = new TupleExp(exp.loc, te.e0, exps);
9444 else
9446 auto args = new Parameters();
9447 args.reserve(j2 - j1);
9448 for (size_t i = j1; i < j2; i++)
9450 Parameter arg = Parameter.getNth(tup.arguments, i);
9451 args.push(arg);
9453 e = new TypeExp(exp.e1.loc, new TypeTuple(args));
9455 e = e.expressionSemantic(sc);
9456 result = e;
9457 return;
9460 exp.type = t1b.nextOf().arrayOf();
9461 // Allow typedef[] -> typedef[]
9462 if (exp.type.equals(t1b))
9463 exp.type = exp.e1.type;
9465 // We might know $ now
9466 setLengthVarIfKnown(exp.lengthVar, t1b);
9468 if (exp.lwr && exp.upr)
9470 exp.lwr = exp.lwr.optimize(WANTvalue);
9471 exp.upr = exp.upr.optimize(WANTvalue);
9473 IntRange lwrRange = getIntRange(exp.lwr);
9474 IntRange uprRange = getIntRange(exp.upr);
9476 if (t1b.ty == Tsarray || t1b.ty == Tarray)
9478 Expression el = new ArrayLengthExp(exp.loc, exp.e1);
9479 el = el.expressionSemantic(sc);
9480 el = el.optimize(WANTvalue);
9481 if (el.op == EXP.int64)
9483 // Array length is known at compile-time. Upper is in bounds if it fits length.
9484 dinteger_t length = el.toInteger();
9485 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length));
9486 exp.upperIsInBounds = bounds.contains(uprRange);
9488 else if (exp.upr.op == EXP.int64 && exp.upr.toInteger() == 0)
9490 // Upper slice expression is '0'. Value is always in bounds.
9491 exp.upperIsInBounds = true;
9493 else if (exp.upr.op == EXP.variable && (cast(VarExp)exp.upr).var.ident == Id.dollar)
9495 // Upper slice expression is '$'. Value is always in bounds.
9496 exp.upperIsInBounds = true;
9499 else if (t1b.ty == Tpointer)
9501 exp.upperIsInBounds = true;
9503 else
9504 assert(0);
9506 exp.lowerIsLessThanUpper = (lwrRange.imax <= uprRange.imin);
9508 //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", exp.upperIsInBounds, exp.lowerIsLessThanUpper);
9511 result = exp;
9514 override void visit(ArrayLengthExp e)
9516 static if (LOGSEMANTIC)
9518 printf("ArrayLengthExp::semantic('%s')\n", e.toChars());
9520 if (e.type)
9522 result = e;
9523 return;
9526 if (Expression ex = unaSemantic(e, sc))
9528 result = ex;
9529 return;
9531 e.e1 = resolveProperties(sc, e.e1);
9533 e.type = Type.tsize_t;
9534 result = e;
9537 override void visit(ArrayExp exp)
9539 static if (LOGSEMANTIC)
9541 printf("ArrayExp::semantic('%s')\n", exp.toChars());
9543 assert(!exp.type);
9545 if (sc.flags & SCOPE.Cfile)
9547 /* See if need to rewrite the AST because of cast/call ambiguity
9549 if (auto e = castCallAmbiguity(exp, sc))
9551 result = expressionSemantic(e, sc);
9552 return;
9556 result = exp.carraySemantic(sc); // C semantics
9557 if (result)
9558 return;
9560 Expression e = exp.op_overload(sc);
9561 if (e)
9563 result = e;
9564 return;
9567 if (isAggregate(exp.e1.type))
9568 error(exp.loc, "no `[]` operator overload for type `%s`", exp.e1.type.toChars());
9569 else if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
9570 error(exp.loc, "static array of `%s` with multiple lengths not allowed", exp.e1.type.toChars());
9571 else if (isIndexableNonAggregate(exp.e1.type))
9572 error(exp.loc, "only one index allowed to index `%s`", exp.e1.type.toChars());
9573 else
9574 error(exp.loc, "cannot use `[]` operator on expression of type `%s`", exp.e1.type.toChars());
9576 result = ErrorExp.get();
9579 override void visit(DotExp exp)
9581 static if (LOGSEMANTIC)
9583 printf("DotExp::semantic('%s')\n", exp.toChars());
9584 if (exp.type)
9585 printf("\ttype = %s\n", exp.type.toChars());
9587 exp.e1 = exp.e1.expressionSemantic(sc);
9588 exp.e2 = exp.e2.expressionSemantic(sc);
9590 if (exp.e1.op == EXP.type)
9592 result = exp.e2;
9593 return;
9595 if (exp.e2.op == EXP.type)
9597 result = exp.e2;
9598 return;
9600 if (auto te = exp.e2.isTemplateExp())
9602 Expression e = new DotTemplateExp(exp.loc, exp.e1, te.td);
9603 result = e.expressionSemantic(sc);
9604 return;
9606 if (!exp.type)
9607 exp.type = exp.e2.type;
9608 result = exp;
9611 override void visit(CommaExp e)
9613 //printf("Semantic.CommaExp() %s\n", e.toChars());
9614 if (e.type)
9616 result = e;
9617 return;
9620 // Allow `((a,b),(x,y))`
9621 if (e.allowCommaExp)
9623 CommaExp.allow(e.e1);
9624 CommaExp.allow(e.e2);
9627 if (Expression ex = binSemanticProp(e, sc))
9629 result = ex;
9630 return;
9632 e.e1 = e.e1.addDtorHook(sc);
9634 if (checkNonAssignmentArrayOp(e.e1))
9635 return setError();
9637 // Comma expressions trigger this conversion
9638 e.e2 = e.e2.arrayFuncConv(sc);
9640 e.type = e.e2.type;
9641 result = e;
9643 if (sc.flags & SCOPE.Cfile)
9644 return;
9646 if (e.type is Type.tvoid)
9648 checkMustUse(e.e1, sc);
9649 discardValue(e.e1);
9651 else if (!e.allowCommaExp && !e.isGenerated)
9652 error(e.loc, "using the result of a comma expression is not allowed");
9655 override void visit(IntervalExp e)
9657 static if (LOGSEMANTIC)
9659 printf("IntervalExp::semantic('%s')\n", e.toChars());
9661 if (e.type)
9663 result = e;
9664 return;
9667 Expression le = e.lwr;
9668 le = le.expressionSemantic(sc);
9669 le = resolveProperties(sc, le);
9671 Expression ue = e.upr;
9672 ue = ue.expressionSemantic(sc);
9673 ue = resolveProperties(sc, ue);
9675 if (le.op == EXP.error)
9677 result = le;
9678 return;
9680 if (ue.op == EXP.error)
9682 result = ue;
9683 return;
9686 e.lwr = le;
9687 e.upr = ue;
9689 e.type = Type.tvoid;
9690 result = e;
9693 override void visit(DelegatePtrExp e)
9695 static if (LOGSEMANTIC)
9697 printf("DelegatePtrExp::semantic('%s')\n", e.toChars());
9699 if (!e.type)
9701 unaSemantic(e, sc);
9702 e.e1 = resolveProperties(sc, e.e1);
9704 if (e.e1.op == EXP.error)
9706 result = e.e1;
9707 return;
9709 e.type = Type.tvoidptr;
9711 result = e;
9714 override void visit(DelegateFuncptrExp e)
9716 static if (LOGSEMANTIC)
9718 printf("DelegateFuncptrExp::semantic('%s')\n", e.toChars());
9720 if (!e.type)
9722 unaSemantic(e, sc);
9723 e.e1 = resolveProperties(sc, e.e1);
9724 if (e.e1.op == EXP.error)
9726 result = e.e1;
9727 return;
9729 e.type = e.e1.type.nextOf().pointerTo();
9731 result = e;
9734 override void visit(IndexExp exp)
9736 static if (LOGSEMANTIC)
9738 printf("IndexExp::semantic('%s')\n", exp.toChars());
9740 if (exp.type)
9742 result = exp;
9743 return;
9746 // operator overloading should be handled in ArrayExp already.
9747 if (!exp.e1.type)
9748 exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
9749 assert(exp.e1.type); // semantic() should already be run on it
9750 if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
9752 exp.e2 = exp.e2.expressionSemantic(sc);
9753 exp.e2 = resolveProperties(sc, exp.e2);
9754 Type nt;
9755 if (exp.e2.op == EXP.type)
9756 nt = new TypeAArray(exp.e1.type, exp.e2.type);
9757 else
9758 nt = new TypeSArray(exp.e1.type, exp.e2);
9759 Expression e = new TypeExp(exp.loc, nt);
9760 result = e.expressionSemantic(sc);
9761 return;
9763 if (exp.e1.op == EXP.error)
9765 result = exp.e1;
9766 return;
9768 if (exp.e1.type.ty == Terror)
9769 return setError();
9771 // Note that unlike C we do not implement the int[ptr]
9773 Type t1b = exp.e1.type.toBasetype();
9775 if (TypeVector tv1 = t1b.isTypeVector())
9777 // Convert e1 to corresponding static array
9778 t1b = tv1.basetype;
9779 t1b = t1b.castMod(tv1.mod);
9780 exp.e1 = exp.e1.castTo(sc, t1b);
9782 if (t1b.ty == Tsarray || t1b.ty == Tarray)
9784 if (!checkAddressable(exp, sc))
9785 return setError();
9788 /* Run semantic on e2
9790 Scope* scx = sc;
9791 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
9793 // Create scope for 'length' variable
9794 ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
9795 sym.parent = sc.scopesym;
9796 sc = sc.push(sym);
9798 if (t1b.ty == Ttuple)
9799 sc = sc.startCTFE();
9800 exp.e2 = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
9801 exp.e2 = resolveProperties(sc, exp.e2);
9802 if (t1b.ty == Ttuple)
9803 sc = sc.endCTFE();
9804 if (exp.e2.op == EXP.tuple)
9806 TupleExp te = cast(TupleExp)exp.e2;
9807 if (te.exps && te.exps.length == 1)
9808 exp.e2 = Expression.combine(te.e0, (*te.exps)[0]); // bug 4444 fix
9810 if (sc != scx)
9811 sc = sc.pop();
9812 if (exp.e2.type == Type.terror)
9813 return setError();
9815 if (checkNonAssignmentArrayOp(exp.e1))
9816 return setError();
9818 switch (t1b.ty)
9820 case Tpointer:
9821 if (t1b.isPtrToFunction())
9823 error(exp.loc, "cannot index function pointer `%s`", exp.e1.toChars());
9824 return setError();
9826 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
9827 if (exp.e2.type == Type.terror)
9828 return setError();
9829 exp.e2 = exp.e2.optimize(WANTvalue);
9830 if (exp.e2.op == EXP.int64 && exp.e2.toInteger() == 0)
9833 else if (sc.setUnsafe(false, exp.loc, "`@safe` function `%s` cannot index pointer `%s`", sc.func, exp.e1))
9835 return setError();
9837 exp.type = (cast(TypeNext)t1b).next;
9838 break;
9840 case Tarray:
9841 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
9842 if (exp.e2.type == Type.terror)
9843 return setError();
9844 exp.type = (cast(TypeNext)t1b).next;
9845 break;
9847 case Tsarray:
9849 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
9850 if (exp.e2.type == Type.terror)
9851 return setError();
9852 exp.type = t1b.nextOf();
9853 break;
9855 case Taarray:
9857 TypeAArray taa = cast(TypeAArray)t1b;
9858 /* We can skip the implicit conversion if they differ only by
9859 * constness
9860 * https://issues.dlang.org/show_bug.cgi?id=2684
9861 * see also bug https://issues.dlang.org/show_bug.cgi?id=2954 b
9863 if (!arrayTypeCompatibleWithoutCasting(exp.e2.type, taa.index))
9865 exp.e2 = exp.e2.implicitCastTo(sc, taa.index); // type checking
9866 if (exp.e2.type == Type.terror)
9867 return setError();
9870 semanticTypeInfo(sc, taa);
9871 checkNewEscape(sc, exp.e2, false);
9873 exp.type = taa.next;
9874 break;
9876 case Ttuple:
9878 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
9879 if (exp.e2.type == Type.terror)
9880 return setError();
9882 exp.e2 = exp.e2.ctfeInterpret();
9883 uinteger_t index = exp.e2.toUInteger();
9885 TupleExp te;
9886 TypeTuple tup;
9887 size_t length;
9888 if (exp.e1.op == EXP.tuple)
9890 te = cast(TupleExp)exp.e1;
9891 tup = null;
9892 length = te.exps.length;
9894 else if (exp.e1.op == EXP.type)
9896 te = null;
9897 tup = cast(TypeTuple)t1b;
9898 length = Parameter.dim(tup.arguments);
9900 else
9901 assert(0);
9903 if (length <= index)
9905 error(exp.loc, "array index `[%llu]` is outside array bounds `[0 .. %llu]`", index, cast(ulong)length);
9906 return setError();
9908 Expression e;
9909 if (exp.e1.op == EXP.tuple)
9911 e = (*te.exps)[cast(size_t)index];
9912 e = Expression.combine(te.e0, e);
9914 else
9915 e = new TypeExp(exp.e1.loc, Parameter.getNth(tup.arguments, cast(size_t)index).type);
9916 result = e;
9917 return;
9919 default:
9920 error(exp.loc, "`%s` must be an array or pointer type, not `%s`", exp.e1.toChars(), exp.e1.type.toChars());
9921 return setError();
9924 // We might know $ now
9925 setLengthVarIfKnown(exp.lengthVar, t1b);
9927 if (t1b.ty == Tsarray || t1b.ty == Tarray)
9929 Expression el = new ArrayLengthExp(exp.loc, exp.e1);
9930 el = el.expressionSemantic(sc);
9931 el = el.optimize(WANTvalue);
9932 if (el.op == EXP.int64)
9934 exp.e2 = exp.e2.optimize(WANTvalue);
9935 dinteger_t length = el.toInteger();
9936 if (length)
9938 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length - 1));
9939 // OR it in, because it might already be set for C array indexing
9940 exp.indexIsInBounds |= bounds.contains(getIntRange(exp.e2));
9942 else if (sc.flags & SCOPE.Cfile && t1b.ty == Tsarray)
9944 if (auto ve = exp.e1.isVarExp())
9946 /* Rewrite 0-length C array ve[exp.e2] as *(ve + exp.e2)
9948 auto vp = ve.castTo(sc, t1b.isTypeSArray().next.pointerTo());
9949 auto e = new AddExp(exp.loc, vp, exp.e2);
9950 auto pe = new PtrExp(exp.loc, e);
9951 result = pe.expressionSemantic(sc).optimize(WANTvalue);
9952 return;
9958 result = exp;
9961 override void visit(PostExp exp)
9963 static if (LOGSEMANTIC)
9965 printf("PostExp::semantic('%s')\n", exp.toChars());
9967 if (exp.type)
9969 result = exp;
9970 return;
9973 if (sc.flags & SCOPE.Cfile)
9975 /* See if need to rewrite the AST because of cast/call ambiguity
9977 if (auto e = castCallAmbiguity(exp, sc))
9979 result = expressionSemantic(e, sc);
9980 return;
9984 if (Expression ex = binSemantic(exp, sc))
9986 result = ex;
9987 return;
9989 Expression e1x = resolveProperties(sc, exp.e1);
9990 if (e1x.op == EXP.error)
9992 result = e1x;
9993 return;
9995 exp.e1 = e1x;
9997 Expression e = exp.op_overload(sc);
9998 if (e)
10000 result = e;
10001 return;
10004 if (exp.e1.checkReadModifyWrite(exp.op))
10005 return setError();
10007 if (exp.e1.op == EXP.slice)
10009 const(char)* s = exp.op == EXP.plusPlus ? "increment" : "decrement";
10010 error(exp.loc, "cannot post-%s array slice `%s`, use pre-%s instead", s, exp.e1.toChars(), s);
10011 return setError();
10014 Type t1 = exp.e1.type.toBasetype();
10015 if (t1.ty == Tclass || t1.ty == Tstruct || exp.e1.op == EXP.arrayLength)
10017 /* Check for operator overloading,
10018 * but rewrite in terms of ++e instead of e++
10021 /* If e1 is not trivial, take a reference to it
10023 Expression de = null;
10024 if (exp.e1.op != EXP.variable && exp.e1.op != EXP.arrayLength)
10026 // ref v = e1;
10027 auto v = copyToTemp(STC.ref_, "__postref", exp.e1);
10028 de = new DeclarationExp(exp.loc, v);
10029 exp.e1 = new VarExp(exp.e1.loc, v);
10032 /* Rewrite as:
10033 * auto tmp = e1; ++e1; tmp
10035 auto tmp = copyToTemp(0, "__pitmp", exp.e1);
10036 Expression ea = new DeclarationExp(exp.loc, tmp);
10038 Expression eb = exp.e1.syntaxCopy();
10039 eb = new PreExp(exp.op == EXP.plusPlus ? EXP.prePlusPlus : EXP.preMinusMinus, exp.loc, eb);
10041 Expression ec = new VarExp(exp.loc, tmp);
10043 // Combine de,ea,eb,ec
10044 if (de)
10045 ea = new CommaExp(exp.loc, de, ea);
10046 e = new CommaExp(exp.loc, ea, eb);
10047 e = new CommaExp(exp.loc, e, ec);
10048 e = e.expressionSemantic(sc);
10049 result = e;
10050 return;
10053 exp.e1 = exp.e1.modifiableLvalue(sc);
10054 exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
10056 e = exp;
10057 if (exp.e1.checkScalar() ||
10058 exp.e1.checkSharedAccess(sc))
10059 return setError();
10060 if (exp.e1.checkNoBool())
10061 return setError();
10063 if (exp.e1.type.ty == Tpointer)
10064 e = scaleFactor(exp, sc);
10065 else
10066 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
10067 e.type = exp.e1.type;
10068 result = e;
10071 override void visit(PreExp exp)
10073 Expression e = exp.op_overload(sc);
10074 // printf("PreExp::semantic('%s')\n", toChars());
10075 if (e)
10077 result = e;
10078 return;
10081 // Rewrite as e1+=1 or e1-=1
10082 if (exp.op == EXP.prePlusPlus)
10083 e = new AddAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
10084 else
10085 e = new MinAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
10086 result = e.expressionSemantic(sc);
10090 * Get the expression initializer for a specific struct
10092 * Params:
10093 * sd = the struct for which the expression initializer is needed
10094 * loc = the location of the initializer
10095 * sc = the scope where the expression is located
10096 * t = the type of the expression
10098 * Returns:
10099 * The expression initializer or error expression if any errors occured
10101 private Expression getInitExp(StructDeclaration sd, Loc loc, Scope* sc, Type t)
10103 if (sd.zeroInit && !sd.isNested())
10105 // https://issues.dlang.org/show_bug.cgi?id=14606
10106 // Always use BlitExp for the special expression: (struct = 0)
10107 return IntegerExp.literal!0;
10110 if (sd.isNested())
10112 auto sle = new StructLiteralExp(loc, sd, null, t);
10113 if (!sd.fill(loc, *sle.elements, true))
10114 return ErrorExp.get();
10115 if (checkFrameAccess(loc, sc, sd, sle.elements.length))
10116 return ErrorExp.get();
10118 sle.type = t;
10119 return sle;
10122 return t.defaultInit(loc);
10125 override void visit(AssignExp exp)
10127 static if (LOGSEMANTIC)
10129 if (exp.op == EXP.blit) printf("BlitExp.toElem('%s')\n", exp.toChars());
10130 if (exp.op == EXP.assign) printf("AssignExp.toElem('%s')\n", exp.toChars());
10131 if (exp.op == EXP.construct) printf("ConstructExp.toElem('%s')\n", exp.toChars());
10134 void setResult(Expression e, int line = __LINE__)
10136 //printf("line %d\n", line);
10137 result = e;
10140 if (exp.type)
10142 return setResult(exp);
10145 Expression e1old = exp.e1;
10147 if (auto e2comma = exp.e2.isCommaExp())
10149 if (!e2comma.isGenerated && !(sc.flags & SCOPE.Cfile))
10150 error(exp.loc, "using the result of a comma expression is not allowed");
10152 /* Rewrite to get rid of the comma from rvalue
10153 * e1=(e0,e2) => e0,(e1=e2)
10155 Expression e0;
10156 exp.e2 = Expression.extractLast(e2comma, e0);
10157 Expression e = Expression.combine(e0, exp);
10158 return setResult(e.expressionSemantic(sc));
10161 /* Look for operator overloading of a[arguments] = e2.
10162 * Do it before e1.expressionSemantic() otherwise the ArrayExp will have been
10163 * converted to unary operator overloading already.
10165 if (auto ae = exp.e1.isArrayExp())
10167 Expression res;
10169 ae.e1 = ae.e1.expressionSemantic(sc);
10170 ae.e1 = resolveProperties(sc, ae.e1);
10171 Expression ae1old = ae.e1;
10173 const(bool) maybeSlice =
10174 (ae.arguments.length == 0 ||
10175 ae.arguments.length == 1 && (*ae.arguments)[0].op == EXP.interval);
10177 IntervalExp ie = null;
10178 if (maybeSlice && ae.arguments.length)
10180 assert((*ae.arguments)[0].op == EXP.interval);
10181 ie = cast(IntervalExp)(*ae.arguments)[0];
10183 Type att = null; // first cyclic `alias this` type
10184 while (true)
10186 if (ae.e1.op == EXP.error)
10187 return setResult(ae.e1);
10189 Expression e0 = null;
10190 Expression ae1save = ae.e1;
10191 ae.lengthVar = null;
10193 Type t1b = ae.e1.type.toBasetype();
10194 AggregateDeclaration ad = isAggregate(t1b);
10195 if (!ad)
10196 break;
10197 if (search_function(ad, Id.indexass))
10199 // Deal with $
10200 res = resolveOpDollar(sc, ae, &e0);
10201 if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
10202 goto Lfallback;
10203 if (res.op == EXP.error)
10204 return setResult(res);
10206 res = exp.e2.expressionSemantic(sc);
10207 if (res.op == EXP.error)
10208 return setResult(res);
10209 exp.e2 = res;
10211 /* Rewrite (a[arguments] = e2) as:
10212 * a.opIndexAssign(e2, arguments)
10214 Expressions* a = ae.arguments.copy();
10215 a.insert(0, exp.e2);
10216 res = new DotIdExp(exp.loc, ae.e1, Id.indexass);
10217 res = new CallExp(exp.loc, res, a);
10218 if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2)
10219 res = res.trySemantic(sc);
10220 else
10221 res = res.expressionSemantic(sc);
10222 if (res)
10223 return setResult(Expression.combine(e0, res));
10226 Lfallback:
10227 if (maybeSlice && search_function(ad, Id.sliceass))
10229 // Deal with $
10230 res = resolveOpDollar(sc, ae, ie, &e0);
10231 if (res.op == EXP.error)
10232 return setResult(res);
10234 res = exp.e2.expressionSemantic(sc);
10235 if (res.op == EXP.error)
10236 return setResult(res);
10238 exp.e2 = res;
10240 /* Rewrite (a[i..j] = e2) as:
10241 * a.opSliceAssign(e2, i, j)
10243 auto a = new Expressions();
10244 a.push(exp.e2);
10245 if (ie)
10247 a.push(ie.lwr);
10248 a.push(ie.upr);
10250 res = new DotIdExp(exp.loc, ae.e1, Id.sliceass);
10251 res = new CallExp(exp.loc, res, a);
10252 res = res.expressionSemantic(sc);
10253 return setResult(Expression.combine(e0, res));
10256 // No operator overloading member function found yet, but
10257 // there might be an alias this to try.
10258 if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type))
10260 /* Rewrite (a[arguments] op e2) as:
10261 * a.aliasthis[arguments] op e2
10263 ae.e1 = resolveAliasThis(sc, ae1save, true);
10264 if (ae.e1)
10265 continue;
10267 break;
10269 ae.e1 = ae1old; // recovery
10270 ae.lengthVar = null;
10273 /* Run this.e1 semantic.
10276 Expression e1x = exp.e1;
10278 /* With UFCS, e.f = value
10279 * Could mean:
10280 * .f(e, value)
10281 * or:
10282 * .f(e) = value
10284 if (auto dti = e1x.isDotTemplateInstanceExp())
10286 Expression e = dti.dotTemplateSemanticProp(sc, DotExpFlag.gag);
10287 if (!e)
10289 return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
10292 e1x = e;
10294 else if (sc.flags & SCOPE.Cfile && e1x.isDotIdExp())
10296 auto die = e1x.isDotIdExp();
10297 e1x = fieldLookup(die.e1, sc, die.ident, die.arrow);
10299 else if (auto die = e1x.isDotIdExp())
10301 Expression e = die.dotIdSemanticProp(sc, 1);
10302 if (e && isDotOpDispatch(e))
10304 /* https://issues.dlang.org/show_bug.cgi?id=19687
10306 * On this branch, e2 is semantically analyzed in resolvePropertiesX,
10307 * but that call is done with gagged errors. That is the only time when
10308 * semantic gets ran on e2, that is why the error never gets to be printed.
10309 * In order to make sure that UFCS is tried with correct parameters, e2
10310 * needs to have semantic ran on it.
10312 auto ode = e;
10313 exp.e2 = exp.e2.expressionSemantic(sc);
10314 uint errors = global.startGagging();
10315 e = resolvePropertiesX(sc, e, exp.e2);
10316 // Any error or if 'e' is not resolved, go to UFCS
10317 if (global.endGagging(errors) || e is ode)
10318 e = null; /* fall down to UFCS */
10319 else
10320 return setResult(e);
10322 if (!e)
10323 return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
10324 e1x = e;
10326 else
10328 if (auto se = e1x.isSliceExp())
10329 se.arrayop = true;
10331 e1x = e1x.expressionSemantic(sc);
10334 /* We have f = value.
10335 * Could mean:
10336 * f(value)
10337 * or:
10338 * f() = value
10340 if (Expression e = resolvePropertiesX(sc, e1x, exp.e2, exp))
10341 return setResult(e);
10343 if (e1x.checkRightThis(sc))
10345 return setError();
10347 exp.e1 = e1x;
10348 assert(exp.e1.type);
10350 Type t1 = exp.e1.type.isTypeEnum() ? exp.e1.type : exp.e1.type.toBasetype();
10352 /* Run this.e2 semantic.
10353 * Different from other binary expressions, the analysis of e2
10354 * depends on the result of e1 in assignments.
10357 Expression e2x = inferType(exp.e2, t1.baseElemOf());
10358 e2x = e2x.expressionSemantic(sc);
10359 if (!t1.isTypeSArray())
10360 e2x = e2x.arrayFuncConv(sc);
10361 e2x = resolveProperties(sc, e2x);
10362 if (e2x.op == EXP.type)
10363 e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684
10364 if (e2x.op == EXP.error)
10365 return setResult(e2x);
10366 // We delay checking the value for structs/classes as these might have
10367 // an opAssign defined.
10368 if ((t1.ty != Tstruct && t1.ty != Tclass && e2x.checkValue()) ||
10369 e2x.checkSharedAccess(sc))
10370 return setError();
10372 auto etmp = checkNoreturnVarAccess(e2x);
10373 if (etmp != e2x)
10374 return setResult(etmp);
10376 exp.e2 = e2x;
10379 /* Rewrite tuple assignment as a tuple of assignments.
10382 Expression e2x = exp.e2;
10384 Ltupleassign:
10385 if (exp.e1.op == EXP.tuple && e2x.op == EXP.tuple)
10387 TupleExp tup1 = cast(TupleExp)exp.e1;
10388 TupleExp tup2 = cast(TupleExp)e2x;
10389 size_t dim = tup1.exps.length;
10390 Expression e = null;
10391 if (dim != tup2.exps.length)
10393 error(exp.loc, "mismatched sequence lengths, %d and %d", cast(int)dim, cast(int)tup2.exps.length);
10394 return setError();
10396 if (dim == 0)
10398 e = IntegerExp.literal!0;
10399 e = new CastExp(exp.loc, e, Type.tvoid); // avoid "has no effect" error
10400 e = Expression.combine(tup1.e0, tup2.e0, e);
10402 else
10404 auto exps = new Expressions(dim);
10405 for (size_t i = 0; i < dim; i++)
10407 Expression ex1 = (*tup1.exps)[i];
10408 Expression ex2 = (*tup2.exps)[i];
10409 (*exps)[i] = new AssignExp(exp.loc, ex1, ex2);
10411 e = new TupleExp(exp.loc, Expression.combine(tup1.e0, tup2.e0), exps);
10413 return setResult(e.expressionSemantic(sc));
10416 /* Look for form: e1 = e2.aliasthis.
10418 if (exp.e1.op == EXP.tuple)
10420 TupleDeclaration td = isAliasThisTuple(e2x);
10421 if (!td)
10422 goto Lnomatch;
10424 assert(exp.e1.type.ty == Ttuple);
10425 TypeTuple tt = cast(TypeTuple)exp.e1.type;
10427 Expression e0;
10428 Expression ev = extractSideEffect(sc, "__tup", e0, e2x);
10430 auto iexps = new Expressions();
10431 iexps.push(ev);
10432 for (size_t u = 0; u < iexps.length; u++)
10434 Lexpand:
10435 Expression e = (*iexps)[u];
10437 Parameter arg = Parameter.getNth(tt.arguments, u);
10438 //printf("[%d] iexps.length = %d, ", u, iexps.length);
10439 //printf("e = (%s %s, %s), ", Token.toChars[e.op], e.toChars(), e.type.toChars());
10440 //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
10442 if (!arg || !e.type.implicitConvTo(arg.type))
10444 // expand initializer to tuple
10445 if (expandAliasThisTuples(iexps, u) != -1)
10447 if (iexps.length <= u)
10448 break;
10449 goto Lexpand;
10451 goto Lnomatch;
10454 e2x = new TupleExp(e2x.loc, e0, iexps);
10455 e2x = e2x.expressionSemantic(sc);
10456 if (e2x.op == EXP.error)
10458 result = e2x;
10459 return;
10461 // Do not need to overwrite this.e2
10462 goto Ltupleassign;
10464 Lnomatch:
10467 /* Inside constructor, if this is the first assignment of object field,
10468 * rewrite this to initializing the field.
10470 if (exp.op == EXP.assign
10471 && exp.e1.checkModifiable(sc) == Modifiable.initialization)
10473 //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars());
10474 auto t = exp.type;
10475 exp = new ConstructExp(exp.loc, exp.e1, exp.e2);
10476 exp.type = t;
10478 // https://issues.dlang.org/show_bug.cgi?id=13515
10479 // set Index::modifiable flag for complex AA element initialization
10480 if (auto ie1 = exp.e1.isIndexExp())
10482 Expression e1x = ie1.markSettingAAElem();
10483 if (e1x.op == EXP.error)
10485 result = e1x;
10486 return;
10490 else if (exp.op == EXP.construct && exp.e1.op == EXP.variable &&
10491 (cast(VarExp)exp.e1).var.storage_class & (STC.out_ | STC.ref_))
10493 exp.memset = MemorySet.referenceInit;
10496 if (exp.op == EXP.assign) // skip EXP.blit and EXP.construct, which are initializations
10498 exp.e1.checkSharedAccess(sc);
10499 checkUnsafeAccess(sc, exp.e1, false, true);
10502 checkUnsafeAccess(sc, exp.e2, true, true); // Initializer must always be checked
10504 /* If it is an assignment from a 'foreign' type,
10505 * check for operator overloading.
10507 if (exp.memset == MemorySet.referenceInit)
10509 // If this is an initialization of a reference,
10510 // do nothing
10512 else if (t1.ty == Tstruct)
10514 auto e1x = exp.e1;
10515 auto e2x = exp.e2;
10516 auto sd = (cast(TypeStruct)t1).sym;
10518 if (exp.op == EXP.construct)
10520 Type t2 = e2x.type.toBasetype();
10521 if (t2.ty == Tstruct && sd == (cast(TypeStruct)t2).sym)
10523 sd.size(exp.loc);
10524 if (sd.sizeok != Sizeok.done)
10525 return setError();
10526 if (!sd.ctor)
10527 sd.ctor = sd.searchCtor();
10529 // https://issues.dlang.org/show_bug.cgi?id=15661
10530 // Look for the form from last of comma chain.
10531 auto e2y = lastComma(e2x);
10533 CallExp ce = (e2y.op == EXP.call) ? cast(CallExp)e2y : null;
10534 DotVarExp dve = (ce && ce.e1.op == EXP.dotVariable)
10535 ? cast(DotVarExp)ce.e1 : null;
10536 if (sd.ctor && ce && dve && dve.var.isCtorDeclaration() &&
10537 // https://issues.dlang.org/show_bug.cgi?id=19389
10538 dve.e1.op != EXP.dotVariable &&
10539 e2y.type.implicitConvTo(t1))
10541 /* Look for form of constructor call which is:
10542 * __ctmp.ctor(arguments...)
10545 /* Before calling the constructor, initialize
10546 * variable with a bit copy of the default
10547 * initializer
10549 Expression einit = getInitExp(sd, exp.loc, sc, t1);
10550 if (einit.op == EXP.error)
10552 result = einit;
10553 return;
10556 auto ae = new BlitExp(exp.loc, exp.e1, einit);
10557 ae.type = e1x.type;
10559 /* Replace __ctmp being constructed with e1.
10560 * We need to copy constructor call expression,
10561 * because it may be used in other place.
10563 auto dvx = cast(DotVarExp)dve.copy();
10564 dvx.e1 = e1x;
10565 auto cx = cast(CallExp)ce.copy();
10566 cx.e1 = dvx;
10567 if (checkConstructorEscape(sc, cx, false))
10568 return setError();
10570 Expression e0;
10571 Expression.extractLast(e2x, e0);
10573 auto e = Expression.combine(e0, ae, cx);
10574 e = e.expressionSemantic(sc);
10575 result = e;
10576 return;
10578 // https://issues.dlang.org/show_bug.cgi?id=21586
10579 // Rewrite CondExp or e1 will miss direct construction, e.g.
10580 // e1 = a ? S(1) : ...; -> AST: e1 = a ? (S(0)).this(1) : ...;
10581 // a temporary created and an extra destructor call.
10582 // AST will be rewritten to:
10583 // a ? e1 = 0, e1.this(1) : ...; -> blitting plus construction
10584 if (e2x.op == EXP.question)
10586 /* Rewrite as:
10587 * a ? e1 = b : e1 = c;
10589 CondExp econd = cast(CondExp)e2x;
10590 Expression ea1 = new ConstructExp(econd.e1.loc, e1x, econd.e1);
10591 Expression ea2 = new ConstructExp(econd.e2.loc, e1x, econd.e2);
10592 Expression e = new CondExp(exp.loc, econd.econd, ea1, ea2);
10593 result = e.expressionSemantic(sc);
10594 return;
10596 if (sd.postblit || sd.hasCopyCtor)
10598 /* We have a copy constructor for this
10601 if (e2x.isLvalue())
10603 if (sd.hasCopyCtor)
10605 /* Rewrite as:
10606 * e1 = init, e1.copyCtor(e2);
10608 Expression einit = new BlitExp(exp.loc, exp.e1, getInitExp(sd, exp.loc, sc, t1));
10609 einit.type = e1x.type;
10611 Expression e;
10612 e = new DotIdExp(exp.loc, e1x, Id.ctor);
10613 e = new CallExp(exp.loc, e, e2x);
10614 e = new CommaExp(exp.loc, einit, e);
10616 //printf("e: %s\n", e.toChars());
10618 result = e.expressionSemantic(sc);
10619 return;
10621 else
10623 if (!e2x.type.implicitConvTo(e1x.type))
10625 error(exp.loc, "conversion error from `%s` to `%s`",
10626 e2x.type.toChars(), e1x.type.toChars());
10627 return setError();
10630 /* Rewrite as:
10631 * (e1 = e2).postblit();
10633 * Blit assignment e1 = e2 returns a reference to the original e1,
10634 * then call the postblit on it.
10636 Expression e = e1x.copy();
10637 e.type = e.type.mutableOf();
10638 if (e.type.isShared && !sd.type.isShared)
10639 e.type = e.type.unSharedOf();
10640 e = new BlitExp(exp.loc, e, e2x);
10641 e = new DotVarExp(exp.loc, e, sd.postblit, false);
10642 e = new CallExp(exp.loc, e);
10643 result = e.expressionSemantic(sc);
10644 return;
10647 else
10649 /* The struct value returned from the function is transferred
10650 * so should not call the destructor on it.
10652 e2x = valueNoDtor(e2x);
10656 // https://issues.dlang.org/show_bug.cgi?id=19251
10657 // if e2 cannot be converted to e1.type, maybe there is an alias this
10658 if (!e2x.implicitConvTo(t1))
10660 AggregateDeclaration ad2 = isAggregate(e2x.type);
10661 if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
10663 /* Rewrite (e1 op e2) as:
10664 * (e1 op e2.aliasthis)
10666 exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
10667 result = exp.expressionSemantic(sc);
10668 return;
10672 else if (!e2x.implicitConvTo(t1))
10674 sd.size(exp.loc);
10675 if (sd.sizeok != Sizeok.done)
10676 return setError();
10677 if (!sd.ctor)
10678 sd.ctor = sd.searchCtor();
10680 if (sd.ctor)
10682 /* Look for implicit constructor call
10683 * Rewrite as:
10684 * e1 = init, e1.ctor(e2)
10687 /* Fix Issue 5153 : https://issues.dlang.org/show_bug.cgi?id=5153
10688 * Using `new` to initialize a struct object is a common mistake, but
10689 * the error message from the compiler is not very helpful in that
10690 * case. If exp.e2 is a NewExp and the type of new is the same as
10691 * the type as exp.e1 (struct in this case), then we know for sure
10692 * that the user wants to instantiate a struct. This is done to avoid
10693 * issuing an error when the user actually wants to call a constructor
10694 * which receives a class object.
10696 * Foo f = new Foo2(0); is a valid expression if Foo has a constructor
10697 * which receives an instance of a Foo2 class
10699 if (exp.e2.op == EXP.new_)
10701 auto newExp = cast(NewExp)(exp.e2);
10702 if (newExp.newtype && newExp.newtype == t1)
10704 error(exp.loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
10705 newExp.toChars(), newExp.type.toChars(), t1.toChars());
10706 errorSupplemental(exp.loc, "Perhaps remove the `new` keyword?");
10707 return setError();
10711 Expression einit = new BlitExp(exp.loc, e1x, getInitExp(sd, exp.loc, sc, t1));
10712 einit.type = e1x.type;
10714 Expression e;
10715 e = new DotIdExp(exp.loc, e1x, Id.ctor);
10716 e = new CallExp(exp.loc, e, e2x);
10717 e = new CommaExp(exp.loc, einit, e);
10718 e = e.expressionSemantic(sc);
10719 result = e;
10720 return;
10722 if (search_function(sd, Id.call))
10724 /* Look for static opCall
10725 * https://issues.dlang.org/show_bug.cgi?id=2702
10726 * Rewrite as:
10727 * e1 = typeof(e1).opCall(arguments)
10729 e2x = typeDotIdExp(e2x.loc, e1x.type, Id.call);
10730 e2x = new CallExp(exp.loc, e2x, exp.e2);
10732 e2x = e2x.expressionSemantic(sc);
10733 e2x = resolveProperties(sc, e2x);
10734 if (e2x.op == EXP.error)
10736 result = e2x;
10737 return;
10739 if (e2x.checkValue() || e2x.checkSharedAccess(sc))
10740 return setError();
10743 else // https://issues.dlang.org/show_bug.cgi?id=11355
10745 AggregateDeclaration ad2 = isAggregate(e2x.type);
10746 if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
10748 /* Rewrite (e1 op e2) as:
10749 * (e1 op e2.aliasthis)
10751 exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
10752 result = exp.expressionSemantic(sc);
10753 return;
10757 else if (exp.op == EXP.assign)
10759 if (e1x.op == EXP.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray)
10762 * Rewrite:
10763 * aa[key] = e2;
10764 * as:
10765 * ref __aatmp = aa;
10766 * ref __aakey = key;
10767 * ref __aaval = e2;
10768 * (__aakey in __aatmp
10769 * ? __aatmp[__aakey].opAssign(__aaval)
10770 * : ConstructExp(__aatmp[__aakey], __aaval));
10772 // ensure we keep the expr modifiable
10773 Expression esetting = (cast(IndexExp)e1x).markSettingAAElem();
10774 if (esetting.op == EXP.error)
10776 result = esetting;
10777 return;
10779 assert(esetting.op == EXP.index);
10780 IndexExp ie = cast(IndexExp) esetting;
10781 Type t2 = e2x.type.toBasetype();
10783 Expression e0 = null;
10784 Expression ea = extractSideEffect(sc, "__aatmp", e0, ie.e1);
10785 Expression ek = extractSideEffect(sc, "__aakey", e0, ie.e2);
10786 Expression ev = extractSideEffect(sc, "__aaval", e0, e2x);
10788 AssignExp ae = cast(AssignExp)exp.copy();
10789 ae.e1 = new IndexExp(exp.loc, ea, ek);
10790 ae.e1 = ae.e1.expressionSemantic(sc);
10791 ae.e1 = ae.e1.optimize(WANTvalue);
10792 ae.e2 = ev;
10793 Expression e = ae.op_overload(sc);
10794 if (e)
10796 Expression ey = null;
10797 if (t2.ty == Tstruct && sd == t2.toDsymbol(sc))
10799 ey = ev;
10801 else if (!ev.implicitConvTo(ie.type) && sd.ctor)
10803 // Look for implicit constructor call
10804 // Rewrite as S().ctor(e2)
10805 ey = new StructLiteralExp(exp.loc, sd, null);
10806 ey = new DotIdExp(exp.loc, ey, Id.ctor);
10807 ey = new CallExp(exp.loc, ey, ev);
10808 ey = ey.trySemantic(sc);
10810 if (ey)
10812 Expression ex;
10813 ex = new IndexExp(exp.loc, ea, ek);
10814 ex = ex.expressionSemantic(sc);
10815 ex = ex.modifiableLvalue(sc); // allocate new slot
10816 ex = ex.optimize(WANTvalue);
10818 ey = new ConstructExp(exp.loc, ex, ey);
10819 ey = ey.expressionSemantic(sc);
10820 if (ey.op == EXP.error)
10822 result = ey;
10823 return;
10825 ex = e;
10827 // https://issues.dlang.org/show_bug.cgi?id=14144
10828 // The whole expression should have the common type
10829 // of opAssign() return and assigned AA entry.
10830 // Even if there's no common type, expression should be typed as void.
10831 if (!typeMerge(sc, EXP.question, ex, ey))
10833 ex = new CastExp(ex.loc, ex, Type.tvoid);
10834 ey = new CastExp(ey.loc, ey, Type.tvoid);
10836 e = new CondExp(exp.loc, new InExp(exp.loc, ek, ea), ex, ey);
10838 e = Expression.combine(e0, e);
10839 e = e.expressionSemantic(sc);
10840 result = e;
10841 return;
10844 else
10846 Expression e = exp.op_overload(sc);
10847 if (e)
10849 result = e;
10850 return;
10854 else
10855 assert(exp.op == EXP.blit);
10857 if (e2x.checkValue())
10858 return setError();
10860 exp.e1 = e1x;
10861 exp.e2 = e2x;
10863 else if (t1.ty == Tclass)
10865 // Disallow assignment operator overloads for same type
10866 if (exp.op == EXP.assign && !exp.e2.implicitConvTo(exp.e1.type))
10868 Expression e = exp.op_overload(sc);
10869 if (e)
10871 result = e;
10872 return;
10875 if (exp.e2.checkValue())
10876 return setError();
10878 else if (t1.ty == Tsarray)
10880 // SliceExp cannot have static array type without context inference.
10881 assert(exp.e1.op != EXP.slice);
10882 Expression e1x = exp.e1;
10883 Expression e2x = exp.e2;
10885 /* C strings come through as static arrays. May need to adjust the size of the
10886 * string to match the size of e1.
10888 Type t2 = e2x.type.toBasetype();
10889 if (sc.flags & SCOPE.Cfile && e2x.isStringExp() && t2.isTypeSArray())
10891 uinteger_t dim1 = t1.isTypeSArray().dim.toInteger();
10892 uinteger_t dim2 = t2.isTypeSArray().dim.toInteger();
10893 if (dim1 + 1 == dim2 || dim2 < dim1)
10895 auto tsa2 = t2.isTypeSArray();
10896 auto newt = tsa2.next.sarrayOf(dim1).immutableOf();
10897 e2x = castTo(e2x, sc, newt);
10898 exp.e2 = e2x;
10902 if (e2x.implicitConvTo(e1x.type))
10904 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()))
10906 if (t1.checkPostblit(e1x.loc, sc))
10907 return setError();
10910 // e2 matches to t1 because of the implicit length match, so
10911 if (isUnaArrayOp(e2x.op) || isBinArrayOp(e2x.op))
10913 // convert e1 to e1[]
10914 // e.g. e1[] = a[] + b[];
10915 auto sle = new SliceExp(e1x.loc, e1x, null, null);
10916 sle.arrayop = true;
10917 e1x = sle.expressionSemantic(sc);
10919 else
10921 // convert e2 to t1 later
10922 // e.g. e1 = [1, 2, 3];
10925 else
10927 if (e2x.implicitConvTo(t1.nextOf().arrayOf()) > MATCH.nomatch)
10929 uinteger_t dim1 = (cast(TypeSArray)t1).dim.toInteger();
10930 uinteger_t dim2 = dim1;
10931 if (auto ale = e2x.isArrayLiteralExp())
10933 dim2 = ale.elements ? ale.elements.length : 0;
10935 else if (auto se = e2x.isSliceExp())
10937 Type tx = toStaticArrayType(se);
10938 if (tx)
10939 dim2 = (cast(TypeSArray)tx).dim.toInteger();
10941 if (dim1 != dim2)
10943 error(exp.loc, "mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2);
10944 return setError();
10948 // May be block or element-wise assignment, so
10949 // convert e1 to e1[]
10950 if (exp.op != EXP.assign)
10952 // If multidimensional static array, treat as one large array
10954 // Find the appropriate array type depending on the assignment, e.g.
10955 // int[3] = int => int[3]
10956 // int[3][2] = int => int[6]
10957 // int[3][2] = int[] => int[3][2]
10958 // int[3][2][4] + int => int[24]
10959 // int[3][2][4] + int[] => int[3][8]
10960 ulong dim = t1.isTypeSArray().dim.toUInteger();
10961 auto type = t1.nextOf();
10963 for (TypeSArray tsa; (tsa = type.isTypeSArray()) !is null; )
10965 import core.checkedint : mulu;
10967 // Accumulate skipped dimensions
10968 bool overflow = false;
10969 dim = mulu(dim, tsa.dim.toUInteger(), overflow);
10970 if (overflow || dim >= uint.max)
10972 // dym exceeds maximum array size
10973 error(exp.loc, "static array `%s` size overflowed to %llu",
10974 e1x.type.toChars(), cast(ulong) dim);
10975 return setError();
10978 // Move to the element type
10979 type = tsa.nextOf().toBasetype();
10981 // Rewrite ex1 as a static array if a matching type was found
10982 if (e2x.implicitConvTo(type) > MATCH.nomatch)
10984 e1x.type = type.sarrayOf(dim);
10985 break;
10989 auto sle = new SliceExp(e1x.loc, e1x, null, null);
10990 sle.arrayop = true;
10991 e1x = sle.expressionSemantic(sc);
10993 if (e1x.op == EXP.error)
10994 return setResult(e1x);
10995 if (e2x.op == EXP.error)
10996 return setResult(e2x);
10998 exp.e1 = e1x;
10999 exp.e2 = e2x;
11000 t1 = e1x.type.toBasetype();
11002 /* Check the mutability of e1.
11004 if (auto ale = exp.e1.isArrayLengthExp())
11006 // e1 is not an lvalue, but we let code generator handle it
11008 auto ale1x = ale.e1.modifiableLvalueImpl(sc, exp.e1);
11009 if (ale1x.op == EXP.error)
11010 return setResult(ale1x);
11011 ale.e1 = ale1x;
11013 Type tn = ale.e1.type.toBasetype().nextOf();
11014 checkDefCtor(ale.loc, tn);
11016 Identifier hook = global.params.tracegc ? Id._d_arraysetlengthTTrace : Id._d_arraysetlengthT;
11017 if (!verifyHookExist(exp.loc, *sc, Id._d_arraysetlengthTImpl, "resizing arrays"))
11018 return setError();
11020 exp.e2 = exp.e2.expressionSemantic(sc);
11021 auto lc = lastComma(exp.e2);
11022 lc = lc.optimize(WANTvalue);
11023 // use slice expression when arr.length = 0 to avoid runtime call
11024 if(lc.op == EXP.int64 && lc.toInteger() == 0)
11026 Expression se = new SliceExp(ale.loc, ale.e1, lc, lc);
11027 Expression as = new AssignExp(ale.loc, ale.e1, se);
11028 as = as.expressionSemantic(sc);
11029 auto res = Expression.combine(as, exp.e2);
11030 res.type = ale.type;
11031 return setResult(res);
11034 if (!sc.needsCodegen()) // if compile time creature only
11036 exp.type = Type.tsize_t;
11037 return setResult(exp);
11040 // Lower to object._d_arraysetlengthTImpl!(typeof(e1))._d_arraysetlengthT{,Trace}(e1, e2)
11041 Expression id = new IdentifierExp(ale.loc, Id.empty);
11042 id = new DotIdExp(ale.loc, id, Id.object);
11043 auto tiargs = new Objects();
11044 tiargs.push(ale.e1.type);
11045 id = new DotTemplateInstanceExp(ale.loc, id, Id._d_arraysetlengthTImpl, tiargs);
11046 id = new DotIdExp(ale.loc, id, hook);
11047 id = id.expressionSemantic(sc);
11049 auto arguments = new Expressions();
11050 arguments.reserve(5);
11051 if (global.params.tracegc)
11053 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
11054 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
11055 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
11056 arguments.push(new StringExp(exp.loc, funcname.toDString()));
11058 arguments.push(ale.e1);
11059 arguments.push(exp.e2);
11061 Expression ce = new CallExp(ale.loc, id, arguments).expressionSemantic(sc);
11062 auto res = new LoweredAssignExp(exp, ce);
11063 // if (global.params.verbose)
11064 // message("lowered %s =>\n %s", exp.toChars(), res.toChars());
11065 res.type = Type.tsize_t;
11066 return setResult(res);
11068 else if (auto se = exp.e1.isSliceExp())
11070 Type tn = se.type.nextOf();
11071 const fun = sc.func;
11072 if (exp.op == EXP.assign && !tn.isMutable() &&
11073 // allow modifiation in module ctor, see
11074 // https://issues.dlang.org/show_bug.cgi?id=9884
11075 (!fun || (fun && !fun.isStaticCtorDeclaration())))
11077 error(exp.loc, "slice `%s` is not mutable", se.toChars());
11078 return setError();
11081 if (exp.op == EXP.assign && !tn.baseElemOf().isAssignable())
11083 error(exp.loc, "slice `%s` is not mutable, struct `%s` has immutable members",
11084 exp.e1.toChars(), tn.baseElemOf().toChars());
11085 result = ErrorExp.get();
11086 return;
11089 // For conditional operator, both branches need conversion.
11090 while (se.e1.op == EXP.slice)
11091 se = cast(SliceExp)se.e1;
11092 if (se.e1.op == EXP.question && se.e1.type.toBasetype().ty == Tsarray)
11094 se.e1 = se.e1.modifiableLvalueImpl(sc, exp.e1);
11095 if (se.e1.op == EXP.error)
11096 return setResult(se.e1);
11099 else
11101 if (t1.ty == Tsarray && exp.op == EXP.assign)
11103 Type tn = exp.e1.type.nextOf();
11104 if (tn && !tn.baseElemOf().isAssignable())
11106 error(exp.loc, "array `%s` is not mutable, struct `%s` has immutable members",
11107 exp.e1.toChars(), tn.baseElemOf().toChars());
11108 result = ErrorExp.get();
11109 return;
11113 Expression e1x = exp.e1;
11115 // Try to do a decent error message with the expression
11116 // before it gets constant folded
11117 if (exp.op == EXP.assign)
11118 e1x = e1x.modifiableLvalueImpl(sc, e1old);
11120 e1x = e1x.optimize(WANTvalue, /*keepLvalue*/ true);
11122 if (e1x.op == EXP.error)
11124 result = e1x;
11125 return;
11127 exp.e1 = e1x;
11130 /* Tweak e2 based on the type of e1.
11132 Expression e2x = exp.e2;
11133 Type t2 = e2x.type.toBasetype();
11135 // If it is a array, get the element type. Note that it may be
11136 // multi-dimensional.
11137 Type telem = t1;
11138 while (telem.ty == Tarray)
11139 telem = telem.nextOf();
11141 if (exp.e1.op == EXP.slice && t1.nextOf() &&
11142 (telem.ty != Tvoid || e2x.op == EXP.null_) &&
11143 e2x.implicitConvTo(t1.nextOf()))
11145 // Check for block assignment. If it is of type void[], void[][], etc,
11146 // '= null' is the only allowable block assignment (Bug 7493)
11147 exp.memset = MemorySet.blockAssign; // make it easy for back end to tell what this is
11148 e2x = e2x.implicitCastTo(sc, t1.nextOf());
11149 if (exp.op != EXP.blit && e2x.isLvalue() && t1.nextOf.checkPostblit(exp.e1.loc, sc))
11150 return setError();
11152 else if (exp.e1.op == EXP.slice &&
11153 (t2.ty == Tarray || t2.ty == Tsarray) &&
11154 t2.nextOf().implicitConvTo(t1.nextOf()))
11156 // Check element-wise assignment.
11158 /* If assigned elements number is known at compile time,
11159 * check the mismatch.
11161 SliceExp se1 = cast(SliceExp)exp.e1;
11162 TypeSArray tsa1 = cast(TypeSArray)toStaticArrayType(se1);
11163 TypeSArray tsa2 = null;
11164 if (auto ale = e2x.isArrayLiteralExp())
11165 tsa2 = cast(TypeSArray)t2.nextOf().sarrayOf(ale.elements.length);
11166 else if (auto se = e2x.isSliceExp())
11167 tsa2 = cast(TypeSArray)toStaticArrayType(se);
11168 else
11169 tsa2 = t2.isTypeSArray();
11171 if (tsa1 && tsa2)
11173 uinteger_t dim1 = tsa1.dim.toInteger();
11174 uinteger_t dim2 = tsa2.dim.toInteger();
11175 if (dim1 != dim2)
11177 error(exp.loc, "mismatched array lengths %d and %d for assignment `%s`", cast(int)dim1, cast(int)dim2, exp.toChars());
11178 return setError();
11182 if (exp.op != EXP.blit &&
11183 (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() ||
11184 e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() ||
11185 e2x.op != EXP.slice && e2x.isLvalue()))
11187 if (t1.nextOf().checkPostblit(exp.e1.loc, sc))
11188 return setError();
11191 Type t2n = t2.nextOf();
11192 Type t1n = t1.nextOf();
11193 int offset;
11194 if (t2n.equivalent(t1n) ||
11195 t1n.isBaseOf(t2n, &offset) && offset == 0)
11197 /* Allow copy of distinct qualifier elements.
11198 * eg.
11199 * char[] dst; const(char)[] src;
11200 * dst[] = src;
11202 * class C {} class D : C {}
11203 * C[2] ca; D[] da;
11204 * ca[] = da;
11206 if (isArrayOpValid(e2x))
11208 // Don't add CastExp to keep AST for array operations
11209 e2x = e2x.copy();
11210 e2x.type = exp.e1.type.constOf();
11212 else
11213 e2x = e2x.castTo(sc, exp.e1.type.constOf());
11215 else
11217 /* https://issues.dlang.org/show_bug.cgi?id=15778
11218 * A string literal has an array type of immutable
11219 * elements by default, and normally it cannot be convertible to
11220 * array type of mutable elements. But for element-wise assignment,
11221 * elements need to be const at best. So we should give a chance
11222 * to change code unit size for polysemous string literal.
11224 if (e2x.op == EXP.string_)
11225 e2x = e2x.implicitCastTo(sc, exp.e1.type.constOf());
11226 else
11227 e2x = e2x.implicitCastTo(sc, exp.e1.type);
11229 if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid)
11231 if (sc.setUnsafe(false, exp.loc, "cannot copy `void[]` to `void[]` in `@safe` code"))
11232 return setError();
11235 else
11237 if (exp.op == EXP.blit)
11238 e2x = e2x.castTo(sc, exp.e1.type);
11239 else
11241 e2x = e2x.implicitCastTo(sc, exp.e1.type);
11243 // Fix Issue 13435: https://issues.dlang.org/show_bug.cgi?id=13435
11245 // If the implicit cast has failed and the assign expression is
11246 // the initialization of a struct member field
11247 if (e2x.op == EXP.error && exp.op == EXP.construct && t1.ty == Tstruct)
11249 scope sd = (cast(TypeStruct)t1).sym;
11250 Dsymbol opAssign = search_function(sd, Id.assign);
11252 // and the struct defines an opAssign
11253 if (opAssign)
11255 // offer more information about the cause of the problem
11256 errorSupplemental(exp.loc,
11257 "`%s` is the first assignment of `%s` therefore it represents its initialization",
11258 exp.toChars(), exp.e1.toChars());
11259 errorSupplemental(exp.loc,
11260 "`opAssign` methods are not used for initialization, but for subsequent assignments");
11265 if (e2x.op == EXP.error)
11267 result = e2x;
11268 return;
11270 exp.e2 = e2x;
11271 t2 = exp.e2.type.toBasetype();
11273 /* Look for array operations
11275 if ((t2.ty == Tarray || t2.ty == Tsarray) && isArrayOpValid(exp.e2))
11277 // Look for valid array operations
11278 if (exp.memset != MemorySet.blockAssign &&
11279 exp.e1.op == EXP.slice &&
11280 (isUnaArrayOp(exp.e2.op) || isBinArrayOp(exp.e2.op)))
11282 exp.type = exp.e1.type;
11283 if (exp.op == EXP.construct) // https://issues.dlang.org/show_bug.cgi?id=10282
11284 // tweak mutability of e1 element
11285 exp.e1.type = exp.e1.type.nextOf().mutableOf().arrayOf();
11286 result = arrayOp(exp, sc);
11287 return;
11290 // Drop invalid array operations in e2
11291 // d = a[] + b[], d = (a[] + b[])[0..2], etc
11292 if (checkNonAssignmentArrayOp(exp.e2, exp.memset != MemorySet.blockAssign && exp.op == EXP.assign))
11293 return setError();
11295 // Remains valid array assignments
11296 // d = d[], d = [1,2,3], etc
11299 /* Don't allow assignment to classes that were allocated on the stack with:
11300 * scope Class c = new Class();
11302 if (exp.e1.op == EXP.variable && exp.op == EXP.assign)
11304 VarExp ve = cast(VarExp)exp.e1;
11305 VarDeclaration vd = ve.var.isVarDeclaration();
11306 if (vd && vd.onstack)
11308 assert(t1.ty == Tclass);
11309 error(exp.loc, "cannot rebind scope variables");
11313 if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.ident == Id.ctfe)
11315 error(exp.loc, "cannot modify compiler-generated variable `__ctfe`");
11318 exp.type = exp.e1.type;
11319 assert(exp.type);
11320 auto assignElem = exp.e2;
11321 auto res = exp.op == EXP.assign ? exp.reorderSettingAAElem(sc) : exp;
11322 /* https://issues.dlang.org/show_bug.cgi?id=22366
11324 * `reorderSettingAAElem` creates a tree of comma expressions, however,
11325 * `checkAssignExp` expects only AssignExps.
11327 if (res == exp) // no `AA[k] = v` rewrite was performed
11328 checkAssignEscape(sc, res, false, false);
11329 else
11330 checkNewEscape(sc, assignElem, false); // assigning to AA puts it on heap
11332 if (auto ae = res.isConstructExp())
11334 Type t1b = ae.e1.type.toBasetype();
11335 if (t1b.ty != Tsarray && t1b.ty != Tarray)
11336 return setResult(res);
11338 // only non-trivial array constructions may need to be lowered (non-POD elements basically)
11339 Type t1e = t1b.nextOf();
11340 TypeStruct ts = t1e.baseElemOf().isTypeStruct();
11341 if (!ts || (!ts.sym.postblit && !ts.sym.hasCopyCtor && !ts.sym.dtor))
11342 return setResult(res);
11344 // don't lower ref-constructions etc.
11345 if (!(t1b.ty == Tsarray || ae.e1.isSliceExp) ||
11346 (ae.e1.isVarExp && ae.e1.isVarExp.var.isVarDeclaration.isReference))
11347 return setResult(res);
11349 // Construction from an equivalent other array?
11350 // Only lower with lvalue RHS elements; let the glue layer move rvalue elements.
11351 Type t2b = ae.e2.type.toBasetype();
11352 // skip over a (possibly implicit) cast of a static array RHS to a slice
11353 Expression rhs = ae.e2;
11354 Type rhsType = t2b;
11355 if (t2b.ty == Tarray)
11357 if (auto ce = rhs.isCastExp())
11359 auto ct = ce.e1.type.toBasetype();
11360 if (ct.ty == Tsarray)
11362 rhs = ce.e1;
11363 rhsType = ct;
11368 if (!sc.needsCodegen()) // interpreter can handle these
11369 return setResult(res);
11371 const lowerToArrayCtor =
11372 ( (rhsType.ty == Tarray && !rhs.isArrayLiteralExp) ||
11373 (rhsType.ty == Tsarray && rhs.isLvalue) ) &&
11374 t1e.equivalent(t2b.nextOf);
11376 // Construction from a single element?
11377 // If the RHS is an rvalue, then we'll need to make a temporary for it (copied multiple times).
11378 const lowerToArraySetCtor = !lowerToArrayCtor && t1e.equivalent(t2b);
11380 if (lowerToArrayCtor || lowerToArraySetCtor)
11382 auto func = lowerToArrayCtor ? Id._d_arrayctor : Id._d_arraysetctor;
11383 const other = lowerToArrayCtor ? "other array" : "value";
11384 if (!verifyHookExist(exp.loc, *sc, func, "construct array with " ~ other, Id.object))
11385 return setError();
11387 // Lower to object._d_array{,set}ctor(e1, e2)
11388 Expression id = new IdentifierExp(exp.loc, Id.empty);
11389 id = new DotIdExp(exp.loc, id, Id.object);
11390 id = new DotIdExp(exp.loc, id, func);
11392 auto arguments = new Expressions();
11393 arguments.push(new CastExp(ae.loc, ae.e1, t1e.arrayOf).expressionSemantic(sc));
11394 if (lowerToArrayCtor)
11396 arguments.push(new CastExp(ae.loc, rhs, t2b.nextOf.arrayOf).expressionSemantic(sc));
11397 Expression ce = new CallExp(exp.loc, id, arguments);
11398 res = ce.expressionSemantic(sc);
11400 else
11402 Expression e0;
11403 // promote an rvalue RHS element to a temporary, it's passed by ref to _d_arraysetctor
11404 if (!ae.e2.isLvalue)
11406 auto vd = copyToTemp(STC.scope_, "__setctor", ae.e2);
11407 e0 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc);
11408 arguments.push(new VarExp(vd.loc, vd).expressionSemantic(sc));
11410 else
11411 arguments.push(ae.e2);
11413 Expression ce = new CallExp(exp.loc, id, arguments);
11414 res = Expression.combine(e0, ce).expressionSemantic(sc);
11417 if (global.params.v.verbose)
11418 message("lowered %s =>\n %s", exp.toChars(), res.toChars());
11421 else if (auto ae = res.isAssignExp())
11422 res = lowerArrayAssign(ae);
11423 else if (auto ce = res.isCommaExp())
11425 if (auto ae1 = ce.e1.isAssignExp())
11426 ce.e1 = lowerArrayAssign(ae1, true);
11427 if (auto ae2 = ce.e2.isAssignExp())
11428 ce.e2 = lowerArrayAssign(ae2, true);
11431 return setResult(res);
11434 /***************************************
11435 * Lower AssignExp to `_d_array{setassign,assign_l,assign_r}` if needed.
11437 * Params:
11438 * ae = the AssignExp to be lowered
11439 * fromCommaExp = indicates whether `ae` is part of a CommaExp or not,
11440 * so no unnecessary temporay variable is created.
11441 * Returns:
11442 * a CommaExp contiaining call a to `_d_array{setassign,assign_l,assign_r}`
11443 * if needed or `ae` otherwise
11445 private Expression lowerArrayAssign(AssignExp ae, bool fromCommaExp = false)
11447 Type t1b = ae.e1.type.toBasetype();
11448 if (t1b.ty != Tsarray && t1b.ty != Tarray)
11449 return ae;
11451 const isArrayAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) &&
11452 (ae.e2.type.ty == Tsarray || ae.e2.type.ty == Tarray) &&
11453 (ae.e1.type.nextOf() && ae.e2.type.nextOf() && ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf()));
11455 const isArraySetAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) &&
11456 (ae.e1.type.nextOf() && ae.e2.type.implicitConvTo(ae.e1.type.nextOf()));
11458 if (!isArrayAssign && !isArraySetAssign)
11459 return ae;
11461 const ts = t1b.nextOf().baseElemOf().isTypeStruct();
11462 if (!ts || (!ts.sym.postblit && !ts.sym.dtor))
11463 return ae;
11465 Expression res;
11466 Identifier func = isArraySetAssign ? Id._d_arraysetassign :
11467 ae.e2.isLvalue() || ae.e2.isSliceExp() ? Id._d_arrayassign_l : Id._d_arrayassign_r;
11469 // Lower to `.object._d_array{setassign,assign_l,assign_r}(e1, e2)``
11470 Expression id = new IdentifierExp(ae.loc, Id.empty);
11471 id = new DotIdExp(ae.loc, id, Id.object);
11472 id = new DotIdExp(ae.loc, id, func);
11474 auto arguments = new Expressions();
11475 arguments.push(new CastExp(ae.loc, ae.e1, ae.e1.type.nextOf.arrayOf)
11476 .expressionSemantic(sc));
11478 Expression eValue2, value2 = ae.e2;
11479 if (isArrayAssign && value2.isLvalue())
11480 value2 = new CastExp(ae.loc, ae.e2, ae.e2.type.nextOf.arrayOf())
11481 .expressionSemantic(sc);
11482 else if (!fromCommaExp &&
11483 (isArrayAssign || (isArraySetAssign && !value2.isLvalue())))
11485 // Rvalues from CommaExps were introduced in `visit(AssignExp)`
11486 // and are temporary variables themselves. Rvalues from trivial
11487 // SliceExps are simply passed by reference without any copying.
11489 // `__assigntmp` will be destroyed together with the array `ae.e1`.
11490 // When `ae.e2` is a variadic arg array, it is also `scope`, so
11491 // `__assigntmp` may also be scope.
11492 StorageClass stc = STC.nodtor;
11493 if (isArrayAssign)
11494 stc |= STC.rvalue | STC.scope_;
11496 auto vd = copyToTemp(stc, "__assigntmp", ae.e2);
11497 eValue2 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc);
11498 value2 = new VarExp(vd.loc, vd).expressionSemantic(sc);
11500 arguments.push(value2);
11502 Expression ce = new CallExp(ae.loc, id, arguments);
11503 res = Expression.combine(eValue2, ce).expressionSemantic(sc);
11504 if (isArrayAssign)
11505 res = Expression.combine(res, ae.e1).expressionSemantic(sc);
11507 if (global.params.v.verbose)
11508 message("lowered %s =>\n %s", ae.toChars(), res.toChars());
11510 res = new LoweredAssignExp(ae, res);
11511 res.type = ae.type;
11513 return res;
11516 override void visit(PowAssignExp exp)
11518 if (exp.type)
11520 result = exp;
11521 return;
11524 Expression e = exp.op_overload(sc);
11525 if (e)
11527 result = e;
11528 return;
11531 if (exp.e1.checkReadModifyWrite(exp.op, exp.e2))
11532 return setError();
11534 assert(exp.e1.type && exp.e2.type);
11535 if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
11537 if (checkNonAssignmentArrayOp(exp.e1))
11538 return setError();
11540 // T[] ^^= ...
11541 if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
11543 // T[] ^^= T
11544 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
11546 else if (Expression ex = typeCombine(exp, sc))
11548 result = ex;
11549 return;
11552 // Check element types are arithmetic
11553 Type tb1 = exp.e1.type.nextOf().toBasetype();
11554 Type tb2 = exp.e2.type.toBasetype();
11555 if (tb2.ty == Tarray || tb2.ty == Tsarray)
11556 tb2 = tb2.nextOf().toBasetype();
11557 if ((tb1.isintegral() || tb1.isfloating()) && (tb2.isintegral() || tb2.isfloating()))
11559 exp.type = exp.e1.type;
11560 result = arrayOp(exp, sc);
11561 return;
11564 else
11566 exp.e1 = exp.e1.modifiableLvalue(sc);
11569 if ((exp.e1.type.isintegral() || exp.e1.type.isfloating()) && (exp.e2.type.isintegral() || exp.e2.type.isfloating()))
11571 Expression e0 = null;
11572 e = exp.reorderSettingAAElem(sc);
11573 e = Expression.extractLast(e, e0);
11574 assert(e == exp);
11576 if (exp.e1.op == EXP.variable)
11578 // Rewrite: e1 = e1 ^^ e2
11579 e = new PowExp(exp.loc, exp.e1.syntaxCopy(), exp.e2);
11580 e = new AssignExp(exp.loc, exp.e1, e);
11582 else
11584 // Rewrite: ref tmp = e1; tmp = tmp ^^ e2
11585 auto v = copyToTemp(STC.ref_, "__powtmp", exp.e1);
11586 auto de = new DeclarationExp(exp.e1.loc, v);
11587 auto ve = new VarExp(exp.e1.loc, v);
11588 e = new PowExp(exp.loc, ve, exp.e2);
11589 e = new AssignExp(exp.loc, new VarExp(exp.e1.loc, v), e);
11590 e = new CommaExp(exp.loc, de, e);
11592 e = Expression.combine(e0, e);
11593 e = e.expressionSemantic(sc);
11594 result = e;
11595 return;
11597 result = exp.incompatibleTypes();
11600 override void visit(CatAssignExp exp)
11602 if (exp.type)
11604 result = exp;
11605 return;
11608 //printf("CatAssignExp::semantic() %s\n", exp.toChars());
11609 Expression e = exp.op_overload(sc);
11610 if (e)
11612 result = e;
11613 return;
11616 if (SliceExp se = exp.e1.isSliceExp())
11618 if (se.e1.type.toBasetype().ty == Tsarray)
11620 error(exp.loc, "cannot append to static array `%s`", se.e1.type.toChars());
11621 return setError();
11625 exp.e1 = exp.e1.modifiableLvalue(sc);
11626 if (exp.e1.op == EXP.error)
11628 result = exp.e1;
11629 return;
11631 if (exp.e2.op == EXP.error)
11633 result = exp.e2;
11634 return;
11637 if (checkNonAssignmentArrayOp(exp.e2))
11638 return setError();
11640 Type tb1 = exp.e1.type.toBasetype();
11641 Type tb1next = tb1.nextOf();
11642 Type tb2 = exp.e2.type.toBasetype();
11644 /* Possibilities:
11645 * EXP.concatenateAssign: appending T[] to T[]
11646 * EXP.concatenateElemAssign: appending T to T[]
11647 * EXP.concatenateDcharAssign: appending dchar to T[]
11649 if ((tb1.ty == Tarray) &&
11650 (tb2.ty == Tarray || tb2.ty == Tsarray) &&
11651 (exp.e2.implicitConvTo(exp.e1.type) ||
11652 (tb2.nextOf().implicitConvTo(tb1next) &&
11653 (tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial)))))
11655 // EXP.concatenateAssign
11656 assert(exp.op == EXP.concatenateAssign);
11657 if (tb1next.checkPostblit(exp.e1.loc, sc))
11658 return setError();
11660 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
11662 else if ((tb1.ty == Tarray) && exp.e2.implicitConvTo(tb1next))
11664 /* https://issues.dlang.org/show_bug.cgi?id=19782
11666 * If e2 is implicitly convertible to tb1next, the conversion
11667 * might be done through alias this, in which case, e2 needs to
11668 * be modified accordingly (e2 => e2.aliasthis).
11670 if (tb2.ty == Tstruct && (cast(TypeStruct)tb2).implicitConvToThroughAliasThis(tb1next))
11671 goto Laliasthis;
11672 if (tb2.ty == Tclass && (cast(TypeClass)tb2).implicitConvToThroughAliasThis(tb1next))
11673 goto Laliasthis;
11674 // Append element
11675 if (tb2.checkPostblit(exp.e2.loc, sc))
11676 return setError();
11678 if (checkNewEscape(sc, exp.e2, false))
11679 return setError();
11681 exp = new CatElemAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, tb1next));
11682 exp.e2 = doCopyOrMove(sc, exp.e2);
11684 else if (tb1.ty == Tarray &&
11685 (tb1next.ty == Tchar || tb1next.ty == Twchar) &&
11686 exp.e2.type.ty != tb1next.ty &&
11687 exp.e2.implicitConvTo(Type.tdchar))
11689 // Append dchar to char[] or wchar[]
11690 exp = new CatDcharAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, Type.tdchar));
11692 /* Do not allow appending wchar to char[] because if wchar happens
11693 * to be a surrogate pair, nothing good can result.
11696 else
11698 // Try alias this on first operand
11699 static Expression tryAliasThisForLhs(BinAssignExp exp, Scope* sc)
11701 AggregateDeclaration ad1 = isAggregate(exp.e1.type);
11702 if (!ad1 || !ad1.aliasthis)
11703 return null;
11705 /* Rewrite (e1 op e2) as:
11706 * (e1.aliasthis op e2)
11708 if (isRecursiveAliasThis(exp.att1, exp.e1.type))
11709 return null;
11710 //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
11711 Expression e1 = new DotIdExp(exp.loc, exp.e1, ad1.aliasthis.ident);
11712 BinExp be = cast(BinExp)exp.copy();
11713 be.e1 = e1;
11714 return be.trySemantic(sc);
11717 // Try alias this on second operand
11718 static Expression tryAliasThisForRhs(BinAssignExp exp, Scope* sc)
11720 AggregateDeclaration ad2 = isAggregate(exp.e2.type);
11721 if (!ad2 || !ad2.aliasthis)
11722 return null;
11723 /* Rewrite (e1 op e2) as:
11724 * (e1 op e2.aliasthis)
11726 if (isRecursiveAliasThis(exp.att2, exp.e2.type))
11727 return null;
11728 //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
11729 Expression e2 = new DotIdExp(exp.loc, exp.e2, ad2.aliasthis.ident);
11730 BinExp be = cast(BinExp)exp.copy();
11731 be.e2 = e2;
11732 return be.trySemantic(sc);
11735 Laliasthis:
11736 result = tryAliasThisForLhs(exp, sc);
11737 if (result)
11738 return;
11740 result = tryAliasThisForRhs(exp, sc);
11741 if (result)
11742 return;
11744 error(exp.loc, "cannot append type `%s` to type `%s`", tb2.toChars(), tb1.toChars());
11745 return setError();
11748 if (exp.e2.checkValue() || exp.e2.checkSharedAccess(sc))
11749 return setError();
11751 exp.type = exp.e1.type;
11752 auto assignElem = exp.e2;
11753 auto res = exp.reorderSettingAAElem(sc);
11754 if (res != exp) // `AA[k] = v` rewrite was performed
11755 checkNewEscape(sc, assignElem, false);
11756 else if (exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign)
11757 checkAssignEscape(sc, res, false, false);
11759 result = res;
11761 if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) && sc.needsCodegen())
11763 // if aa ordering is triggered, `res` will be a CommaExp
11764 // and `.e2` will be the rewritten original expression.
11766 // `output` will point to the expression that the lowering will overwrite
11767 Expression* output;
11768 if (auto comma = res.isCommaExp())
11770 output = &comma.e2;
11771 // manual cast because it could be either CatAssignExp or CatElemAssignExp
11772 exp = cast(CatAssignExp)comma.e2;
11774 else
11776 output = &result;
11777 exp = cast(CatAssignExp)result;
11780 if (exp.op == EXP.concatenateAssign)
11782 Identifier hook = global.params.tracegc ? Id._d_arrayappendTTrace : Id._d_arrayappendT;
11784 if (!verifyHookExist(exp.loc, *sc, hook, "appending array to arrays", Id.object))
11785 return setError();
11787 // Lower to object._d_arrayappendT{,Trace}({file, line, funcname}, e1, e2)
11788 Expression id = new IdentifierExp(exp.loc, Id.empty);
11789 id = new DotIdExp(exp.loc, id, Id.object);
11790 id = new DotIdExp(exp.loc, id, hook);
11792 auto arguments = new Expressions();
11793 arguments.reserve(5);
11794 if (global.params.tracegc)
11796 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
11797 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
11798 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
11799 arguments.push(new StringExp(exp.loc, funcname.toDString()));
11802 arguments.push(exp.e1);
11803 arguments.push(exp.e2);
11804 Expression ce = new CallExp(exp.loc, id, arguments);
11806 exp.lowering = ce.expressionSemantic(sc);
11807 *output = exp;
11809 else if (exp.op == EXP.concatenateElemAssign)
11811 /* Do not lower concats to the indices array returned by
11812 *`static foreach`, as this array is only used at compile-time.
11814 if (auto ve = exp.e1.isVarExp)
11816 import core.stdc.ctype : isdigit;
11817 // The name of the indices array that static foreach loops uses.
11818 // See dmd.cond.lowerNonArrayAggregate
11819 enum varName = "__res";
11820 const(char)[] id = ve.var.ident.toString;
11821 if (ve.var.storage_class & STC.temp && id.length > varName.length &&
11822 id[0 .. varName.length] == varName && id[varName.length].isdigit)
11823 return;
11826 Identifier hook = global.params.tracegc ? Id._d_arrayappendcTXTrace : Id._d_arrayappendcTX;
11827 if (!verifyHookExist(exp.loc, *sc, hook, "appending element to arrays", Id.object))
11828 return setError();
11830 // Lower to object._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2
11831 Expression id = new IdentifierExp(exp.loc, Id.empty);
11832 id = new DotIdExp(exp.loc, id, Id.object);
11833 id = new DotIdExp(exp.loc, id, hook);
11835 auto arguments = new Expressions();
11836 arguments.reserve(5);
11837 if (global.params.tracegc)
11839 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
11840 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
11841 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
11842 arguments.push(new StringExp(exp.loc, funcname.toDString()));
11845 Expression eValue1;
11846 Expression value1 = extractSideEffect(sc, "__appendtmp", eValue1, exp.e1);
11848 arguments.push(value1);
11849 arguments.push(new IntegerExp(exp.loc, 1, Type.tsize_t));
11851 Expression ce = new CallExp(exp.loc, id, arguments);
11853 Expression eValue2;
11854 Expression value2 = exp.e2;
11855 if (!value2.isVarExp() && !value2.isConst())
11857 /* Before the template hook, this check was performed in e2ir.d
11858 * for expressions like `a ~= a[$-1]`. Here, $ will be modified
11859 * by calling `_d_arrayappendcTX`, so we need to save `a[$-1]` in
11860 * a temporary variable.
11862 value2 = extractSideEffect(sc, "__appendtmp", eValue2, value2, true);
11864 // `__appendtmp*` will be destroyed together with the array `exp.e1`.
11865 auto vd = eValue2.isDeclarationExp().declaration.isVarDeclaration();
11866 vd.storage_class |= STC.nodtor;
11867 // Be more explicit that this "declaration" is local to the expression
11868 vd.storage_class |= STC.exptemp;
11871 auto ale = new ArrayLengthExp(exp.loc, value1);
11872 auto elem = new IndexExp(exp.loc, value1, new MinExp(exp.loc, ale, IntegerExp.literal!1));
11873 auto ae = new ConstructExp(exp.loc, elem, value2);
11875 auto e0 = Expression.combine(ce, ae).expressionSemantic(sc);
11876 e0 = Expression.combine(e0, value1);
11877 e0 = Expression.combine(eValue1, e0);
11878 e0 = Expression.combine(eValue2, e0);
11880 exp.lowering = e0.expressionSemantic(sc);
11881 *output = exp;
11886 override void visit(AddExp exp)
11888 static if (LOGSEMANTIC)
11890 printf("AddExp::semantic('%s')\n", exp.toChars());
11892 if (exp.type)
11894 result = exp;
11895 return;
11898 if (Expression ex = binSemanticProp(exp, sc))
11900 result = ex;
11901 return;
11903 Expression e = exp.op_overload(sc);
11904 if (e)
11906 result = e;
11907 return;
11910 /* ImportC: convert arrays to pointers, functions to pointers to functions
11912 exp.e1 = exp.e1.arrayFuncConv(sc);
11913 exp.e2 = exp.e2.arrayFuncConv(sc);
11915 Type tb1 = exp.e1.type.toBasetype();
11916 Type tb2 = exp.e2.type.toBasetype();
11918 bool err = false;
11919 if (tb1.ty == Tdelegate || tb1.isPtrToFunction())
11921 err |= exp.e1.checkArithmetic(exp.op) || exp.e1.checkSharedAccess(sc);
11923 if (tb2.ty == Tdelegate || tb2.isPtrToFunction())
11925 err |= exp.e2.checkArithmetic(exp.op) || exp.e2.checkSharedAccess(sc);
11927 if (err)
11928 return setError();
11930 if (tb1.ty == Tpointer && exp.e2.type.isintegral() || tb2.ty == Tpointer && exp.e1.type.isintegral())
11932 result = scaleFactor(exp, sc);
11933 return;
11936 if (tb1.ty == Tpointer && tb2.ty == Tpointer)
11938 result = exp.incompatibleTypes();
11939 return;
11942 if (Expression ex = typeCombine(exp, sc))
11944 result = ex;
11945 return;
11948 Type tb = exp.type.toBasetype();
11949 if (tb.ty == Tarray || tb.ty == Tsarray)
11951 if (!isArrayOpValid(exp))
11953 result = arrayOpInvalidError(exp);
11954 return;
11956 result = exp;
11957 return;
11960 tb1 = exp.e1.type.toBasetype();
11961 if (!target.isVectorOpSupported(tb1, exp.op, tb2))
11963 result = exp.incompatibleTypes();
11964 return;
11966 if ((tb1.isreal() && exp.e2.type.isimaginary()) || (tb1.isimaginary() && exp.e2.type.isreal()))
11968 switch (exp.type.toBasetype().ty)
11970 case Tfloat32:
11971 case Timaginary32:
11972 exp.type = Type.tcomplex32;
11973 break;
11975 case Tfloat64:
11976 case Timaginary64:
11977 exp.type = Type.tcomplex64;
11978 break;
11980 case Tfloat80:
11981 case Timaginary80:
11982 exp.type = Type.tcomplex80;
11983 break;
11985 default:
11986 assert(0);
11989 result = exp;
11992 override void visit(MinExp exp)
11994 static if (LOGSEMANTIC)
11996 printf("MinExp::semantic('%s')\n", exp.toChars());
11998 if (exp.type)
12000 result = exp;
12001 return;
12004 if (Expression ex = binSemanticProp(exp, sc))
12006 result = ex;
12007 return;
12009 Expression e = exp.op_overload(sc);
12010 if (e)
12012 result = e;
12013 return;
12016 /* ImportC: convert arrays to pointers, functions to pointers to functions
12018 exp.e1 = exp.e1.arrayFuncConv(sc);
12019 exp.e2 = exp.e2.arrayFuncConv(sc);
12021 Type t1 = exp.e1.type.toBasetype();
12022 Type t2 = exp.e2.type.toBasetype();
12024 bool err = false;
12025 if (t1.ty == Tdelegate || t1.isPtrToFunction())
12027 err |= exp.e1.checkArithmetic(exp.op) || exp.e1.checkSharedAccess(sc);
12029 if (t2.ty == Tdelegate || t2.isPtrToFunction())
12031 err |= exp.e2.checkArithmetic(exp.op) || exp.e2.checkSharedAccess(sc);
12033 if (err)
12034 return setError();
12036 if (t1.ty == Tpointer)
12038 if (t2.ty == Tpointer)
12040 // https://dlang.org/spec/expression.html#add_expressions
12041 // "If both operands are pointers, and the operator is -, the pointers are
12042 // subtracted and the result is divided by the size of the type pointed to
12043 // by the operands. It is an error if the pointers point to different types."
12044 Type p1 = t1.nextOf();
12045 Type p2 = t2.nextOf();
12047 if (!p1.equivalent(p2))
12049 // Deprecation to remain for at least a year, after which this should be
12050 // changed to an error
12051 // See https://github.com/dlang/dmd/pull/7332
12052 deprecation(exp.loc,
12053 "cannot subtract pointers to different types: `%s` and `%s`.",
12054 t1.toChars(), t2.toChars());
12057 // Need to divide the result by the stride
12058 // Replace (ptr - ptr) with (ptr - ptr) / stride
12059 long stride;
12061 // make sure pointer types are compatible
12062 if (Expression ex = typeCombine(exp, sc))
12064 result = ex;
12065 return;
12068 exp.type = Type.tptrdiff_t;
12069 stride = t2.nextOf().size();
12070 if (stride == 0)
12072 e = new IntegerExp(exp.loc, 0, Type.tptrdiff_t);
12074 else if (stride == cast(long)SIZE_INVALID)
12075 e = ErrorExp.get();
12076 else
12078 e = new DivExp(exp.loc, exp, new IntegerExp(Loc.initial, stride, Type.tptrdiff_t));
12079 e.type = Type.tptrdiff_t;
12082 else if (t2.isintegral())
12083 e = scaleFactor(exp, sc);
12084 else
12086 error(exp.loc, "can't subtract `%s` from pointer", t2.toChars());
12087 e = ErrorExp.get();
12089 result = e;
12090 return;
12092 if (t2.ty == Tpointer)
12094 exp.type = exp.e2.type;
12095 error(exp.loc, "can't subtract pointer from `%s`", exp.e1.type.toChars());
12096 return setError();
12099 if (Expression ex = typeCombine(exp, sc))
12101 result = ex;
12102 return;
12105 Type tb = exp.type.toBasetype();
12106 if (tb.ty == Tarray || tb.ty == Tsarray)
12108 if (!isArrayOpValid(exp))
12110 result = arrayOpInvalidError(exp);
12111 return;
12113 result = exp;
12114 return;
12117 t1 = exp.e1.type.toBasetype();
12118 t2 = exp.e2.type.toBasetype();
12119 if (!target.isVectorOpSupported(t1, exp.op, t2))
12121 result = exp.incompatibleTypes();
12122 return;
12124 if ((t1.isreal() && t2.isimaginary()) || (t1.isimaginary() && t2.isreal()))
12126 switch (exp.type.ty)
12128 case Tfloat32:
12129 case Timaginary32:
12130 exp.type = Type.tcomplex32;
12131 break;
12133 case Tfloat64:
12134 case Timaginary64:
12135 exp.type = Type.tcomplex64;
12136 break;
12138 case Tfloat80:
12139 case Timaginary80:
12140 exp.type = Type.tcomplex80;
12141 break;
12143 default:
12144 assert(0);
12147 result = exp;
12148 return;
12152 * If the given expression is a `CatExp`, the function tries to lower it to
12153 * `_d_arraycatnTX`.
12155 * Params:
12156 * ee = the `CatExp` to lower
12157 * Returns:
12158 * `_d_arraycatnTX(e1, e2, ..., en)` if `ee` is `e1 ~ e2 ~ ... en`
12159 * `ee` otherwise
12161 private Expression lowerToArrayCat(CatExp exp)
12163 // String literals are concatenated by the compiler. No lowering is needed.
12164 if ((exp.e1.isStringExp() && (exp.e2.isIntegerExp() || exp.e2.isStringExp())) ||
12165 (exp.e2.isStringExp() && (exp.e1.isIntegerExp() || exp.e1.isStringExp())))
12166 return exp;
12168 bool useTraceGCHook = global.params.tracegc && sc.needsCodegen();
12170 Identifier hook = useTraceGCHook ? Id._d_arraycatnTXTrace : Id._d_arraycatnTX;
12171 if (!verifyHookExist(exp.loc, *sc, hook, "concatenating arrays"))
12173 setError();
12174 return result;
12177 void handleCatArgument(Expressions *arguments, Expression e)
12179 if (auto ce = e.isCatExp())
12181 Expression lowering = ce.lowering;
12183 /* Skip `file`, `line`, and `funcname` if the hook of the parent
12184 * `CatExp` is `_d_arraycatnTXTrace`.
12186 if (auto callExp = isRuntimeHook(lowering, hook))
12188 if (hook == Id._d_arraycatnTX)
12189 arguments.pushSlice((*callExp.arguments)[]);
12190 else
12191 arguments.pushSlice((*callExp.arguments)[3 .. $]);
12194 else
12195 arguments.push(e);
12198 auto arguments = new Expressions();
12199 if (useTraceGCHook)
12201 auto funcname = (sc.callsc && sc.callsc.func) ?
12202 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
12203 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
12204 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
12205 arguments.push(new StringExp(exp.loc, funcname.toDString()));
12208 handleCatArgument(arguments, exp.e1);
12209 handleCatArgument(arguments, exp.e2);
12211 Expression id = new IdentifierExp(exp.loc, Id.empty);
12212 id = new DotIdExp(exp.loc, id, Id.object);
12214 auto tiargs = new Objects();
12215 tiargs.push(exp.type);
12216 id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs);
12217 id = new CallExp(exp.loc, id, arguments);
12218 return id.expressionSemantic(sc);
12221 void trySetCatExpLowering(Expression exp)
12223 /* `_d_arraycatnTX` canot be used with `-betterC`, but `CatExp`s may be
12224 * used with `-betterC`, but only during CTFE.
12226 if (!global.params.useGC)
12227 return;
12229 if (auto ce = exp.isCatExp())
12230 ce.lowering = lowerToArrayCat(ce);
12233 override void visit(CatExp exp)
12235 // https://dlang.org/spec/expression.html#cat_expressions
12236 //printf("CatExp.semantic() %s\n", toChars());
12237 if (exp.type)
12239 result = exp;
12240 return;
12243 if (Expression ex = binSemanticProp(exp, sc))
12245 result = ex;
12246 return;
12248 Expression e = exp.op_overload(sc);
12249 if (e)
12251 result = e;
12252 return;
12255 Type tb1 = exp.e1.type.toBasetype();
12256 Type tb2 = exp.e2.type.toBasetype();
12258 auto f1 = checkNonAssignmentArrayOp(exp.e1);
12259 auto f2 = checkNonAssignmentArrayOp(exp.e2);
12260 if (f1 || f2)
12261 return setError();
12263 Type tb1next = tb1.nextOf();
12264 Type tb2next = tb2.nextOf();
12266 // Check for: array ~ array
12267 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)))
12269 /* https://issues.dlang.org/show_bug.cgi?id=9248
12270 * Here to avoid the case of:
12271 * void*[] a = [cast(void*)1];
12272 * void*[] b = [cast(void*)2];
12273 * a ~ b;
12274 * becoming:
12275 * a ~ [cast(void*)b];
12278 /* https://issues.dlang.org/show_bug.cgi?id=14682
12279 * Also to avoid the case of:
12280 * int[][] a;
12281 * a ~ [];
12282 * becoming:
12283 * a ~ cast(int[])[];
12285 goto Lpeer;
12288 // Check for: array ~ element
12289 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && tb2.ty != Tvoid)
12291 if (exp.e1.op == EXP.arrayLiteral)
12293 exp.e2 = doCopyOrMove(sc, exp.e2);
12294 // https://issues.dlang.org/show_bug.cgi?id=14686
12295 // Postblit call appears in AST, and this is
12296 // finally translated to an ArrayLiteralExp in below optimize().
12298 else if (exp.e1.op == EXP.string_)
12300 // No postblit call exists on character (integer) value.
12302 else
12304 if (tb2.checkPostblit(exp.e2.loc, sc))
12305 return setError();
12306 // Postblit call will be done in runtime helper function
12309 if (exp.e1.op == EXP.arrayLiteral && exp.e1.implicitConvTo(tb2.arrayOf()))
12311 exp.e1 = exp.e1.implicitCastTo(sc, tb2.arrayOf());
12312 exp.type = tb2.arrayOf();
12313 goto L2elem;
12315 if (exp.e2.implicitConvTo(tb1next) >= MATCH.convert)
12317 exp.e2 = exp.e2.implicitCastTo(sc, tb1next);
12318 exp.type = tb1next.arrayOf();
12319 L2elem:
12320 if (checkNewEscape(sc, exp.e2, false))
12321 return setError();
12322 result = exp.optimize(WANTvalue);
12323 trySetCatExpLowering(result);
12324 return;
12327 // Check for: element ~ array
12328 if ((tb2.ty == Tsarray || tb2.ty == Tarray) && tb1.ty != Tvoid)
12330 if (exp.e2.op == EXP.arrayLiteral)
12332 exp.e1 = doCopyOrMove(sc, exp.e1);
12334 else if (exp.e2.op == EXP.string_)
12337 else
12339 if (tb1.checkPostblit(exp.e1.loc, sc))
12340 return setError();
12343 if (exp.e2.op == EXP.arrayLiteral && exp.e2.implicitConvTo(tb1.arrayOf()))
12345 exp.e2 = exp.e2.implicitCastTo(sc, tb1.arrayOf());
12346 exp.type = tb1.arrayOf();
12347 goto L1elem;
12349 if (exp.e1.implicitConvTo(tb2next) >= MATCH.convert)
12351 exp.e1 = exp.e1.implicitCastTo(sc, tb2next);
12352 exp.type = tb2next.arrayOf();
12353 L1elem:
12354 if (checkNewEscape(sc, exp.e1, false))
12355 return setError();
12356 result = exp.optimize(WANTvalue);
12357 trySetCatExpLowering(result);
12358 return;
12362 Lpeer:
12363 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && (tb2.ty == Tsarray || tb2.ty == Tarray) && (tb1next.mod || tb2next.mod) && (tb1next.mod != tb2next.mod))
12365 Type t1 = tb1next.mutableOf().constOf().arrayOf();
12366 Type t2 = tb2next.mutableOf().constOf().arrayOf();
12367 if (exp.e1.op == EXP.string_ && !(cast(StringExp)exp.e1).committed)
12368 exp.e1.type = t1;
12369 else
12370 exp.e1 = exp.e1.castTo(sc, t1);
12371 if (exp.e2.op == EXP.string_ && !(cast(StringExp)exp.e2).committed)
12372 exp.e2.type = t2;
12373 else
12374 exp.e2 = exp.e2.castTo(sc, t2);
12377 if (Expression ex = typeCombine(exp, sc))
12379 result = ex;
12380 trySetCatExpLowering(result);
12381 return;
12383 exp.type = exp.type.toHeadMutable();
12385 Type tb = exp.type.toBasetype();
12386 if (tb.ty == Tsarray)
12387 exp.type = tb.nextOf().arrayOf();
12388 if (exp.type.ty == Tarray && tb1next && tb2next && tb1next.mod != tb2next.mod)
12390 exp.type = exp.type.nextOf().toHeadMutable().arrayOf();
12392 if (Type tbn = tb.nextOf())
12394 if (tbn.checkPostblit(exp.loc, sc))
12395 return setError();
12397 Type t1 = exp.e1.type.toBasetype();
12398 Type t2 = exp.e2.type.toBasetype();
12399 if ((t1.ty == Tarray || t1.ty == Tsarray) &&
12400 (t2.ty == Tarray || t2.ty == Tsarray))
12402 // Normalize to ArrayLiteralExp or StringExp as far as possible
12403 e = exp.optimize(WANTvalue);
12405 else
12407 //printf("(%s) ~ (%s)\n", e1.toChars(), e2.toChars());
12408 result = exp.incompatibleTypes();
12409 return;
12412 result = e;
12413 trySetCatExpLowering(result);
12416 override void visit(MulExp exp)
12418 version (none)
12420 printf("MulExp::semantic() %s\n", exp.toChars());
12422 if (exp.type)
12424 result = exp;
12425 return;
12428 if (Expression ex = binSemanticProp(exp, sc))
12430 result = ex;
12431 return;
12433 Expression e = exp.op_overload(sc);
12434 if (e)
12436 result = e;
12437 return;
12440 if (Expression ex = typeCombine(exp, sc))
12442 result = ex;
12443 return;
12446 Type tb = exp.type.toBasetype();
12447 if (tb.ty == Tarray || tb.ty == Tsarray)
12449 if (!isArrayOpValid(exp))
12451 result = arrayOpInvalidError(exp);
12452 return;
12454 result = exp;
12455 return;
12458 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
12459 return setError();
12461 if (exp.type.isfloating())
12463 Type t1 = exp.e1.type;
12464 Type t2 = exp.e2.type;
12466 if (t1.isreal())
12468 exp.type = t2;
12470 else if (t2.isreal())
12472 exp.type = t1;
12474 else if (t1.isimaginary())
12476 if (t2.isimaginary())
12478 switch (t1.toBasetype().ty)
12480 case Timaginary32:
12481 exp.type = Type.tfloat32;
12482 break;
12484 case Timaginary64:
12485 exp.type = Type.tfloat64;
12486 break;
12488 case Timaginary80:
12489 exp.type = Type.tfloat80;
12490 break;
12492 default:
12493 assert(0);
12496 // iy * iv = -yv
12497 exp.e1.type = exp.type;
12498 exp.e2.type = exp.type;
12499 e = new NegExp(exp.loc, exp);
12500 e = e.expressionSemantic(sc);
12501 result = e;
12502 return;
12504 else
12505 exp.type = t2; // t2 is complex
12507 else if (t2.isimaginary())
12509 exp.type = t1; // t1 is complex
12512 else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12514 result = exp.incompatibleTypes();
12515 return;
12517 result = exp;
12520 override void visit(DivExp exp)
12522 if (exp.type)
12524 result = exp;
12525 return;
12528 if (Expression ex = binSemanticProp(exp, sc))
12530 result = ex;
12531 return;
12533 Expression e = exp.op_overload(sc);
12534 if (e)
12536 result = e;
12537 return;
12540 if (Expression ex = typeCombine(exp, sc))
12542 result = ex;
12543 return;
12546 Type tb = exp.type.toBasetype();
12547 if (tb.ty == Tarray || tb.ty == Tsarray)
12549 if (!isArrayOpValid(exp))
12551 result = arrayOpInvalidError(exp);
12552 return;
12554 result = exp;
12555 return;
12558 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
12559 return setError();
12561 if (exp.type.isfloating())
12563 Type t1 = exp.e1.type;
12564 Type t2 = exp.e2.type;
12566 if (t1.isreal())
12568 exp.type = t2;
12569 if (t2.isimaginary())
12571 // x/iv = i(-x/v)
12572 exp.e2.type = t1;
12573 e = new NegExp(exp.loc, exp);
12574 e = e.expressionSemantic(sc);
12575 result = e;
12576 return;
12579 else if (t2.isreal())
12581 exp.type = t1;
12583 else if (t1.isimaginary())
12585 if (t2.isimaginary())
12587 switch (t1.toBasetype().ty)
12589 case Timaginary32:
12590 exp.type = Type.tfloat32;
12591 break;
12593 case Timaginary64:
12594 exp.type = Type.tfloat64;
12595 break;
12597 case Timaginary80:
12598 exp.type = Type.tfloat80;
12599 break;
12601 default:
12602 assert(0);
12605 else
12606 exp.type = t2; // t2 is complex
12608 else if (t2.isimaginary())
12610 exp.type = t1; // t1 is complex
12613 else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12615 result = exp.incompatibleTypes();
12616 return;
12618 result = exp;
12621 override void visit(ModExp exp)
12623 if (exp.type)
12625 result = exp;
12626 return;
12629 if (Expression ex = binSemanticProp(exp, sc))
12631 result = ex;
12632 return;
12634 Expression e = exp.op_overload(sc);
12635 if (e)
12637 result = e;
12638 return;
12641 if (Expression ex = typeCombine(exp, sc))
12643 result = ex;
12644 return;
12647 Type tb = exp.type.toBasetype();
12648 if (tb.ty == Tarray || tb.ty == Tsarray)
12650 if (!isArrayOpValid(exp))
12652 result = arrayOpInvalidError(exp);
12653 return;
12655 result = exp;
12656 return;
12658 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12660 result = exp.incompatibleTypes();
12661 return;
12664 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
12665 return setError();
12667 if (exp.type.isfloating())
12669 exp.type = exp.e1.type;
12670 if (exp.e2.type.iscomplex())
12672 error(exp.loc, "cannot perform modulo complex arithmetic");
12673 return setError();
12676 result = exp;
12679 override void visit(PowExp exp)
12681 if (exp.type)
12683 result = exp;
12684 return;
12687 //printf("PowExp::semantic() %s\n", toChars());
12688 if (Expression ex = binSemanticProp(exp, sc))
12690 result = ex;
12691 return;
12693 Expression e = exp.op_overload(sc);
12694 if (e)
12696 result = e;
12697 return;
12700 if (Expression ex = typeCombine(exp, sc))
12702 result = ex;
12703 return;
12706 Type tb = exp.type.toBasetype();
12707 if (tb.ty == Tarray || tb.ty == Tsarray)
12709 if (!isArrayOpValid(exp))
12711 result = arrayOpInvalidError(exp);
12712 return;
12714 result = exp;
12715 return;
12718 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
12719 return setError();
12721 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12723 result = exp.incompatibleTypes();
12724 return;
12727 // First, attempt to fold the expression.
12728 e = exp.optimize(WANTvalue);
12729 if (e.op != EXP.pow)
12731 e = e.expressionSemantic(sc);
12732 result = e;
12733 return;
12736 Module mmath = Module.loadStdMath();
12737 if (!mmath)
12739 error(e.loc, "`%s` requires `std.math` for `^^` operators", e.toChars());
12740 return setError();
12742 e = new ScopeExp(exp.loc, mmath);
12744 if (exp.e2.op == EXP.float64 && exp.e2.toReal() == CTFloat.half)
12746 // Replace e1 ^^ 0.5 with .std.math.sqrt(e1)
12747 e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._sqrt), exp.e1);
12749 else
12751 // Replace e1 ^^ e2 with .std.math.pow(e1, e2)
12752 e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._pow), exp.e1, exp.e2);
12754 e = e.expressionSemantic(sc);
12755 result = e;
12756 return;
12759 override void visit(ShlExp exp)
12761 //printf("ShlExp::semantic(), type = %p\n", type);
12762 if (exp.type)
12764 result = exp;
12765 return;
12768 if (Expression ex = binSemanticProp(exp, sc))
12770 result = ex;
12771 return;
12773 Expression e = exp.op_overload(sc);
12774 if (e)
12776 result = e;
12777 return;
12780 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
12781 return setError();
12783 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
12785 result = exp.incompatibleTypes();
12786 return;
12788 exp.e1 = integralPromotions(exp.e1, sc);
12789 if (exp.e2.type.toBasetype().ty != Tvector)
12790 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
12792 exp.type = exp.e1.type;
12793 result = exp;
12796 override void visit(ShrExp exp)
12798 if (exp.type)
12800 result = exp;
12801 return;
12804 if (Expression ex = binSemanticProp(exp, sc))
12806 result = ex;
12807 return;
12809 Expression e = exp.op_overload(sc);
12810 if (e)
12812 result = e;
12813 return;
12816 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
12817 return setError();
12819 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
12821 result = exp.incompatibleTypes();
12822 return;
12824 exp.e1 = integralPromotions(exp.e1, sc);
12825 if (exp.e2.type.toBasetype().ty != Tvector)
12826 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
12828 exp.type = exp.e1.type;
12829 result = exp;
12832 override void visit(UshrExp exp)
12834 if (exp.type)
12836 result = exp;
12837 return;
12840 if (Expression ex = binSemanticProp(exp, sc))
12842 result = ex;
12843 return;
12845 Expression e = exp.op_overload(sc);
12846 if (e)
12848 result = e;
12849 return;
12852 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
12853 return setError();
12855 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
12857 result = exp.incompatibleTypes();
12858 return;
12860 exp.e1 = integralPromotions(exp.e1, sc);
12861 if (exp.e2.type.toBasetype().ty != Tvector)
12862 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
12864 exp.type = exp.e1.type;
12865 result = exp;
12868 override void visit(AndExp exp)
12870 if (exp.type)
12872 result = exp;
12873 return;
12876 if (Expression ex = binSemanticProp(exp, sc))
12878 result = ex;
12879 return;
12881 Expression e = exp.op_overload(sc);
12882 if (e)
12884 result = e;
12885 return;
12888 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
12890 exp.type = exp.e1.type;
12891 result = exp;
12892 return;
12895 if (Expression ex = typeCombine(exp, sc))
12897 result = ex;
12898 return;
12901 Type tb = exp.type.toBasetype();
12902 if (tb.ty == Tarray || tb.ty == Tsarray)
12904 if (!isArrayOpValid(exp))
12906 result = arrayOpInvalidError(exp);
12907 return;
12909 result = exp;
12910 return;
12912 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12914 result = exp.incompatibleTypes();
12915 return;
12917 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
12918 return setError();
12920 result = exp;
12923 override void visit(OrExp exp)
12925 if (exp.type)
12927 result = exp;
12928 return;
12931 if (Expression ex = binSemanticProp(exp, sc))
12933 result = ex;
12934 return;
12936 Expression e = exp.op_overload(sc);
12937 if (e)
12939 result = e;
12940 return;
12943 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
12945 exp.type = exp.e1.type;
12946 result = exp;
12947 return;
12950 if (Expression ex = typeCombine(exp, sc))
12952 result = ex;
12953 return;
12956 Type tb = exp.type.toBasetype();
12957 if (tb.ty == Tarray || tb.ty == Tsarray)
12959 if (!isArrayOpValid(exp))
12961 result = arrayOpInvalidError(exp);
12962 return;
12964 result = exp;
12965 return;
12967 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12969 result = exp.incompatibleTypes();
12970 return;
12972 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
12973 return setError();
12975 result = exp;
12978 override void visit(XorExp exp)
12980 if (exp.type)
12982 result = exp;
12983 return;
12986 if (Expression ex = binSemanticProp(exp, sc))
12988 result = ex;
12989 return;
12991 Expression e = exp.op_overload(sc);
12992 if (e)
12994 result = e;
12995 return;
12998 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
13000 exp.type = exp.e1.type;
13001 result = exp;
13002 return;
13005 if (Expression ex = typeCombine(exp, sc))
13007 result = ex;
13008 return;
13011 Type tb = exp.type.toBasetype();
13012 if (tb.ty == Tarray || tb.ty == Tsarray)
13014 if (!isArrayOpValid(exp))
13016 result = arrayOpInvalidError(exp);
13017 return;
13019 result = exp;
13020 return;
13022 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
13024 result = exp.incompatibleTypes();
13025 return;
13027 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
13028 return setError();
13030 result = exp;
13033 override void visit(LogicalExp exp)
13035 static if (LOGSEMANTIC)
13037 printf("LogicalExp::semantic() %s\n", exp.toChars());
13040 if (exp.type)
13042 result = exp;
13043 return;
13046 exp.setNoderefOperands();
13048 Expression e1x = exp.e1.expressionSemantic(sc);
13050 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
13051 if (e1x.op == EXP.type)
13052 e1x = resolveAliasThis(sc, e1x);
13054 e1x = resolveProperties(sc, e1x);
13055 e1x = e1x.toBoolean(sc);
13057 if (sc.flags & SCOPE.condition)
13059 /* If in static if, don't evaluate e2 if we don't have to.
13061 e1x = e1x.optimize(WANTvalue);
13062 if (e1x.toBool().hasValue(exp.op == EXP.orOr))
13064 if (sc.flags & SCOPE.Cfile)
13065 result = new IntegerExp(exp.op == EXP.orOr);
13066 else
13067 result = IntegerExp.createBool(exp.op == EXP.orOr);
13068 return;
13072 CtorFlow ctorflow = sc.ctorflow.clone();
13073 Expression e2x = exp.e2.expressionSemantic(sc);
13074 sc.merge(exp.loc, ctorflow);
13075 ctorflow.freeFieldinit();
13077 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
13078 if (e2x.op == EXP.type)
13079 e2x = resolveAliasThis(sc, e2x);
13081 e2x = resolveProperties(sc, e2x);
13083 auto f1 = checkNonAssignmentArrayOp(e1x);
13084 auto f2 = checkNonAssignmentArrayOp(e2x);
13085 if (f1 || f2)
13086 return setError();
13088 // Unless the right operand is 'void', the expression is converted to 'bool'.
13089 if (e2x.type.ty != Tvoid)
13090 e2x = e2x.toBoolean(sc);
13092 if (e2x.op == EXP.type || e2x.op == EXP.scope_)
13094 error(exp.loc, "`%s` is not an expression", exp.e2.toChars());
13095 return setError();
13097 if (e1x.op == EXP.error || e1x.type.ty == Tnoreturn)
13099 result = e1x;
13100 return;
13102 if (e2x.op == EXP.error)
13104 result = e2x;
13105 return;
13108 // The result type is 'bool', unless the right operand has type 'void'.
13109 if (e2x.type.ty == Tvoid)
13110 exp.type = Type.tvoid;
13111 else
13112 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
13114 exp.e1 = e1x;
13115 exp.e2 = e2x;
13116 result = exp;
13120 override void visit(CmpExp exp)
13122 static if (LOGSEMANTIC)
13124 printf("CmpExp::semantic('%s')\n", exp.toChars());
13126 if (exp.type)
13128 result = exp;
13129 return;
13132 exp.setNoderefOperands();
13134 if (Expression ex = binSemanticProp(exp, sc))
13136 result = ex;
13137 return;
13139 Type t1 = exp.e1.type.toBasetype();
13140 Type t2 = exp.e2.type.toBasetype();
13141 if (t1.ty == Tclass && exp.e2.op == EXP.null_ || t2.ty == Tclass && exp.e1.op == EXP.null_)
13143 error(exp.loc, "do not use `null` when comparing class types");
13144 return setError();
13148 EXP cmpop = exp.op;
13149 if (auto e = exp.op_overload(sc, &cmpop))
13151 if (!e.type.isscalar() && e.type.equals(exp.e1.type))
13153 error(exp.loc, "recursive `opCmp` expansion");
13154 return setError();
13156 if (e.op == EXP.call)
13159 if (t1.ty == Tclass && t2.ty == Tclass)
13161 // Lower to object.__cmp(e1, e2)
13162 Expression cl = new IdentifierExp(exp.loc, Id.empty);
13163 cl = new DotIdExp(exp.loc, cl, Id.object);
13164 cl = new DotIdExp(exp.loc, cl, Id.__cmp);
13165 cl = cl.expressionSemantic(sc);
13167 auto arguments = new Expressions();
13168 // Check if op_overload found a better match by calling e2.opCmp(e1)
13169 // If the operands were swapped, then the result must be reversed
13170 // e1.opCmp(e2) == -e2.opCmp(e1)
13171 // cmpop takes care of this
13172 if (exp.op == cmpop)
13174 arguments.push(exp.e1);
13175 arguments.push(exp.e2);
13177 else
13179 // Use better match found by op_overload
13180 arguments.push(exp.e2);
13181 arguments.push(exp.e1);
13184 cl = new CallExp(exp.loc, cl, arguments);
13185 cl = new CmpExp(cmpop, exp.loc, cl, new IntegerExp(0));
13186 result = cl.expressionSemantic(sc);
13187 return;
13190 e = new CmpExp(cmpop, exp.loc, e, IntegerExp.literal!0);
13191 e = e.expressionSemantic(sc);
13193 result = e;
13194 return;
13198 if (Expression ex = typeCombine(exp, sc))
13200 result = ex;
13201 return;
13204 auto f1 = checkNonAssignmentArrayOp(exp.e1);
13205 auto f2 = checkNonAssignmentArrayOp(exp.e2);
13206 if (f1 || f2)
13207 return setError();
13209 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
13211 // Special handling for array comparisons
13212 Expression arrayLowering = null;
13213 t1 = exp.e1.type.toBasetype();
13214 t2 = exp.e2.type.toBasetype();
13215 if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && (t2.ty == Tarray || t2.ty == Tsarray || t2.ty == Tpointer))
13217 Type t1next = t1.nextOf();
13218 Type t2next = t2.nextOf();
13219 if (t1next.implicitConvTo(t2next) < MATCH.constant && t2next.implicitConvTo(t1next) < MATCH.constant && (t1next.ty != Tvoid && t2next.ty != Tvoid))
13221 error(exp.loc, "array comparison type mismatch, `%s` vs `%s`", t1next.toChars(), t2next.toChars());
13222 return setError();
13225 if ((t1.ty == Tarray || t1.ty == Tsarray) &&
13226 (t2.ty == Tarray || t2.ty == Tsarray))
13228 if (!verifyHookExist(exp.loc, *sc, Id.__cmp, "comparing arrays"))
13229 return setError();
13231 // Lower to object.__cmp(e1, e2)
13232 Expression al = new IdentifierExp(exp.loc, Id.empty);
13233 al = new DotIdExp(exp.loc, al, Id.object);
13234 al = new DotIdExp(exp.loc, al, Id.__cmp);
13235 al = al.expressionSemantic(sc);
13237 auto arguments = new Expressions(2);
13238 (*arguments)[0] = exp.e1;
13239 (*arguments)[1] = exp.e2;
13241 al = new CallExp(exp.loc, al, arguments);
13242 al = new CmpExp(exp.op, exp.loc, al, IntegerExp.literal!0);
13244 arrayLowering = al;
13247 else if (t1.ty == Tstruct || t2.ty == Tstruct || (t1.ty == Tclass && t2.ty == Tclass))
13249 if (t2.ty == Tstruct)
13250 error(exp.loc, "need member function `opCmp()` for %s `%s` to compare", t2.toDsymbol(sc).kind(), t2.toChars());
13251 else
13252 error(exp.loc, "need member function `opCmp()` for %s `%s` to compare", t1.toDsymbol(sc).kind(), t1.toChars());
13253 return setError();
13255 else if (t1.iscomplex() || t2.iscomplex())
13257 error(exp.loc, "compare not defined for complex operands");
13258 return setError();
13260 else if (t1.ty == Taarray || t2.ty == Taarray)
13262 error(exp.loc, "`%s` is not defined for associative arrays", EXPtoString(exp.op).ptr);
13263 return setError();
13265 else if (!target.isVectorOpSupported(t1, exp.op, t2))
13267 result = exp.incompatibleTypes();
13268 return;
13270 else
13272 bool r1 = exp.e1.checkValue() || exp.e1.checkSharedAccess(sc);
13273 bool r2 = exp.e2.checkValue() || exp.e2.checkSharedAccess(sc);
13274 if (r1 || r2)
13275 return setError();
13278 //printf("CmpExp: %s, type = %s\n", e.toChars(), e.type.toChars());
13279 if (arrayLowering)
13281 arrayLowering = arrayLowering.expressionSemantic(sc);
13282 result = arrayLowering;
13283 return;
13286 if (auto tv = t1.isTypeVector())
13287 exp.type = tv.toBooleanVector();
13289 result = exp;
13290 return;
13293 override void visit(InExp exp)
13295 if (exp.type)
13297 result = exp;
13298 return;
13301 if (Expression ex = binSemanticProp(exp, sc))
13303 result = ex;
13304 return;
13306 Expression e = exp.op_overload(sc);
13307 if (e)
13309 result = e;
13310 return;
13313 Type t2b = exp.e2.type.toBasetype();
13314 switch (t2b.ty)
13316 case Taarray:
13318 TypeAArray ta = cast(TypeAArray)t2b;
13320 // Special handling for array keys
13321 if (!arrayTypeCompatibleWithoutCasting(exp.e1.type, ta.index))
13323 // Convert key to type of key
13324 exp.e1 = exp.e1.implicitCastTo(sc, ta.index);
13327 semanticTypeInfo(sc, ta.index);
13329 // Return type is pointer to value
13330 exp.type = ta.nextOf().pointerTo();
13331 break;
13334 case Terror:
13335 return setError();
13337 case Tarray, Tsarray:
13338 result = exp.incompatibleTypes();
13339 errorSupplemental(exp.loc, "`in` is only allowed on associative arrays");
13340 const(char)* slice = (t2b.ty == Tsarray) ? "[]" : "";
13341 errorSupplemental(exp.loc, "perhaps use `std.algorithm.find(%s, %s%s)` instead",
13342 exp.e1.toChars(), exp.e2.toChars(), slice);
13343 return;
13345 default:
13346 result = exp.incompatibleTypes();
13347 return;
13349 result = exp;
13352 override void visit(RemoveExp e)
13354 if (Expression ex = binSemantic(e, sc))
13356 result = ex;
13357 return;
13359 result = e;
13362 override void visit(EqualExp exp)
13364 //printf("EqualExp::semantic('%s')\n", exp.toChars());
13365 if (exp.type)
13367 result = exp;
13368 return;
13371 exp.setNoderefOperands();
13373 if (auto e = binSemanticProp(exp, sc))
13375 result = e;
13376 return;
13378 if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
13380 /* https://issues.dlang.org/show_bug.cgi?id=12520
13381 * empty tuples are represented as types so special cases are added
13382 * so that they can be compared for equality with tuples of values.
13384 static auto extractTypeTupAndExpTup(Expression e)
13386 static struct Result { bool ttEmpty; bool te; }
13387 auto tt = e.op == EXP.type ? e.isTypeExp().type.isTypeTuple() : null;
13388 return Result(tt && (!tt.arguments || !tt.arguments.length), e.isTupleExp() !is null);
13390 auto tups1 = extractTypeTupAndExpTup(exp.e1);
13391 auto tups2 = extractTypeTupAndExpTup(exp.e2);
13392 // AliasSeq!() == AliasSeq!(<at least a value>)
13393 if (tups1.ttEmpty && tups2.te)
13395 result = IntegerExp.createBool(exp.op != EXP.equal);
13396 return;
13398 // AliasSeq!(<at least a value>) == AliasSeq!()
13399 else if (tups1.te && tups2.ttEmpty)
13401 result = IntegerExp.createBool(exp.op != EXP.equal);
13402 return;
13404 // AliasSeq!() == AliasSeq!()
13405 else if (tups1.ttEmpty && tups2.ttEmpty)
13407 result = IntegerExp.createBool(exp.op == EXP.equal);
13408 return;
13410 // otherwise, two types are really not comparable
13411 result = exp.incompatibleTypes();
13412 return;
13416 auto t1 = exp.e1.type;
13417 auto t2 = exp.e2.type;
13418 if (t1.ty == Tenum && t2.ty == Tenum && !t1.equivalent(t2))
13419 error(exp.loc, "comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`",
13420 t1.toChars(), t2.toChars());
13423 /* Before checking for operator overloading, check to see if we're
13424 * comparing the addresses of two statics. If so, we can just see
13425 * if they are the same symbol.
13427 if (exp.e1.op == EXP.address && exp.e2.op == EXP.address)
13429 AddrExp ae1 = cast(AddrExp)exp.e1;
13430 AddrExp ae2 = cast(AddrExp)exp.e2;
13431 if (ae1.e1.op == EXP.variable && ae2.e1.op == EXP.variable)
13433 VarExp ve1 = cast(VarExp)ae1.e1;
13434 VarExp ve2 = cast(VarExp)ae2.e1;
13435 if (ve1.var == ve2.var)
13437 // They are the same, result is 'true' for ==, 'false' for !=
13438 result = IntegerExp.createBool(exp.op == EXP.equal);
13439 return;
13444 Type t1 = exp.e1.type.toBasetype();
13445 Type t2 = exp.e2.type.toBasetype();
13447 // Indicates whether the comparison of the 2 specified array types
13448 // requires an object.__equals() lowering.
13449 static bool needsDirectEq(Type t1, Type t2, Scope* sc)
13451 Type t1n = t1.nextOf().toBasetype();
13452 Type t2n = t2.nextOf().toBasetype();
13453 if ((t1n.ty.isSomeChar && t2n.ty.isSomeChar) ||
13454 (t1n.ty == Tvoid || t2n.ty == Tvoid))
13456 return false;
13458 if (t1n.constOf() != t2n.constOf())
13459 return true;
13461 Type t = t1n;
13462 while (t.toBasetype().nextOf())
13463 t = t.nextOf().toBasetype();
13464 if (auto ts = t.isTypeStruct())
13466 // semanticTypeInfo() makes sure hasIdentityEquals has been computed
13467 if (global.params.useTypeInfo && Type.dtypeinfo)
13468 semanticTypeInfo(sc, ts);
13470 return ts.sym.hasIdentityEquals; // has custom opEquals
13473 return false;
13476 if (auto e = exp.op_overload(sc))
13478 result = e;
13479 return;
13483 const isArrayComparison = (t1.ty == Tarray || t1.ty == Tsarray) &&
13484 (t2.ty == Tarray || t2.ty == Tsarray);
13485 const needsArrayLowering = isArrayComparison && needsDirectEq(t1, t2, sc);
13487 if (!needsArrayLowering)
13489 // https://issues.dlang.org/show_bug.cgi?id=23783
13490 if (exp.e1.checkSharedAccess(sc) || exp.e2.checkSharedAccess(sc))
13491 return setError();
13492 if (auto e = typeCombine(exp, sc))
13494 result = e;
13495 return;
13499 auto f1 = checkNonAssignmentArrayOp(exp.e1);
13500 auto f2 = checkNonAssignmentArrayOp(exp.e2);
13501 if (f1 || f2)
13502 return setError();
13504 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
13506 if (!isArrayComparison)
13508 if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
13510 // Cast both to complex
13511 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
13512 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80);
13516 // lower some array comparisons to object.__equals(e1, e2)
13517 if (needsArrayLowering || (t1.ty == Tarray && t2.ty == Tarray))
13519 //printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars());
13521 // https://issues.dlang.org/show_bug.cgi?id=22390
13522 // Equality comparison between array of noreturns simply lowers to length equality comparison
13523 if (t1.nextOf.isTypeNoreturn() && t2.nextOf.isTypeNoreturn())
13525 Expression exp_l1 = new DotIdExp(exp.e1.loc, exp.e1, Id.length);
13526 Expression exp_l2 = new DotIdExp(exp.e2.loc, exp.e2, Id.length);
13527 auto e = new EqualExp(EXP.equal, exp.loc, exp_l1, exp_l2);
13528 result = e.expressionSemantic(sc);
13529 return;
13532 if (!verifyHookExist(exp.loc, *sc, Id.__equals, "equal checks on arrays"))
13533 return setError();
13535 Expression __equals = new IdentifierExp(exp.loc, Id.empty);
13536 Identifier id = Identifier.idPool("__equals");
13537 __equals = new DotIdExp(exp.loc, __equals, Id.object);
13538 __equals = new DotIdExp(exp.loc, __equals, id);
13540 /* https://issues.dlang.org/show_bug.cgi?id=23674
13542 * Optimize before creating the call expression to the
13543 * druntime hook as the optimizer may output errors
13544 * that will get swallowed otherwise.
13546 exp.e1 = exp.e1.optimize(WANTvalue);
13547 exp.e2 = exp.e2.optimize(WANTvalue);
13549 auto arguments = new Expressions(2);
13550 (*arguments)[0] = exp.e1;
13551 (*arguments)[1] = exp.e2;
13553 __equals = new CallExp(exp.loc, __equals, arguments);
13554 if (exp.op == EXP.notEqual)
13556 __equals = new NotExp(exp.loc, __equals);
13558 __equals = __equals.trySemantic(sc); // for better error message
13559 if (!__equals)
13561 error(exp.loc, "incompatible types for array comparison: `%s` and `%s`",
13562 exp.e1.type.toChars(), exp.e2.type.toChars());
13563 __equals = ErrorExp.get();
13566 result = __equals;
13567 return;
13570 if (exp.e1.type.toBasetype().ty == Taarray)
13571 semanticTypeInfo(sc, exp.e1.type.toBasetype());
13574 if (!target.isVectorOpSupported(t1, exp.op, t2))
13576 result = exp.incompatibleTypes();
13577 return;
13580 if (auto tv = t1.isTypeVector())
13581 exp.type = tv.toBooleanVector();
13583 result = exp;
13586 override void visit(IdentityExp exp)
13588 if (exp.type)
13590 result = exp;
13591 return;
13594 exp.setNoderefOperands();
13596 if (auto e = binSemanticProp(exp, sc))
13598 result = e;
13599 return;
13602 if (auto e = typeCombine(exp, sc))
13604 result = e;
13605 return;
13608 auto f1 = checkNonAssignmentArrayOp(exp.e1);
13609 auto f2 = checkNonAssignmentArrayOp(exp.e2);
13610 if (f1 || f2)
13611 return setError();
13613 if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
13615 result = exp.incompatibleTypes();
13616 return;
13619 exp.type = Type.tbool;
13621 if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
13623 // Cast both to complex
13624 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
13625 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80);
13628 auto tb1 = exp.e1.type.toBasetype();
13629 auto tb2 = exp.e2.type.toBasetype();
13630 if (!target.isVectorOpSupported(tb1, exp.op, tb2))
13632 result = exp.incompatibleTypes();
13633 return;
13636 if (exp.e1.op == EXP.call)
13637 exp.e1 = (cast(CallExp)exp.e1).addDtorHook(sc);
13638 if (exp.e2.op == EXP.call)
13639 exp.e2 = (cast(CallExp)exp.e2).addDtorHook(sc);
13641 if (exp.e1.type.toBasetype().ty == Tsarray ||
13642 exp.e2.type.toBasetype().ty == Tsarray)
13643 deprecation(exp.loc, "identity comparison of static arrays "
13644 ~ "implicitly coerces them to slices, "
13645 ~ "which are compared by reference");
13647 result = exp;
13650 override void visit(CondExp exp)
13652 static if (LOGSEMANTIC)
13654 printf("CondExp::semantic('%s')\n", exp.toChars());
13656 if (exp.type)
13658 result = exp;
13659 return;
13662 if (auto die = exp.econd.isDotIdExp())
13663 die.noderef = true;
13665 Expression ec = exp.econd.expressionSemantic(sc);
13666 ec = resolveProperties(sc, ec);
13667 ec = ec.toBoolean(sc);
13669 CtorFlow ctorflow_root = sc.ctorflow.clone();
13670 Expression e1x = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
13671 e1x = resolveProperties(sc, e1x);
13673 CtorFlow ctorflow1 = sc.ctorflow;
13674 sc.ctorflow = ctorflow_root;
13675 Expression e2x = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
13676 e2x = resolveProperties(sc, e2x);
13678 sc.merge(exp.loc, ctorflow1);
13679 ctorflow1.freeFieldinit();
13681 if (ec.op == EXP.error)
13683 result = ec;
13684 return;
13686 if (ec.type == Type.terror)
13687 return setError();
13688 exp.econd = ec;
13690 if (e1x.op == EXP.error)
13692 result = e1x;
13693 return;
13695 if (e1x.type == Type.terror)
13696 return setError();
13697 exp.e1 = e1x;
13699 if (e2x.op == EXP.error)
13701 result = e2x;
13702 return;
13704 if (e2x.type == Type.terror)
13705 return setError();
13706 exp.e2 = e2x;
13708 auto f0 = checkNonAssignmentArrayOp(exp.econd);
13709 auto f1 = checkNonAssignmentArrayOp(exp.e1);
13710 auto f2 = checkNonAssignmentArrayOp(exp.e2);
13711 if (f0 || f1 || f2)
13712 return setError();
13714 Type t1 = exp.e1.type;
13715 Type t2 = exp.e2.type;
13717 // https://issues.dlang.org/show_bug.cgi?id=23767
13718 // `cast(void*) 0` should be treated as `null` so the ternary expression
13719 // gets the pointer type of the other branch
13720 if (sc.flags & SCOPE.Cfile)
13722 static void rewriteCNull(ref Expression e, ref Type t)
13724 if (!t.isTypePointer())
13725 return;
13726 if (auto ie = e.optimize(WANTvalue).isIntegerExp())
13728 if (ie.getInteger() == 0)
13730 e = new NullExp(e.loc, Type.tnull);
13731 t = Type.tnull;
13735 rewriteCNull(exp.e1, t1);
13736 rewriteCNull(exp.e2, t2);
13739 if (t1.ty == Tnoreturn)
13741 exp.type = t2;
13742 exp.e1 = specialNoreturnCast(exp.e1, exp.type);
13744 else if (t2.ty == Tnoreturn)
13746 exp.type = t1;
13747 exp.e2 = specialNoreturnCast(exp.e2, exp.type);
13749 // If either operand is void the result is void, we have to cast both
13750 // the expression to void so that we explicitly discard the expression
13751 // value if any
13752 // https://issues.dlang.org/show_bug.cgi?id=16598
13753 else if (t1.ty == Tvoid || t2.ty == Tvoid)
13755 exp.type = Type.tvoid;
13756 exp.e1 = exp.e1.castTo(sc, exp.type);
13757 exp.e2 = exp.e2.castTo(sc, exp.type);
13759 else if (t1 == t2)
13760 exp.type = t1;
13761 else
13763 if (Expression ex = typeCombine(exp, sc))
13765 result = ex;
13766 return;
13769 switch (exp.e1.type.toBasetype().ty)
13771 case Tcomplex32:
13772 case Tcomplex64:
13773 case Tcomplex80:
13774 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
13775 break;
13776 default:
13777 break;
13779 switch (exp.e2.type.toBasetype().ty)
13781 case Tcomplex32:
13782 case Tcomplex64:
13783 case Tcomplex80:
13784 exp.e1 = exp.e1.castTo(sc, exp.e2.type);
13785 break;
13786 default:
13787 break;
13789 if (exp.type.toBasetype().ty == Tarray)
13791 exp.e1 = exp.e1.castTo(sc, exp.type);
13792 exp.e2 = exp.e2.castTo(sc, exp.type);
13795 exp.type = exp.type.merge2();
13796 version (none)
13798 printf("res: %s\n", exp.type.toChars());
13799 printf("e1 : %s\n", exp.e1.type.toChars());
13800 printf("e2 : %s\n", exp.e2.type.toChars());
13803 /* https://issues.dlang.org/show_bug.cgi?id=14696
13804 * If either e1 or e2 contain temporaries which need dtor,
13805 * make them conditional.
13806 * Rewrite:
13807 * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2)
13808 * to:
13809 * (auto __cond = cond) ? (... __tmp1) : (... __tmp2)
13810 * and replace edtors of __tmp1 and __tmp2 with:
13811 * __tmp1.edtor --> __cond && __tmp1.dtor()
13812 * __tmp2.edtor --> __cond || __tmp2.dtor()
13814 exp.hookDtors(sc);
13816 result = exp;
13819 override void visit(GenericExp exp)
13821 static if (LOGSEMANTIC)
13823 printf("GenericExp::semantic('%s')\n", exp.toChars());
13825 // C11 6.5.1.1 Generic Selection
13827 auto ec = exp.cntlExp.expressionSemantic(sc).arrayFuncConv(sc);
13828 bool errors = ec.isErrorExp() !is null;
13829 auto tc = ec.type;
13831 auto types = (*exp.types)[];
13832 foreach (i, ref t; types)
13834 if (!t)
13835 continue; // `default:` case
13836 t = t.typeSemantic(ec.loc, sc);
13837 if (t.isTypeError())
13839 errors = true;
13840 continue;
13843 /* C11 6.5.1-2 duplicate check
13845 /* C11 distinguishes int, long, and long long. But D doesn't, so depending on the
13846 * C target, a long may have the same type as `int` in the D type system.
13847 * So, skip checks when this may be the case. Later pick the first match
13849 if (
13850 (t.ty == Tint32 || t.ty == Tuns32) && target.c.longsize == 4 ||
13851 (t.ty == Tint64 || t.ty == Tuns64) && target.c.longsize == 8 ||
13852 (t.ty == Tfloat64 || t.ty == Timaginary64 || t.ty == Tcomplex64) && target.c.long_doublesize == 8
13854 continue;
13856 foreach (t2; types[0 .. i])
13858 if (t2 && t2.equals(t))
13860 error(ec.loc, "generic association type `%s` can only appear once", t.toChars());
13861 errors = true;
13862 break;
13867 auto exps = (*exp.exps)[];
13868 foreach (ref e; exps)
13870 e = e.expressionSemantic(sc);
13871 if (e.isErrorExp())
13872 errors = true;
13875 if (errors)
13876 return setError();
13878 enum size_t None = ~0;
13879 size_t imatch = None;
13880 size_t idefault = None;
13881 foreach (const i, t; types)
13883 if (t)
13885 /* if tc is compatible with t, it's a match
13886 * C11 6.2.7 defines a compatible type as being the same type, including qualifiers
13888 if (tc.equals(t))
13890 assert(imatch == None);
13891 imatch = i;
13892 break; // pick first match
13895 else
13896 idefault = i; // multiple defaults are not allowed, and are caught by cparse
13899 if (imatch == None)
13900 imatch = idefault;
13901 if (imatch == None)
13903 error(exp.loc, "no compatible generic association type for controlling expression type `%s`", tc.toChars());
13904 return setError();
13907 result = exps[imatch];
13910 override void visit(FileInitExp e)
13912 //printf("FileInitExp::semantic()\n");
13913 e.type = Type.tstring;
13914 result = e;
13917 override void visit(LineInitExp e)
13919 e.type = Type.tint32;
13920 result = e;
13923 override void visit(ModuleInitExp e)
13925 //printf("ModuleInitExp::semantic()\n");
13926 e.type = Type.tstring;
13927 result = e;
13930 override void visit(FuncInitExp e)
13932 //printf("FuncInitExp::semantic()\n");
13933 e.type = Type.tstring;
13934 if (sc.func)
13936 result = e.resolveLoc(Loc.initial, sc);
13937 return;
13939 result = e;
13942 override void visit(PrettyFuncInitExp e)
13944 //printf("PrettyFuncInitExp::semantic()\n");
13945 e.type = Type.tstring;
13946 if (sc.func)
13948 result = e.resolveLoc(Loc.initial, sc);
13949 return;
13952 result = e;
13956 /**********************************
13957 * Try to run semantic routines.
13958 * If they fail, return NULL.
13960 Expression trySemantic(Expression exp, Scope* sc)
13962 //printf("+trySemantic(%s)\n", exp.toChars());
13963 uint errors = global.startGagging();
13964 Expression e = expressionSemantic(exp, sc);
13965 if (global.endGagging(errors))
13967 e = null;
13969 //printf("-trySemantic(%s)\n", exp.toChars());
13970 return e;
13973 /**************************
13974 * Helper function for easy error propagation.
13975 * If error occurs, returns ErrorExp. Otherwise returns NULL.
13977 Expression unaSemantic(UnaExp e, Scope* sc)
13979 static if (LOGSEMANTIC)
13981 printf("UnaExp::semantic('%s')\n", e.toChars());
13983 Expression e1x = e.e1.expressionSemantic(sc);
13984 if (e1x.op == EXP.error)
13985 return e1x;
13986 e.e1 = e1x;
13987 return null;
13990 /**************************
13991 * Helper function for easy error propagation.
13992 * If error occurs, returns ErrorExp. Otherwise returns NULL.
13994 Expression binSemantic(BinExp e, Scope* sc)
13996 static if (LOGSEMANTIC)
13998 printf("BinExp::semantic('%s')\n", e.toChars());
14000 Expression e1x = e.e1.expressionSemantic(sc);
14001 Expression e2x = e.e2.expressionSemantic(sc);
14003 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
14004 if (e1x.op == EXP.type)
14005 e1x = resolveAliasThis(sc, e1x);
14006 if (e2x.op == EXP.type)
14007 e2x = resolveAliasThis(sc, e2x);
14009 if (e1x.op == EXP.error)
14010 return e1x;
14011 if (e2x.op == EXP.error)
14012 return e2x;
14013 e.e1 = e1x;
14014 e.e2 = e2x;
14015 return null;
14018 Expression binSemanticProp(BinExp e, Scope* sc)
14020 if (Expression ex = binSemantic(e, sc))
14021 return ex;
14022 Expression e1x = resolveProperties(sc, e.e1);
14023 Expression e2x = resolveProperties(sc, e.e2);
14024 if (e1x.op == EXP.error)
14025 return e1x;
14026 if (e2x.op == EXP.error)
14027 return e2x;
14028 e.e1 = e1x;
14029 e.e2 = e2x;
14030 return null;
14033 // entrypoint for semantic ExpressionSemanticVisitor
14034 extern (C++) Expression expressionSemantic(Expression e, Scope* sc)
14036 scope v = new ExpressionSemanticVisitor(sc);
14037 e.accept(v);
14038 return v.result;
14041 private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc)
14043 //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars());
14044 if (Expression ex = unaSemantic(exp, sc))
14045 return ex;
14047 if (!(sc.flags & SCOPE.Cfile) && exp.ident == Id._mangleof)
14049 // symbol.mangleof
14051 // return mangleof as an Expression
14052 static Expression dotMangleof(const ref Loc loc, Scope* sc, Dsymbol ds)
14054 assert(ds);
14055 if (auto f = ds.isFuncDeclaration())
14057 if (f.checkForwardRef(loc))
14058 return ErrorExp.get();
14060 if (f.purityInprocess || f.safetyInprocess || f.nothrowInprocess || f.nogcInprocess)
14062 error(loc, "%s `%s` cannot retrieve its `.mangleof` while inferring attributes", f.kind, f.toPrettyChars);
14063 return ErrorExp.get();
14066 OutBuffer buf;
14067 mangleToBuffer(ds, buf);
14068 Expression e = new StringExp(loc, buf.extractSlice());
14069 return e.expressionSemantic(sc);
14072 Dsymbol ds;
14073 switch (exp.e1.op)
14075 case EXP.scope_: return dotMangleof(exp.loc, sc, exp.e1.isScopeExp().sds);
14076 case EXP.variable: return dotMangleof(exp.loc, sc, exp.e1.isVarExp().var);
14077 case EXP.dotVariable: return dotMangleof(exp.loc, sc, exp.e1.isDotVarExp().var);
14078 case EXP.overloadSet: return dotMangleof(exp.loc, sc, exp.e1.isOverExp().vars);
14079 case EXP.template_:
14081 TemplateExp te = exp.e1.isTemplateExp();
14082 return dotMangleof(exp.loc, sc, ds = te.fd ? te.fd.isDsymbol() : te.td);
14085 default:
14086 break;
14090 if (exp.e1.isVarExp() && exp.e1.type.toBasetype().isTypeSArray() && exp.ident == Id.length)
14092 // bypass checkPurity
14093 return exp.e1.type.dotExp(sc, exp.e1, exp.ident, cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref));
14096 if (!exp.e1.isDotExp())
14098 exp.e1 = resolvePropertiesX(sc, exp.e1);
14101 if (auto te = exp.e1.isTupleExp())
14103 if (exp.ident == Id.offsetof)
14105 /* 'distribute' the .offsetof to each of the tuple elements.
14107 auto exps = new Expressions(te.exps.length);
14108 foreach (i, e; (*te.exps)[])
14110 (*exps)[i] = new DotIdExp(e.loc, e, Id.offsetof);
14112 // Don't evaluate te.e0 in runtime
14113 Expression e = new TupleExp(exp.loc, null, exps);
14114 e = e.expressionSemantic(sc);
14115 return e;
14117 if (exp.ident == Id.length)
14119 // Don't evaluate te.e0 in runtime
14120 return new IntegerExp(exp.loc, te.exps.length, Type.tsize_t);
14124 // https://issues.dlang.org/show_bug.cgi?id=14416
14125 // Template has no built-in properties except for 'stringof'.
14126 if ((exp.e1.isDotTemplateExp() || exp.e1.isTemplateExp()) && exp.ident != Id.stringof)
14128 error(exp.loc, "template `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
14129 return ErrorExp.get();
14131 if (!exp.e1.type)
14133 error(exp.loc, "expression `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
14134 return ErrorExp.get();
14137 return exp;
14140 private bool checkDisabled(Dsymbol s, ref Loc loc, Scope* sc)
14142 if (auto d = s.isDeclaration())
14143 return d.checkDisabled(loc, sc);
14145 return false;
14148 /******************************
14149 * Resolve properties, i.e. `e1.ident`, without seeing UFCS.
14150 * Params:
14151 * exp = expression to resolve
14152 * sc = context
14153 * gag = do not emit error messages, just return `null`
14154 * Returns:
14155 * resolved expression, null if error
14157 Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
14159 //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars());
14161 //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
14163 const cfile = (sc.flags & SCOPE.Cfile) != 0;
14165 /* Special case: rewrite this.id and super.id
14166 * to be classtype.id and baseclasstype.id
14167 * if we have no this pointer.
14169 if ((exp.e1.isThisExp() || exp.e1.isSuperExp()) && !hasThis(sc))
14171 if (AggregateDeclaration ad = sc.getStructClassScope())
14173 if (exp.e1.isThisExp())
14175 exp.e1 = new TypeExp(exp.e1.loc, ad.type);
14177 else
14179 if (auto cd = ad.isClassDeclaration())
14181 if (cd.baseClass)
14182 exp.e1 = new TypeExp(exp.e1.loc, cd.baseClass.type);
14189 Expression e = dotIdSemanticPropX(exp, sc);
14190 if (e != exp)
14191 return e;
14194 Expression eleft;
14195 Expression eright;
14196 if (auto de = exp.e1.isDotExp())
14198 eleft = de.e1;
14199 eright = de.e2;
14201 else
14203 eleft = null;
14204 eright = exp.e1;
14207 Type t1b = exp.e1.type.toBasetype();
14209 if (auto ie = eright.isScopeExp()) // also used for template alias's
14211 auto flags = SearchLocalsOnly;
14212 /* Disable access to another module's private imports.
14213 * The check for 'is sds our current module' is because
14214 * the current module should have access to its own imports.
14216 if (ie.sds.isModule() && ie.sds != sc._module)
14217 flags |= IgnorePrivateImports;
14218 if (sc.flags & SCOPE.ignoresymbolvisibility)
14219 flags |= IgnoreSymbolVisibility;
14220 Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags);
14221 /* Check for visibility before resolving aliases because public
14222 * aliases to private symbols are public.
14224 if (s && !(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc._module, s))
14226 s = null;
14228 if (s)
14230 auto p = s.isPackage();
14231 if (p && checkAccess(sc, p))
14233 s = null;
14236 if (s)
14238 // if 's' is a tuple variable, the tuple is returned.
14239 s = s.toAlias();
14241 s.checkDeprecated(exp.loc, sc);
14242 s.checkDisabled(exp.loc, sc);
14244 if (auto em = s.isEnumMember())
14246 return em.getVarExp(exp.loc, sc);
14248 if (auto v = s.isVarDeclaration())
14250 //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars());
14251 if (!v.type ||
14252 !v.type.deco && v.inuse)
14254 if (v.inuse)
14255 error(exp.loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
14256 else
14257 error(exp.loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
14258 return ErrorExp.get();
14260 if (v.type.isTypeError())
14261 return ErrorExp.get();
14263 if ((v.storage_class & STC.manifest) && v._init && !exp.wantsym)
14265 /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2().
14266 * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably
14267 * be reverted. `wantsym` is the hack to work around the problem.
14269 if (v.inuse)
14271 error(exp.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
14272 return ErrorExp.get();
14274 auto e = v.expandInitializer(exp.loc);
14275 v.inuse++;
14276 e = e.expressionSemantic(sc);
14277 v.inuse--;
14278 return e;
14281 Expression e;
14282 if (v.needThis())
14284 if (!eleft)
14285 eleft = new ThisExp(exp.loc);
14286 e = new DotVarExp(exp.loc, eleft, v);
14287 e = e.expressionSemantic(sc);
14289 else
14291 e = new VarExp(exp.loc, v);
14292 if (eleft)
14294 e = new CommaExp(exp.loc, eleft, e);
14295 e.type = v.type;
14298 e = e.deref();
14299 return e.expressionSemantic(sc);
14302 if (auto f = s.isFuncDeclaration())
14304 //printf("it's a function\n");
14305 if (!f.functionSemantic())
14306 return ErrorExp.get();
14307 Expression e;
14308 if (f.needThis())
14310 if (!eleft)
14311 eleft = new ThisExp(exp.loc);
14312 e = new DotVarExp(exp.loc, eleft, f, true);
14313 e = e.expressionSemantic(sc);
14315 else
14317 e = new VarExp(exp.loc, f, true);
14318 if (eleft)
14320 e = new CommaExp(exp.loc, eleft, e);
14321 e.type = f.type;
14324 return e;
14326 if (auto td = s.isTemplateDeclaration())
14328 Expression e;
14329 if (eleft)
14330 e = new DotTemplateExp(exp.loc, eleft, td);
14331 else
14332 e = new TemplateExp(exp.loc, td);
14333 e = e.expressionSemantic(sc);
14334 return e;
14336 if (OverDeclaration od = s.isOverDeclaration())
14338 Expression e = new VarExp(exp.loc, od, true);
14339 if (eleft)
14341 e = new CommaExp(exp.loc, eleft, e);
14342 e.type = Type.tvoid; // ambiguous type?
14344 return e.expressionSemantic(sc);
14346 if (auto o = s.isOverloadSet())
14348 //printf("'%s' is an overload set\n", o.toChars());
14349 return new OverExp(exp.loc, o);
14352 if (auto t = s.getType())
14354 return (new TypeExp(exp.loc, t)).expressionSemantic(sc);
14357 if (auto tup = s.isTupleDeclaration())
14359 if (eleft)
14361 Expression e = new DotVarExp(exp.loc, eleft, tup);
14362 e = e.expressionSemantic(sc);
14363 return e;
14365 Expression e = new TupleExp(exp.loc, tup);
14366 e = e.expressionSemantic(sc);
14367 return e;
14370 if (auto sds = s.isScopeDsymbol())
14372 //printf("it's a ScopeDsymbol %s\n", ident.toChars());
14373 Expression e = new ScopeExp(exp.loc, sds);
14374 e = e.expressionSemantic(sc);
14375 if (eleft)
14376 e = new DotExp(exp.loc, eleft, e);
14377 return e;
14380 if (auto imp = s.isImport())
14382 Expression se = new ScopeExp(exp.loc, imp.pkg);
14383 return se.expressionSemantic(sc);
14386 if (auto attr = s.isAttribDeclaration())
14388 if (auto sm = ie.sds.search(exp.loc, exp.ident, flags))
14390 auto es = new DsymbolExp(exp.loc, sm);
14391 return es;
14395 // BUG: handle other cases like in IdentifierExp::semantic()
14396 debug
14398 printf("s = %p '%s', kind = '%s'\n", s, s.toChars(), s.kind());
14400 assert(0);
14402 else if (exp.ident == Id.stringof)
14404 Expression e = new StringExp(exp.loc, ie.toString());
14405 e = e.expressionSemantic(sc);
14406 return e;
14408 if (ie.sds.isPackage() || ie.sds.isImport() || ie.sds.isModule())
14410 gag = false;
14412 if (gag)
14413 return null;
14414 s = ie.sds.search_correct(exp.ident);
14415 if (s && symbolIsVisible(sc, s))
14417 if (s.isPackage())
14418 error(exp.loc, "undefined identifier `%s` in %s `%s`, perhaps add `static import %s;`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars(), s.toPrettyChars());
14419 else
14420 error(exp.loc, "undefined identifier `%s` in %s `%s`, did you mean %s `%s`?", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars(), s.kind(), s.toChars());
14422 else
14423 error(exp.loc, "undefined identifier `%s` in %s `%s`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars());
14424 return ErrorExp.get();
14426 else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum &&
14428 exp.ident == Id.__sizeof ||
14429 exp.ident == Id.__xalignof ||
14430 !cfile &&
14431 (exp.ident == Id._mangleof ||
14432 exp.ident == Id.offsetof ||
14433 exp.ident == Id._init ||
14434 exp.ident == Id.stringof)
14437 Type t1bn = t1b.nextOf();
14438 if (gag)
14440 if (AggregateDeclaration ad = isAggregate(t1bn))
14442 if (!ad.members) // https://issues.dlang.org/show_bug.cgi?id=11312
14443 return null;
14447 /* Rewrite:
14448 * p.ident
14449 * as:
14450 * (*p).ident
14452 if (gag && t1bn.ty == Tvoid)
14453 return null;
14454 Expression e = new PtrExp(exp.loc, exp.e1);
14455 e = e.expressionSemantic(sc);
14456 const newFlag = cast(DotExpFlag) (gag * DotExpFlag.gag | exp.noderef * DotExpFlag.noDeref);
14457 return e.type.dotExp(sc, e, exp.ident, newFlag);
14459 else if (exp.ident == Id.__xalignof &&
14460 exp.e1.isVarExp() &&
14461 exp.e1.isVarExp().var.isVarDeclaration() &&
14462 !exp.e1.isVarExp().var.isVarDeclaration().alignment.isUnknown())
14464 // For `x.alignof` get the alignment of the variable, not the alignment of its type
14465 const explicitAlignment = exp.e1.isVarExp().var.isVarDeclaration().alignment;
14466 const naturalAlignment = exp.e1.type.alignsize();
14467 const actualAlignment = explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get();
14468 Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
14469 return e;
14471 else if ((exp.ident == Id.max || exp.ident == Id.min) &&
14472 exp.e1.isVarExp() &&
14473 exp.e1.isVarExp().var.isBitFieldDeclaration())
14475 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
14476 auto bf = exp.e1.isVarExp().var.isBitFieldDeclaration();
14477 return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type);
14479 else if ((exp.ident == Id.max || exp.ident == Id.min) &&
14480 exp.e1.isDotVarExp() &&
14481 exp.e1.isDotVarExp().var.isBitFieldDeclaration())
14483 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
14484 auto bf = exp.e1.isDotVarExp().var.isBitFieldDeclaration();
14485 return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type);
14487 else
14489 if (exp.e1.isTypeExp() || exp.e1.isTemplateExp())
14490 gag = false;
14492 const flag = cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref | gag * DotExpFlag.gag);
14494 Expression e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag);
14495 if (e)
14497 e = e.expressionSemantic(sc);
14499 return e;
14504 * Resolve `e1.ident!tiargs` without seeing UFCS.
14505 * Params:
14506 * exp = the `DotTemplateInstanceExp` to resolve
14507 * sc = the semantic scope
14508 * gag = stop "not a property" error and return `null`.
14509 * Returns:
14510 * `null` if error or not found, or the resolved expression.
14512 Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, bool gag)
14514 static if (LOGSEMANTIC)
14516 printf("DotTemplateInstanceExpY::semantic('%s')\n", exp.toChars());
14519 static Expression errorExp()
14521 return ErrorExp.get();
14524 Expression e1 = exp.e1;
14526 if (exp.ti.tempdecl && exp.ti.tempdecl.parent && exp.ti.tempdecl.parent.isTemplateMixin())
14528 // if 'ti.tempdecl' happens to be found in a mixin template don't lose that info
14529 // and do the symbol search in that context (Issue: 19476)
14530 auto tm = cast(TemplateMixin)exp.ti.tempdecl.parent;
14531 e1 = new DotExp(exp.e1.loc, exp.e1, new ScopeExp(tm.loc, tm));
14534 auto die = new DotIdExp(exp.loc, e1, exp.ti.name);
14536 Expression e = die.dotIdSemanticPropX(sc);
14537 if (e == die)
14539 exp.e1 = die.e1; // take back
14540 Type t1b = exp.e1.type.toBasetype();
14541 if (t1b.ty == Tarray || t1b.ty == Tsarray || t1b.ty == Taarray || t1b.ty == Tnull || (t1b.isTypeBasic() && t1b.ty != Tvoid))
14543 /* No built-in type has templatized properties, so do shortcut.
14544 * It is necessary in: 1024.max!"a < b"
14546 if (gag)
14547 return null;
14549 e = die.dotIdSemanticProp(sc, gag);
14550 if (gag)
14552 if (!e ||
14553 isDotOpDispatch(e))
14555 /* opDispatch!tiargs would be a function template that needs IFTI,
14556 * so it's not a template
14558 return null;
14562 assert(e);
14564 if (e.op == EXP.error)
14565 return e;
14566 if (DotVarExp dve = e.isDotVarExp())
14568 if (FuncDeclaration fd = dve.var.isFuncDeclaration())
14570 if (TemplateDeclaration td = fd.findTemplateDeclRoot())
14572 e = new DotTemplateExp(dve.loc, dve.e1, td);
14573 e = e.expressionSemantic(sc);
14576 else if (OverDeclaration od = dve.var.isOverDeclaration())
14578 exp.e1 = dve.e1; // pull semantic() result
14580 if (!exp.findTempDecl(sc))
14581 goto Lerr;
14582 if (exp.ti.needsTypeInference(sc))
14583 return exp;
14584 exp.ti.dsymbolSemantic(sc);
14585 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
14586 return errorExp();
14588 if (Declaration v = exp.ti.toAlias().isDeclaration())
14590 if (v.type && !v.type.deco)
14591 v.type = v.type.typeSemantic(v.loc, sc);
14592 return new DotVarExp(exp.loc, exp.e1, v)
14593 .expressionSemantic(sc);
14595 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
14596 .expressionSemantic(sc);
14599 else if (e.op == EXP.variable)
14601 VarExp ve = cast(VarExp)e;
14602 if (FuncDeclaration fd = ve.var.isFuncDeclaration())
14604 if (TemplateDeclaration td = fd.findTemplateDeclRoot())
14606 e = new TemplateExp(ve.loc, td)
14607 .expressionSemantic(sc);
14610 else if (OverDeclaration od = ve.var.isOverDeclaration())
14612 exp.ti.tempdecl = od;
14613 return new ScopeExp(exp.loc, exp.ti)
14614 .expressionSemantic(sc);
14618 if (DotTemplateExp dte = e.isDotTemplateExp())
14620 exp.e1 = dte.e1; // pull semantic() result
14622 exp.ti.tempdecl = dte.td;
14623 if (!exp.ti.semanticTiargs(sc))
14624 return errorExp();
14625 if (exp.ti.needsTypeInference(sc))
14626 return exp;
14627 exp.ti.dsymbolSemantic(sc);
14628 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
14629 return errorExp();
14631 if (Declaration v = exp.ti.toAlias().isDeclaration())
14633 return new DotVarExp(exp.loc, exp.e1, v)
14634 .expressionSemantic(sc);
14636 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
14637 .expressionSemantic(sc);
14639 else if (e.op == EXP.template_)
14641 exp.ti.tempdecl = (cast(TemplateExp)e).td;
14642 return new ScopeExp(exp.loc, exp.ti)
14643 .expressionSemantic(sc);
14645 else if (DotExp de = e.isDotExp())
14647 if (de.e2.op == EXP.overloadSet)
14649 if (!exp.findTempDecl(sc) || !exp.ti.semanticTiargs(sc))
14651 return errorExp();
14653 if (exp.ti.needsTypeInference(sc))
14654 return exp;
14655 exp.ti.dsymbolSemantic(sc);
14656 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
14657 return errorExp();
14659 if (Declaration v = exp.ti.toAlias().isDeclaration())
14661 if (v.type && !v.type.deco)
14662 v.type = v.type.typeSemantic(v.loc, sc);
14663 return new DotVarExp(exp.loc, exp.e1, v)
14664 .expressionSemantic(sc);
14666 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
14667 .expressionSemantic(sc);
14670 else if (OverExp oe = e.isOverExp())
14672 exp.ti.tempdecl = oe.vars;
14673 return new ScopeExp(exp.loc, exp.ti)
14674 .expressionSemantic(sc);
14677 Lerr:
14678 error(exp.loc, "`%s` isn't a template", e.toChars());
14679 return errorExp();
14682 MATCH matchType(FuncExp funcExp, Type to, Scope* sc, FuncExp* presult, ErrorSink eSink)
14684 auto loc = funcExp.loc;
14685 auto tok = funcExp.tok;
14686 auto td = funcExp.td;
14687 auto fd = funcExp.fd;
14688 auto type = funcExp.type;
14690 MATCH cannotInfer()
14692 eSink.error(loc, "cannot infer parameter types from `%s`", to.toChars());
14693 return MATCH.nomatch;
14696 //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars());
14697 if (presult)
14698 *presult = null;
14700 TypeFunction tof = null;
14701 if (to.ty == Tdelegate)
14703 if (tok == TOK.function_)
14705 eSink.error(loc, "cannot match function literal to delegate type `%s`", to.toChars());
14706 return MATCH.nomatch;
14708 tof = cast(TypeFunction)to.nextOf();
14710 else if (to.ty == Tpointer && (tof = to.nextOf().isTypeFunction()) !is null)
14712 if (tok == TOK.delegate_)
14714 eSink.error(loc, "cannot match delegate literal to function pointer type `%s`", to.toChars());
14715 return MATCH.nomatch;
14719 if (td)
14721 if (!tof)
14723 return cannotInfer();
14726 // Parameter types inference from 'tof'
14727 assert(td._scope);
14728 TypeFunction tf = fd.type.isTypeFunction();
14729 //printf("\ttof = %s\n", tof.toChars());
14730 //printf("\ttf = %s\n", tf.toChars());
14731 const dim = tf.parameterList.length;
14733 if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs)
14734 return cannotInfer();
14736 auto tiargs = new Objects();
14737 tiargs.reserve(td.parameters.length);
14739 foreach (tp; *td.parameters)
14741 size_t u = 0;
14742 foreach (i, p; tf.parameterList)
14744 if (auto ti = p.type.isTypeIdentifier())
14745 if (ti && ti.ident == tp.ident)
14746 break;
14748 ++u;
14750 assert(u < dim);
14751 Parameter pto = tof.parameterList[u];
14752 Type t = pto.type;
14753 if (t.ty == Terror)
14754 return cannotInfer();
14755 tf.parameterList[u].storageClass = tof.parameterList[u].storageClass;
14756 tiargs.push(t);
14759 // Set target of return type inference
14760 if (!tf.next && tof.next)
14761 fd.treq = to;
14763 auto ti = new TemplateInstance(loc, td, tiargs);
14764 Expression ex = (new ScopeExp(loc, ti)).expressionSemantic(td._scope);
14766 // Reset inference target for the later re-semantic
14767 fd.treq = null;
14769 if (ex.op == EXP.error)
14770 return MATCH.nomatch;
14771 if (auto ef = ex.isFuncExp())
14772 return ef.matchType(to, sc, presult, eSink);
14773 else
14774 return cannotInfer();
14777 if (!tof || !tof.next)
14778 return MATCH.nomatch;
14780 assert(type && type != Type.tvoid);
14781 if (fd.type.ty == Terror)
14782 return MATCH.nomatch;
14783 auto tfx = fd.type.isTypeFunction();
14784 bool convertMatch = (type.ty != to.ty);
14786 if (fd.inferRetType && tfx.next.implicitConvTo(tof.next) == MATCH.convert)
14788 /* If return type is inferred and covariant return,
14789 * tweak return statements to required return type.
14791 * interface I {}
14792 * class C : Object, I{}
14794 * I delegate() dg = delegate() { return new class C(); }
14796 convertMatch = true;
14798 auto tfy = new TypeFunction(tfx.parameterList, tof.next,
14799 tfx.linkage, STC.undefined_);
14800 tfy.mod = tfx.mod;
14801 tfy.trust = tfx.trust;
14802 tfy.isnothrow = tfx.isnothrow;
14803 tfy.isnogc = tfx.isnogc;
14804 tfy.purity = tfx.purity;
14805 tfy.isproperty = tfx.isproperty;
14806 tfy.isref = tfx.isref;
14807 tfy.isInOutParam = tfx.isInOutParam;
14808 tfy.isInOutQual = tfx.isInOutQual;
14809 tfy.deco = tfy.merge().deco;
14811 tfx = tfy;
14813 Type tx;
14814 if (tok == TOK.delegate_ ||
14815 tok == TOK.reserved && (type.ty == Tdelegate || type.ty == Tpointer && to.ty == Tdelegate))
14817 // Allow conversion from implicit function pointer to delegate
14818 tx = new TypeDelegate(tfx);
14819 tx.deco = tx.merge().deco;
14821 else
14823 assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer || fd.errors);
14824 tx = tfx.pointerTo();
14826 //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars());
14828 MATCH m = tx.implicitConvTo(to);
14829 if (m > MATCH.nomatch)
14831 // MATCH.exact: exact type match
14832 // MATCH.constant: covairiant type match (eg. attributes difference)
14833 // MATCH.convert: context conversion
14834 m = convertMatch ? MATCH.convert : tx.equals(to) ? MATCH.exact : MATCH.constant;
14836 if (presult)
14838 (*presult) = cast(FuncExp)funcExp.copy();
14839 (*presult).type = to;
14841 // https://issues.dlang.org/show_bug.cgi?id=12508
14842 // Tweak function body for covariant returns.
14843 (*presult).fd.modifyReturns(sc, tof.next);
14846 else if (!cast(ErrorSinkNull)eSink)
14848 auto ts = toAutoQualChars(tx, to);
14849 eSink.error(loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
14850 funcExp.toChars(), ts[0], ts[1]);
14852 return m;
14855 private bool checkSharedAccessBin(BinExp binExp, Scope* sc)
14857 const r1 = binExp.e1.checkSharedAccess(sc);
14858 const r2 = binExp.e2.checkSharedAccess(sc);
14859 return (r1 || r2);
14862 /***************************************
14863 * If expression is shared, check that we can access it.
14864 * Give error message if not.
14866 * Params:
14867 * e = expression to check
14868 * sc = context
14869 * returnRef = Whether this expression is for a `return` statement
14870 * off a `ref` function, in which case a single level
14871 * of dereference is allowed (e.g. `shared(int)*`).
14872 * Returns:
14873 * true on error
14875 bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
14877 if (global.params.noSharedAccess != FeatureState.enabled ||
14878 !sc ||
14879 sc.intypeof ||
14880 sc.flags & SCOPE.ctfe)
14882 return false;
14885 //printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef);
14887 bool check(Expression e, bool allowRef)
14889 bool sharedError(Expression e)
14891 // https://dlang.org/phobos/core_atomic.html
14892 error(e.loc, "direct access to shared `%s` is not allowed, see `core.atomic`", e.toChars());
14893 return true;
14896 // Error by default
14897 bool visit(Expression e)
14899 // https://issues.dlang.org/show_bug.cgi?id=23639
14900 // Should be able to cast(shared)
14901 if (!e.isCastExp() && e.type.isShared())
14902 return sharedError(e);
14903 return false;
14906 bool visitNew(NewExp e)
14908 if (e.thisexp)
14909 check(e.thisexp, false);
14910 return false;
14913 bool visitVar(VarExp e)
14915 // https://issues.dlang.org/show_bug.cgi?id=20908
14916 // direct access to init symbols is ok as they
14917 // cannot be modified.
14918 if (e.var.isSymbolDeclaration())
14919 return false;
14921 // https://issues.dlang.org/show_bug.cgi?id=22626
14922 // Synchronized functions don't need to use core.atomic
14923 // when accessing `this`.
14924 if (sc.func && sc.func.isSynchronized())
14926 if (e.var.isThisDeclaration())
14927 return false;
14928 else
14929 return sharedError(e);
14931 else if (!allowRef && e.var.type.isShared())
14932 return sharedError(e);
14934 return false;
14937 bool visitAddr(AddrExp e)
14939 return check(e.e1, true);
14942 bool visitPtr(PtrExp e)
14944 if (!allowRef && e.type.isShared())
14945 return sharedError(e);
14947 if (e.e1.type.isShared())
14948 return sharedError(e);
14950 return check(e.e1, false);
14953 bool visitDotVar(DotVarExp e)
14955 //printf("dotvarexp = %s\n", e.toChars());
14956 if (e.type.isShared())
14958 if (e.e1.isThisExp())
14960 // https://issues.dlang.org/show_bug.cgi?id=22626
14961 if (sc.func && sc.func.isSynchronized())
14962 return false;
14964 // https://issues.dlang.org/show_bug.cgi?id=23790
14965 if (e.e1.type.isTypeStruct())
14966 return false;
14969 auto fd = e.var.isFuncDeclaration();
14970 const sharedFunc = fd && fd.type.isShared;
14971 if (!allowRef && !sharedFunc)
14972 return sharedError(e);
14974 // Allow using `DotVarExp` within value types
14975 if (e.e1.type.isTypeSArray() || e.e1.type.isTypeStruct())
14976 return check(e.e1, allowRef);
14978 // If we end up with a single `VarExp`, it might be a `ref` param
14979 // `shared ref T` param == `shared(T)*`.
14980 if (auto ve = e.e1.isVarExp())
14982 return check(e.e1, allowRef && (ve.var.storage_class & STC.ref_));
14985 return sharedError(e);
14988 return check(e.e1, false);
14991 bool visitIndex(IndexExp e)
14993 if (!allowRef && e.type.isShared())
14994 return sharedError(e);
14996 if (e.e1.type.isShared())
14997 return sharedError(e);
14999 return check(e.e1, false);
15002 bool visitComma(CommaExp e)
15004 // Cannot be `return ref` since we can't use the return,
15005 // but it's better to show that error than an unrelated `shared` one
15006 return check(e.e2, true);
15009 switch (e.op)
15011 default: return visit(e);
15013 // Those have no indirections / can be ignored
15014 case EXP.call:
15015 case EXP.error:
15016 case EXP.complex80:
15017 case EXP.int64:
15018 case EXP.null_: return false;
15020 case EXP.variable: return visitVar(e.isVarExp());
15021 case EXP.new_: return visitNew(e.isNewExp());
15022 case EXP.address: return visitAddr(e.isAddrExp());
15023 case EXP.star: return visitPtr(e.isPtrExp());
15024 case EXP.dotVariable: return visitDotVar(e.isDotVarExp());
15025 case EXP.index: return visitIndex(e.isIndexExp());
15029 return check(e, returnRef);
15032 /****************************************
15033 * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE_FULL_PATH__ to loc.
15035 Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
15037 Expression visit(Expression exp)
15039 if (auto unaExp = exp.isUnaExp())
15041 unaExp.e1 = unaExp.e1.resolveLoc(loc, sc);
15042 return unaExp;
15044 exp.loc = loc;
15045 return exp;
15048 Expression visitCat(CatExp exp)
15050 exp.e1 = exp.e1.resolveLoc(loc, sc);
15051 exp.e2 = exp.e2.resolveLoc(loc, sc);
15052 return exp;
15055 Expression visitFileInit(FileInitExp exp)
15057 //printf("FileInitExp::resolve() %s\n", exp.toChars());
15058 const(char)* s;
15059 if (exp.op == EXP.fileFullPath)
15060 s = FileName.toAbsolute(loc.isValid() ? loc.filename : sc._module.srcfile.toChars());
15061 else
15062 s = loc.isValid() ? loc.filename : sc._module.ident.toChars();
15064 Expression e = new StringExp(loc, s.toDString());
15065 return e.expressionSemantic(sc);
15068 Expression visitLineInit(LineInitExp _)
15070 Expression e = new IntegerExp(loc, loc.linnum, Type.tint32);
15071 return e.expressionSemantic(sc);
15074 Expression visitModuleInit(ModuleInitExp _)
15076 const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString();
15077 Expression e = new StringExp(loc, s);
15078 return e.expressionSemantic(sc);
15081 Expression visitFuncInit(FuncInitExp _)
15083 const(char)* s;
15084 if (sc.callsc && sc.callsc.func)
15085 s = sc.callsc.func.Dsymbol.toPrettyChars();
15086 else if (sc.func)
15087 s = sc.func.Dsymbol.toPrettyChars();
15088 else
15089 s = "";
15090 Expression e = new StringExp(loc, s.toDString());
15091 return e.expressionSemantic(sc);
15094 Expression visitPrettyFunc(PrettyFuncInitExp _)
15096 FuncDeclaration fd = (sc.callsc && sc.callsc.func)
15097 ? sc.callsc.func
15098 : sc.func;
15100 const(char)* s;
15101 if (fd)
15103 const funcStr = fd.Dsymbol.toPrettyChars();
15104 OutBuffer buf;
15105 functionToBufferWithIdent(fd.type.isTypeFunction(), buf, funcStr, fd.isStatic);
15106 s = buf.extractChars();
15108 else
15110 s = "";
15113 Expression e = new StringExp(loc, s.toDString());
15114 e = e.expressionSemantic(sc);
15115 e.type = Type.tstring;
15116 return e;
15119 switch(exp.op)
15121 default: return visit(exp);
15122 case EXP.concatenate: return visitCat(exp.isCatExp());
15123 case EXP.file:
15124 case EXP.fileFullPath: return visitFileInit(exp.isFileInitExp());
15125 case EXP.line: return visitLineInit(exp.isLineInitExp);
15126 case EXP.moduleString: return visitModuleInit(exp.isModuleInitExp());
15127 case EXP.functionString: return visitFuncInit(exp.isFuncInitExp());
15128 case EXP.prettyFunction: return visitPrettyFunc(exp.isPrettyFuncInitExp());
15132 /************************************************
15133 * Destructors are attached to VarDeclarations.
15134 * Hence, if expression returns a temp that needs a destructor,
15135 * make sure and create a VarDeclaration for that temp.
15137 Expression addDtorHook(Expression e, Scope* sc)
15139 Expression visit(Expression exp)
15141 return exp;
15144 Expression visitStructLiteral(StructLiteralExp exp)
15146 auto sd = exp.sd;
15147 /* If struct requires a destructor, rewrite as:
15148 * (S tmp = S()),tmp
15149 * so that the destructor can be hung on tmp.
15151 if (sd.dtor && sc.func)
15153 /* Make an identifier for the temporary of the form:
15154 * __sl%s%d, where %s is the struct name
15156 char[10] buf = void;
15157 const prefix = "__sl";
15158 const ident = sd.ident.toString;
15159 const fullLen = prefix.length + ident.length;
15160 const len = fullLen < buf.length ? fullLen : buf.length;
15161 buf[0 .. prefix.length] = prefix;
15162 buf[prefix.length .. len] = ident[0 .. len - prefix.length];
15164 auto tmp = copyToTemp(0, buf[0 .. len], exp);
15165 Expression ae = new DeclarationExp(exp.loc, tmp);
15166 Expression e = new CommaExp(exp.loc, ae, new VarExp(exp.loc, tmp));
15167 e = e.expressionSemantic(sc);
15168 return e;
15171 return exp;
15174 Expression visitCall(CallExp exp)
15176 auto e1 = exp.e1;
15177 auto type = exp.type;
15178 /* Only need to add dtor hook if it's a type that needs destruction.
15179 * Use same logic as VarDeclaration::callScopeDtor()
15182 if (auto tf = e1.type.isTypeFunction())
15184 if (tf.isref)
15185 return exp;
15188 Type tv = type.baseElemOf();
15189 if (auto ts = tv.isTypeStruct())
15191 StructDeclaration sd = ts.sym;
15192 if (sd.dtor)
15194 /* Type needs destruction, so declare a tmp
15195 * which the back end will recognize and call dtor on
15197 auto tmp = copyToTemp(0, Id.__tmpfordtor.toString(), exp);
15198 auto de = new DeclarationExp(exp.loc, tmp);
15199 auto ve = new VarExp(exp.loc, tmp);
15200 Expression e = new CommaExp(exp.loc, de, ve);
15201 e = e.expressionSemantic(sc);
15202 return e;
15206 return exp;
15209 Expression visitCast(CastExp exp)
15211 if (exp.to.toBasetype().ty == Tvoid) // look past the cast(void)
15212 exp.e1 = exp.e1.addDtorHook(sc);
15213 return exp;
15216 Expression visitComma(CommaExp exp)
15218 exp.e2 = exp.e2.addDtorHook(sc);
15219 return exp;
15222 switch(e.op)
15224 default: return visit(e);
15226 case EXP.structLiteral: return visitStructLiteral(e.isStructLiteralExp());
15227 case EXP.call: return visitCall(e.isCallExp());
15228 case EXP.cast_: return visitCast(e.isCastExp());
15229 case EXP.comma: return visitComma(e.isCommaExp());
15233 /*******************************
15234 * Try to convert an expression to be an lvalue.
15236 * Give error if we're not an lvalue.
15237 * Params:
15238 * _this = expression to convert
15239 * sc = scope
15240 * action = for error messages, what the lvalue is needed for (e.g. take address of for `&x`, modify for `x++`)
15241 * Returns: converted expression, or `ErrorExp` on error
15243 extern(C++) Expression toLvalue(Expression _this, Scope* sc, const(char)* action)
15245 return toLvalueImpl(_this, sc, action, _this);
15248 // e = original un-lowered expression for error messages, in case of recursive calls
15249 private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action, Expression e)
15251 if (!action)
15252 action = "create lvalue of";
15254 assert(e);
15255 Expression visit(Expression _this)
15257 // BinaryAssignExp does not have an EXP associated
15258 // so it's treated on the default path.
15259 // Lvalue-ness will be handled in glue :layer.
15260 if (_this.isBinAssignExp())
15261 return _this;
15262 if (!_this.loc.isValid())
15263 _this.loc = e.loc;
15265 if (e.op == EXP.type)
15266 error(_this.loc, "cannot %s type `%s`", action, e.type.toChars());
15267 else if (e.op == EXP.template_)
15268 error(_this.loc, "cannot %s template `%s`, perhaps instantiate it first", action, e.toChars());
15269 else
15270 error(_this.loc, "cannot %s expression `%s` because it is not an lvalue", action, e.toChars());
15272 return ErrorExp.get();
15275 Expression visitInteger(IntegerExp _this)
15277 if (!_this.loc.isValid())
15278 _this.loc = e.loc;
15279 error(e.loc, "cannot %s constant `%s`", action, e.toChars());
15280 return ErrorExp.get();
15283 Expression visitThis(ThisExp _this)
15285 if (_this.type.toBasetype().ty == Tclass)
15287 // Class `this` is an rvalue; struct `this` is an lvalue.
15288 return visit(_this);
15291 return _this;
15294 Expression visitString(StringExp _this)
15296 //printf("StringExp::toLvalue(%s) type = %s\n", _this.toChars(), _this.type ? _this.type.toChars() : NULL);
15297 return (_this.type && _this.type.toBasetype().ty == Tsarray) ? _this : visit(_this);
15300 Expression visitStructLiteral(StructLiteralExp _this)
15302 if (sc.flags & SCOPE.Cfile)
15303 return _this; // C struct literals are lvalues
15304 else
15305 return visit(_this);
15308 Expression visitTemplate(TemplateExp _this)
15310 if (!_this.fd)
15311 return visit(_this);
15313 assert(sc);
15314 return symbolToExp(_this.fd, _this.loc, sc, true);
15318 Expression visitVar(VarExp _this)
15320 auto var = _this.var;
15321 if (var.storage_class & STC.manifest)
15323 error(_this.loc, "cannot %s manifest constant `%s`", action, var.toChars());
15324 return ErrorExp.get();
15326 if (var.storage_class & STC.lazy_ && !_this.delegateWasExtracted)
15328 error(_this.loc, "cannot %s lazy variable `%s`", action, var.toChars());
15329 return ErrorExp.get();
15331 if (var.ident == Id.ctfe)
15333 error(_this.loc, "cannot %s compiler-generated variable `__ctfe`", action);
15334 return ErrorExp.get();
15336 if (var.ident == Id.dollar) // https://issues.dlang.org/show_bug.cgi?id=13574
15338 error(_this.loc, "cannot %s operator `$`", action);
15339 return ErrorExp.get();
15341 return _this;
15344 Expression visitDotVar(DotVarExp _this)
15346 auto e1 = _this.e1;
15347 auto var = _this.var;
15348 //printf("DotVarExp::toLvalue(%s)\n", toChars());
15349 if (sc && sc.flags & SCOPE.Cfile)
15351 /* C11 6.5.2.3-3: A postfix expression followed by the '.' or '->' operator
15352 * is an lvalue if the first expression is an lvalue.
15354 if (!e1.isLvalue())
15355 return visit(_this);
15357 if (!_this.isLvalue())
15358 return visit(_this);
15359 if (e1.op == EXP.this_ && sc.ctorflow.fieldinit.length && !(sc.ctorflow.callSuper & CSX.any_ctor))
15361 if (VarDeclaration vd = var.isVarDeclaration())
15363 auto ad = vd.isMember2();
15364 if (ad && ad.fields.length == sc.ctorflow.fieldinit.length)
15366 foreach (i, f; ad.fields)
15368 if (f == vd)
15370 if (!(sc.ctorflow.fieldinit[i].csx & CSX.this_ctor))
15372 /* If the address of vd is taken, assume it is thereby initialized
15373 * https://issues.dlang.org/show_bug.cgi?id=15869
15375 modifyFieldVar(_this.loc, sc, vd, e1);
15377 break;
15383 return _this;
15386 Expression visitCall(CallExp _this)
15388 if (_this.isLvalue())
15389 return _this;
15390 return visit(_this);
15393 Expression visitCast(CastExp _this)
15395 if (sc && sc.flags & SCOPE.Cfile)
15397 /* C11 6.5.4-5: A cast does not yield an lvalue.
15399 return visit(_this);
15401 if (_this.isLvalue())
15402 return _this;
15403 return visit(_this);
15406 Expression visitVectorArray(VectorArrayExp _this)
15408 _this.e1 = _this.e1.toLvalueImpl(sc, action, e);
15409 return _this;
15412 Expression visitSlice(SliceExp _this)
15414 //printf("SliceExp::toLvalue(%s) _this.type = %s\n", _this.toChars(), _this.type ? _this.type.toChars() : NULL);
15415 return (_this.type && _this.type.toBasetype().ty == Tsarray) ? _this : visit(_this);
15418 Expression visitArray(ArrayExp _this)
15420 if (_this.type && _this.type.toBasetype().ty == Tvoid)
15421 error(_this.loc, "`void`s have no value");
15422 return _this;
15425 Expression visitComma(CommaExp _this)
15427 _this.e2 = _this.e2.toLvalue(sc, action);
15428 return _this;
15431 Expression visitDelegatePointer(DelegatePtrExp _this)
15433 _this.e1 = _this.e1.toLvalueImpl(sc, action, e);
15434 return _this;
15437 Expression visitDelegateFuncptr(DelegateFuncptrExp _this)
15439 _this.e1 = _this.e1.toLvalueImpl(sc, action, e);
15440 return _this;
15443 Expression visitIndex(IndexExp _this)
15445 if (_this.isLvalue())
15446 return _this;
15447 return visit(_this);
15450 Expression visitAssign(AssignExp _this)
15452 if (_this.e1.op == EXP.slice || _this.e1.op == EXP.arrayLength)
15454 return visit(_this);
15457 /* In front-end level, AssignExp should make an lvalue of e1.
15458 * Taking the address of e1 will be handled in low level layer,
15459 * so this function does nothing.
15461 return _this;
15464 Expression visitCond(CondExp _this)
15466 // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
15467 CondExp e = cast(CondExp)(_this.copy());
15468 e.e1 = _this.e1.toLvalue(sc, action).addressOf();
15469 e.e2 = _this.e2.toLvalue(sc, action).addressOf();
15470 e.type = _this.type.pointerTo();
15471 return new PtrExp(_this.loc, e, _this.type);
15475 switch(_this.op)
15477 default: return visit(_this);
15479 case EXP.int64: return visitInteger(_this.isIntegerExp());
15480 case EXP.error: return _this;
15481 case EXP.identifier: return _this;
15482 case EXP.dSymbol: return _this;
15483 case EXP.this_: return visitThis(_this.isThisExp());
15484 case EXP.super_: return visitThis(_this.isSuperExp());
15485 case EXP.string_: return visitString(_this.isStringExp());
15486 case EXP.structLiteral: return visitStructLiteral(_this.isStructLiteralExp());
15487 case EXP.template_: return visitTemplate(_this.isTemplateExp());
15488 case EXP.variable: return visitVar(_this.isVarExp());
15489 case EXP.overloadSet: return _this;
15490 case EXP.dotVariable: return visitDotVar(_this.isDotVarExp());
15491 case EXP.call: return visitCall(_this.isCallExp());
15492 case EXP.star: return _this;
15493 case EXP.cast_: return visitCast(_this.isCastExp());
15494 case EXP.vectorArray: return visitVectorArray(_this.isVectorArrayExp());
15495 case EXP.slice: return visitSlice(_this.isSliceExp());
15496 case EXP.array: return visitArray(_this.isArrayExp());
15497 case EXP.comma: return visitComma(_this.isCommaExp());
15498 case EXP.delegatePointer: return visitDelegatePointer(_this.isDelegatePtrExp());
15499 case EXP.delegateFunctionPointer: return visitDelegateFuncptr(_this.isDelegateFuncptrExp());
15500 case EXP.index: return visitIndex(_this.isIndexExp());
15501 case EXP.construct: return visitAssign(_this.isConstructExp());
15502 case EXP.loweredAssignExp: return visitAssign(_this.isLoweredAssignExp());
15503 case EXP.blit: return visitAssign(_this.isBlitExp());
15504 case EXP.assign: return visitAssign(_this.isAssignExp());
15505 case EXP.question: return visitCond(_this.isCondExp());
15509 /***************************************
15510 * Parameters:
15511 * sc: scope
15512 * flag: 1: do not issue error message for invalid modification
15513 2: the exp is a DotVarExp and a subfield of the leftmost
15514 variable is modified
15515 * Returns:
15516 * Whether the type is modifiable
15518 Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag = ModifyFlags.none)
15520 switch(exp.op)
15522 case EXP.variable:
15523 auto varExp = cast(VarExp)exp;
15525 //printf("VarExp::checkModifiable %s", varExp.toChars());
15526 assert(varExp.type);
15527 return varExp.var.checkModify(varExp.loc, sc, null, flag);
15529 case EXP.dotVariable:
15530 auto dotVarExp = cast(DotVarExp)exp;
15532 //printf("DotVarExp::checkModifiable %s %s\n", dotVarExp.toChars(), dotVarExp.type.toChars());
15533 if (dotVarExp.e1.op == EXP.this_)
15534 return dotVarExp.var.checkModify(dotVarExp.loc, sc, dotVarExp.e1, flag);
15536 /* https://issues.dlang.org/show_bug.cgi?id=12764
15537 * If inside a constructor and an expression of type `this.field.var`
15538 * is encountered, where `field` is a struct declaration with
15539 * default construction disabled, we must make sure that
15540 * assigning to `var` does not imply that `field` was initialized
15542 if (sc.func && sc.func.isCtorDeclaration())
15544 // if inside a constructor scope and e1 of this DotVarExp
15545 // is another DotVarExp, then check if the leftmost expression is a `this` identifier
15546 if (auto dve = dotVarExp.e1.isDotVarExp())
15548 // Iterate the chain of DotVarExp to find `this`
15549 // Keep track whether access to fields was limited to union members
15550 // s.t. one can initialize an entire struct inside nested unions
15551 // (but not its members)
15552 bool onlyUnion = true;
15553 while (true)
15555 auto v = dve.var.isVarDeclaration();
15556 assert(v);
15558 // Accessing union member?
15559 auto t = v.type.isTypeStruct();
15560 if (!t || !t.sym.isUnionDeclaration())
15561 onlyUnion = false;
15563 // Another DotVarExp left?
15564 if (!dve.e1 || dve.e1.op != EXP.dotVariable)
15565 break;
15567 dve = cast(DotVarExp) dve.e1;
15570 if (dve.e1.op == EXP.this_)
15572 scope v = dve.var.isVarDeclaration();
15573 /* if v is a struct member field with no initializer, no default construction
15574 * and v wasn't intialized before
15576 if (v && v.isField() && !v._init && !v.ctorinit)
15578 if (auto ts = v.type.isTypeStruct())
15580 if (ts.sym.noDefaultCtor)
15582 /* checkModify will consider that this is an initialization
15583 * of v while it is actually an assignment of a field of v
15585 scope modifyLevel = v.checkModify(dotVarExp.loc, sc, dve.e1, !onlyUnion ? (flag | ModifyFlags.fieldAssign) : flag);
15586 if (modifyLevel == Modifiable.initialization)
15588 // https://issues.dlang.org/show_bug.cgi?id=22118
15589 // v is a union type field that was assigned
15590 // a variable, therefore it counts as initialization
15591 if (v.ctorinit)
15592 return Modifiable.initialization;
15594 return Modifiable.yes;
15596 return modifyLevel;
15604 //printf("\te1 = %s\n", e1.toChars());
15605 return dotVarExp.e1.checkModifiable(sc, flag);
15607 case EXP.star:
15608 auto ptrExp = cast(PtrExp)exp;
15609 if (auto se = ptrExp.e1.isSymOffExp())
15611 return se.var.checkModify(ptrExp.loc, sc, null, flag);
15613 else if (auto ae = ptrExp.e1.isAddrExp())
15615 return ae.e1.checkModifiable(sc, flag);
15617 return Modifiable.yes;
15619 case EXP.slice:
15620 auto sliceExp = cast(SliceExp)exp;
15622 //printf("SliceExp::checkModifiable %s\n", sliceExp.toChars());
15623 auto e1 = sliceExp.e1;
15624 if (e1.type.ty == Tsarray || (e1.op == EXP.index && e1.type.ty != Tarray) || e1.op == EXP.slice)
15626 return e1.checkModifiable(sc, flag);
15628 return Modifiable.yes;
15630 case EXP.comma:
15631 return (cast(CommaExp)exp).e2.checkModifiable(sc, flag);
15633 case EXP.index:
15634 auto indexExp = cast(IndexExp)exp;
15635 auto e1 = indexExp.e1;
15636 if (e1.type.ty == Tsarray ||
15637 e1.type.ty == Taarray ||
15638 (e1.op == EXP.index && e1.type.ty != Tarray) ||
15639 e1.op == EXP.slice)
15641 return e1.checkModifiable(sc, flag);
15643 return Modifiable.yes;
15645 case EXP.question:
15646 auto condExp = cast(CondExp)exp;
15647 if (condExp.e1.checkModifiable(sc, flag) != Modifiable.no
15648 && condExp.e2.checkModifiable(sc, flag) != Modifiable.no)
15649 return Modifiable.yes;
15650 return Modifiable.no;
15652 default:
15653 return exp.type ? Modifiable.yes : Modifiable.no; // default modifiable
15658 * Similar to `toLvalue`, but also enforce it is mutable or raise an error.
15659 * Params:
15660 * _this = Expression to convert
15661 * sc = scope
15662 * Returns: `_this` converted to an lvalue, or an `ErrorExp`
15664 extern(C++) Expression modifiableLvalue(Expression _this, Scope* sc)
15666 return modifiableLvalueImpl(_this, sc, _this);
15669 // e = original / un-lowered expression to print in error messages
15670 private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression e)
15672 assert(e);
15673 Expression visit(Expression exp)
15675 //printf("Expression::modifiableLvalue() %s, type = %s\n", exp.toChars(), exp.type.toChars());
15676 // See if this expression is a modifiable lvalue (i.e. not const)
15677 if (exp.isBinAssignExp())
15678 return exp.toLvalue(sc, "modify");
15680 auto type = exp.type;
15681 if (checkModifiable(exp, sc) == Modifiable.yes)
15683 assert(type);
15684 if (!type.isMutable())
15686 if (auto dve = exp.isDotVarExp())
15688 if (isNeedThisScope(sc, dve.var))
15689 for (Dsymbol s = sc.func; s; s = s.toParentLocal())
15691 FuncDeclaration ff = s.isFuncDeclaration();
15692 if (!ff)
15693 break;
15694 if (!ff.type.isMutable)
15696 error(exp.loc, "cannot modify `%s` in `%s` function", exp.toChars(), MODtoChars(type.mod));
15697 return ErrorExp.get();
15701 error(exp.loc, "cannot modify `%s` expression `%s`", MODtoChars(type.mod), exp.toChars());
15702 return ErrorExp.get();
15704 else if (!type.isAssignable())
15706 error(exp.loc, "cannot modify struct instance `%s` of type `%s` because it contains `const` or `immutable` members",
15707 exp.toChars(), type.toChars());
15708 return ErrorExp.get();
15711 return exp.toLvalueImpl(sc, "modify", e);
15714 Expression visitString(StringExp exp)
15716 error(exp.loc, "cannot modify string literal `%s`", exp.toChars());
15717 return ErrorExp.get();
15720 Expression visitVar(VarExp exp)
15722 //printf("VarExp::modifiableLvalue('%s')\n", exp.var.toChars());
15723 if (exp.var.storage_class & STC.manifest)
15725 error(exp.loc, "cannot modify manifest constant `%s`", exp.toChars());
15726 return ErrorExp.get();
15728 // See if this expression is a modifiable lvalue (i.e. not const)
15729 return visit(exp);
15732 Expression visitPtr(PtrExp exp)
15734 //printf("PtrExp::modifiableLvalue() %s, type %s\n", exp.toChars(), exp.type.toChars());
15735 Declaration var;
15736 auto e1 = exp.e1;
15737 if (auto se = e1.isSymOffExp())
15738 var = se.var;
15739 else if (auto ve = e1.isVarExp())
15740 var = ve.var;
15741 if (var && var.type.isFunction_Delegate_PtrToFunction())
15743 if (var.type.isTypeFunction())
15744 error(exp.loc, "function `%s` is not an lvalue and cannot be modified", var.toChars());
15745 else
15746 error(exp.loc, "function pointed to by `%s` is not an lvalue and cannot be modified", var.toChars());
15747 return ErrorExp.get();
15749 return visit(exp);
15752 Expression visitSlice(SliceExp exp)
15754 error(exp.loc, "slice expression `%s` is not a modifiable lvalue", exp.toChars());
15755 return exp;
15758 Expression visitComma(CommaExp exp)
15760 exp.e2 = exp.e2.modifiableLvalueImpl(sc, e);
15761 return exp;
15764 Expression visitDelegatePtr(DelegatePtrExp exp)
15766 if (sc.setUnsafe(false, exp.loc, "cannot modify delegate pointer in `@safe` code `%s`", exp))
15768 return ErrorExp.get();
15770 return visit(exp);
15773 Expression visitDelegateFuncptr(DelegateFuncptrExp exp)
15775 if (sc.setUnsafe(false, exp.loc, "cannot modify delegate function pointer in `@safe` code `%s`", exp))
15777 return ErrorExp.get();
15779 return visit(exp);
15782 Expression visitIndex(IndexExp exp)
15784 //printf("IndexExp::modifiableLvalue(%s)\n", exp.toChars());
15785 Expression ex = exp.markSettingAAElem();
15786 if (ex.op == EXP.error)
15787 return ex;
15789 return visit(exp);
15792 Expression visitCond(CondExp exp)
15794 if (!exp.e1.isLvalue() && !exp.e2.isLvalue())
15796 error(exp.loc, "conditional expression `%s` is not a modifiable lvalue", exp.toChars());
15797 return ErrorExp.get();
15799 exp.e1 = exp.e1.modifiableLvalue(sc);
15800 exp.e2 = exp.e2.modifiableLvalue(sc);
15801 return exp.toLvalue(sc, "modify");
15804 switch(_this.op)
15806 default: return visit(_this);
15807 case EXP.string_: return visitString(_this.isStringExp());
15808 case EXP.variable: return visitVar(_this.isVarExp());
15809 case EXP.star: return visitPtr(_this.isPtrExp());
15810 case EXP.slice: return visitSlice(_this.isSliceExp());
15811 case EXP.comma: return visitComma(_this.isCommaExp());
15812 case EXP.delegatePointer: return visitDelegatePtr(_this.isDelegatePtrExp());
15813 case EXP.delegateFunctionPointer: return visitDelegateFuncptr(_this.isDelegateFuncptrExp());
15814 case EXP.index: return visitIndex(_this.isIndexExp());
15815 case EXP.question: return visitCond(_this.isCondExp());
15820 /****************************************************
15821 * Determine if `exp`, which gets its address taken, can do so safely.
15822 * Params:
15823 * sc = context
15824 * exp = expression having its address taken
15825 * v = the variable getting its address taken
15826 * Returns:
15827 * `true` if ok, `false` for error
15829 bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
15831 //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars());
15832 if (v is null)
15833 return true;
15835 if (!v.canTakeAddressOf())
15837 error(exp.loc, "cannot take address of `%s`", exp.toChars());
15838 return false;
15840 if (sc.func && !sc.intypeof && !v.isDataseg())
15842 if (sc.useDIP1000 != FeatureState.enabled &&
15843 !(v.storage_class & STC.temp) &&
15844 sc.setUnsafe(false, exp.loc, "cannot take address of local `%s` in `@safe` function `%s`", v, sc.func))
15846 return false;
15849 return true;
15852 /**************************************
15853 * This check ensures that the object in `exp` can have its address taken, or
15854 * issue a diagnostic error.
15855 * Params:
15856 * e = expression to check
15857 * sc = context
15858 * Returns:
15859 * true if the expression is addressable
15861 bool checkAddressable(Expression e, Scope* sc)
15863 Expression ex = e;
15864 while (true)
15866 switch (ex.op)
15868 case EXP.dotVariable:
15869 // https://issues.dlang.org/show_bug.cgi?id=22749
15870 // Error about taking address of any bit-field, regardless of
15871 // whether SCOPE.Cfile is set.
15872 if (auto bf = ex.isDotVarExp().var.isBitFieldDeclaration())
15874 error(e.loc, "cannot take address of bit-field `%s`", bf.toChars());
15875 return false;
15877 goto case EXP.cast_;
15879 case EXP.index:
15880 ex = ex.isBinExp().e1;
15881 continue;
15883 case EXP.address:
15884 case EXP.array:
15885 case EXP.cast_:
15886 ex = ex.isUnaExp().e1;
15887 continue;
15889 case EXP.variable:
15890 if (sc.flags & SCOPE.Cfile)
15892 // C11 6.5.3.2: A variable that has its address taken cannot be
15893 // stored in a register.
15894 // C11 6.3.2.1: An array that has its address computed with `[]`
15895 // or cast to an lvalue pointer cannot be stored in a register.
15896 if (ex.isVarExp().var.storage_class & STC.register)
15898 if (e.isIndexExp())
15899 error(e.loc, "cannot index through register variable `%s`", ex.toChars());
15900 else
15901 error(e.loc, "cannot take address of register variable `%s`", ex.toChars());
15902 return false;
15905 break;
15907 default:
15908 break;
15910 break;
15912 return true;
15916 /*******************************
15917 * Checks the attributes of a function.
15918 * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`)
15919 * and usage of `deprecated` and `@disabled`-ed symbols are checked.
15921 * Params:
15922 * exp = expression to check attributes for
15923 * sc = scope of the function
15924 * f = function to be checked
15925 * Returns: `true` if error occur.
15927 private bool checkFunctionAttributes(Expression exp, Scope* sc, FuncDeclaration f)
15929 bool error = f.checkDisabled(exp.loc, sc);
15930 error |= f.checkDeprecated(exp.loc, sc);
15931 error |= f.checkPurity(exp.loc, sc);
15932 error |= f.checkSafety(exp.loc, sc);
15933 error |= f.checkNogc(exp.loc, sc);
15934 return error;
15937 /*******************************
15938 * Helper function for `getRightThis()`.
15939 * Gets `this` of the next outer aggregate.
15940 * Params:
15941 * loc = location to use for error messages
15942 * sc = context
15943 * s = the parent symbol of the existing `this`
15944 * ad = struct or class we need the correct `this` for
15945 * e1 = existing `this`
15946 * t = type of the existing `this`
15947 * var = the specific member of ad we're accessing
15948 * flag = if true, return `null` instead of throwing an error
15949 * Returns:
15950 * Expression representing the `this` for the var
15952 Expression getThisSkipNestedFuncs(const ref Loc loc, Scope* sc, Dsymbol s, AggregateDeclaration ad, Expression e1, Type t, Dsymbol var, bool flag = false)
15954 int n = 0;
15955 while (s && s.isFuncDeclaration())
15957 FuncDeclaration f = s.isFuncDeclaration();
15958 if (f.vthis)
15960 n++;
15961 e1 = new VarExp(loc, f.vthis);
15962 if (f.hasDualContext())
15964 // (*__this)[i]
15965 if (n > 1)
15966 e1 = e1.expressionSemantic(sc);
15967 e1 = new PtrExp(loc, e1);
15968 uint i = f.followInstantiationContext(ad);
15969 e1 = new IndexExp(loc, e1, new IntegerExp(i));
15970 s = f.toParentP(ad);
15971 continue;
15974 else
15976 if (flag)
15977 return null;
15978 error(e1.loc, "need `this` of type `%s` to access member `%s` from static function `%s`", ad.toChars(), var.toChars(), f.toChars());
15979 e1 = ErrorExp.get();
15980 return e1;
15982 s = s.toParent2();
15984 if (n > 1 || e1.op == EXP.index)
15985 e1 = e1.expressionSemantic(sc);
15986 if (s && e1.type.equivalent(Type.tvoidptr))
15988 if (auto sad = s.isAggregateDeclaration())
15990 Type ta = sad.handleType();
15991 if (ta.ty == Tstruct)
15992 ta = ta.pointerTo();
15993 e1.type = ta;
15996 e1.type = e1.type.addMod(t.mod);
15997 return e1;
16000 /*******************************
16001 * Make a dual-context container for use as a `this` argument.
16002 * Params:
16003 * loc = location to use for error messages
16004 * sc = current scope
16005 * fd = target function that will take the `this` argument
16006 * Returns:
16007 * Temporary closure variable.
16008 * Note:
16009 * The function `fd` is added to the nested references of the
16010 * newly created variable such that a closure is made for the variable when
16011 * the address of `fd` is taken.
16013 VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration fd)
16015 Type tthis2 = Type.tvoidptr.sarrayOf(2);
16016 VarDeclaration vthis2 = new VarDeclaration(loc, tthis2, Identifier.generateId("__this"), null);
16017 vthis2.storage_class |= STC.temp;
16018 vthis2.dsymbolSemantic(sc);
16019 vthis2.parent = sc.parent;
16020 // make it a closure var
16021 assert(sc.func);
16022 sc.func.closureVars.push(vthis2);
16023 // add `fd` to the nested refs
16024 vthis2.nestedrefs.push(fd);
16025 return vthis2;
16028 /*******************************
16029 * Make sure that the runtime hook `id` exists.
16030 * Params:
16031 * loc = location to use for error messages
16032 * sc = current scope
16033 * id = the hook identifier
16034 * description = what the hook does
16035 * module_ = what module the hook is located in
16036 * Returns:
16037 * a `bool` indicating if the hook is present.
16039 bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string description, Identifier module_ = Id.object)
16041 auto rootSymbol = sc.search(loc, Id.empty, null);
16042 if (auto moduleSymbol = rootSymbol.search(loc, module_))
16043 if (moduleSymbol.search(loc, id))
16044 return true;
16045 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);
16046 return false;
16049 /***************************************
16050 * Fit elements[] to the corresponding types of the `sd`'s fields.
16052 * Params:
16053 * sd = the struct declaration
16054 * loc = location to use for error messages
16055 * sc = context
16056 * elements = explicit arguments used to construct object
16057 * stype = the constructed object type.
16058 * Returns:
16059 * false if any errors occur,
16060 * otherwise true and elements[] are rewritten for the output.
16062 private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions* elements, Type stype)
16064 if (!elements)
16065 return true;
16067 const nfields = sd.nonHiddenFields();
16068 size_t offset = 0;
16069 for (size_t i = 0; i < elements.length; i++)
16071 Expression e = (*elements)[i];
16072 if (!e)
16073 continue;
16075 e = resolveProperties(sc, e);
16076 if (i >= nfields)
16078 if (i < sd.fields.length && e.op == EXP.null_)
16080 // CTFE sometimes creates null as hidden pointer; we'll allow this.
16081 continue;
16083 .error(loc, "more initializers than fields (%llu) of `%s`", cast(ulong)nfields, sd.toChars());
16084 return false;
16086 VarDeclaration v = sd.fields[i];
16087 if (v.offset < offset)
16089 .error(loc, "overlapping initialization for `%s`", v.toChars());
16090 if (!sd.isUnionDeclaration())
16092 enum errorMsg = "`struct` initializers that contain anonymous unions" ~
16093 " must initialize only the first member of a `union`. All subsequent" ~
16094 " non-overlapping fields are default initialized";
16095 .errorSupplemental(loc, errorMsg);
16097 return false;
16099 const vsize = v.type.size();
16100 if (vsize == SIZE_INVALID)
16101 return false;
16102 offset = cast(uint)(v.offset + vsize);
16104 Type t = v.type;
16105 if (stype)
16106 t = t.addMod(stype.mod);
16107 Type origType = t;
16108 Type tb = t.toBasetype();
16110 const hasPointers = tb.hasPointers();
16111 if (hasPointers)
16113 if ((!stype.alignment.isDefault() && stype.alignment.get() < target.ptrsize ||
16114 (v.offset & (target.ptrsize - 1))) &&
16115 (sc.setUnsafe(false, loc,
16116 "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, v)))
16118 return false;
16122 /* Look for case of initializing a static array with a too-short
16123 * string literal, such as:
16124 * char[5] foo = "abc";
16125 * Allow this by doing an explicit cast, which will lengthen the string
16126 * literal.
16128 if (e.op == EXP.string_ && tb.ty == Tsarray)
16130 StringExp se = cast(StringExp)e;
16131 Type typeb = se.type.toBasetype();
16132 TY tynto = tb.nextOf().ty;
16133 if (!se.committed &&
16134 (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar &&
16135 se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger())
16137 e = se.castTo(sc, t);
16138 goto L1;
16142 while (!e.implicitConvTo(t) && tb.ty == Tsarray)
16144 /* Static array initialization, as in:
16145 * T[3][5] = e;
16147 t = tb.nextOf();
16148 tb = t.toBasetype();
16150 if (!e.implicitConvTo(t))
16151 t = origType; // restore type for better diagnostic
16153 e = e.implicitCastTo(sc, t);
16155 if (e.op == EXP.error)
16156 return false;
16158 (*elements)[i] = doCopyOrMove(sc, e);
16160 return true;
16165 * Returns `em` as a VariableExp
16166 * Params:
16167 * em = the EnumMember to wrap
16168 * loc = location of use of em
16169 * sc = scope of use of em
16170 * Returns:
16171 * VarExp referenceing `em` or ErrorExp if `em` if disabled/deprecated
16173 Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc)
16175 dsymbolSemantic(em, sc);
16176 if (em.errors)
16177 return ErrorExp.get();
16178 em.checkDisabled(loc, sc);
16180 if (em.depdecl && !em.depdecl._scope)
16181 em.depdecl._scope = sc;
16182 em.checkDeprecated(loc, sc);
16184 if (em.errors)
16185 return ErrorExp.get();
16186 Expression e = new VarExp(loc, em);
16187 e = e.expressionSemantic(sc);
16188 if (!(sc.flags & SCOPE.Cfile) && em.isCsymbol())
16190 /* C11 types them as int. But if in D file,
16191 * type qualified names as the enum
16193 e.type = em.parent.isEnumDeclaration().type;
16194 assert(e.type);
16196 return e;
16200 /*****************************
16201 * Try to treat `exp` as a boolean,
16202 * Params:
16203 * exp = the expression
16204 * sc = scope to evalute `exp` in
16205 * Returns:
16206 * Modified expression on success, ErrorExp on error
16208 Expression toBoolean(Expression exp, Scope* sc)
16210 switch(exp.op)
16212 case EXP.delete_:
16213 error(exp.loc, "`delete` does not give a boolean result");
16214 return ErrorExp.get();
16216 case EXP.comma:
16217 auto ce = exp.isCommaExp();
16218 auto ex2 = ce.e2.toBoolean(sc);
16219 if (ex2.op == EXP.error)
16220 return ex2;
16221 ce.e2 = ex2;
16222 ce.type = ce.e2.type;
16223 return ce;
16225 case EXP.assign:
16226 case EXP.construct:
16227 case EXP.blit:
16228 case EXP.loweredAssignExp:
16229 if (sc.flags & SCOPE.Cfile)
16230 return exp;
16231 // Things like:
16232 // if (a = b) ...
16233 // are usually mistakes.
16234 error(exp.loc, "assignment cannot be used as a condition, perhaps `==` was meant?");
16235 return ErrorExp.get();
16237 //LogicalExp
16238 case EXP.andAnd:
16239 case EXP.orOr:
16240 auto le = exp.isLogicalExp();
16241 auto ex2 = le.e2.toBoolean(sc);
16242 if (ex2.op == EXP.error)
16243 return ex2;
16244 le.e2 = ex2;
16245 return le;
16247 case EXP.question:
16248 auto ce = exp.isCondExp();
16249 auto ex1 = ce.e1.toBoolean(sc);
16250 auto ex2 = ce.e2.toBoolean(sc);
16251 if (ex1.op == EXP.error)
16252 return ex1;
16253 if (ex2.op == EXP.error)
16254 return ex2;
16255 ce.e1 = ex1;
16256 ce.e2 = ex2;
16257 return ce;
16260 default:
16261 // Default is 'yes' - do nothing
16262 Expression e = arrayFuncConv(exp, sc);
16263 Type t = e.type;
16264 Type tb = t.toBasetype();
16265 Type att = null;
16267 while (1)
16269 // Structs can be converted to bool using opCast(bool)()
16270 if (auto ts = tb.isTypeStruct())
16272 AggregateDeclaration ad = ts.sym;
16273 /* Don't really need to check for opCast first, but by doing so we
16274 * get better error messages if it isn't there.
16276 if (Dsymbol fd = search_function(ad, Id._cast))
16278 e = new CastExp(exp.loc, e, Type.tbool);
16279 e = e.expressionSemantic(sc);
16280 return e;
16283 // Forward to aliasthis.
16284 if (ad.aliasthis && !isRecursiveAliasThis(att, tb))
16286 e = resolveAliasThis(sc, e);
16287 t = e.type;
16288 tb = e.type.toBasetype();
16289 continue;
16292 break;
16295 if (!t.isBoolean())
16297 if (tb != Type.terror)
16298 error(exp.loc, "expression `%s` of type `%s` does not have a boolean value",
16299 exp.toChars(), t.toChars());
16300 return ErrorExp.get();
16302 return e;