d: Merge upstream dmd, druntime f1a045928e
[official-gcc.git] / gcc / d / dmd / expressionsem.d
blobc21b382c71ec5cfd9b73266e906157d28a3678cc
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(SearchOptFlags 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 |= SearchOpt.unqualifiedModule; // tell Module.search() that SearchOpt.localsOnly 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 SearchOptFlags flags = SearchOpt.all;
914 Dsymbol s;
916 if (sc.flags & SCOPE.ignoresymbolvisibility)
917 flags |= SearchOpt.ignoreVisibility;
919 // First look in local scopes
920 s = searchScopes(flags | SearchOpt.localsOnly);
921 if (!s)
923 // Second look in imported modules
924 s = searchScopes(flags | SearchOpt.importsOnly);
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", toChars(init));
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 Dsymbol pscopesym;
6748 auto conflict = sc.search(Loc.initial, s.ident, pscopesym);
6749 error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
6750 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
6751 conflict.kind(), conflict.toChars());
6752 return setError();
6755 if (v && (sc.flags & SCOPE.Cfile))
6757 /* Do semantic() on initializer last so this will be legal:
6758 * int a = a;
6760 e.declaration.dsymbolSemantic(sc);
6761 s.parent = sc.parent;
6764 if (sc.func)
6766 // https://issues.dlang.org/show_bug.cgi?id=11720
6767 if ((s.isFuncDeclaration() ||
6768 s.isAggregateDeclaration() ||
6769 s.isEnumDeclaration() ||
6770 s.isTemplateDeclaration() ||
6772 ) && !sc.func.localsymtab.insert(s))
6774 // Get the previous symbol
6775 Dsymbol originalSymbol = sc.func.localsymtab.lookup(s.ident);
6777 // Perturb the name mangling so that the symbols can co-exist
6778 // instead of colliding
6779 s.localNum = cast(ushort)(originalSymbol.localNum + 1);
6780 // 65535 should be enough for anyone
6781 if (!s.localNum)
6783 error(e.loc, "more than 65535 symbols with name `%s` generated", s.ident.toChars());
6784 return setError();
6787 // Replace originalSymbol with s, which updates the localCount
6788 sc.func.localsymtab.update(s);
6790 // The mangling change only works for D mangling
6793 if (!(sc.flags & SCOPE.Cfile))
6795 /* https://issues.dlang.org/show_bug.cgi?id=21272
6796 * If we are in a foreach body we need to extract the
6797 * function containing the foreach
6799 FuncDeclaration fes_enclosing_func;
6800 if (sc.func && sc.func.fes)
6801 fes_enclosing_func = sc.enclosing.enclosing.func;
6803 // Disallow shadowing
6804 for (Scope* scx = sc.enclosing; scx && (scx.func == sc.func || (fes_enclosing_func && scx.func == fes_enclosing_func)); scx = scx.enclosing)
6806 Dsymbol s2;
6807 if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2)
6809 // allow STC.local symbols to be shadowed
6810 // TODO: not really an optimal design
6811 auto decl = s2.isDeclaration();
6812 if (!decl || !(decl.storage_class & STC.local))
6814 if (sc.func.fes)
6816 deprecation(e.loc, "%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
6818 else
6820 error(e.loc, "%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
6821 return setError();
6829 if (!s.isVarDeclaration())
6831 Scope* sc2 = sc;
6832 if (sc2.stc & (STC.pure_ | STC.nothrow_ | STC.nogc))
6833 sc2 = sc.push();
6834 sc2.stc &= ~(STC.pure_ | STC.nothrow_ | STC.nogc);
6835 e.declaration.dsymbolSemantic(sc2);
6836 if (sc2 != sc)
6837 sc2.pop();
6838 s.parent = sc.parent;
6840 if (global.errors == olderrors)
6842 e.declaration.semantic2(sc);
6843 if (global.errors == olderrors)
6845 e.declaration.semantic3(sc);
6848 // todo: error in declaration should be propagated.
6850 e.type = Type.tvoid;
6851 result = e;
6854 override void visit(TypeidExp exp)
6856 static if (LOGSEMANTIC)
6858 printf("TypeidExp::semantic() %s\n", exp.toChars());
6860 Type ta = isType(exp.obj);
6861 Expression ea = isExpression(exp.obj);
6862 Dsymbol sa = isDsymbol(exp.obj);
6863 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
6865 if (ta)
6867 dmd.typesem.resolve(ta, exp.loc, sc, ea, ta, sa, true);
6870 if (ea)
6872 if (auto sym = getDsymbol(ea))
6873 ea = symbolToExp(sym, exp.loc, sc, false);
6874 else
6875 ea = ea.expressionSemantic(sc);
6876 ea = resolveProperties(sc, ea);
6877 ta = ea.type;
6878 if (ea.op == EXP.type)
6879 ea = null;
6882 if (!ta)
6884 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
6885 error(exp.loc, "no type for `typeid(%s)`", ea ? ea.toChars() : (sa ? sa.toChars() : ""));
6886 return setError();
6889 ta.checkComplexTransition(exp.loc, sc);
6891 Expression e;
6892 auto tb = ta.toBasetype();
6893 if (ea && tb.ty == Tclass)
6895 if (tb.toDsymbol(sc).isClassDeclaration().classKind == ClassKind.cpp)
6897 error(exp.loc, "runtime type information is not supported for `extern(C++)` classes");
6898 e = ErrorExp.get();
6900 else if (!Type.typeinfoclass)
6902 error(exp.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
6903 e = ErrorExp.get();
6905 else
6907 /* Get the dynamic type, which is .classinfo
6909 ea = ea.expressionSemantic(sc);
6910 e = new TypeidExp(ea.loc, ea);
6911 e.type = Type.typeinfoclass.type;
6914 else if (ta.ty == Terror)
6916 e = ErrorExp.get();
6918 else
6920 // Handle this in the glue layer
6921 e = new TypeidExp(exp.loc, ta);
6923 bool genObjCode = true;
6925 // https://issues.dlang.org/show_bug.cgi?id=23650
6926 // We generate object code for typeinfo, required
6927 // by typeid, only if in non-speculative context
6928 if (sc.flags & SCOPE.compile)
6930 genObjCode = false;
6933 e.type = getTypeInfoType(exp.loc, ta, sc, genObjCode);
6934 semanticTypeInfo(sc, ta);
6936 if (ea)
6938 e = new CommaExp(exp.loc, ea, e); // execute ea
6939 e = e.expressionSemantic(sc);
6942 result = e;
6945 override void visit(TraitsExp e)
6947 result = semanticTraits(e, sc);
6950 override void visit(HaltExp e)
6952 static if (LOGSEMANTIC)
6954 printf("HaltExp::semantic()\n");
6956 e.type = Type.tnoreturn;
6957 result = e;
6960 override void visit(IsExp e)
6962 /* is(targ id tok tspec)
6963 * is(targ id : tok2)
6964 * is(targ id == tok2)
6966 Type tded = null;
6968 void yes()
6970 //printf("yes\n");
6971 if (!e.id)
6973 result = IntegerExp.createBool(true);
6974 return;
6977 Dsymbol s;
6978 Tuple tup = isTuple(tded);
6979 if (tup)
6980 s = new TupleDeclaration(e.loc, e.id, &tup.objects);
6981 else
6982 s = new AliasDeclaration(e.loc, e.id, tded);
6983 s.dsymbolSemantic(sc);
6985 /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there.
6986 * More investigation is needed.
6988 if (!tup && !sc.insert(s))
6990 Dsymbol pscopesym;
6991 auto conflict = sc.search(Loc.initial, s.ident, pscopesym);
6992 error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
6993 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
6994 conflict.kind(), conflict.toChars());
6997 unSpeculative(sc, s);
6999 result = IntegerExp.createBool(true);
7001 void no()
7003 result = IntegerExp.createBool(false);
7004 //printf("no\n");
7007 static if (LOGSEMANTIC)
7009 printf("IsExp::semantic(%s)\n", e.toChars());
7011 if (e.id && !(sc.flags & SCOPE.condition))
7013 error(e.loc, "can only declare type aliases within `static if` conditionals or `static assert`s");
7014 return setError();
7017 if (e.tok2 == TOK.package_ || e.tok2 == TOK.module_) // These is() expressions are special because they can work on modules, not just types.
7019 const oldErrors = global.startGagging();
7020 Dsymbol sym = e.targ.toDsymbol(sc);
7021 global.endGagging(oldErrors);
7023 if (sym is null)
7024 return no();
7025 Package p = resolveIsPackage(sym);
7026 if (p is null)
7027 return no();
7028 if (e.tok2 == TOK.package_ && p.isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module.
7029 return no();
7030 else if(e.tok2 == TOK.module_ && !(p.isModule() || p.isPackageMod()))
7031 return no();
7032 tded = e.targ;
7033 return yes();
7037 Scope* sc2 = sc.copy(); // keep sc.flags
7038 sc2.tinst = null;
7039 sc2.minst = null;
7040 sc2.flags |= SCOPE.fullinst;
7041 Type t = e.targ.trySemantic(e.loc, sc2);
7042 sc2.pop();
7043 if (!t) // errors, so condition is false
7044 return no();
7045 e.targ = t;
7048 if (e.tok2 != TOK.reserved)
7050 switch (e.tok2)
7052 case TOK.struct_:
7053 if (e.targ.ty != Tstruct)
7054 return no();
7055 if ((cast(TypeStruct)e.targ).sym.isUnionDeclaration())
7056 return no();
7057 tded = e.targ;
7058 break;
7060 case TOK.union_:
7061 if (e.targ.ty != Tstruct)
7062 return no();
7063 if (!(cast(TypeStruct)e.targ).sym.isUnionDeclaration())
7064 return no();
7065 tded = e.targ;
7066 break;
7068 case TOK.class_:
7069 if (e.targ.ty != Tclass)
7070 return no();
7071 if ((cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
7072 return no();
7073 tded = e.targ;
7074 break;
7076 case TOK.interface_:
7077 if (e.targ.ty != Tclass)
7078 return no();
7079 if (!(cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
7080 return no();
7081 tded = e.targ;
7082 break;
7084 case TOK.const_:
7085 if (!e.targ.isConst())
7086 return no();
7087 tded = e.targ;
7088 break;
7090 case TOK.immutable_:
7091 if (!e.targ.isImmutable())
7092 return no();
7093 tded = e.targ;
7094 break;
7096 case TOK.shared_:
7097 if (!e.targ.isShared())
7098 return no();
7099 tded = e.targ;
7100 break;
7102 case TOK.inout_:
7103 if (!e.targ.isWild())
7104 return no();
7105 tded = e.targ;
7106 break;
7108 case TOK.super_:
7109 // If class or interface, get the base class and interfaces
7110 if (e.targ.ty != Tclass)
7111 return no();
7112 else
7114 ClassDeclaration cd = (cast(TypeClass)e.targ).sym;
7115 auto args = new Parameters();
7116 args.reserve(cd.baseclasses.length);
7117 if (cd.semanticRun < PASS.semanticdone)
7118 cd.dsymbolSemantic(null);
7119 for (size_t i = 0; i < cd.baseclasses.length; i++)
7121 BaseClass* b = (*cd.baseclasses)[i];
7122 args.push(new Parameter(Loc.initial, STC.in_, b.type, null, null, null));
7124 tded = new TypeTuple(args);
7126 break;
7128 case TOK.enum_:
7129 if (e.targ.ty != Tenum)
7130 return no();
7131 if (e.id)
7132 tded = (cast(TypeEnum)e.targ).sym.getMemtype(e.loc);
7133 else
7134 tded = e.targ;
7136 if (tded.ty == Terror)
7137 return setError();
7138 break;
7140 case TOK.delegate_:
7141 if (e.targ.ty != Tdelegate)
7142 return no();
7143 tded = (cast(TypeDelegate)e.targ).next; // the underlying function type
7144 break;
7146 case TOK.function_:
7147 if (e.targ.ty != Tfunction)
7148 return no();
7149 goto case;
7150 case TOK.parameters:
7152 if (auto tf = e.targ.isFunction_Delegate_PtrToFunction())
7153 tded = tf;
7154 else
7155 return no();
7157 /* Generate tuple from function parameter types.
7159 auto args = new Parameters();
7160 foreach (i, arg; tded.isTypeFunction().parameterList)
7162 assert(arg && arg.type);
7163 /* If one of the default arguments was an error,
7164 don't return an invalid tuple
7166 if (e.tok2 == TOK.parameters && arg.defaultArg && arg.defaultArg.op == EXP.error)
7167 return setError();
7168 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));
7170 tded = new TypeTuple(args);
7171 break;
7173 case TOK.return_:
7174 /* Get the 'return type' for the function,
7175 * delegate, or pointer to function.
7177 if (auto tf = e.targ.isFunction_Delegate_PtrToFunction())
7178 tded = tf.next;
7179 else
7180 return no();
7181 break;
7183 case TOK.argumentTypes:
7184 /* Generate a type tuple of the equivalent types used to determine if a
7185 * function argument of this type can be passed in registers.
7186 * The results of this are highly platform dependent, and intended
7187 * primarly for use in implementing va_arg().
7189 tded = target.toArgTypes(e.targ);
7190 if (!tded)
7191 return no();
7192 // not valid for a parameter
7193 break;
7195 case TOK.vector:
7196 if (e.targ.ty != Tvector)
7197 return no();
7198 tded = (cast(TypeVector)e.targ).basetype;
7199 break;
7201 default:
7202 assert(0);
7205 // https://issues.dlang.org/show_bug.cgi?id=18753
7206 if (tded)
7207 return yes();
7208 return no();
7210 else if (e.tspec && !e.id && !(e.parameters && e.parameters.length))
7212 /* Evaluate to true if targ matches tspec
7213 * is(targ == tspec)
7214 * is(targ : tspec)
7216 e.tspec = e.tspec.typeSemantic(e.loc, sc);
7217 //printf("targ = %s, %s\n", e.targ.toChars(), e.targ.deco);
7218 //printf("tspec = %s, %s\n", e.tspec.toChars(), e.tspec.deco);
7220 if (e.tok == TOK.colon)
7222 // current scope is itself deprecated, or deprecations are not errors
7223 const bool deprecationAllowed = sc.isDeprecated
7224 || global.params.useDeprecated != DiagnosticReporting.error;
7225 const bool preventAliasThis = e.targ.hasDeprecatedAliasThis && !deprecationAllowed;
7227 if (preventAliasThis && e.targ.ty == Tstruct)
7229 if ((cast(TypeStruct) e.targ).implicitConvToWithoutAliasThis(e.tspec))
7230 return yes();
7231 else
7232 return no();
7234 else if (preventAliasThis && e.targ.ty == Tclass)
7236 if ((cast(TypeClass) e.targ).implicitConvToWithoutAliasThis(e.tspec))
7237 return yes();
7238 else
7239 return no();
7241 else if (e.targ.implicitConvTo(e.tspec))
7242 return yes();
7243 else
7244 return no();
7246 else /* == */
7248 if (e.targ.equals(e.tspec))
7249 return yes();
7250 else
7251 return no();
7254 else if (e.tspec)
7256 /* Evaluate to true if targ matches tspec.
7257 * If true, declare id as an alias for the specialized type.
7258 * is(targ == tspec, tpl)
7259 * is(targ : tspec, tpl)
7260 * is(targ id == tspec)
7261 * is(targ id : tspec)
7262 * is(targ id == tspec, tpl)
7263 * is(targ id : tspec, tpl)
7265 Identifier tid = e.id ? e.id : Identifier.generateId("__isexp_id");
7266 e.parameters.insert(0, new TemplateTypeParameter(e.loc, tid, null, null));
7268 Objects dedtypes = Objects(e.parameters.length);
7269 dedtypes.zero();
7271 MATCH m = deduceType(e.targ, sc, e.tspec, e.parameters, &dedtypes, null, 0, e.tok == TOK.equal);
7273 if (m == MATCH.nomatch || (m != MATCH.exact && e.tok == TOK.equal))
7275 return no();
7277 else
7279 tded = cast(Type)dedtypes[0];
7280 if (!tded)
7281 tded = e.targ;
7282 Objects tiargs = Objects(1);
7283 tiargs[0] = e.targ;
7285 /* Declare trailing parameters
7287 for (size_t i = 1; i < e.parameters.length; i++)
7289 TemplateParameter tp = (*e.parameters)[i];
7290 Declaration s = null;
7292 m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, &dedtypes, &s);
7293 if (m == MATCH.nomatch)
7294 return no();
7295 s.dsymbolSemantic(sc);
7296 if (!sc.insert(s))
7298 Dsymbol pscopesym;
7299 auto conflict = sc.search(Loc.initial, s.ident, pscopesym);
7300 error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
7301 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
7302 conflict.kind(), conflict.toChars());
7305 unSpeculative(sc, s);
7307 return yes();
7310 else if (e.id)
7312 /* Declare id as an alias for type targ. Evaluate to true
7313 * is(targ id)
7315 tded = e.targ;
7317 return yes();
7320 override void visit(BinAssignExp exp)
7322 if (exp.type)
7324 result = exp;
7325 return;
7328 Expression e = exp.op_overload(sc);
7329 if (e)
7331 result = e;
7332 return;
7335 if (exp.e1.op == EXP.arrayLength)
7337 // arr.length op= e2;
7338 e = rewriteOpAssign(exp);
7339 e = e.expressionSemantic(sc);
7340 result = e;
7341 return;
7343 if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
7345 if (checkNonAssignmentArrayOp(exp.e1))
7346 return setError();
7348 if (exp.e1.op == EXP.slice)
7349 (cast(SliceExp)exp.e1).arrayop = true;
7351 // T[] op= ...
7352 if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
7354 // T[] op= T
7355 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
7357 else if (Expression ex = typeCombine(exp, sc))
7359 result = ex;
7360 return;
7362 exp.type = exp.e1.type;
7363 result = arrayOp(exp, sc);
7364 return;
7367 exp.e1 = exp.e1.expressionSemantic(sc);
7368 exp.e1 = exp.e1.modifiableLvalue(sc);
7369 exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
7370 exp.type = exp.e1.type;
7372 if (auto ad = isAggregate(exp.e1.type))
7374 if (const s = search_function(ad, Id.opOpAssign))
7376 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());
7377 return setError();
7380 if (exp.e1.checkScalar() ||
7381 exp.e1.checkReadModifyWrite(exp.op, exp.e2) ||
7382 exp.e1.checkSharedAccess(sc))
7383 return setError();
7385 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);
7386 int bitwise = (exp.op == EXP.andAssign || exp.op == EXP.orAssign || exp.op == EXP.xorAssign);
7387 int shift = (exp.op == EXP.leftShiftAssign || exp.op == EXP.rightShiftAssign || exp.op == EXP.unsignedRightShiftAssign);
7389 if (bitwise && exp.type.toBasetype().ty == Tbool)
7390 exp.e2 = exp.e2.implicitCastTo(sc, exp.type);
7391 else if (exp.checkNoBool())
7392 return setError();
7394 if ((exp.op == EXP.addAssign || exp.op == EXP.minAssign) && exp.e1.type.toBasetype().ty == Tpointer && exp.e2.type.toBasetype().isintegral())
7396 result = scaleFactor(exp, sc);
7397 return;
7400 if (Expression ex = typeCombine(exp, sc))
7402 result = ex;
7403 return;
7406 if (arith && (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)))
7407 return setError();
7408 if ((bitwise || shift) && (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)))
7409 return setError();
7411 if (shift)
7413 if (exp.e2.type.toBasetype().ty != Tvector)
7414 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
7417 if (!target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
7419 result = exp.incompatibleTypes();
7420 return;
7423 if (exp.e1.op == EXP.error || exp.e2.op == EXP.error)
7424 return setError();
7426 e = exp.checkOpAssignTypes(sc);
7427 if (e.op == EXP.error)
7429 result = e;
7430 return;
7433 assert(e.op == EXP.assign || e == exp);
7434 result = (cast(BinExp)e).reorderSettingAAElem(sc);
7437 private Expression compileIt(MixinExp exp)
7439 OutBuffer buf;
7440 if (expressionsToString(buf, sc, exp.exps))
7441 return null;
7443 uint errors = global.errors;
7444 const len = buf.length;
7445 const str = buf.extractChars()[0 .. len];
7446 const bool doUnittests = global.params.parsingUnittestsRequired();
7447 auto loc = adjustLocForMixin(str, exp.loc, global.params.mixinOut);
7448 scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
7449 p.transitionIn = global.params.v.vin;
7450 p.nextToken();
7451 //printf("p.loc.linnum = %d\n", p.loc.linnum);
7453 Expression e = p.parseExpression();
7454 if (global.errors != errors)
7455 return null;
7457 if (p.token.value != TOK.endOfFile)
7459 error(e.loc, "unexpected token `%s` after %s expression",
7460 p.token.toChars(), EXPtoString(e.op).ptr);
7461 errorSupplemental(e.loc, "while parsing string mixin expression `%s`",
7462 str.ptr);
7463 return null;
7465 return e;
7468 override void visit(MixinExp exp)
7470 /* https://dlang.org/spec/expression.html#mixin_expressions
7473 static if (LOGSEMANTIC)
7475 printf("MixinExp::semantic('%s')\n", exp.toChars());
7478 auto e = compileIt(exp);
7479 if (!e)
7480 return setError();
7481 result = e.expressionSemantic(sc);
7484 override void visit(ImportExp e)
7486 static if (LOGSEMANTIC)
7488 printf("ImportExp::semantic('%s')\n", e.toChars());
7491 auto se = semanticString(sc, e.e1, "file name argument");
7492 if (!se)
7493 return setError();
7494 se = se.toUTF8(sc);
7496 auto namez = se.toStringz();
7497 if (!global.filePath)
7499 error(e.loc, "need `-J` switch to import text file `%s`", namez.ptr);
7500 return setError();
7503 /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
7504 * ('Path Traversal') attacks.
7505 * https://cwe.mitre.org/data/definitions/22.html
7508 if (FileName.absolute(namez))
7510 error(e.loc, "absolute path is not allowed in import expression: `%s`", se.toChars());
7511 return setError();
7514 auto idxReserved = FileName.findReservedChar(namez);
7515 if (idxReserved != size_t.max)
7517 error(e.loc, "`%s` is not a valid filename on this platform", se.toChars());
7518 errorSupplemental(e.loc, "Character `'%c'` is reserved and cannot be used", namez[idxReserved]);
7519 return setError();
7522 if (FileName.refersToParentDir(namez))
7524 error(e.loc, "path refers to parent (`..`) directory: `%s`", se.toChars());
7525 return setError();
7528 auto resolvedNamez = FileName.searchPath(global.filePath, namez, false);
7529 if (!resolvedNamez)
7531 error(e.loc, "file `%s` cannot be found or not in a path specified with `-J`", se.toChars());
7532 errorSupplemental(e.loc, "Path(s) searched (as provided by `-J`):");
7533 foreach (idx, path; *global.filePath)
7535 const attr = FileName.exists(path);
7536 const(char)* err = attr == 2 ? "" :
7537 (attr == 1 ? " (not a directory)" : " (path not found)");
7538 errorSupplemental(e.loc, "[%llu]: `%s`%s", cast(ulong)idx, path, err);
7540 return setError();
7543 sc._module.contentImportedFiles.push(resolvedNamez.ptr);
7544 if (global.params.v.verbose)
7546 const slice = se.peekString();
7547 message("file %.*s\t(%s)", cast(int)slice.length, slice.ptr, resolvedNamez.ptr);
7549 if (global.params.moduleDeps.buffer !is null)
7551 OutBuffer* ob = global.params.moduleDeps.buffer;
7552 Module imod = sc._module;
7554 if (!global.params.moduleDeps.name)
7555 ob.writestring("depsFile ");
7556 ob.writestring(imod.toPrettyChars());
7557 ob.writestring(" (");
7558 escapePath(ob, imod.srcfile.toChars());
7559 ob.writestring(") : ");
7560 if (global.params.moduleDeps.name)
7561 ob.writestring("string : ");
7562 ob.write(se.peekString());
7563 ob.writestring(" (");
7564 escapePath(ob, resolvedNamez.ptr);
7565 ob.writestring(")");
7566 ob.writenl();
7568 if (global.params.makeDeps.doOutput)
7570 global.params.makeDeps.files.push(resolvedNamez.ptr);
7574 auto fileName = FileName(resolvedNamez);
7575 if (auto fmResult = global.fileManager.lookup(fileName))
7577 se = new StringExp(e.loc, fmResult);
7579 else
7581 error(e.loc, "cannot read file `%s`", resolvedNamez.ptr);
7582 return setError();
7585 result = se.expressionSemantic(sc);
7588 override void visit(AssertExp exp)
7590 // https://dlang.org/spec/expression.html#assert_expressions
7591 static if (LOGSEMANTIC)
7593 printf("AssertExp::semantic('%s')\n", exp.toChars());
7596 const generateMsg = !exp.msg &&
7597 sc.needsCodegen() && // let ctfe interpreter handle the error message
7598 global.params.checkAction == CHECKACTION.context &&
7599 global.params.useAssert == CHECKENABLE.on &&
7600 !((exp.e1.isIntegerExp() && (exp.e1.toInteger() == 0)) ||
7601 exp.e1.isNullExp());
7602 Expression temporariesPrefix;
7604 if (generateMsg)
7605 // no message - use assert expression as msg
7607 if (!verifyHookExist(exp.loc, *sc, Id._d_assert_fail, "generating assert messages"))
7608 return setError();
7612 auto a = e1, b = e2;
7613 assert(a == b, _d_assert_fail!"=="(a, b));
7618 Stores the result of an operand expression into a temporary
7619 if necessary, e.g. if it is an impure fuction call containing side
7620 effects as in https://issues.dlang.org/show_bug.cgi?id=20114
7622 Params:
7623 op = an expression which may require a temporary (added to
7624 `temporariesPrefix`: `auto tmp = op`) and will be replaced
7625 by `tmp` if necessary
7627 Returns: (possibly replaced) `op`
7629 Expression maybePromoteToTmp(ref Expression op)
7631 // https://issues.dlang.org/show_bug.cgi?id=20989
7632 // Flag that _d_assert_fail will never dereference `array.ptr` to avoid safety
7633 // errors for `assert(!array.ptr)` => `_d_assert_fail!"!"(array.ptr)`
7635 auto die = op.isDotIdExp();
7636 if (die && die.ident == Id.ptr)
7637 die.noderef = true;
7640 op = op.expressionSemantic(sc);
7641 op = resolveProperties(sc, op);
7643 // Detect assert's using static operator overloads (e.g. `"var" in environment`)
7644 if (auto te = op.isTypeExp())
7646 // Replace the TypeExp with it's textual representation
7647 // Including "..." in the error message isn't quite right but
7648 // proper solutions require more drastic changes, e.g. directly
7649 // using miniFormat and combine instead of calling _d_assert_fail
7650 auto name = new StringExp(te.loc, te.toString());
7651 return name.expressionSemantic(sc);
7654 // Create a temporary for expressions with side effects
7655 // Defensively assume that function calls may have side effects even
7656 // though it's not detected by hasSideEffect (e.g. `debug puts("Hello")` )
7657 // Rewriting CallExp's also avoids some issues with the inliner/debug generation
7658 if (op.hasSideEffect(true))
7660 // Don't create an invalid temporary for void-expressions
7661 // Further semantic will issue an appropriate error
7662 if (op.type.ty == Tvoid)
7663 return op;
7665 // https://issues.dlang.org/show_bug.cgi?id=21590
7666 // Don't create unnecessary temporaries and detect `assert(a = b)`
7667 if (op.isAssignExp() || op.isBinAssignExp())
7669 auto left = (cast(BinExp) op).e1;
7671 // Find leftmost expression to handle other rewrites,
7672 // e.g. --(++a) => a += 1 -= 1
7673 while (left.isAssignExp() || left.isBinAssignExp())
7674 left = (cast(BinExp) left).e1;
7676 // Only use the assignee if it's a variable and skip
7677 // other lvalues (e.g. ref's returned by functions)
7678 if (left.isVarExp())
7679 return left;
7681 // Sanity check that `op` can be converted to boolean
7682 // But don't raise errors for assignments enclosed in another expression
7683 if (op is exp.e1)
7684 op.toBoolean(sc);
7687 // Tuples with side-effects already receive a temporary during semantic
7688 if (op.type.isTypeTuple())
7690 auto te = op.isTupleExp();
7691 assert(te);
7693 // Create a new tuple without the associated temporary
7694 auto res = new TupleExp(op.loc, te.exps);
7695 return res.expressionSemantic(sc);
7698 const stc = op.isLvalue() ? STC.ref_ : 0;
7699 auto tmp = copyToTemp(stc, "__assertOp", op);
7700 tmp.dsymbolSemantic(sc);
7702 auto decl = new DeclarationExp(op.loc, tmp);
7703 temporariesPrefix = Expression.combine(temporariesPrefix, decl);
7705 op = new VarExp(op.loc, tmp);
7706 op = op.expressionSemantic(sc);
7708 return op;
7711 // if the assert condition is a mixin expression, try to compile it
7712 if (auto ce = exp.e1.isMixinExp())
7714 if (auto e1 = compileIt(ce))
7715 exp.e1 = e1;
7718 Expressions* es;
7719 Objects* tiargs;
7720 Loc loc = exp.e1.loc;
7722 const op = exp.e1.op;
7723 bool isEqualsCallExpression;
7724 if (const callExp = exp.e1.isCallExp())
7726 // https://issues.dlang.org/show_bug.cgi?id=20331
7727 // callExp.f may be null if the assert contains a call to
7728 // a function pointer or literal
7729 if (const callExpFunc = callExp.f)
7731 const callExpIdent = callExpFunc.ident;
7732 isEqualsCallExpression = callExpIdent == Id.__equals ||
7733 callExpIdent == Id.eq;
7736 if (op == EXP.equal || op == EXP.notEqual ||
7737 op == EXP.lessThan || op == EXP.greaterThan ||
7738 op == EXP.lessOrEqual || op == EXP.greaterOrEqual ||
7739 op == EXP.identity || op == EXP.notIdentity ||
7740 op == EXP.in_ ||
7741 isEqualsCallExpression)
7743 es = new Expressions(3);
7744 tiargs = new Objects(1);
7746 if (isEqualsCallExpression)
7748 auto callExp = cast(CallExp) exp.e1;
7749 auto args = callExp.arguments;
7751 // structs with opEquals get rewritten to a DotVarExp:
7752 // a.opEquals(b)
7753 // https://issues.dlang.org/show_bug.cgi?id=20100
7754 if (args.length == 1)
7756 auto dv = callExp.e1.isDotVarExp();
7757 assert(dv);
7759 // runtime args
7760 (*es)[1] = maybePromoteToTmp(dv.e1);
7761 (*es)[2] = maybePromoteToTmp((*args)[0]);
7763 else
7765 // runtime args
7766 (*es)[1] = maybePromoteToTmp((*args)[0]);
7767 (*es)[2] = maybePromoteToTmp((*args)[1]);
7770 else
7772 auto binExp = cast(EqualExp) exp.e1;
7774 // runtime args
7775 (*es)[1] = maybePromoteToTmp(binExp.e1);
7776 (*es)[2] = maybePromoteToTmp(binExp.e2);
7779 // template args
7780 Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : EXPtoString(exp.e1.op));
7781 comp = comp.expressionSemantic(sc);
7782 (*es)[0] = comp;
7783 (*tiargs)[0] = (*es)[1].type;
7786 // Format exp.e1 before any additional boolean conversion
7787 // Ignore &&/|| because "assert(...) failed" is more informative than "false != true"
7788 else if (op != EXP.andAnd && op != EXP.orOr)
7790 es = new Expressions(2);
7791 tiargs = new Objects(1);
7793 if (auto ne = exp.e1.isNotExp())
7795 // Fetch the (potential non-bool) expression and fold
7796 // (n) negations into (n % 2) negations, e.g. !!a => a
7797 for (bool neg = true; ; neg = !neg)
7799 if (auto ne2 = ne.e1.isNotExp())
7800 ne = ne2;
7801 else
7803 (*es)[0] = new StringExp(loc, neg ? "!" : "");
7804 (*es)[1] = maybePromoteToTmp(ne.e1);
7805 break;
7809 else
7810 { // Simply format exp.e1
7811 (*es)[0] = new StringExp(loc, "");
7812 (*es)[1] = maybePromoteToTmp(exp.e1);
7815 (*tiargs)[0] = (*es)[1].type;
7817 // Passing __ctfe to auto ref infers ref and aborts compilation:
7818 // "cannot modify compiler-generated variable __ctfe"
7819 auto ve = (*es)[1].isVarExp();
7820 if (ve && ve.var.ident == Id.ctfe)
7822 exp.msg = new StringExp(loc, "assert(__ctfe) failed!");
7823 goto LSkip;
7826 else
7828 OutBuffer buf;
7829 buf.printf("`%s` failed", exp.toChars());
7830 exp.msg = new StringExp(Loc.initial, buf.extractSlice());
7831 goto LSkip;
7834 Expression __assertFail = new IdentifierExp(exp.loc, Id.empty);
7835 auto assertFail = new DotIdExp(loc, __assertFail, Id.object);
7837 auto dt = new DotTemplateInstanceExp(loc, assertFail, Id._d_assert_fail, tiargs);
7838 auto ec = CallExp.create(loc, dt, es);
7839 exp.msg = ec;
7842 LSkip:
7843 if (Expression ex = unaSemantic(exp, sc))
7845 result = ex;
7846 return;
7849 exp.e1 = resolveProperties(sc, exp.e1);
7850 // BUG: see if we can do compile time elimination of the Assert
7851 exp.e1 = exp.e1.optimize(WANTvalue);
7852 exp.e1 = exp.e1.toBoolean(sc);
7854 if (exp.e1.op == EXP.error)
7856 result = exp.e1;
7857 return;
7860 if (exp.msg)
7862 exp.msg = expressionSemantic(exp.msg, sc);
7863 exp.msg = resolveProperties(sc, exp.msg);
7864 exp.msg = exp.msg.implicitCastTo(sc, Type.tchar.constOf().arrayOf());
7865 exp.msg = exp.msg.optimize(WANTvalue);
7866 checkParamArgumentEscape(sc, null, null, null, STC.undefined_, exp.msg, true, false);
7869 if (exp.msg && exp.msg.op == EXP.error)
7871 result = exp.msg;
7872 return;
7875 auto f1 = checkNonAssignmentArrayOp(exp.e1);
7876 auto f2 = exp.msg && checkNonAssignmentArrayOp(exp.msg);
7877 if (f1 || f2)
7878 return setError();
7880 if (exp.e1.toBool().hasValue(false))
7882 /* This is an `assert(0)` which means halt program execution
7884 FuncDeclaration fd = sc.parent.isFuncDeclaration();
7885 if (fd)
7886 fd.hasReturnExp |= 4;
7887 sc.ctorflow.orCSX(CSX.halt);
7889 if (global.params.useAssert == CHECKENABLE.off)
7891 Expression e = new HaltExp(exp.loc);
7892 e = e.expressionSemantic(sc);
7893 result = e;
7894 return;
7897 // Only override the type when it isn't already some flavour of noreturn,
7898 // e.g. when this assert was generated by defaultInitLiteral
7899 if (!exp.type || !exp.type.isTypeNoreturn())
7900 exp.type = Type.tnoreturn;
7902 else
7903 exp.type = Type.tvoid;
7905 result = !temporariesPrefix
7906 ? exp
7907 : Expression.combine(temporariesPrefix, exp).expressionSemantic(sc);
7910 override void visit(ThrowExp te)
7912 import dmd.statementsem;
7914 if (throwSemantic(te.loc, te.e1, sc))
7915 result = te;
7916 else
7917 setError();
7920 override void visit(DotIdExp exp)
7922 static if (LOGSEMANTIC)
7924 printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars());
7925 //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op));
7928 if (sc.flags & SCOPE.Cfile)
7930 /* See if need to rewrite the AST because of cast/call ambiguity
7932 if (auto e = castCallAmbiguity(exp, sc))
7934 result = expressionSemantic(e, sc);
7935 return;
7938 if (exp.arrow) // ImportC only
7939 exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
7941 if (exp.ident == Id.__xalignof && exp.e1.isTypeExp())
7943 // C11 6.5.3 says _Alignof only applies to types
7944 Expression e;
7945 Type t;
7946 Dsymbol s;
7947 dmd.typesem.resolve(exp.e1.type, exp.e1.loc, sc, e, t, s, true);
7948 if (e)
7950 error(exp.e1.loc, "argument to `_Alignof` must be a type");
7951 return setError();
7953 else if (t)
7955 // Note similarity to getProperty() implementation of __xalignof
7956 const explicitAlignment = t.alignment();
7957 const naturalAlignment = t.alignsize();
7958 const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get());
7959 result = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
7961 else if (s)
7963 error(exp.e1.loc, "argument to `_Alignof` must be a type");
7964 return setError();
7966 else
7967 assert(0);
7968 return;
7971 if (exp.ident != Id.__sizeof)
7973 result = fieldLookup(exp.e1, sc, exp.ident, exp.arrow);
7974 return;
7978 Expression e = exp.dotIdSemanticProp(sc, 1);
7980 if (e && isDotOpDispatch(e))
7982 auto ode = e;
7983 uint errors = global.startGagging();
7984 e = resolvePropertiesX(sc, e);
7985 // Any error or if 'e' is not resolved, go to UFCS
7986 if (global.endGagging(errors) || e is ode)
7987 e = null; /* fall down to UFCS */
7988 else
7990 result = e;
7991 return;
7994 if (!e) // if failed to find the property
7996 /* If ident is not a valid property, rewrite:
7997 * e1.ident
7998 * as:
7999 * .ident(e1)
8001 e = resolveUFCSProperties(sc, exp);
8003 result = e;
8006 override void visit(DotTemplateExp e)
8008 if (e.type)
8010 result = e;
8011 return;
8013 if (Expression ex = unaSemantic(e, sc))
8015 result = ex;
8016 return;
8018 // 'void' like TemplateExp
8019 e.type = Type.tvoid;
8020 result = e;
8023 override void visit(DotVarExp exp)
8025 static if (LOGSEMANTIC)
8027 printf("DotVarExp::semantic('%s')\n", exp.toChars());
8029 if (exp.type)
8031 result = exp;
8032 return;
8035 exp.var = exp.var.toAlias().isDeclaration();
8037 exp.e1 = exp.e1.expressionSemantic(sc);
8039 if (auto tup = exp.var.isTupleDeclaration())
8041 /* Replace:
8042 * e1.tuple(a, b, c)
8043 * with:
8044 * tuple(e1.a, e1.b, e1.c)
8046 Expression e0;
8047 Expression ev = sc.func ? extractSideEffect(sc, "__tup", e0, exp.e1) : exp.e1;
8049 auto exps = new Expressions();
8050 exps.reserve(tup.objects.length);
8051 for (size_t i = 0; i < tup.objects.length; i++)
8053 RootObject o = (*tup.objects)[i];
8054 Expression e;
8055 Declaration var;
8056 switch (o.dyncast()) with (DYNCAST)
8058 case expression:
8059 e = cast(Expression)o;
8060 if (auto se = e.isDsymbolExp())
8061 var = se.s.isDeclaration();
8062 else if (auto ve = e.isVarExp())
8063 if (!ve.var.isFuncDeclaration())
8064 // Exempt functions for backwards compatibility reasons.
8065 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
8066 var = ve.var;
8067 break;
8068 case dsymbol:
8069 Dsymbol s = cast(Dsymbol) o;
8070 Declaration d = s.isDeclaration();
8071 if (!d || d.isFuncDeclaration())
8072 // Exempt functions for backwards compatibility reasons.
8073 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
8074 e = new DsymbolExp(exp.loc, s);
8075 else
8076 var = d;
8077 break;
8078 case type:
8079 e = new TypeExp(exp.loc, cast(Type)o);
8080 break;
8081 default:
8082 error(exp.loc, "`%s` is not an expression", o.toChars());
8083 return setError();
8085 if (var)
8086 e = new DotVarExp(exp.loc, ev, var);
8087 exps.push(e);
8090 Expression e = new TupleExp(exp.loc, e0, exps);
8091 e = e.expressionSemantic(sc);
8092 result = e;
8093 return;
8095 else if (auto ad = exp.var.isAliasDeclaration())
8097 if (auto t = ad.getType())
8099 result = new TypeExp(exp.loc, t).expressionSemantic(sc);
8100 return;
8104 exp.e1 = exp.e1.addDtorHook(sc);
8106 Type t1 = exp.e1.type;
8108 if (FuncDeclaration fd = exp.var.isFuncDeclaration())
8110 // for functions, do checks after overload resolution
8111 if (!fd.functionSemantic())
8112 return setError();
8114 /* https://issues.dlang.org/show_bug.cgi?id=13843
8115 * If fd obviously has no overloads, we should
8116 * normalize AST, and it will give a chance to wrap fd with FuncExp.
8118 if ((fd.isNested() && !fd.isThis()) || fd.isFuncLiteralDeclaration())
8120 // (e1, fd)
8121 auto e = symbolToExp(fd, exp.loc, sc, false);
8122 result = Expression.combine(exp.e1, e);
8123 return;
8126 exp.type = fd.type;
8127 assert(exp.type);
8129 else if (OverDeclaration od = exp.var.isOverDeclaration())
8131 exp.type = Type.tvoid; // ambiguous type?
8133 else
8135 exp.type = exp.var.type;
8136 if (!exp.type && global.errors) // var is goofed up, just return error.
8137 return setError();
8138 assert(exp.type);
8140 if (t1.ty == Tpointer)
8141 t1 = t1.nextOf();
8143 exp.type = exp.type.addMod(t1.mod);
8145 // https://issues.dlang.org/show_bug.cgi?id=23109
8146 // Run semantic on the DotVarExp type
8147 if (auto handle = exp.type.isClassHandle())
8149 if (handle.semanticRun < PASS.semanticdone && !handle.isBaseInfoComplete())
8150 handle.dsymbolSemantic(null);
8153 Dsymbol vparent = exp.var.toParent();
8154 AggregateDeclaration ad = vparent ? vparent.isAggregateDeclaration() : null;
8155 if (Expression e1x = getRightThis(exp.loc, sc, ad, exp.e1, exp.var, 1))
8156 exp.e1 = e1x;
8157 else
8159 /* Later checkRightThis will report correct error for invalid field variable access.
8161 Expression e = new VarExp(exp.loc, exp.var);
8162 e = e.expressionSemantic(sc);
8163 result = e;
8164 return;
8166 checkAccess(exp.loc, sc, exp.e1, exp.var);
8168 VarDeclaration v = exp.var.isVarDeclaration();
8169 if (v && (v.isDataseg() || (v.storage_class & STC.manifest)))
8171 Expression e = expandVar(WANTvalue, v);
8172 if (e)
8174 result = e;
8175 return;
8179 if (v && (v.isDataseg() || // fix https://issues.dlang.org/show_bug.cgi?id=8238
8180 (!v.needThis() && v.semanticRun > PASS.initial))) // fix https://issues.dlang.org/show_bug.cgi?id=17258
8182 // (e1, v)
8183 checkAccess(exp.loc, sc, exp.e1, v);
8184 Expression e = new VarExp(exp.loc, v);
8185 e = new CommaExp(exp.loc, exp.e1, e);
8186 e = e.expressionSemantic(sc);
8187 result = e;
8188 return;
8191 //printf("-DotVarExp::semantic('%s')\n", toChars());
8192 result = exp;
8195 override void visit(DotTemplateInstanceExp exp)
8197 static if (LOGSEMANTIC)
8199 printf("DotTemplateInstanceExp::semantic('%s')\n", exp.toChars());
8201 if (exp.type)
8203 result = exp;
8204 return;
8206 // Indicate we need to resolve by UFCS.
8207 Expression e = exp.dotTemplateSemanticProp(sc, DotExpFlag.gag);
8208 if (!e)
8209 e = resolveUFCSProperties(sc, exp);
8210 if (e is exp)
8211 e.type = Type.tvoid; // Unresolved type, because it needs inference
8212 result = e;
8215 override void visit(DelegateExp e)
8217 static if (LOGSEMANTIC)
8219 printf("DelegateExp::semantic('%s')\n", e.toChars());
8221 if (e.type)
8223 result = e;
8224 return;
8227 e.e1 = e.e1.expressionSemantic(sc);
8229 e.type = new TypeDelegate(e.func.type.isTypeFunction());
8230 e.type = e.type.typeSemantic(e.loc, sc);
8232 FuncDeclaration f = e.func.toAliasFunc();
8233 AggregateDeclaration ad = f.isMemberLocal();
8234 if (f.needThis())
8235 e.e1 = getRightThis(e.loc, sc, ad, e.e1, f);
8237 if (f.type.ty == Tfunction)
8239 TypeFunction tf = cast(TypeFunction)f.type;
8240 if (!MODmethodConv(e.e1.type.mod, f.type.mod))
8242 OutBuffer thisBuf, funcBuf;
8243 MODMatchToBuffer(&thisBuf, e.e1.type.mod, tf.mod);
8244 MODMatchToBuffer(&funcBuf, tf.mod, e.e1.type.mod);
8245 error(e.loc, "%smethod `%s` is not callable using a %s`%s`",
8246 funcBuf.peekChars(), f.toPrettyChars(), thisBuf.peekChars(), e.e1.toChars());
8247 return setError();
8250 if (ad && ad.isClassDeclaration() && ad.type != e.e1.type)
8252 // A downcast is required for interfaces
8253 // https://issues.dlang.org/show_bug.cgi?id=3706
8254 e.e1 = new CastExp(e.loc, e.e1, ad.type);
8255 e.e1 = e.e1.expressionSemantic(sc);
8257 result = e;
8258 // declare dual-context container
8259 if (f.hasDualContext() && !sc.intypeof && sc.func)
8261 // check access to second `this`
8262 if (AggregateDeclaration ad2 = f.isMember2())
8264 Expression te = new ThisExp(e.loc).expressionSemantic(sc);
8265 if (te.op != EXP.error)
8266 te = getRightThis(e.loc, sc, ad2, te, f);
8267 if (te.op == EXP.error)
8269 error(e.loc, "need `this` of type `%s` to make delegate from function `%s`", ad2.toChars(), f.toChars());
8270 return setError();
8273 VarDeclaration vthis2 = makeThis2Argument(e.loc, sc, f);
8274 e.vthis2 = vthis2;
8275 Expression de = new DeclarationExp(e.loc, vthis2);
8276 result = Expression.combine(de, result);
8277 result = result.expressionSemantic(sc);
8281 override void visit(DotTypeExp exp)
8283 static if (LOGSEMANTIC)
8285 printf("DotTypeExp::semantic('%s')\n", exp.toChars());
8287 if (exp.type)
8289 result = exp;
8290 return;
8293 if (auto e = unaSemantic(exp, sc))
8295 result = e;
8296 return;
8299 exp.type = exp.sym.getType().addMod(exp.e1.type.mod);
8300 result = exp;
8303 override void visit(AddrExp exp)
8305 static if (LOGSEMANTIC)
8307 printf("AddrExp::semantic('%s')\n", exp.toChars());
8309 if (exp.type)
8311 result = exp;
8312 return;
8315 if (Expression ex = unaSemantic(exp, sc))
8317 result = ex;
8318 return;
8321 if (sc.flags & SCOPE.Cfile)
8323 /* Special handling for &"string"/&(T[]){0, 1}
8324 * since C regards string/array literals as lvalues
8326 auto e = exp.e1;
8327 if(e.isStringExp() || e.isArrayLiteralExp())
8329 e.type = typeSemantic(e.type, Loc.initial, sc);
8330 // if type is already a pointer exp is an illegal expression of the form `&(&"")`
8331 if (!e.type.isTypePointer())
8333 e.type = e.type.pointerTo();
8334 result = e;
8335 return;
8337 else
8339 // `toLvalue` call further below is upon exp.e1, omitting & from the error message
8340 exp.toLvalue(sc, "take address of");
8341 return setError();
8346 int wasCond = exp.e1.op == EXP.question;
8348 if (exp.e1.op == EXP.dotTemplateInstance)
8350 DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)exp.e1;
8351 TemplateInstance ti = dti.ti;
8353 //assert(ti.needsTypeInference(sc));
8354 ti.dsymbolSemantic(sc);
8355 if (!ti.inst || ti.errors) // if template failed to expand
8356 return setError();
8358 Dsymbol s = ti.toAlias();
8359 FuncDeclaration f = s.isFuncDeclaration();
8360 if (f)
8362 exp.e1 = new DotVarExp(exp.e1.loc, dti.e1, f);
8363 exp.e1 = exp.e1.expressionSemantic(sc);
8367 else if (exp.e1.op == EXP.scope_)
8369 TemplateInstance ti = (cast(ScopeExp)exp.e1).sds.isTemplateInstance();
8370 if (ti)
8372 //assert(ti.needsTypeInference(sc));
8373 ti.dsymbolSemantic(sc);
8374 if (!ti.inst || ti.errors) // if template failed to expand
8375 return setError();
8377 Dsymbol s = ti.toAlias();
8378 FuncDeclaration f = s.isFuncDeclaration();
8379 if (f)
8381 exp.e1 = new VarExp(exp.e1.loc, f);
8382 exp.e1 = exp.e1.expressionSemantic(sc);
8386 /* https://issues.dlang.org/show_bug.cgi?id=809
8388 * If the address of a lazy variable is taken,
8389 * the expression is rewritten so that the type
8390 * of it is the delegate type. This means that
8391 * the symbol is not going to represent a call
8392 * to the delegate anymore, but rather, the
8393 * actual symbol.
8395 if (auto ve = exp.e1.isVarExp())
8397 if (ve.var.storage_class & STC.lazy_)
8399 exp.e1 = exp.e1.expressionSemantic(sc);
8400 exp.e1 = resolveProperties(sc, exp.e1);
8401 if (auto callExp = exp.e1.isCallExp())
8403 if (callExp.e1.type.toBasetype().ty == Tdelegate)
8405 /* https://issues.dlang.org/show_bug.cgi?id=20551
8407 * Cannot take address of lazy parameter in @safe code
8408 * because it might end up being a pointer to undefined
8409 * memory.
8411 if (1)
8413 if (sc.setUnsafe(false, exp.loc,
8414 "cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve, sc.func))
8416 setError();
8417 return;
8420 VarExp ve2 = callExp.e1.isVarExp();
8421 ve2.delegateWasExtracted = true;
8422 ve2.var.storage_class |= STC.scope_;
8423 result = ve2;
8424 return;
8430 exp.e1 = exp.e1.toLvalue(sc, "take address of");
8431 if (exp.e1.op == EXP.error)
8433 result = exp.e1;
8434 return;
8436 if (checkNonAssignmentArrayOp(exp.e1))
8437 return setError();
8439 if (!exp.e1.type)
8441 error(exp.loc, "cannot take address of `%s`", exp.e1.toChars());
8442 return setError();
8444 if (!checkAddressable(exp, sc))
8445 return setError();
8447 bool hasOverloads;
8448 if (auto f = isFuncAddress(exp, &hasOverloads))
8450 if (!hasOverloads && f.checkForwardRef(exp.loc))
8451 return setError();
8453 else if (!exp.e1.type.deco)
8455 // try to resolve the type
8456 exp.e1.type = exp.e1.type.typeSemantic(exp.e1.loc, sc);
8457 if (!exp.e1.type.deco) // still couldn't resolve it
8459 if (auto ve = exp.e1.isVarExp())
8461 Declaration d = ve.var;
8462 error(exp.loc, "forward reference to %s `%s`", d.kind(), d.toChars());
8464 else
8465 error(exp.loc, "forward reference to type `%s` of expression `%s`", exp.e1.type.toChars(), exp.e1.toChars());
8466 return setError();
8470 exp.type = exp.e1.type.pointerTo();
8472 // See if this should really be a delegate
8473 if (exp.e1.op == EXP.dotVariable)
8475 DotVarExp dve = cast(DotVarExp)exp.e1;
8476 FuncDeclaration f = dve.var.isFuncDeclaration();
8477 if (f)
8479 f = f.toAliasFunc(); // FIXME, should see overloads
8480 // https://issues.dlang.org/show_bug.cgi?id=1983
8481 if (!dve.hasOverloads)
8482 f.tookAddressOf++;
8484 Expression e;
8485 if (f.needThis())
8486 e = new DelegateExp(exp.loc, dve.e1, f, dve.hasOverloads);
8487 else // It is a function pointer. Convert &v.f() --> (v, &V.f())
8488 e = new CommaExp(exp.loc, dve.e1, new AddrExp(exp.loc, new VarExp(exp.loc, f, dve.hasOverloads)));
8489 e = e.expressionSemantic(sc);
8490 result = e;
8491 return;
8494 // Look for misaligned pointer in @safe mode
8495 if (checkUnsafeAccess(sc, dve, !exp.type.isMutable(), true))
8496 return setError();
8498 else if (exp.e1.op == EXP.variable)
8500 VarExp ve = cast(VarExp)exp.e1;
8501 VarDeclaration v = ve.var.isVarDeclaration();
8502 if (v)
8504 if (!checkAddressVar(sc, exp.e1, v))
8505 return setError();
8507 v.checkPurity(ve.loc, sc);
8509 FuncDeclaration f = ve.var.isFuncDeclaration();
8510 if (f)
8512 /* Because nested functions cannot be overloaded,
8513 * mark here that we took its address because castTo()
8514 * may not be called with an exact match.
8516 * https://issues.dlang.org/show_bug.cgi?id=19285 :
8517 * We also need to make sure we aren't inside a typeof. Ideally the compiler
8518 * would do typeof(...) semantic analysis speculatively then collect information
8519 * about what it used rather than relying on what are effectively semantically-global
8520 * variables but it doesn't.
8522 if (!sc.isFromSpeculativeSemanticContext() && (!ve.hasOverloads || (f.isNested() && !f.needThis())))
8524 // TODO: Refactor to use a proper interface that can keep track of causes.
8525 f.tookAddressOf++;
8528 if (f.isNested() && !f.needThis())
8530 if (f.isFuncLiteralDeclaration())
8532 if (!f.FuncDeclaration.isNested())
8534 /* Supply a 'null' for a this pointer if no this is available
8536 Expression e = new DelegateExp(exp.loc, new NullExp(exp.loc, Type.tnull), f, ve.hasOverloads);
8537 e = e.expressionSemantic(sc);
8538 result = e;
8539 return;
8542 Expression e = new DelegateExp(exp.loc, exp.e1, f, ve.hasOverloads);
8543 e = e.expressionSemantic(sc);
8544 result = e;
8545 return;
8547 if (f.needThis())
8549 auto memberFunc = hasThis(sc);
8550 if (memberFunc && haveSameThis(memberFunc, f))
8552 /* Should probably supply 'this' after overload resolution,
8553 * not before.
8555 Expression ethis = new ThisExp(exp.loc);
8556 Expression e = new DelegateExp(exp.loc, ethis, f, ve.hasOverloads);
8557 e = e.expressionSemantic(sc);
8558 result = e;
8559 return;
8561 if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_))
8563 sc.setUnsafe(false, exp.loc,
8564 "`this` reference necessary to take address of member `%s` in `@safe` function `%s`",
8565 f, sc.func);
8570 else if (exp.e1.op == EXP.index)
8572 /* For:
8573 * int[3] a;
8574 * &a[i]
8575 * check 'a' the same as for a regular variable
8577 if (VarDeclaration v = expToVariable(exp.e1))
8579 v.checkPurity(exp.e1.loc, sc);
8582 else if (wasCond)
8584 /* a ? b : c was transformed to *(a ? &b : &c), but we still
8585 * need to do safety checks
8587 assert(exp.e1.op == EXP.star);
8588 PtrExp pe = cast(PtrExp)exp.e1;
8589 assert(pe.e1.op == EXP.question);
8590 CondExp ce = cast(CondExp)pe.e1;
8591 assert(ce.e1.op == EXP.address);
8592 assert(ce.e2.op == EXP.address);
8594 // Re-run semantic on the address expressions only
8595 ce.e1.type = null;
8596 ce.e1 = ce.e1.expressionSemantic(sc);
8597 ce.e2.type = null;
8598 ce.e2 = ce.e2.expressionSemantic(sc);
8600 result = exp.optimize(WANTvalue);
8603 override void visit(PtrExp exp)
8605 static if (LOGSEMANTIC)
8607 printf("PtrExp::semantic('%s')\n", exp.toChars());
8609 if (exp.type)
8611 result = exp;
8612 return;
8615 Expression e = exp.op_overload(sc);
8616 if (e)
8618 result = e;
8619 return;
8622 exp.e1 = exp.e1.arrayFuncConv(sc);
8624 Type tb = exp.e1.type.toBasetype();
8625 switch (tb.ty)
8627 case Tpointer:
8628 exp.type = (cast(TypePointer)tb).next;
8629 break;
8631 case Tsarray:
8632 case Tarray:
8633 if (isNonAssignmentArrayOp(exp.e1))
8634 goto default;
8635 error(exp.loc, "using `*` on an array is no longer supported; use `*(%s).ptr` instead", exp.e1.toChars());
8636 exp.type = (cast(TypeArray)tb).next;
8637 exp.e1 = exp.e1.castTo(sc, exp.type.pointerTo());
8638 break;
8640 case Terror:
8641 return setError();
8643 case Tnull:
8644 exp.type = Type.tnoreturn; // typeof(*null) is bottom type
8645 break;
8647 default:
8648 error(exp.loc, "can only `*` a pointer, not a `%s`", exp.e1.type.toChars());
8649 goto case Terror;
8652 if (sc.flags & SCOPE.Cfile && exp.type && exp.type.toBasetype().ty == Tvoid)
8654 // https://issues.dlang.org/show_bug.cgi?id=23752
8655 // `&*((void*)(0))` is allowed in C
8656 result = exp;
8657 return;
8660 if (exp.checkValue())
8661 return setError();
8663 result = exp;
8666 override void visit(NegExp exp)
8668 static if (LOGSEMANTIC)
8670 printf("NegExp::semantic('%s')\n", exp.toChars());
8672 if (exp.type)
8674 result = exp;
8675 return;
8678 Expression e = exp.op_overload(sc);
8679 if (e)
8681 result = e;
8682 return;
8685 fix16997(sc, exp);
8686 exp.type = exp.e1.type;
8687 Type tb = exp.type.toBasetype();
8688 if (tb.ty == Tarray || tb.ty == Tsarray)
8690 if (!isArrayOpValid(exp.e1))
8692 result = arrayOpInvalidError(exp);
8693 return;
8695 result = exp;
8696 return;
8698 if (!target.isVectorOpSupported(tb, exp.op))
8700 result = exp.incompatibleTypes();
8701 return;
8703 if (exp.e1.checkNoBool())
8704 return setError();
8705 if (exp.e1.checkArithmetic(exp.op) ||
8706 exp.e1.checkSharedAccess(sc))
8707 return setError();
8709 result = exp;
8712 override void visit(UAddExp exp)
8714 static if (LOGSEMANTIC)
8716 printf("UAddExp::semantic('%s')\n", exp.toChars());
8718 assert(!exp.type);
8720 Expression e = exp.op_overload(sc);
8721 if (e)
8723 result = e;
8724 return;
8727 fix16997(sc, exp);
8728 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op))
8730 result = exp.incompatibleTypes();
8731 return;
8733 if (exp.e1.checkNoBool())
8734 return setError();
8735 if (exp.e1.checkArithmetic(exp.op))
8736 return setError();
8737 if (exp.e1.checkSharedAccess(sc))
8738 return setError();
8740 result = exp.e1;
8743 override void visit(ComExp exp)
8745 if (exp.type)
8747 result = exp;
8748 return;
8751 Expression e = exp.op_overload(sc);
8752 if (e)
8754 result = e;
8755 return;
8758 fix16997(sc, exp);
8759 exp.type = exp.e1.type;
8760 Type tb = exp.type.toBasetype();
8761 if (tb.ty == Tarray || tb.ty == Tsarray)
8763 if (!isArrayOpValid(exp.e1))
8765 result = arrayOpInvalidError(exp);
8766 return;
8768 result = exp;
8769 return;
8771 if (!target.isVectorOpSupported(tb, exp.op))
8773 result = exp.incompatibleTypes();
8774 return;
8776 if (exp.e1.checkNoBool())
8777 return setError();
8778 if (exp.e1.checkIntegral() ||
8779 exp.e1.checkSharedAccess(sc))
8780 return setError();
8782 result = exp;
8785 override void visit(NotExp e)
8787 if (e.type)
8789 result = e;
8790 return;
8793 e.setNoderefOperand();
8795 // Note there is no operator overload
8796 if (Expression ex = unaSemantic(e, sc))
8798 result = ex;
8799 return;
8802 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
8803 if (e.e1.op == EXP.type)
8804 e.e1 = resolveAliasThis(sc, e.e1);
8806 e.e1 = resolveProperties(sc, e.e1);
8807 e.e1 = e.e1.toBoolean(sc);
8808 if (e.e1.type == Type.terror)
8810 result = e.e1;
8811 return;
8814 if (!target.isVectorOpSupported(e.e1.type.toBasetype(), e.op))
8816 result = e.incompatibleTypes();
8818 // https://issues.dlang.org/show_bug.cgi?id=13910
8819 // Today NotExp can take an array as its operand.
8820 if (checkNonAssignmentArrayOp(e.e1))
8821 return setError();
8823 e.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
8824 result = e;
8827 override void visit(DeleteExp exp)
8829 // @@@DEPRECATED_2.109@@@
8830 // 1. Deprecated since 2.079
8831 // 2. Error since 2.099
8832 // 3. Removal of keyword, "delete" can be used for other identities
8833 if (!exp.isRAII)
8835 error(exp.loc, "the `delete` keyword is obsolete");
8836 errorSupplemental(exp.loc, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead");
8837 return setError();
8840 Expression e = exp;
8842 if (Expression ex = unaSemantic(exp, sc))
8844 result = ex;
8845 return;
8847 exp.e1 = resolveProperties(sc, exp.e1);
8848 exp.e1 = exp.e1.modifiableLvalue(sc);
8849 if (exp.e1.op == EXP.error)
8851 result = exp.e1;
8852 return;
8854 exp.type = Type.tvoid;
8856 Type tb = exp.e1.type.toBasetype();
8858 /* Now that `delete` in user code is an error, we only get here when
8859 * `isRAII` has been set to true for the deletion of a `scope class`. */
8860 if (tb.ty != Tclass)
8862 error(exp.loc, "cannot delete type `%s`", exp.e1.type.toChars());
8863 return setError();
8866 ClassDeclaration cd = (cast(TypeClass)tb).sym;
8867 if (cd.isCOMinterface())
8869 /* Because COM classes are deleted by IUnknown.Release()
8871 error(exp.loc, "cannot `delete` instance of COM interface `%s`", cd.toChars());
8872 return setError();
8875 bool err = false;
8876 if (cd.dtor)
8878 err |= !cd.dtor.functionSemantic();
8879 err |= cd.dtor.checkPurity(exp.loc, sc);
8880 err |= cd.dtor.checkSafety(exp.loc, sc);
8881 err |= cd.dtor.checkNogc(exp.loc, sc);
8883 if (err)
8884 return setError();
8886 result = e;
8889 override void visit(CastExp exp)
8891 static if (LOGSEMANTIC)
8893 printf("CastExp::semantic('%s')\n", exp.toChars());
8895 //static int x; assert(++x < 10);
8896 if (exp.type)
8898 result = exp;
8899 return;
8902 if ((sc && sc.flags & SCOPE.Cfile) &&
8903 exp.to && (exp.to.ty == Tident || exp.to.ty == Tsarray) &&
8904 (exp.e1.op == EXP.address || exp.e1.op == EXP.star ||
8905 exp.e1.op == EXP.uadd || exp.e1.op == EXP.negate))
8907 /* Ambiguous cases arise from CParser if type-name is just an identifier.
8908 * ( identifier ) cast-expression
8909 * ( identifier [expression]) cast-expression
8910 * If we determine that `identifier` is a variable, and cast-expression
8911 * is one of the unary operators (& * + -), then rewrite this cast
8912 * as a binary expression.
8914 Loc loc = exp.loc;
8915 Type t;
8916 Expression e;
8917 Dsymbol s;
8918 exp.to.resolve(loc, sc, e, t, s);
8919 if (e !is null)
8921 if (auto ex = exp.e1.isAddrExp()) // (ident) &exp -> (ident & exp)
8922 result = new AndExp(loc, e, ex.e1);
8923 else if (auto ex = exp.e1.isPtrExp()) // (ident) *exp -> (ident * exp)
8924 result = new MulExp(loc, e, ex.e1);
8925 else if (auto ex = exp.e1.isUAddExp()) // (ident) +exp -> (ident + exp)
8926 result = new AddExp(loc, e, ex.e1);
8927 else if (auto ex = exp.e1.isNegExp()) // (ident) -exp -> (ident - exp)
8928 result = new MinExp(loc, e, ex.e1);
8930 assert(result);
8931 result = result.expressionSemantic(sc);
8932 return;
8936 if (exp.to)
8938 exp.to = exp.to.typeSemantic(exp.loc, sc);
8939 if (exp.to == Type.terror)
8940 return setError();
8942 if (!exp.to.hasPointers())
8943 exp.setNoderefOperand();
8945 // When e1 is a template lambda, this cast may instantiate it with
8946 // the type 'to'.
8947 exp.e1 = inferType(exp.e1, exp.to);
8950 if (auto e = unaSemantic(exp, sc))
8952 result = e;
8953 return;
8956 if (exp.to && !exp.to.isTypeSArray() && !exp.to.isTypeFunction())
8957 exp.e1 = exp.e1.arrayFuncConv(sc);
8959 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
8960 if (exp.e1.op == EXP.type)
8961 exp.e1 = resolveAliasThis(sc, exp.e1);
8963 auto e1x = resolveProperties(sc, exp.e1);
8964 if (e1x.op == EXP.error)
8966 result = e1x;
8967 return;
8969 if (e1x.checkType())
8970 return setError();
8971 exp.e1 = e1x;
8973 if (!exp.e1.type)
8975 error(exp.loc, "cannot cast `%s`", exp.e1.toChars());
8976 return setError();
8979 // https://issues.dlang.org/show_bug.cgi?id=19954
8980 if (exp.e1.type.ty == Ttuple)
8982 if (exp.to)
8984 if (TypeTuple tt = exp.to.isTypeTuple())
8986 if (exp.e1.type.implicitConvTo(tt))
8988 result = exp.e1.castTo(sc, tt);
8989 return;
8993 TupleExp te = exp.e1.isTupleExp();
8994 if (te.exps.length == 1)
8995 exp.e1 = (*te.exps)[0];
8998 // only allow S(x) rewrite if cast specified S explicitly.
8999 // See https://issues.dlang.org/show_bug.cgi?id=18545
9000 const bool allowImplicitConstruction = exp.to !is null;
9002 if (!exp.to) // Handle cast(const) and cast(immutable), etc.
9004 exp.to = exp.e1.type.castMod(exp.mod);
9005 exp.to = exp.to.typeSemantic(exp.loc, sc);
9007 if (exp.to == Type.terror)
9008 return setError();
9011 if (exp.to.ty == Ttuple)
9013 error(exp.loc, "cannot cast `%s` of type `%s` to type sequence `%s`", exp.e1.toChars(), exp.e1.type.toChars(), exp.to.toChars());
9014 return setError();
9017 // cast(void) is used to mark e1 as unused, so it is safe
9018 if (exp.to.ty == Tvoid)
9020 exp.type = exp.to;
9021 result = exp;
9022 return;
9025 if (!exp.to.equals(exp.e1.type) && exp.mod == cast(ubyte)~0)
9027 if (Expression e = exp.op_overload(sc))
9029 result = e.implicitCastTo(sc, exp.to);
9030 return;
9034 Type t1b = exp.e1.type.toBasetype();
9035 Type tob = exp.to.toBasetype();
9037 if (allowImplicitConstruction && tob.ty == Tstruct && !tob.equals(t1b))
9039 /* Look to replace:
9040 * cast(S)t
9041 * with:
9042 * S(t)
9045 // Rewrite as to.call(e1)
9046 Expression e = new TypeExp(exp.loc, exp.to);
9047 e = new CallExp(exp.loc, e, exp.e1);
9048 e = e.trySemantic(sc);
9049 if (e)
9051 result = e;
9052 return;
9056 if (!t1b.equals(tob) && (t1b.ty == Tarray || t1b.ty == Tsarray))
9058 if (checkNonAssignmentArrayOp(exp.e1))
9059 return setError();
9062 Expression ex = exp.e1.castTo(sc, exp.to);
9063 if (ex.op == EXP.error)
9065 result = ex;
9066 return;
9069 // Check for unsafe casts
9070 if (!isSafeCast(ex, t1b, tob))
9072 if (sc.setUnsafe(false, exp.loc, "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to))
9074 return setError();
9078 // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built
9079 // to handle certain casts. Those casts which `object.__ArrayCast` does not support are filtered out.
9080 // See `e2ir.toElemCast` for other types of casts. If `object.__ArrayCast` is improved to support more
9081 // casts these conditions and potentially some logic in `e2ir.toElemCast` can be removed.
9082 if (tob.ty == Tarray)
9084 // https://issues.dlang.org/show_bug.cgi?id=19840
9085 if (auto ad = isAggregate(t1b))
9087 if (ad.aliasthis)
9089 Expression e = resolveAliasThis(sc, exp.e1);
9090 e = new CastExp(exp.loc, e, exp.to);
9091 result = e.expressionSemantic(sc);
9092 return;
9096 if(t1b.ty == Tarray && exp.e1.op != EXP.arrayLiteral && sc.needsCodegen())
9098 auto tFrom = t1b.nextOf();
9099 auto tTo = tob.nextOf();
9101 // https://issues.dlang.org/show_bug.cgi?id=20130
9102 if (exp.e1.op != EXP.string_ || !ex.isStringExp)
9104 const uint fromSize = cast(uint)tFrom.size();
9105 const uint toSize = cast(uint)tTo.size();
9106 if (fromSize == SIZE_INVALID || toSize == SIZE_INVALID)
9107 return setError();
9109 // If array element sizes do not match, we must adjust the dimensions
9110 if (fromSize != toSize)
9112 if (!verifyHookExist(exp.loc, *sc, Id.__ArrayCast, "casting array of structs"))
9113 return setError();
9115 // A runtime check is needed in case arrays don't line up. That check should
9116 // be done in the implementation of `object.__ArrayCast`
9117 if (toSize == 0 || (fromSize % toSize) != 0)
9119 // lower to `object.__ArrayCast!(TFrom, TTo)(from)`
9121 // fully qualify as `object.__ArrayCast`
9122 Expression id = new IdentifierExp(exp.loc, Id.empty);
9123 auto dotid = new DotIdExp(exp.loc, id, Id.object);
9125 auto tiargs = new Objects();
9126 tiargs.push(tFrom);
9127 tiargs.push(tTo);
9128 auto dt = new DotTemplateInstanceExp(exp.loc, dotid, Id.__ArrayCast, tiargs);
9130 auto arguments = new Expressions();
9131 arguments.push(exp.e1);
9132 Expression ce = new CallExp(exp.loc, dt, arguments);
9134 result = expressionSemantic(ce, sc);
9135 return;
9142 if (sc && sc.flags & SCOPE.Cfile)
9144 /* C11 6.5.4-5: A cast does not yield an lvalue.
9145 * So ensure that castTo does not strip away the cast so that this
9146 * can be enforced in other semantic visitor methods.
9148 if (!ex.isCastExp())
9150 ex = new CastExp(exp.loc, ex, exp.to);
9151 ex.type = exp.to;
9154 result = ex;
9157 override void visit(VectorExp exp)
9159 static if (LOGSEMANTIC)
9161 printf("VectorExp::semantic('%s')\n", exp.toChars());
9163 if (exp.type)
9165 result = exp;
9166 return;
9169 exp.e1 = exp.e1.expressionSemantic(sc);
9170 exp.type = exp.to.typeSemantic(exp.loc, sc);
9171 if (exp.e1.op == EXP.error || exp.type.ty == Terror)
9173 result = exp.e1;
9174 return;
9177 Type tb = exp.type.toBasetype();
9178 assert(tb.ty == Tvector);
9179 TypeVector tv = cast(TypeVector)tb;
9180 Type te = tv.elementType();
9181 exp.dim = cast(int)(tv.size(exp.loc) / te.size(exp.loc));
9183 bool checkElem(Expression elem)
9185 if (elem.isConst() == 1)
9186 return false;
9188 error(exp.loc, "constant expression expected, not `%s`", elem.toChars());
9189 return true;
9192 exp.e1 = exp.e1.optimize(WANTvalue);
9193 bool res;
9194 if (exp.e1.op == EXP.arrayLiteral)
9196 foreach (i; 0 .. exp.dim)
9198 // Do not stop on first error - check all AST nodes even if error found
9199 res |= checkElem(exp.e1.isArrayLiteralExp()[i]);
9202 else if (exp.e1.type.ty == Tvoid)
9203 checkElem(exp.e1);
9205 result = res ? ErrorExp.get() : exp;
9208 override void visit(VectorArrayExp e)
9210 static if (LOGSEMANTIC)
9212 printf("VectorArrayExp::semantic('%s')\n", e.toChars());
9214 if (!e.type)
9216 unaSemantic(e, sc);
9217 e.e1 = resolveProperties(sc, e.e1);
9219 if (e.e1.op == EXP.error)
9221 result = e.e1;
9222 return;
9224 assert(e.e1.type.ty == Tvector);
9225 e.type = e.e1.type.isTypeVector().basetype;
9227 result = e;
9230 override void visit(SliceExp exp)
9232 static if (LOGSEMANTIC)
9234 printf("SliceExp::semantic('%s')\n", exp.toChars());
9236 if (exp.type)
9238 result = exp;
9239 return;
9242 // operator overloading should be handled in ArrayExp already.
9243 if (Expression ex = unaSemantic(exp, sc))
9245 result = ex;
9246 return;
9248 exp.e1 = resolveProperties(sc, exp.e1);
9249 if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
9251 if (exp.lwr || exp.upr)
9253 error(exp.loc, "cannot slice type `%s`", exp.e1.toChars());
9254 return setError();
9256 Expression e = new TypeExp(exp.loc, exp.e1.type.arrayOf());
9257 result = e.expressionSemantic(sc);
9258 return;
9260 if (!exp.lwr && !exp.upr)
9262 if (exp.e1.op == EXP.arrayLiteral)
9264 // Convert [a,b,c][] to [a,b,c]
9265 Type t1b = exp.e1.type.toBasetype();
9266 Expression e = exp.e1;
9267 if (t1b.ty == Tsarray)
9269 e = e.copy();
9270 e.type = t1b.nextOf().arrayOf();
9272 result = e;
9273 return;
9275 if (exp.e1.op == EXP.slice)
9277 // Convert e[][] to e[]
9278 SliceExp se = cast(SliceExp)exp.e1;
9279 if (!se.lwr && !se.upr)
9281 result = se;
9282 return;
9285 if (isArrayOpOperand(exp.e1))
9287 // Convert (a[]+b[])[] to a[]+b[]
9288 result = exp.e1;
9289 return;
9292 if (exp.e1.op == EXP.error)
9294 result = exp.e1;
9295 return;
9297 if (exp.e1.type.ty == Terror)
9298 return setError();
9300 Type t1b = exp.e1.type.toBasetype();
9301 if (auto tp = t1b.isTypePointer())
9303 if (t1b.isPtrToFunction())
9305 error(exp.loc, "cannot slice function pointer `%s`", exp.e1.toChars());
9306 return setError();
9308 if (!exp.lwr || !exp.upr)
9310 error(exp.loc, "upper and lower bounds are needed to slice a pointer");
9311 if (auto ad = isAggregate(tp.next.toBasetype()))
9313 auto s = search_function(ad, Id.index);
9314 if (!s) s = search_function(ad, Id.slice);
9315 if (s)
9317 auto fd = s.isFuncDeclaration();
9318 if ((fd && !fd.getParameterList().length) || s.isTemplateDeclaration())
9320 errorSupplemental(exp.loc,
9321 "pointer `%s` points to an aggregate that defines an `%s`, perhaps you meant `(*%s)[]`",
9322 exp.e1.toChars(),
9323 s.ident.toChars(),
9324 exp.e1.toChars()
9331 return setError();
9333 if (sc.setUnsafe(false, exp.loc, "pointer slicing not allowed in safe functions"))
9334 return setError();
9336 else if (t1b.ty == Tarray)
9339 else if (t1b.ty == Tsarray)
9342 else if (t1b.ty == Ttuple)
9344 if (!exp.lwr && !exp.upr)
9346 result = exp.e1;
9347 return;
9349 if (!exp.lwr || !exp.upr)
9351 error(exp.loc, "need upper and lower bound to slice a sequence");
9352 return setError();
9355 else if (t1b.ty == Tvector && exp.e1.isLvalue())
9357 // Convert e1 to corresponding static array
9358 TypeVector tv1 = cast(TypeVector)t1b;
9359 t1b = tv1.basetype;
9360 t1b = t1b.castMod(tv1.mod);
9361 exp.e1.type = t1b;
9363 else
9365 error(exp.loc, "`%s` cannot be sliced with `[]`", t1b.ty == Tvoid ? exp.e1.toChars() : t1b.toChars());
9366 return setError();
9369 /* Run semantic on lwr and upr.
9371 Scope* scx = sc;
9372 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
9374 // Create scope for 'length' variable
9375 ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
9376 sym.parent = sc.scopesym;
9377 sc = sc.push(sym);
9379 if (exp.lwr)
9381 if (t1b.ty == Ttuple)
9382 sc = sc.startCTFE();
9383 exp.lwr = exp.lwr.expressionSemantic(sc);
9384 exp.lwr = resolveProperties(sc, exp.lwr);
9385 if (t1b.ty == Ttuple)
9386 sc = sc.endCTFE();
9387 exp.lwr = exp.lwr.implicitCastTo(sc, Type.tsize_t);
9389 if (exp.upr)
9391 if (t1b.ty == Ttuple)
9392 sc = sc.startCTFE();
9393 exp.upr = exp.upr.expressionSemantic(sc);
9394 exp.upr = resolveProperties(sc, exp.upr);
9395 if (t1b.ty == Ttuple)
9396 sc = sc.endCTFE();
9397 exp.upr = exp.upr.implicitCastTo(sc, Type.tsize_t);
9399 if (sc != scx)
9400 sc = sc.pop();
9401 if (exp.lwr && exp.lwr.type == Type.terror || exp.upr && exp.upr.type == Type.terror)
9402 return setError();
9404 if (t1b.ty == Ttuple)
9406 exp.lwr = exp.lwr.ctfeInterpret();
9407 exp.upr = exp.upr.ctfeInterpret();
9408 uinteger_t i1 = exp.lwr.toUInteger();
9409 uinteger_t i2 = exp.upr.toUInteger();
9411 TupleExp te;
9412 TypeTuple tup;
9413 size_t length;
9414 if (exp.e1.op == EXP.tuple) // slicing an expression tuple
9416 te = cast(TupleExp)exp.e1;
9417 tup = null;
9418 length = te.exps.length;
9420 else if (exp.e1.op == EXP.type) // slicing a type tuple
9422 te = null;
9423 tup = cast(TypeTuple)t1b;
9424 length = Parameter.dim(tup.arguments);
9426 else
9427 assert(0);
9429 if (i2 < i1 || length < i2)
9431 error(exp.loc, "string slice `[%llu .. %llu]` is out of bounds", i1, i2);
9432 return setError();
9435 size_t j1 = cast(size_t)i1;
9436 size_t j2 = cast(size_t)i2;
9437 Expression e;
9438 if (exp.e1.op == EXP.tuple)
9440 auto exps = new Expressions(j2 - j1);
9441 for (size_t i = 0; i < j2 - j1; i++)
9443 (*exps)[i] = (*te.exps)[j1 + i];
9445 e = new TupleExp(exp.loc, te.e0, exps);
9447 else
9449 auto args = new Parameters();
9450 args.reserve(j2 - j1);
9451 for (size_t i = j1; i < j2; i++)
9453 Parameter arg = Parameter.getNth(tup.arguments, i);
9454 args.push(arg);
9456 e = new TypeExp(exp.e1.loc, new TypeTuple(args));
9458 e = e.expressionSemantic(sc);
9459 result = e;
9460 return;
9463 exp.type = t1b.nextOf().arrayOf();
9464 // Allow typedef[] -> typedef[]
9465 if (exp.type.equals(t1b))
9466 exp.type = exp.e1.type;
9468 // We might know $ now
9469 setLengthVarIfKnown(exp.lengthVar, t1b);
9471 if (exp.lwr && exp.upr)
9473 exp.lwr = exp.lwr.optimize(WANTvalue);
9474 exp.upr = exp.upr.optimize(WANTvalue);
9476 IntRange lwrRange = getIntRange(exp.lwr);
9477 IntRange uprRange = getIntRange(exp.upr);
9479 if (t1b.ty == Tsarray || t1b.ty == Tarray)
9481 Expression el = new ArrayLengthExp(exp.loc, exp.e1);
9482 el = el.expressionSemantic(sc);
9483 el = el.optimize(WANTvalue);
9484 if (el.op == EXP.int64)
9486 // Array length is known at compile-time. Upper is in bounds if it fits length.
9487 dinteger_t length = el.toInteger();
9488 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length));
9489 exp.upperIsInBounds = bounds.contains(uprRange);
9491 else if (exp.upr.op == EXP.int64 && exp.upr.toInteger() == 0)
9493 // Upper slice expression is '0'. Value is always in bounds.
9494 exp.upperIsInBounds = true;
9496 else if (exp.upr.op == EXP.variable && (cast(VarExp)exp.upr).var.ident == Id.dollar)
9498 // Upper slice expression is '$'. Value is always in bounds.
9499 exp.upperIsInBounds = true;
9502 else if (t1b.ty == Tpointer)
9504 exp.upperIsInBounds = true;
9506 else
9507 assert(0);
9509 exp.lowerIsLessThanUpper = (lwrRange.imax <= uprRange.imin);
9511 //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", exp.upperIsInBounds, exp.lowerIsLessThanUpper);
9514 result = exp;
9517 override void visit(ArrayLengthExp e)
9519 static if (LOGSEMANTIC)
9521 printf("ArrayLengthExp::semantic('%s')\n", e.toChars());
9523 if (e.type)
9525 result = e;
9526 return;
9529 if (Expression ex = unaSemantic(e, sc))
9531 result = ex;
9532 return;
9534 e.e1 = resolveProperties(sc, e.e1);
9536 e.type = Type.tsize_t;
9537 result = e;
9540 override void visit(ArrayExp exp)
9542 static if (LOGSEMANTIC)
9544 printf("ArrayExp::semantic('%s')\n", exp.toChars());
9546 assert(!exp.type);
9548 if (sc.flags & SCOPE.Cfile)
9550 /* See if need to rewrite the AST because of cast/call ambiguity
9552 if (auto e = castCallAmbiguity(exp, sc))
9554 result = expressionSemantic(e, sc);
9555 return;
9559 result = exp.carraySemantic(sc); // C semantics
9560 if (result)
9561 return;
9563 Expression e = exp.op_overload(sc);
9564 if (e)
9566 result = e;
9567 return;
9570 if (isAggregate(exp.e1.type))
9571 error(exp.loc, "no `[]` operator overload for type `%s`", exp.e1.type.toChars());
9572 else if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
9573 error(exp.loc, "static array of `%s` with multiple lengths not allowed", exp.e1.type.toChars());
9574 else if (isIndexableNonAggregate(exp.e1.type))
9575 error(exp.loc, "only one index allowed to index `%s`", exp.e1.type.toChars());
9576 else
9577 error(exp.loc, "cannot use `[]` operator on expression of type `%s`", exp.e1.type.toChars());
9579 result = ErrorExp.get();
9582 override void visit(DotExp exp)
9584 static if (LOGSEMANTIC)
9586 printf("DotExp::semantic('%s')\n", exp.toChars());
9587 if (exp.type)
9588 printf("\ttype = %s\n", exp.type.toChars());
9590 exp.e1 = exp.e1.expressionSemantic(sc);
9591 exp.e2 = exp.e2.expressionSemantic(sc);
9593 if (exp.e1.op == EXP.type)
9595 result = exp.e2;
9596 return;
9598 if (exp.e2.op == EXP.type)
9600 result = exp.e2;
9601 return;
9603 if (auto te = exp.e2.isTemplateExp())
9605 Expression e = new DotTemplateExp(exp.loc, exp.e1, te.td);
9606 result = e.expressionSemantic(sc);
9607 return;
9609 if (!exp.type)
9610 exp.type = exp.e2.type;
9611 result = exp;
9614 override void visit(CommaExp e)
9616 //printf("Semantic.CommaExp() %s\n", e.toChars());
9617 if (e.type)
9619 result = e;
9620 return;
9623 // Allow `((a,b),(x,y))`
9624 if (e.allowCommaExp)
9626 CommaExp.allow(e.e1);
9627 CommaExp.allow(e.e2);
9630 if (Expression ex = binSemanticProp(e, sc))
9632 result = ex;
9633 return;
9635 e.e1 = e.e1.addDtorHook(sc);
9637 if (checkNonAssignmentArrayOp(e.e1))
9638 return setError();
9640 // Comma expressions trigger this conversion
9641 e.e2 = e.e2.arrayFuncConv(sc);
9643 e.type = e.e2.type;
9644 result = e;
9646 if (sc.flags & SCOPE.Cfile)
9647 return;
9649 if (e.type is Type.tvoid)
9651 checkMustUse(e.e1, sc);
9652 discardValue(e.e1);
9654 else if (!e.allowCommaExp && !e.isGenerated)
9655 error(e.loc, "using the result of a comma expression is not allowed");
9658 override void visit(IntervalExp e)
9660 static if (LOGSEMANTIC)
9662 printf("IntervalExp::semantic('%s')\n", e.toChars());
9664 if (e.type)
9666 result = e;
9667 return;
9670 Expression le = e.lwr;
9671 le = le.expressionSemantic(sc);
9672 le = resolveProperties(sc, le);
9674 Expression ue = e.upr;
9675 ue = ue.expressionSemantic(sc);
9676 ue = resolveProperties(sc, ue);
9678 if (le.op == EXP.error)
9680 result = le;
9681 return;
9683 if (ue.op == EXP.error)
9685 result = ue;
9686 return;
9689 e.lwr = le;
9690 e.upr = ue;
9692 e.type = Type.tvoid;
9693 result = e;
9696 override void visit(DelegatePtrExp e)
9698 static if (LOGSEMANTIC)
9700 printf("DelegatePtrExp::semantic('%s')\n", e.toChars());
9702 if (!e.type)
9704 unaSemantic(e, sc);
9705 e.e1 = resolveProperties(sc, e.e1);
9707 if (e.e1.op == EXP.error)
9709 result = e.e1;
9710 return;
9712 e.type = Type.tvoidptr;
9714 result = e;
9717 override void visit(DelegateFuncptrExp e)
9719 static if (LOGSEMANTIC)
9721 printf("DelegateFuncptrExp::semantic('%s')\n", e.toChars());
9723 if (!e.type)
9725 unaSemantic(e, sc);
9726 e.e1 = resolveProperties(sc, e.e1);
9727 if (e.e1.op == EXP.error)
9729 result = e.e1;
9730 return;
9732 e.type = e.e1.type.nextOf().pointerTo();
9734 result = e;
9737 override void visit(IndexExp exp)
9739 static if (LOGSEMANTIC)
9741 printf("IndexExp::semantic('%s')\n", exp.toChars());
9743 if (exp.type)
9745 result = exp;
9746 return;
9749 // operator overloading should be handled in ArrayExp already.
9750 if (!exp.e1.type)
9751 exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
9752 assert(exp.e1.type); // semantic() should already be run on it
9753 if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
9755 exp.e2 = exp.e2.expressionSemantic(sc);
9756 exp.e2 = resolveProperties(sc, exp.e2);
9757 Type nt;
9758 if (exp.e2.op == EXP.type)
9759 nt = new TypeAArray(exp.e1.type, exp.e2.type);
9760 else
9761 nt = new TypeSArray(exp.e1.type, exp.e2);
9762 Expression e = new TypeExp(exp.loc, nt);
9763 result = e.expressionSemantic(sc);
9764 return;
9766 if (exp.e1.op == EXP.error)
9768 result = exp.e1;
9769 return;
9771 if (exp.e1.type.ty == Terror)
9772 return setError();
9774 // Note that unlike C we do not implement the int[ptr]
9776 Type t1b = exp.e1.type.toBasetype();
9778 if (TypeVector tv1 = t1b.isTypeVector())
9780 // Convert e1 to corresponding static array
9781 t1b = tv1.basetype;
9782 t1b = t1b.castMod(tv1.mod);
9783 exp.e1 = exp.e1.castTo(sc, t1b);
9785 if (t1b.ty == Tsarray || t1b.ty == Tarray)
9787 if (!checkAddressable(exp, sc))
9788 return setError();
9791 /* Run semantic on e2
9793 Scope* scx = sc;
9794 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
9796 // Create scope for 'length' variable
9797 ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
9798 sym.parent = sc.scopesym;
9799 sc = sc.push(sym);
9801 if (t1b.ty == Ttuple)
9802 sc = sc.startCTFE();
9803 exp.e2 = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
9804 exp.e2 = resolveProperties(sc, exp.e2);
9805 if (t1b.ty == Ttuple)
9806 sc = sc.endCTFE();
9807 if (exp.e2.op == EXP.tuple)
9809 TupleExp te = cast(TupleExp)exp.e2;
9810 if (te.exps && te.exps.length == 1)
9811 exp.e2 = Expression.combine(te.e0, (*te.exps)[0]); // bug 4444 fix
9813 if (sc != scx)
9814 sc = sc.pop();
9815 if (exp.e2.type == Type.terror)
9816 return setError();
9818 if (checkNonAssignmentArrayOp(exp.e1))
9819 return setError();
9821 switch (t1b.ty)
9823 case Tpointer:
9824 if (t1b.isPtrToFunction())
9826 error(exp.loc, "cannot index function pointer `%s`", exp.e1.toChars());
9827 return setError();
9829 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
9830 if (exp.e2.type == Type.terror)
9831 return setError();
9832 exp.e2 = exp.e2.optimize(WANTvalue);
9833 if (exp.e2.op == EXP.int64 && exp.e2.toInteger() == 0)
9836 else if (sc.setUnsafe(false, exp.loc, "`@safe` function `%s` cannot index pointer `%s`", sc.func, exp.e1))
9838 return setError();
9840 exp.type = (cast(TypeNext)t1b).next;
9841 break;
9843 case Tarray:
9844 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
9845 if (exp.e2.type == Type.terror)
9846 return setError();
9847 exp.type = (cast(TypeNext)t1b).next;
9848 break;
9850 case Tsarray:
9852 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
9853 if (exp.e2.type == Type.terror)
9854 return setError();
9855 exp.type = t1b.nextOf();
9856 break;
9858 case Taarray:
9860 TypeAArray taa = cast(TypeAArray)t1b;
9861 /* We can skip the implicit conversion if they differ only by
9862 * constness
9863 * https://issues.dlang.org/show_bug.cgi?id=2684
9864 * see also bug https://issues.dlang.org/show_bug.cgi?id=2954 b
9866 if (!arrayTypeCompatibleWithoutCasting(exp.e2.type, taa.index))
9868 exp.e2 = exp.e2.implicitCastTo(sc, taa.index); // type checking
9869 if (exp.e2.type == Type.terror)
9870 return setError();
9873 semanticTypeInfo(sc, taa);
9874 checkNewEscape(sc, exp.e2, false);
9876 exp.type = taa.next;
9877 break;
9879 case Ttuple:
9881 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
9882 if (exp.e2.type == Type.terror)
9883 return setError();
9885 exp.e2 = exp.e2.ctfeInterpret();
9886 uinteger_t index = exp.e2.toUInteger();
9888 TupleExp te;
9889 TypeTuple tup;
9890 size_t length;
9891 if (exp.e1.op == EXP.tuple)
9893 te = cast(TupleExp)exp.e1;
9894 tup = null;
9895 length = te.exps.length;
9897 else if (exp.e1.op == EXP.type)
9899 te = null;
9900 tup = cast(TypeTuple)t1b;
9901 length = Parameter.dim(tup.arguments);
9903 else
9904 assert(0);
9906 if (length <= index)
9908 error(exp.loc, "array index `[%llu]` is outside array bounds `[0 .. %llu]`", index, cast(ulong)length);
9909 return setError();
9911 Expression e;
9912 if (exp.e1.op == EXP.tuple)
9914 e = (*te.exps)[cast(size_t)index];
9915 e = Expression.combine(te.e0, e);
9917 else
9918 e = new TypeExp(exp.e1.loc, Parameter.getNth(tup.arguments, cast(size_t)index).type);
9919 result = e;
9920 return;
9922 default:
9923 error(exp.loc, "`%s` must be an array or pointer type, not `%s`", exp.e1.toChars(), exp.e1.type.toChars());
9924 return setError();
9927 // We might know $ now
9928 setLengthVarIfKnown(exp.lengthVar, t1b);
9930 if (t1b.ty == Tsarray || t1b.ty == Tarray)
9932 Expression el = new ArrayLengthExp(exp.loc, exp.e1);
9933 el = el.expressionSemantic(sc);
9934 el = el.optimize(WANTvalue);
9935 if (el.op == EXP.int64)
9937 exp.e2 = exp.e2.optimize(WANTvalue);
9938 dinteger_t length = el.toInteger();
9939 if (length)
9941 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length - 1));
9942 // OR it in, because it might already be set for C array indexing
9943 exp.indexIsInBounds |= bounds.contains(getIntRange(exp.e2));
9945 else if (sc.flags & SCOPE.Cfile && t1b.ty == Tsarray)
9947 if (auto ve = exp.e1.isVarExp())
9949 /* Rewrite 0-length C array ve[exp.e2] as *(ve + exp.e2)
9951 auto vp = ve.castTo(sc, t1b.isTypeSArray().next.pointerTo());
9952 auto e = new AddExp(exp.loc, vp, exp.e2);
9953 auto pe = new PtrExp(exp.loc, e);
9954 result = pe.expressionSemantic(sc).optimize(WANTvalue);
9955 return;
9961 result = exp;
9964 override void visit(PostExp exp)
9966 static if (LOGSEMANTIC)
9968 printf("PostExp::semantic('%s')\n", exp.toChars());
9970 if (exp.type)
9972 result = exp;
9973 return;
9976 if (sc.flags & SCOPE.Cfile)
9978 /* See if need to rewrite the AST because of cast/call ambiguity
9980 if (auto e = castCallAmbiguity(exp, sc))
9982 result = expressionSemantic(e, sc);
9983 return;
9987 if (Expression ex = binSemantic(exp, sc))
9989 result = ex;
9990 return;
9992 Expression e1x = resolveProperties(sc, exp.e1);
9993 if (e1x.op == EXP.error)
9995 result = e1x;
9996 return;
9998 exp.e1 = e1x;
10000 Expression e = exp.op_overload(sc);
10001 if (e)
10003 result = e;
10004 return;
10007 if (exp.e1.checkReadModifyWrite(exp.op))
10008 return setError();
10010 if (exp.e1.op == EXP.slice)
10012 const(char)* s = exp.op == EXP.plusPlus ? "increment" : "decrement";
10013 error(exp.loc, "cannot post-%s array slice `%s`, use pre-%s instead", s, exp.e1.toChars(), s);
10014 return setError();
10017 Type t1 = exp.e1.type.toBasetype();
10018 if (t1.ty == Tclass || t1.ty == Tstruct || exp.e1.op == EXP.arrayLength)
10020 /* Check for operator overloading,
10021 * but rewrite in terms of ++e instead of e++
10024 /* If e1 is not trivial, take a reference to it
10026 Expression de = null;
10027 if (exp.e1.op != EXP.variable && exp.e1.op != EXP.arrayLength)
10029 // ref v = e1;
10030 auto v = copyToTemp(STC.ref_, "__postref", exp.e1);
10031 de = new DeclarationExp(exp.loc, v);
10032 exp.e1 = new VarExp(exp.e1.loc, v);
10035 /* Rewrite as:
10036 * auto tmp = e1; ++e1; tmp
10038 auto tmp = copyToTemp(0, "__pitmp", exp.e1);
10039 Expression ea = new DeclarationExp(exp.loc, tmp);
10041 Expression eb = exp.e1.syntaxCopy();
10042 eb = new PreExp(exp.op == EXP.plusPlus ? EXP.prePlusPlus : EXP.preMinusMinus, exp.loc, eb);
10044 Expression ec = new VarExp(exp.loc, tmp);
10046 // Combine de,ea,eb,ec
10047 if (de)
10048 ea = new CommaExp(exp.loc, de, ea);
10049 e = new CommaExp(exp.loc, ea, eb);
10050 e = new CommaExp(exp.loc, e, ec);
10051 e = e.expressionSemantic(sc);
10052 result = e;
10053 return;
10056 exp.e1 = exp.e1.modifiableLvalue(sc);
10057 exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
10059 e = exp;
10060 if (exp.e1.checkScalar() ||
10061 exp.e1.checkSharedAccess(sc))
10062 return setError();
10063 if (exp.e1.checkNoBool())
10064 return setError();
10066 if (exp.e1.type.ty == Tpointer)
10067 e = scaleFactor(exp, sc);
10068 else
10069 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
10070 e.type = exp.e1.type;
10071 result = e;
10074 override void visit(PreExp exp)
10076 Expression e = exp.op_overload(sc);
10077 // printf("PreExp::semantic('%s')\n", toChars());
10078 if (e)
10080 result = e;
10081 return;
10084 // Rewrite as e1+=1 or e1-=1
10085 if (exp.op == EXP.prePlusPlus)
10086 e = new AddAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
10087 else
10088 e = new MinAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
10089 result = e.expressionSemantic(sc);
10093 * Get the expression initializer for a specific struct
10095 * Params:
10096 * sd = the struct for which the expression initializer is needed
10097 * loc = the location of the initializer
10098 * sc = the scope where the expression is located
10099 * t = the type of the expression
10101 * Returns:
10102 * The expression initializer or error expression if any errors occured
10104 private Expression getInitExp(StructDeclaration sd, Loc loc, Scope* sc, Type t)
10106 if (sd.zeroInit && !sd.isNested())
10108 // https://issues.dlang.org/show_bug.cgi?id=14606
10109 // Always use BlitExp for the special expression: (struct = 0)
10110 return IntegerExp.literal!0;
10113 if (sd.isNested())
10115 auto sle = new StructLiteralExp(loc, sd, null, t);
10116 if (!sd.fill(loc, *sle.elements, true))
10117 return ErrorExp.get();
10118 if (checkFrameAccess(loc, sc, sd, sle.elements.length))
10119 return ErrorExp.get();
10121 sle.type = t;
10122 return sle;
10125 return t.defaultInit(loc);
10128 override void visit(AssignExp exp)
10130 static if (LOGSEMANTIC)
10132 if (exp.op == EXP.blit) printf("BlitExp.toElem('%s')\n", exp.toChars());
10133 if (exp.op == EXP.assign) printf("AssignExp.toElem('%s')\n", exp.toChars());
10134 if (exp.op == EXP.construct) printf("ConstructExp.toElem('%s')\n", exp.toChars());
10137 void setResult(Expression e, int line = __LINE__)
10139 //printf("line %d\n", line);
10140 result = e;
10143 if (exp.type)
10145 return setResult(exp);
10148 Expression e1old = exp.e1;
10150 if (auto e2comma = exp.e2.isCommaExp())
10152 if (!e2comma.isGenerated && !(sc.flags & SCOPE.Cfile))
10153 error(exp.loc, "using the result of a comma expression is not allowed");
10155 /* Rewrite to get rid of the comma from rvalue
10156 * e1=(e0,e2) => e0,(e1=e2)
10158 Expression e0;
10159 exp.e2 = Expression.extractLast(e2comma, e0);
10160 Expression e = Expression.combine(e0, exp);
10161 return setResult(e.expressionSemantic(sc));
10164 /* Look for operator overloading of a[arguments] = e2.
10165 * Do it before e1.expressionSemantic() otherwise the ArrayExp will have been
10166 * converted to unary operator overloading already.
10168 if (auto ae = exp.e1.isArrayExp())
10170 Expression res;
10172 ae.e1 = ae.e1.expressionSemantic(sc);
10173 ae.e1 = resolveProperties(sc, ae.e1);
10174 Expression ae1old = ae.e1;
10176 const(bool) maybeSlice =
10177 (ae.arguments.length == 0 ||
10178 ae.arguments.length == 1 && (*ae.arguments)[0].op == EXP.interval);
10180 IntervalExp ie = null;
10181 if (maybeSlice && ae.arguments.length)
10183 assert((*ae.arguments)[0].op == EXP.interval);
10184 ie = cast(IntervalExp)(*ae.arguments)[0];
10186 Type att = null; // first cyclic `alias this` type
10187 while (true)
10189 if (ae.e1.op == EXP.error)
10190 return setResult(ae.e1);
10192 Expression e0 = null;
10193 Expression ae1save = ae.e1;
10194 ae.lengthVar = null;
10196 Type t1b = ae.e1.type.toBasetype();
10197 AggregateDeclaration ad = isAggregate(t1b);
10198 if (!ad)
10199 break;
10200 if (search_function(ad, Id.indexass))
10202 // Deal with $
10203 res = resolveOpDollar(sc, ae, &e0);
10204 if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
10205 goto Lfallback;
10206 if (res.op == EXP.error)
10207 return setResult(res);
10209 res = exp.e2.expressionSemantic(sc);
10210 if (res.op == EXP.error)
10211 return setResult(res);
10212 exp.e2 = res;
10214 /* Rewrite (a[arguments] = e2) as:
10215 * a.opIndexAssign(e2, arguments)
10217 Expressions* a = ae.arguments.copy();
10218 a.insert(0, exp.e2);
10219 res = new DotIdExp(exp.loc, ae.e1, Id.indexass);
10220 res = new CallExp(exp.loc, res, a);
10221 if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2)
10222 res = res.trySemantic(sc);
10223 else
10224 res = res.expressionSemantic(sc);
10225 if (res)
10226 return setResult(Expression.combine(e0, res));
10229 Lfallback:
10230 if (maybeSlice && search_function(ad, Id.sliceass))
10232 // Deal with $
10233 res = resolveOpDollar(sc, ae, ie, &e0);
10234 if (res.op == EXP.error)
10235 return setResult(res);
10237 res = exp.e2.expressionSemantic(sc);
10238 if (res.op == EXP.error)
10239 return setResult(res);
10241 exp.e2 = res;
10243 /* Rewrite (a[i..j] = e2) as:
10244 * a.opSliceAssign(e2, i, j)
10246 auto a = new Expressions();
10247 a.push(exp.e2);
10248 if (ie)
10250 a.push(ie.lwr);
10251 a.push(ie.upr);
10253 res = new DotIdExp(exp.loc, ae.e1, Id.sliceass);
10254 res = new CallExp(exp.loc, res, a);
10255 res = res.expressionSemantic(sc);
10256 return setResult(Expression.combine(e0, res));
10259 // No operator overloading member function found yet, but
10260 // there might be an alias this to try.
10261 if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type))
10263 /* Rewrite (a[arguments] op e2) as:
10264 * a.aliasthis[arguments] op e2
10266 ae.e1 = resolveAliasThis(sc, ae1save, true);
10267 if (ae.e1)
10268 continue;
10270 break;
10272 ae.e1 = ae1old; // recovery
10273 ae.lengthVar = null;
10276 /* Run this.e1 semantic.
10279 Expression e1x = exp.e1;
10281 /* With UFCS, e.f = value
10282 * Could mean:
10283 * .f(e, value)
10284 * or:
10285 * .f(e) = value
10287 if (auto dti = e1x.isDotTemplateInstanceExp())
10289 Expression e = dti.dotTemplateSemanticProp(sc, DotExpFlag.gag);
10290 if (!e)
10292 return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
10295 e1x = e;
10297 else if (sc.flags & SCOPE.Cfile && e1x.isDotIdExp())
10299 auto die = e1x.isDotIdExp();
10300 e1x = fieldLookup(die.e1, sc, die.ident, die.arrow);
10302 else if (auto die = e1x.isDotIdExp())
10304 Expression e = die.dotIdSemanticProp(sc, 1);
10305 if (e && isDotOpDispatch(e))
10307 /* https://issues.dlang.org/show_bug.cgi?id=19687
10309 * On this branch, e2 is semantically analyzed in resolvePropertiesX,
10310 * but that call is done with gagged errors. That is the only time when
10311 * semantic gets ran on e2, that is why the error never gets to be printed.
10312 * In order to make sure that UFCS is tried with correct parameters, e2
10313 * needs to have semantic ran on it.
10315 auto ode = e;
10316 exp.e2 = exp.e2.expressionSemantic(sc);
10317 uint errors = global.startGagging();
10318 e = resolvePropertiesX(sc, e, exp.e2);
10319 // Any error or if 'e' is not resolved, go to UFCS
10320 if (global.endGagging(errors) || e is ode)
10321 e = null; /* fall down to UFCS */
10322 else
10323 return setResult(e);
10325 if (!e)
10326 return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
10327 e1x = e;
10329 else
10331 if (auto se = e1x.isSliceExp())
10332 se.arrayop = true;
10334 e1x = e1x.expressionSemantic(sc);
10337 /* We have f = value.
10338 * Could mean:
10339 * f(value)
10340 * or:
10341 * f() = value
10343 if (Expression e = resolvePropertiesX(sc, e1x, exp.e2, exp))
10344 return setResult(e);
10346 if (e1x.checkRightThis(sc))
10348 return setError();
10350 exp.e1 = e1x;
10351 assert(exp.e1.type);
10353 Type t1 = exp.e1.type.isTypeEnum() ? exp.e1.type : exp.e1.type.toBasetype();
10355 /* Run this.e2 semantic.
10356 * Different from other binary expressions, the analysis of e2
10357 * depends on the result of e1 in assignments.
10360 Expression e2x = inferType(exp.e2, t1.baseElemOf());
10361 e2x = e2x.expressionSemantic(sc);
10362 if (!t1.isTypeSArray())
10363 e2x = e2x.arrayFuncConv(sc);
10364 e2x = resolveProperties(sc, e2x);
10365 if (e2x.op == EXP.type)
10366 e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684
10367 if (e2x.op == EXP.error)
10368 return setResult(e2x);
10369 // We delay checking the value for structs/classes as these might have
10370 // an opAssign defined.
10371 if ((t1.ty != Tstruct && t1.ty != Tclass && e2x.checkValue()) ||
10372 e2x.checkSharedAccess(sc))
10373 return setError();
10375 auto etmp = checkNoreturnVarAccess(e2x);
10376 if (etmp != e2x)
10377 return setResult(etmp);
10379 exp.e2 = e2x;
10382 /* Rewrite tuple assignment as a tuple of assignments.
10385 Expression e2x = exp.e2;
10387 Ltupleassign:
10388 if (exp.e1.op == EXP.tuple && e2x.op == EXP.tuple)
10390 TupleExp tup1 = cast(TupleExp)exp.e1;
10391 TupleExp tup2 = cast(TupleExp)e2x;
10392 size_t dim = tup1.exps.length;
10393 Expression e = null;
10394 if (dim != tup2.exps.length)
10396 error(exp.loc, "mismatched sequence lengths, %d and %d", cast(int)dim, cast(int)tup2.exps.length);
10397 return setError();
10399 if (dim == 0)
10401 e = IntegerExp.literal!0;
10402 e = new CastExp(exp.loc, e, Type.tvoid); // avoid "has no effect" error
10403 e = Expression.combine(tup1.e0, tup2.e0, e);
10405 else
10407 auto exps = new Expressions(dim);
10408 for (size_t i = 0; i < dim; i++)
10410 Expression ex1 = (*tup1.exps)[i];
10411 Expression ex2 = (*tup2.exps)[i];
10412 (*exps)[i] = new AssignExp(exp.loc, ex1, ex2);
10414 e = new TupleExp(exp.loc, Expression.combine(tup1.e0, tup2.e0), exps);
10416 return setResult(e.expressionSemantic(sc));
10419 /* Look for form: e1 = e2.aliasthis.
10421 if (exp.e1.op == EXP.tuple)
10423 TupleDeclaration td = isAliasThisTuple(e2x);
10424 if (!td)
10425 goto Lnomatch;
10427 assert(exp.e1.type.ty == Ttuple);
10428 TypeTuple tt = cast(TypeTuple)exp.e1.type;
10430 Expression e0;
10431 Expression ev = extractSideEffect(sc, "__tup", e0, e2x);
10433 auto iexps = new Expressions();
10434 iexps.push(ev);
10435 for (size_t u = 0; u < iexps.length; u++)
10437 Lexpand:
10438 Expression e = (*iexps)[u];
10440 Parameter arg = Parameter.getNth(tt.arguments, u);
10441 //printf("[%d] iexps.length = %d, ", u, iexps.length);
10442 //printf("e = (%s %s, %s), ", Token.toChars[e.op], e.toChars(), e.type.toChars());
10443 //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
10445 if (!arg || !e.type.implicitConvTo(arg.type))
10447 // expand initializer to tuple
10448 if (expandAliasThisTuples(iexps, u) != -1)
10450 if (iexps.length <= u)
10451 break;
10452 goto Lexpand;
10454 goto Lnomatch;
10457 e2x = new TupleExp(e2x.loc, e0, iexps);
10458 e2x = e2x.expressionSemantic(sc);
10459 if (e2x.op == EXP.error)
10461 result = e2x;
10462 return;
10464 // Do not need to overwrite this.e2
10465 goto Ltupleassign;
10467 Lnomatch:
10470 /* Inside constructor, if this is the first assignment of object field,
10471 * rewrite this to initializing the field.
10473 if (exp.op == EXP.assign
10474 && exp.e1.checkModifiable(sc) == Modifiable.initialization)
10476 //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars());
10477 auto t = exp.type;
10478 exp = new ConstructExp(exp.loc, exp.e1, exp.e2);
10479 exp.type = t;
10481 // https://issues.dlang.org/show_bug.cgi?id=13515
10482 // set Index::modifiable flag for complex AA element initialization
10483 if (auto ie1 = exp.e1.isIndexExp())
10485 Expression e1x = ie1.markSettingAAElem();
10486 if (e1x.op == EXP.error)
10488 result = e1x;
10489 return;
10493 else if (exp.op == EXP.construct && exp.e1.op == EXP.variable &&
10494 (cast(VarExp)exp.e1).var.storage_class & (STC.out_ | STC.ref_))
10496 exp.memset = MemorySet.referenceInit;
10499 if (exp.op == EXP.assign) // skip EXP.blit and EXP.construct, which are initializations
10501 exp.e1.checkSharedAccess(sc);
10502 checkUnsafeAccess(sc, exp.e1, false, true);
10505 checkUnsafeAccess(sc, exp.e2, true, true); // Initializer must always be checked
10507 /* If it is an assignment from a 'foreign' type,
10508 * check for operator overloading.
10510 if (exp.memset == MemorySet.referenceInit)
10512 // If this is an initialization of a reference,
10513 // do nothing
10515 else if (t1.ty == Tstruct)
10517 auto e1x = exp.e1;
10518 auto e2x = exp.e2;
10519 auto sd = (cast(TypeStruct)t1).sym;
10521 if (exp.op == EXP.construct)
10523 Type t2 = e2x.type.toBasetype();
10524 if (t2.ty == Tstruct && sd == (cast(TypeStruct)t2).sym)
10526 sd.size(exp.loc);
10527 if (sd.sizeok != Sizeok.done)
10528 return setError();
10529 if (!sd.ctor)
10530 sd.ctor = sd.searchCtor();
10532 // https://issues.dlang.org/show_bug.cgi?id=15661
10533 // Look for the form from last of comma chain.
10534 auto e2y = lastComma(e2x);
10536 CallExp ce = (e2y.op == EXP.call) ? cast(CallExp)e2y : null;
10537 DotVarExp dve = (ce && ce.e1.op == EXP.dotVariable)
10538 ? cast(DotVarExp)ce.e1 : null;
10539 if (sd.ctor && ce && dve && dve.var.isCtorDeclaration() &&
10540 // https://issues.dlang.org/show_bug.cgi?id=19389
10541 dve.e1.op != EXP.dotVariable &&
10542 e2y.type.implicitConvTo(t1))
10544 /* Look for form of constructor call which is:
10545 * __ctmp.ctor(arguments...)
10548 /* Before calling the constructor, initialize
10549 * variable with a bit copy of the default
10550 * initializer
10552 Expression einit = getInitExp(sd, exp.loc, sc, t1);
10553 if (einit.op == EXP.error)
10555 result = einit;
10556 return;
10559 auto ae = new BlitExp(exp.loc, exp.e1, einit);
10560 ae.type = e1x.type;
10562 /* Replace __ctmp being constructed with e1.
10563 * We need to copy constructor call expression,
10564 * because it may be used in other place.
10566 auto dvx = cast(DotVarExp)dve.copy();
10567 dvx.e1 = e1x;
10568 auto cx = cast(CallExp)ce.copy();
10569 cx.e1 = dvx;
10570 if (checkConstructorEscape(sc, cx, false))
10571 return setError();
10573 Expression e0;
10574 Expression.extractLast(e2x, e0);
10576 auto e = Expression.combine(e0, ae, cx);
10577 e = e.expressionSemantic(sc);
10578 result = e;
10579 return;
10581 // https://issues.dlang.org/show_bug.cgi?id=21586
10582 // Rewrite CondExp or e1 will miss direct construction, e.g.
10583 // e1 = a ? S(1) : ...; -> AST: e1 = a ? (S(0)).this(1) : ...;
10584 // a temporary created and an extra destructor call.
10585 // AST will be rewritten to:
10586 // a ? e1 = 0, e1.this(1) : ...; -> blitting plus construction
10587 if (e2x.op == EXP.question)
10589 /* Rewrite as:
10590 * a ? e1 = b : e1 = c;
10592 CondExp econd = cast(CondExp)e2x;
10593 Expression ea1 = new ConstructExp(econd.e1.loc, e1x, econd.e1);
10594 Expression ea2 = new ConstructExp(econd.e2.loc, e1x, econd.e2);
10595 Expression e = new CondExp(exp.loc, econd.econd, ea1, ea2);
10596 result = e.expressionSemantic(sc);
10597 return;
10599 if (sd.postblit || sd.hasCopyCtor)
10601 /* We have a copy constructor for this
10604 if (e2x.isLvalue())
10606 if (sd.hasCopyCtor)
10608 /* Rewrite as:
10609 * e1 = init, e1.copyCtor(e2);
10611 Expression einit = new BlitExp(exp.loc, exp.e1, getInitExp(sd, exp.loc, sc, t1));
10612 einit.type = e1x.type;
10614 Expression e;
10615 e = new DotIdExp(exp.loc, e1x, Id.ctor);
10616 e = new CallExp(exp.loc, e, e2x);
10617 e = new CommaExp(exp.loc, einit, e);
10619 //printf("e: %s\n", e.toChars());
10621 result = e.expressionSemantic(sc);
10622 return;
10624 else
10626 if (!e2x.type.implicitConvTo(e1x.type))
10628 error(exp.loc, "conversion error from `%s` to `%s`",
10629 e2x.type.toChars(), e1x.type.toChars());
10630 return setError();
10633 /* Rewrite as:
10634 * (e1 = e2).postblit();
10636 * Blit assignment e1 = e2 returns a reference to the original e1,
10637 * then call the postblit on it.
10639 Expression e = e1x.copy();
10640 e.type = e.type.mutableOf();
10641 if (e.type.isShared && !sd.type.isShared)
10642 e.type = e.type.unSharedOf();
10643 e = new BlitExp(exp.loc, e, e2x);
10644 e = new DotVarExp(exp.loc, e, sd.postblit, false);
10645 e = new CallExp(exp.loc, e);
10646 result = e.expressionSemantic(sc);
10647 return;
10650 else
10652 /* The struct value returned from the function is transferred
10653 * so should not call the destructor on it.
10655 e2x = valueNoDtor(e2x);
10659 // https://issues.dlang.org/show_bug.cgi?id=19251
10660 // if e2 cannot be converted to e1.type, maybe there is an alias this
10661 if (!e2x.implicitConvTo(t1))
10663 AggregateDeclaration ad2 = isAggregate(e2x.type);
10664 if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
10666 /* Rewrite (e1 op e2) as:
10667 * (e1 op e2.aliasthis)
10669 exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
10670 result = exp.expressionSemantic(sc);
10671 return;
10675 else if (!e2x.implicitConvTo(t1))
10677 sd.size(exp.loc);
10678 if (sd.sizeok != Sizeok.done)
10679 return setError();
10680 if (!sd.ctor)
10681 sd.ctor = sd.searchCtor();
10683 if (sd.ctor)
10685 /* Look for implicit constructor call
10686 * Rewrite as:
10687 * e1 = init, e1.ctor(e2)
10690 /* Fix Issue 5153 : https://issues.dlang.org/show_bug.cgi?id=5153
10691 * Using `new` to initialize a struct object is a common mistake, but
10692 * the error message from the compiler is not very helpful in that
10693 * case. If exp.e2 is a NewExp and the type of new is the same as
10694 * the type as exp.e1 (struct in this case), then we know for sure
10695 * that the user wants to instantiate a struct. This is done to avoid
10696 * issuing an error when the user actually wants to call a constructor
10697 * which receives a class object.
10699 * Foo f = new Foo2(0); is a valid expression if Foo has a constructor
10700 * which receives an instance of a Foo2 class
10702 if (exp.e2.op == EXP.new_)
10704 auto newExp = cast(NewExp)(exp.e2);
10705 if (newExp.newtype && newExp.newtype == t1)
10707 error(exp.loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
10708 newExp.toChars(), newExp.type.toChars(), t1.toChars());
10709 errorSupplemental(exp.loc, "Perhaps remove the `new` keyword?");
10710 return setError();
10714 Expression einit = new BlitExp(exp.loc, e1x, getInitExp(sd, exp.loc, sc, t1));
10715 einit.type = e1x.type;
10717 Expression e;
10718 e = new DotIdExp(exp.loc, e1x, Id.ctor);
10719 e = new CallExp(exp.loc, e, e2x);
10720 e = new CommaExp(exp.loc, einit, e);
10721 e = e.expressionSemantic(sc);
10722 result = e;
10723 return;
10725 if (search_function(sd, Id.call))
10727 /* Look for static opCall
10728 * https://issues.dlang.org/show_bug.cgi?id=2702
10729 * Rewrite as:
10730 * e1 = typeof(e1).opCall(arguments)
10732 e2x = typeDotIdExp(e2x.loc, e1x.type, Id.call);
10733 e2x = new CallExp(exp.loc, e2x, exp.e2);
10735 e2x = e2x.expressionSemantic(sc);
10736 e2x = resolveProperties(sc, e2x);
10737 if (e2x.op == EXP.error)
10739 result = e2x;
10740 return;
10742 if (e2x.checkValue() || e2x.checkSharedAccess(sc))
10743 return setError();
10746 else // https://issues.dlang.org/show_bug.cgi?id=11355
10748 AggregateDeclaration ad2 = isAggregate(e2x.type);
10749 if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
10751 /* Rewrite (e1 op e2) as:
10752 * (e1 op e2.aliasthis)
10754 exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
10755 result = exp.expressionSemantic(sc);
10756 return;
10760 else if (exp.op == EXP.assign)
10762 if (e1x.op == EXP.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray)
10765 * Rewrite:
10766 * aa[key] = e2;
10767 * as:
10768 * ref __aatmp = aa;
10769 * ref __aakey = key;
10770 * ref __aaval = e2;
10771 * (__aakey in __aatmp
10772 * ? __aatmp[__aakey].opAssign(__aaval)
10773 * : ConstructExp(__aatmp[__aakey], __aaval));
10775 // ensure we keep the expr modifiable
10776 Expression esetting = (cast(IndexExp)e1x).markSettingAAElem();
10777 if (esetting.op == EXP.error)
10779 result = esetting;
10780 return;
10782 assert(esetting.op == EXP.index);
10783 IndexExp ie = cast(IndexExp) esetting;
10784 Type t2 = e2x.type.toBasetype();
10786 Expression e0 = null;
10787 Expression ea = extractSideEffect(sc, "__aatmp", e0, ie.e1);
10788 Expression ek = extractSideEffect(sc, "__aakey", e0, ie.e2);
10789 Expression ev = extractSideEffect(sc, "__aaval", e0, e2x);
10791 AssignExp ae = cast(AssignExp)exp.copy();
10792 ae.e1 = new IndexExp(exp.loc, ea, ek);
10793 ae.e1 = ae.e1.expressionSemantic(sc);
10794 ae.e1 = ae.e1.optimize(WANTvalue);
10795 ae.e2 = ev;
10796 Expression e = ae.op_overload(sc);
10797 if (e)
10799 Expression ey = null;
10800 if (t2.ty == Tstruct && sd == t2.toDsymbol(sc))
10802 ey = ev;
10804 else if (!ev.implicitConvTo(ie.type) && sd.ctor)
10806 // Look for implicit constructor call
10807 // Rewrite as S().ctor(e2)
10808 ey = new StructLiteralExp(exp.loc, sd, null);
10809 ey = new DotIdExp(exp.loc, ey, Id.ctor);
10810 ey = new CallExp(exp.loc, ey, ev);
10811 ey = ey.trySemantic(sc);
10813 if (ey)
10815 Expression ex;
10816 ex = new IndexExp(exp.loc, ea, ek);
10817 ex = ex.expressionSemantic(sc);
10818 ex = ex.modifiableLvalue(sc); // allocate new slot
10819 ex = ex.optimize(WANTvalue);
10821 ey = new ConstructExp(exp.loc, ex, ey);
10822 ey = ey.expressionSemantic(sc);
10823 if (ey.op == EXP.error)
10825 result = ey;
10826 return;
10828 ex = e;
10830 // https://issues.dlang.org/show_bug.cgi?id=14144
10831 // The whole expression should have the common type
10832 // of opAssign() return and assigned AA entry.
10833 // Even if there's no common type, expression should be typed as void.
10834 if (!typeMerge(sc, EXP.question, ex, ey))
10836 ex = new CastExp(ex.loc, ex, Type.tvoid);
10837 ey = new CastExp(ey.loc, ey, Type.tvoid);
10839 e = new CondExp(exp.loc, new InExp(exp.loc, ek, ea), ex, ey);
10841 e = Expression.combine(e0, e);
10842 e = e.expressionSemantic(sc);
10843 result = e;
10844 return;
10847 else
10849 Expression e = exp.op_overload(sc);
10850 if (e)
10852 result = e;
10853 return;
10857 else
10858 assert(exp.op == EXP.blit);
10860 if (e2x.checkValue())
10861 return setError();
10863 exp.e1 = e1x;
10864 exp.e2 = e2x;
10866 else if (t1.ty == Tclass)
10868 // Disallow assignment operator overloads for same type
10869 if (exp.op == EXP.assign && !exp.e2.implicitConvTo(exp.e1.type))
10871 Expression e = exp.op_overload(sc);
10872 if (e)
10874 result = e;
10875 return;
10878 if (exp.e2.checkValue())
10879 return setError();
10881 else if (t1.ty == Tsarray)
10883 // SliceExp cannot have static array type without context inference.
10884 assert(exp.e1.op != EXP.slice);
10885 Expression e1x = exp.e1;
10886 Expression e2x = exp.e2;
10888 /* C strings come through as static arrays. May need to adjust the size of the
10889 * string to match the size of e1.
10891 Type t2 = e2x.type.toBasetype();
10892 if (sc.flags & SCOPE.Cfile && e2x.isStringExp() && t2.isTypeSArray())
10894 uinteger_t dim1 = t1.isTypeSArray().dim.toInteger();
10895 uinteger_t dim2 = t2.isTypeSArray().dim.toInteger();
10896 if (dim1 + 1 == dim2 || dim2 < dim1)
10898 auto tsa2 = t2.isTypeSArray();
10899 auto newt = tsa2.next.sarrayOf(dim1).immutableOf();
10900 e2x = castTo(e2x, sc, newt);
10901 exp.e2 = e2x;
10905 if (e2x.implicitConvTo(e1x.type))
10907 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()))
10909 if (t1.checkPostblit(e1x.loc, sc))
10910 return setError();
10913 // e2 matches to t1 because of the implicit length match, so
10914 if (isUnaArrayOp(e2x.op) || isBinArrayOp(e2x.op))
10916 // convert e1 to e1[]
10917 // e.g. e1[] = a[] + b[];
10918 auto sle = new SliceExp(e1x.loc, e1x, null, null);
10919 sle.arrayop = true;
10920 e1x = sle.expressionSemantic(sc);
10922 else
10924 // convert e2 to t1 later
10925 // e.g. e1 = [1, 2, 3];
10928 else
10930 if (e2x.implicitConvTo(t1.nextOf().arrayOf()) > MATCH.nomatch)
10932 uinteger_t dim1 = (cast(TypeSArray)t1).dim.toInteger();
10933 uinteger_t dim2 = dim1;
10934 if (auto ale = e2x.isArrayLiteralExp())
10936 dim2 = ale.elements ? ale.elements.length : 0;
10938 else if (auto se = e2x.isSliceExp())
10940 Type tx = toStaticArrayType(se);
10941 if (tx)
10942 dim2 = (cast(TypeSArray)tx).dim.toInteger();
10944 if (dim1 != dim2)
10946 error(exp.loc, "mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2);
10947 return setError();
10951 // May be block or element-wise assignment, so
10952 // convert e1 to e1[]
10953 if (exp.op != EXP.assign)
10955 // If multidimensional static array, treat as one large array
10957 // Find the appropriate array type depending on the assignment, e.g.
10958 // int[3] = int => int[3]
10959 // int[3][2] = int => int[6]
10960 // int[3][2] = int[] => int[3][2]
10961 // int[3][2][4] + int => int[24]
10962 // int[3][2][4] + int[] => int[3][8]
10963 ulong dim = t1.isTypeSArray().dim.toUInteger();
10964 auto type = t1.nextOf();
10966 for (TypeSArray tsa; (tsa = type.isTypeSArray()) !is null; )
10968 import core.checkedint : mulu;
10970 // Accumulate skipped dimensions
10971 bool overflow = false;
10972 dim = mulu(dim, tsa.dim.toUInteger(), overflow);
10973 if (overflow || dim >= uint.max)
10975 // dym exceeds maximum array size
10976 error(exp.loc, "static array `%s` size overflowed to %llu",
10977 e1x.type.toChars(), cast(ulong) dim);
10978 return setError();
10981 // Move to the element type
10982 type = tsa.nextOf().toBasetype();
10984 // Rewrite ex1 as a static array if a matching type was found
10985 if (e2x.implicitConvTo(type) > MATCH.nomatch)
10987 e1x.type = type.sarrayOf(dim);
10988 break;
10992 auto sle = new SliceExp(e1x.loc, e1x, null, null);
10993 sle.arrayop = true;
10994 e1x = sle.expressionSemantic(sc);
10996 if (e1x.op == EXP.error)
10997 return setResult(e1x);
10998 if (e2x.op == EXP.error)
10999 return setResult(e2x);
11001 exp.e1 = e1x;
11002 exp.e2 = e2x;
11003 t1 = e1x.type.toBasetype();
11005 /* Check the mutability of e1.
11007 if (auto ale = exp.e1.isArrayLengthExp())
11009 // e1 is not an lvalue, but we let code generator handle it
11011 auto ale1x = ale.e1.modifiableLvalueImpl(sc, exp.e1);
11012 if (ale1x.op == EXP.error)
11013 return setResult(ale1x);
11014 ale.e1 = ale1x;
11016 Type tn = ale.e1.type.toBasetype().nextOf();
11017 checkDefCtor(ale.loc, tn);
11019 Identifier hook = global.params.tracegc ? Id._d_arraysetlengthTTrace : Id._d_arraysetlengthT;
11020 if (!verifyHookExist(exp.loc, *sc, Id._d_arraysetlengthTImpl, "resizing arrays"))
11021 return setError();
11023 exp.e2 = exp.e2.expressionSemantic(sc);
11024 auto lc = lastComma(exp.e2);
11025 lc = lc.optimize(WANTvalue);
11026 // use slice expression when arr.length = 0 to avoid runtime call
11027 if(lc.op == EXP.int64 && lc.toInteger() == 0)
11029 Expression se = new SliceExp(ale.loc, ale.e1, lc, lc);
11030 Expression as = new AssignExp(ale.loc, ale.e1, se);
11031 as = as.expressionSemantic(sc);
11032 auto res = Expression.combine(as, exp.e2);
11033 res.type = ale.type;
11034 return setResult(res);
11037 if (!sc.needsCodegen()) // if compile time creature only
11039 exp.type = Type.tsize_t;
11040 return setResult(exp);
11043 // Lower to object._d_arraysetlengthTImpl!(typeof(e1))._d_arraysetlengthT{,Trace}(e1, e2)
11044 Expression id = new IdentifierExp(ale.loc, Id.empty);
11045 id = new DotIdExp(ale.loc, id, Id.object);
11046 auto tiargs = new Objects();
11047 tiargs.push(ale.e1.type);
11048 id = new DotTemplateInstanceExp(ale.loc, id, Id._d_arraysetlengthTImpl, tiargs);
11049 id = new DotIdExp(ale.loc, id, hook);
11050 id = id.expressionSemantic(sc);
11052 auto arguments = new Expressions();
11053 arguments.reserve(5);
11054 if (global.params.tracegc)
11056 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
11057 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
11058 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
11059 arguments.push(new StringExp(exp.loc, funcname.toDString()));
11061 arguments.push(ale.e1);
11062 arguments.push(exp.e2);
11064 Expression ce = new CallExp(ale.loc, id, arguments).expressionSemantic(sc);
11065 auto res = new LoweredAssignExp(exp, ce);
11066 // if (global.params.verbose)
11067 // message("lowered %s =>\n %s", exp.toChars(), res.toChars());
11068 res.type = Type.tsize_t;
11069 return setResult(res);
11071 else if (auto se = exp.e1.isSliceExp())
11073 Type tn = se.type.nextOf();
11074 const fun = sc.func;
11075 if (exp.op == EXP.assign && !tn.isMutable() &&
11076 // allow modifiation in module ctor, see
11077 // https://issues.dlang.org/show_bug.cgi?id=9884
11078 (!fun || (fun && !fun.isStaticCtorDeclaration())))
11080 error(exp.loc, "slice `%s` is not mutable", se.toChars());
11081 return setError();
11084 if (exp.op == EXP.assign && !tn.baseElemOf().isAssignable())
11086 error(exp.loc, "slice `%s` is not mutable, struct `%s` has immutable members",
11087 exp.e1.toChars(), tn.baseElemOf().toChars());
11088 result = ErrorExp.get();
11089 return;
11092 // For conditional operator, both branches need conversion.
11093 while (se.e1.op == EXP.slice)
11094 se = cast(SliceExp)se.e1;
11095 if (se.e1.op == EXP.question && se.e1.type.toBasetype().ty == Tsarray)
11097 se.e1 = se.e1.modifiableLvalueImpl(sc, exp.e1);
11098 if (se.e1.op == EXP.error)
11099 return setResult(se.e1);
11102 else
11104 if (t1.ty == Tsarray && exp.op == EXP.assign)
11106 Type tn = exp.e1.type.nextOf();
11107 if (tn && !tn.baseElemOf().isAssignable())
11109 error(exp.loc, "array `%s` is not mutable, struct `%s` has immutable members",
11110 exp.e1.toChars(), tn.baseElemOf().toChars());
11111 result = ErrorExp.get();
11112 return;
11116 Expression e1x = exp.e1;
11118 // Try to do a decent error message with the expression
11119 // before it gets constant folded
11120 if (exp.op == EXP.assign)
11121 e1x = e1x.modifiableLvalueImpl(sc, e1old);
11123 e1x = e1x.optimize(WANTvalue, /*keepLvalue*/ true);
11125 if (e1x.op == EXP.error)
11127 result = e1x;
11128 return;
11130 exp.e1 = e1x;
11133 /* Tweak e2 based on the type of e1.
11135 Expression e2x = exp.e2;
11136 Type t2 = e2x.type.toBasetype();
11138 // If it is a array, get the element type. Note that it may be
11139 // multi-dimensional.
11140 Type telem = t1;
11141 while (telem.ty == Tarray)
11142 telem = telem.nextOf();
11144 if (exp.e1.op == EXP.slice && t1.nextOf() &&
11145 (telem.ty != Tvoid || e2x.op == EXP.null_) &&
11146 e2x.implicitConvTo(t1.nextOf()))
11148 // Check for block assignment. If it is of type void[], void[][], etc,
11149 // '= null' is the only allowable block assignment (Bug 7493)
11150 exp.memset = MemorySet.blockAssign; // make it easy for back end to tell what this is
11151 e2x = e2x.implicitCastTo(sc, t1.nextOf());
11152 if (exp.op != EXP.blit && e2x.isLvalue() && t1.nextOf.checkPostblit(exp.e1.loc, sc))
11153 return setError();
11155 else if (exp.e1.op == EXP.slice &&
11156 (t2.ty == Tarray || t2.ty == Tsarray) &&
11157 t2.nextOf().implicitConvTo(t1.nextOf()))
11159 // Check element-wise assignment.
11161 /* If assigned elements number is known at compile time,
11162 * check the mismatch.
11164 SliceExp se1 = cast(SliceExp)exp.e1;
11165 TypeSArray tsa1 = cast(TypeSArray)toStaticArrayType(se1);
11166 TypeSArray tsa2 = null;
11167 if (auto ale = e2x.isArrayLiteralExp())
11168 tsa2 = cast(TypeSArray)t2.nextOf().sarrayOf(ale.elements.length);
11169 else if (auto se = e2x.isSliceExp())
11170 tsa2 = cast(TypeSArray)toStaticArrayType(se);
11171 else
11172 tsa2 = t2.isTypeSArray();
11174 if (tsa1 && tsa2)
11176 uinteger_t dim1 = tsa1.dim.toInteger();
11177 uinteger_t dim2 = tsa2.dim.toInteger();
11178 if (dim1 != dim2)
11180 error(exp.loc, "mismatched array lengths %d and %d for assignment `%s`", cast(int)dim1, cast(int)dim2, exp.toChars());
11181 return setError();
11185 if (exp.op != EXP.blit &&
11186 (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() ||
11187 e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() ||
11188 e2x.op != EXP.slice && e2x.isLvalue()))
11190 if (t1.nextOf().checkPostblit(exp.e1.loc, sc))
11191 return setError();
11194 Type t2n = t2.nextOf();
11195 Type t1n = t1.nextOf();
11196 int offset;
11197 if (t2n.equivalent(t1n) ||
11198 t1n.isBaseOf(t2n, &offset) && offset == 0)
11200 /* Allow copy of distinct qualifier elements.
11201 * eg.
11202 * char[] dst; const(char)[] src;
11203 * dst[] = src;
11205 * class C {} class D : C {}
11206 * C[2] ca; D[] da;
11207 * ca[] = da;
11209 if (isArrayOpValid(e2x))
11211 // Don't add CastExp to keep AST for array operations
11212 e2x = e2x.copy();
11213 e2x.type = exp.e1.type.constOf();
11215 else
11216 e2x = e2x.castTo(sc, exp.e1.type.constOf());
11218 else
11220 /* https://issues.dlang.org/show_bug.cgi?id=15778
11221 * A string literal has an array type of immutable
11222 * elements by default, and normally it cannot be convertible to
11223 * array type of mutable elements. But for element-wise assignment,
11224 * elements need to be const at best. So we should give a chance
11225 * to change code unit size for polysemous string literal.
11227 if (e2x.op == EXP.string_)
11228 e2x = e2x.implicitCastTo(sc, exp.e1.type.constOf());
11229 else
11230 e2x = e2x.implicitCastTo(sc, exp.e1.type);
11232 if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid)
11234 if (sc.setUnsafe(false, exp.loc, "cannot copy `void[]` to `void[]` in `@safe` code"))
11235 return setError();
11238 else
11240 if (exp.op == EXP.blit)
11241 e2x = e2x.castTo(sc, exp.e1.type);
11242 else
11244 e2x = e2x.implicitCastTo(sc, exp.e1.type);
11246 // Fix Issue 13435: https://issues.dlang.org/show_bug.cgi?id=13435
11248 // If the implicit cast has failed and the assign expression is
11249 // the initialization of a struct member field
11250 if (e2x.op == EXP.error && exp.op == EXP.construct && t1.ty == Tstruct)
11252 scope sd = (cast(TypeStruct)t1).sym;
11253 Dsymbol opAssign = search_function(sd, Id.assign);
11255 // and the struct defines an opAssign
11256 if (opAssign)
11258 // offer more information about the cause of the problem
11259 errorSupplemental(exp.loc,
11260 "`%s` is the first assignment of `%s` therefore it represents its initialization",
11261 exp.toChars(), exp.e1.toChars());
11262 errorSupplemental(exp.loc,
11263 "`opAssign` methods are not used for initialization, but for subsequent assignments");
11268 if (e2x.op == EXP.error)
11270 result = e2x;
11271 return;
11273 exp.e2 = e2x;
11274 t2 = exp.e2.type.toBasetype();
11276 /* Look for array operations
11278 if ((t2.ty == Tarray || t2.ty == Tsarray) && isArrayOpValid(exp.e2))
11280 // Look for valid array operations
11281 if (exp.memset != MemorySet.blockAssign &&
11282 exp.e1.op == EXP.slice &&
11283 (isUnaArrayOp(exp.e2.op) || isBinArrayOp(exp.e2.op)))
11285 exp.type = exp.e1.type;
11286 if (exp.op == EXP.construct) // https://issues.dlang.org/show_bug.cgi?id=10282
11287 // tweak mutability of e1 element
11288 exp.e1.type = exp.e1.type.nextOf().mutableOf().arrayOf();
11289 result = arrayOp(exp, sc);
11290 return;
11293 // Drop invalid array operations in e2
11294 // d = a[] + b[], d = (a[] + b[])[0..2], etc
11295 if (checkNonAssignmentArrayOp(exp.e2, exp.memset != MemorySet.blockAssign && exp.op == EXP.assign))
11296 return setError();
11298 // Remains valid array assignments
11299 // d = d[], d = [1,2,3], etc
11302 /* Don't allow assignment to classes that were allocated on the stack with:
11303 * scope Class c = new Class();
11305 if (exp.e1.op == EXP.variable && exp.op == EXP.assign)
11307 VarExp ve = cast(VarExp)exp.e1;
11308 VarDeclaration vd = ve.var.isVarDeclaration();
11309 if (vd && vd.onstack)
11311 assert(t1.ty == Tclass);
11312 error(exp.loc, "cannot rebind scope variables");
11316 if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.ident == Id.ctfe)
11318 error(exp.loc, "cannot modify compiler-generated variable `__ctfe`");
11321 exp.type = exp.e1.type;
11322 assert(exp.type);
11323 auto assignElem = exp.e2;
11324 auto res = exp.op == EXP.assign ? exp.reorderSettingAAElem(sc) : exp;
11325 /* https://issues.dlang.org/show_bug.cgi?id=22366
11327 * `reorderSettingAAElem` creates a tree of comma expressions, however,
11328 * `checkAssignExp` expects only AssignExps.
11330 if (res == exp) // no `AA[k] = v` rewrite was performed
11331 checkAssignEscape(sc, res, false, false);
11332 else
11333 checkNewEscape(sc, assignElem, false); // assigning to AA puts it on heap
11335 if (auto ae = res.isConstructExp())
11337 Type t1b = ae.e1.type.toBasetype();
11338 if (t1b.ty != Tsarray && t1b.ty != Tarray)
11339 return setResult(res);
11341 // only non-trivial array constructions may need to be lowered (non-POD elements basically)
11342 Type t1e = t1b.nextOf();
11343 TypeStruct ts = t1e.baseElemOf().isTypeStruct();
11344 if (!ts || (!ts.sym.postblit && !ts.sym.hasCopyCtor && !ts.sym.dtor))
11345 return setResult(res);
11347 // don't lower ref-constructions etc.
11348 if (!(t1b.ty == Tsarray || ae.e1.isSliceExp) ||
11349 (ae.e1.isVarExp && ae.e1.isVarExp.var.isVarDeclaration.isReference))
11350 return setResult(res);
11352 // Construction from an equivalent other array?
11353 // Only lower with lvalue RHS elements; let the glue layer move rvalue elements.
11354 Type t2b = ae.e2.type.toBasetype();
11355 // skip over a (possibly implicit) cast of a static array RHS to a slice
11356 Expression rhs = ae.e2;
11357 Type rhsType = t2b;
11358 if (t2b.ty == Tarray)
11360 if (auto ce = rhs.isCastExp())
11362 auto ct = ce.e1.type.toBasetype();
11363 if (ct.ty == Tsarray)
11365 rhs = ce.e1;
11366 rhsType = ct;
11371 if (!sc.needsCodegen()) // interpreter can handle these
11372 return setResult(res);
11374 const lowerToArrayCtor =
11375 ( (rhsType.ty == Tarray && !rhs.isArrayLiteralExp) ||
11376 (rhsType.ty == Tsarray && rhs.isLvalue) ) &&
11377 t1e.equivalent(t2b.nextOf);
11379 // Construction from a single element?
11380 // If the RHS is an rvalue, then we'll need to make a temporary for it (copied multiple times).
11381 const lowerToArraySetCtor = !lowerToArrayCtor && t1e.equivalent(t2b);
11383 if (lowerToArrayCtor || lowerToArraySetCtor)
11385 auto func = lowerToArrayCtor ? Id._d_arrayctor : Id._d_arraysetctor;
11386 const other = lowerToArrayCtor ? "other array" : "value";
11387 if (!verifyHookExist(exp.loc, *sc, func, "construct array with " ~ other, Id.object))
11388 return setError();
11390 // Lower to object._d_array{,set}ctor(e1, e2)
11391 Expression id = new IdentifierExp(exp.loc, Id.empty);
11392 id = new DotIdExp(exp.loc, id, Id.object);
11393 id = new DotIdExp(exp.loc, id, func);
11395 auto arguments = new Expressions();
11396 arguments.push(new CastExp(ae.loc, ae.e1, t1e.arrayOf).expressionSemantic(sc));
11397 if (lowerToArrayCtor)
11399 arguments.push(new CastExp(ae.loc, rhs, t2b.nextOf.arrayOf).expressionSemantic(sc));
11400 Expression ce = new CallExp(exp.loc, id, arguments);
11401 res = ce.expressionSemantic(sc);
11403 else
11405 Expression e0;
11406 // promote an rvalue RHS element to a temporary, it's passed by ref to _d_arraysetctor
11407 if (!ae.e2.isLvalue)
11409 auto vd = copyToTemp(STC.scope_, "__setctor", ae.e2);
11410 e0 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc);
11411 arguments.push(new VarExp(vd.loc, vd).expressionSemantic(sc));
11413 else
11414 arguments.push(ae.e2);
11416 Expression ce = new CallExp(exp.loc, id, arguments);
11417 res = Expression.combine(e0, ce).expressionSemantic(sc);
11420 if (global.params.v.verbose)
11421 message("lowered %s =>\n %s", exp.toChars(), res.toChars());
11424 else if (auto ae = res.isAssignExp())
11425 res = lowerArrayAssign(ae);
11426 else if (auto ce = res.isCommaExp())
11428 if (auto ae1 = ce.e1.isAssignExp())
11429 ce.e1 = lowerArrayAssign(ae1, true);
11430 if (auto ae2 = ce.e2.isAssignExp())
11431 ce.e2 = lowerArrayAssign(ae2, true);
11434 return setResult(res);
11437 /***************************************
11438 * Lower AssignExp to `_d_array{setassign,assign_l,assign_r}` if needed.
11440 * Params:
11441 * ae = the AssignExp to be lowered
11442 * fromCommaExp = indicates whether `ae` is part of a CommaExp or not,
11443 * so no unnecessary temporay variable is created.
11444 * Returns:
11445 * a CommaExp contiaining call a to `_d_array{setassign,assign_l,assign_r}`
11446 * if needed or `ae` otherwise
11448 private Expression lowerArrayAssign(AssignExp ae, bool fromCommaExp = false)
11450 Type t1b = ae.e1.type.toBasetype();
11451 if (t1b.ty != Tsarray && t1b.ty != Tarray)
11452 return ae;
11454 const isArrayAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) &&
11455 (ae.e2.type.ty == Tsarray || ae.e2.type.ty == Tarray) &&
11456 (ae.e1.type.nextOf() && ae.e2.type.nextOf() && ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf()));
11458 const isArraySetAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) &&
11459 (ae.e1.type.nextOf() && ae.e2.type.implicitConvTo(ae.e1.type.nextOf()));
11461 if (!isArrayAssign && !isArraySetAssign)
11462 return ae;
11464 const ts = t1b.nextOf().baseElemOf().isTypeStruct();
11465 if (!ts || (!ts.sym.postblit && !ts.sym.dtor))
11466 return ae;
11468 Expression res;
11469 Identifier func = isArraySetAssign ? Id._d_arraysetassign :
11470 ae.e2.isLvalue() || ae.e2.isSliceExp() ? Id._d_arrayassign_l : Id._d_arrayassign_r;
11472 // Lower to `.object._d_array{setassign,assign_l,assign_r}(e1, e2)``
11473 Expression id = new IdentifierExp(ae.loc, Id.empty);
11474 id = new DotIdExp(ae.loc, id, Id.object);
11475 id = new DotIdExp(ae.loc, id, func);
11477 auto arguments = new Expressions();
11478 arguments.push(new CastExp(ae.loc, ae.e1, ae.e1.type.nextOf.arrayOf)
11479 .expressionSemantic(sc));
11481 Expression eValue2, value2 = ae.e2;
11482 if (isArrayAssign && value2.isLvalue())
11483 value2 = new CastExp(ae.loc, ae.e2, ae.e2.type.nextOf.arrayOf())
11484 .expressionSemantic(sc);
11485 else if (!fromCommaExp &&
11486 (isArrayAssign || (isArraySetAssign && !value2.isLvalue())))
11488 // Rvalues from CommaExps were introduced in `visit(AssignExp)`
11489 // and are temporary variables themselves. Rvalues from trivial
11490 // SliceExps are simply passed by reference without any copying.
11492 // `__assigntmp` will be destroyed together with the array `ae.e1`.
11493 // When `ae.e2` is a variadic arg array, it is also `scope`, so
11494 // `__assigntmp` may also be scope.
11495 StorageClass stc = STC.nodtor;
11496 if (isArrayAssign)
11497 stc |= STC.rvalue | STC.scope_;
11499 auto vd = copyToTemp(stc, "__assigntmp", ae.e2);
11500 eValue2 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc);
11501 value2 = new VarExp(vd.loc, vd).expressionSemantic(sc);
11503 arguments.push(value2);
11505 Expression ce = new CallExp(ae.loc, id, arguments);
11506 res = Expression.combine(eValue2, ce).expressionSemantic(sc);
11507 if (isArrayAssign)
11508 res = Expression.combine(res, ae.e1).expressionSemantic(sc);
11510 if (global.params.v.verbose)
11511 message("lowered %s =>\n %s", ae.toChars(), res.toChars());
11513 res = new LoweredAssignExp(ae, res);
11514 res.type = ae.type;
11516 return res;
11519 override void visit(PowAssignExp exp)
11521 if (exp.type)
11523 result = exp;
11524 return;
11527 Expression e = exp.op_overload(sc);
11528 if (e)
11530 result = e;
11531 return;
11534 if (exp.e1.checkReadModifyWrite(exp.op, exp.e2))
11535 return setError();
11537 assert(exp.e1.type && exp.e2.type);
11538 if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
11540 if (checkNonAssignmentArrayOp(exp.e1))
11541 return setError();
11543 // T[] ^^= ...
11544 if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
11546 // T[] ^^= T
11547 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
11549 else if (Expression ex = typeCombine(exp, sc))
11551 result = ex;
11552 return;
11555 // Check element types are arithmetic
11556 Type tb1 = exp.e1.type.nextOf().toBasetype();
11557 Type tb2 = exp.e2.type.toBasetype();
11558 if (tb2.ty == Tarray || tb2.ty == Tsarray)
11559 tb2 = tb2.nextOf().toBasetype();
11560 if ((tb1.isintegral() || tb1.isfloating()) && (tb2.isintegral() || tb2.isfloating()))
11562 exp.type = exp.e1.type;
11563 result = arrayOp(exp, sc);
11564 return;
11567 else
11569 exp.e1 = exp.e1.modifiableLvalue(sc);
11572 if ((exp.e1.type.isintegral() || exp.e1.type.isfloating()) && (exp.e2.type.isintegral() || exp.e2.type.isfloating()))
11574 Expression e0 = null;
11575 e = exp.reorderSettingAAElem(sc);
11576 e = Expression.extractLast(e, e0);
11577 assert(e == exp);
11579 if (exp.e1.op == EXP.variable)
11581 // Rewrite: e1 = e1 ^^ e2
11582 e = new PowExp(exp.loc, exp.e1.syntaxCopy(), exp.e2);
11583 e = new AssignExp(exp.loc, exp.e1, e);
11585 else
11587 // Rewrite: ref tmp = e1; tmp = tmp ^^ e2
11588 auto v = copyToTemp(STC.ref_, "__powtmp", exp.e1);
11589 auto de = new DeclarationExp(exp.e1.loc, v);
11590 auto ve = new VarExp(exp.e1.loc, v);
11591 e = new PowExp(exp.loc, ve, exp.e2);
11592 e = new AssignExp(exp.loc, new VarExp(exp.e1.loc, v), e);
11593 e = new CommaExp(exp.loc, de, e);
11595 e = Expression.combine(e0, e);
11596 e = e.expressionSemantic(sc);
11597 result = e;
11598 return;
11600 result = exp.incompatibleTypes();
11603 override void visit(CatAssignExp exp)
11605 if (exp.type)
11607 result = exp;
11608 return;
11611 //printf("CatAssignExp::semantic() %s\n", exp.toChars());
11612 Expression e = exp.op_overload(sc);
11613 if (e)
11615 result = e;
11616 return;
11619 if (SliceExp se = exp.e1.isSliceExp())
11621 if (se.e1.type.toBasetype().ty == Tsarray)
11623 error(exp.loc, "cannot append to static array `%s`", se.e1.type.toChars());
11624 return setError();
11628 exp.e1 = exp.e1.modifiableLvalue(sc);
11629 if (exp.e1.op == EXP.error)
11631 result = exp.e1;
11632 return;
11634 if (exp.e2.op == EXP.error)
11636 result = exp.e2;
11637 return;
11640 if (checkNonAssignmentArrayOp(exp.e2))
11641 return setError();
11643 Type tb1 = exp.e1.type.toBasetype();
11644 Type tb1next = tb1.nextOf();
11645 Type tb2 = exp.e2.type.toBasetype();
11647 /* Possibilities:
11648 * EXP.concatenateAssign: appending T[] to T[]
11649 * EXP.concatenateElemAssign: appending T to T[]
11650 * EXP.concatenateDcharAssign: appending dchar to T[]
11652 if ((tb1.ty == Tarray) &&
11653 (tb2.ty == Tarray || tb2.ty == Tsarray) &&
11654 (exp.e2.implicitConvTo(exp.e1.type) ||
11655 (tb2.nextOf().implicitConvTo(tb1next) &&
11656 (tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial)))))
11658 // EXP.concatenateAssign
11659 assert(exp.op == EXP.concatenateAssign);
11660 if (tb1next.checkPostblit(exp.e1.loc, sc))
11661 return setError();
11663 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
11665 else if ((tb1.ty == Tarray) && exp.e2.implicitConvTo(tb1next))
11667 /* https://issues.dlang.org/show_bug.cgi?id=19782
11669 * If e2 is implicitly convertible to tb1next, the conversion
11670 * might be done through alias this, in which case, e2 needs to
11671 * be modified accordingly (e2 => e2.aliasthis).
11673 if (tb2.ty == Tstruct && (cast(TypeStruct)tb2).implicitConvToThroughAliasThis(tb1next))
11674 goto Laliasthis;
11675 if (tb2.ty == Tclass && (cast(TypeClass)tb2).implicitConvToThroughAliasThis(tb1next))
11676 goto Laliasthis;
11677 // Append element
11678 if (tb2.checkPostblit(exp.e2.loc, sc))
11679 return setError();
11681 if (checkNewEscape(sc, exp.e2, false))
11682 return setError();
11684 exp = new CatElemAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, tb1next));
11685 exp.e2 = doCopyOrMove(sc, exp.e2);
11687 else if (tb1.ty == Tarray &&
11688 (tb1next.ty == Tchar || tb1next.ty == Twchar) &&
11689 exp.e2.type.ty != tb1next.ty &&
11690 exp.e2.implicitConvTo(Type.tdchar))
11692 // Append dchar to char[] or wchar[]
11693 exp = new CatDcharAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, Type.tdchar));
11695 /* Do not allow appending wchar to char[] because if wchar happens
11696 * to be a surrogate pair, nothing good can result.
11699 else
11701 // Try alias this on first operand
11702 static Expression tryAliasThisForLhs(BinAssignExp exp, Scope* sc)
11704 AggregateDeclaration ad1 = isAggregate(exp.e1.type);
11705 if (!ad1 || !ad1.aliasthis)
11706 return null;
11708 /* Rewrite (e1 op e2) as:
11709 * (e1.aliasthis op e2)
11711 if (isRecursiveAliasThis(exp.att1, exp.e1.type))
11712 return null;
11713 //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
11714 Expression e1 = new DotIdExp(exp.loc, exp.e1, ad1.aliasthis.ident);
11715 BinExp be = cast(BinExp)exp.copy();
11716 be.e1 = e1;
11717 return be.trySemantic(sc);
11720 // Try alias this on second operand
11721 static Expression tryAliasThisForRhs(BinAssignExp exp, Scope* sc)
11723 AggregateDeclaration ad2 = isAggregate(exp.e2.type);
11724 if (!ad2 || !ad2.aliasthis)
11725 return null;
11726 /* Rewrite (e1 op e2) as:
11727 * (e1 op e2.aliasthis)
11729 if (isRecursiveAliasThis(exp.att2, exp.e2.type))
11730 return null;
11731 //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
11732 Expression e2 = new DotIdExp(exp.loc, exp.e2, ad2.aliasthis.ident);
11733 BinExp be = cast(BinExp)exp.copy();
11734 be.e2 = e2;
11735 return be.trySemantic(sc);
11738 Laliasthis:
11739 result = tryAliasThisForLhs(exp, sc);
11740 if (result)
11741 return;
11743 result = tryAliasThisForRhs(exp, sc);
11744 if (result)
11745 return;
11747 error(exp.loc, "cannot append type `%s` to type `%s`", tb2.toChars(), tb1.toChars());
11748 return setError();
11751 if (exp.e2.checkValue() || exp.e2.checkSharedAccess(sc))
11752 return setError();
11754 exp.type = exp.e1.type;
11755 auto assignElem = exp.e2;
11756 auto res = exp.reorderSettingAAElem(sc);
11757 if (res != exp) // `AA[k] = v` rewrite was performed
11758 checkNewEscape(sc, assignElem, false);
11759 else if (exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign)
11760 checkAssignEscape(sc, res, false, false);
11762 result = res;
11764 if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) && sc.needsCodegen())
11766 // if aa ordering is triggered, `res` will be a CommaExp
11767 // and `.e2` will be the rewritten original expression.
11769 // `output` will point to the expression that the lowering will overwrite
11770 Expression* output;
11771 if (auto comma = res.isCommaExp())
11773 output = &comma.e2;
11774 // manual cast because it could be either CatAssignExp or CatElemAssignExp
11775 exp = cast(CatAssignExp)comma.e2;
11777 else
11779 output = &result;
11780 exp = cast(CatAssignExp)result;
11783 if (exp.op == EXP.concatenateAssign)
11785 Identifier hook = global.params.tracegc ? Id._d_arrayappendTTrace : Id._d_arrayappendT;
11787 if (!verifyHookExist(exp.loc, *sc, hook, "appending array to arrays", Id.object))
11788 return setError();
11790 // Lower to object._d_arrayappendT{,Trace}({file, line, funcname}, e1, e2)
11791 Expression id = new IdentifierExp(exp.loc, Id.empty);
11792 id = new DotIdExp(exp.loc, id, Id.object);
11793 id = new DotIdExp(exp.loc, id, hook);
11795 auto arguments = new Expressions();
11796 arguments.reserve(5);
11797 if (global.params.tracegc)
11799 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
11800 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
11801 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
11802 arguments.push(new StringExp(exp.loc, funcname.toDString()));
11805 arguments.push(exp.e1);
11806 arguments.push(exp.e2);
11807 Expression ce = new CallExp(exp.loc, id, arguments);
11809 exp.lowering = ce.expressionSemantic(sc);
11810 *output = exp;
11812 else if (exp.op == EXP.concatenateElemAssign)
11814 /* Do not lower concats to the indices array returned by
11815 *`static foreach`, as this array is only used at compile-time.
11817 if (auto ve = exp.e1.isVarExp)
11819 import core.stdc.ctype : isdigit;
11820 // The name of the indices array that static foreach loops uses.
11821 // See dmd.cond.lowerNonArrayAggregate
11822 enum varName = "__res";
11823 const(char)[] id = ve.var.ident.toString;
11824 if (ve.var.storage_class & STC.temp && id.length > varName.length &&
11825 id[0 .. varName.length] == varName && id[varName.length].isdigit)
11826 return;
11829 Identifier hook = global.params.tracegc ? Id._d_arrayappendcTXTrace : Id._d_arrayappendcTX;
11830 if (!verifyHookExist(exp.loc, *sc, hook, "appending element to arrays", Id.object))
11831 return setError();
11833 // Lower to object._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2
11834 Expression id = new IdentifierExp(exp.loc, Id.empty);
11835 id = new DotIdExp(exp.loc, id, Id.object);
11836 id = new DotIdExp(exp.loc, id, hook);
11838 auto arguments = new Expressions();
11839 arguments.reserve(5);
11840 if (global.params.tracegc)
11842 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
11843 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
11844 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
11845 arguments.push(new StringExp(exp.loc, funcname.toDString()));
11848 Expression eValue1;
11849 Expression value1 = extractSideEffect(sc, "__appendtmp", eValue1, exp.e1);
11851 arguments.push(value1);
11852 arguments.push(new IntegerExp(exp.loc, 1, Type.tsize_t));
11854 Expression ce = new CallExp(exp.loc, id, arguments);
11856 Expression eValue2;
11857 Expression value2 = exp.e2;
11858 if (!value2.isVarExp() && !value2.isConst())
11860 /* Before the template hook, this check was performed in e2ir.d
11861 * for expressions like `a ~= a[$-1]`. Here, $ will be modified
11862 * by calling `_d_arrayappendcTX`, so we need to save `a[$-1]` in
11863 * a temporary variable.
11865 value2 = extractSideEffect(sc, "__appendtmp", eValue2, value2, true);
11867 // `__appendtmp*` will be destroyed together with the array `exp.e1`.
11868 auto vd = eValue2.isDeclarationExp().declaration.isVarDeclaration();
11869 vd.storage_class |= STC.nodtor;
11870 // Be more explicit that this "declaration" is local to the expression
11871 vd.storage_class |= STC.exptemp;
11874 auto ale = new ArrayLengthExp(exp.loc, value1);
11875 auto elem = new IndexExp(exp.loc, value1, new MinExp(exp.loc, ale, IntegerExp.literal!1));
11876 auto ae = new ConstructExp(exp.loc, elem, value2);
11878 auto e0 = Expression.combine(ce, ae).expressionSemantic(sc);
11879 e0 = Expression.combine(e0, value1);
11880 e0 = Expression.combine(eValue1, e0);
11881 e0 = Expression.combine(eValue2, e0);
11883 exp.lowering = e0.expressionSemantic(sc);
11884 *output = exp;
11889 override void visit(AddExp exp)
11891 static if (LOGSEMANTIC)
11893 printf("AddExp::semantic('%s')\n", exp.toChars());
11895 if (exp.type)
11897 result = exp;
11898 return;
11901 if (Expression ex = binSemanticProp(exp, sc))
11903 result = ex;
11904 return;
11906 Expression e = exp.op_overload(sc);
11907 if (e)
11909 result = e;
11910 return;
11913 /* ImportC: convert arrays to pointers, functions to pointers to functions
11915 exp.e1 = exp.e1.arrayFuncConv(sc);
11916 exp.e2 = exp.e2.arrayFuncConv(sc);
11918 Type tb1 = exp.e1.type.toBasetype();
11919 Type tb2 = exp.e2.type.toBasetype();
11921 bool err = false;
11922 if (tb1.ty == Tdelegate || tb1.isPtrToFunction())
11924 err |= exp.e1.checkArithmetic(exp.op) || exp.e1.checkSharedAccess(sc);
11926 if (tb2.ty == Tdelegate || tb2.isPtrToFunction())
11928 err |= exp.e2.checkArithmetic(exp.op) || exp.e2.checkSharedAccess(sc);
11930 if (err)
11931 return setError();
11933 if (tb1.ty == Tpointer && exp.e2.type.isintegral() || tb2.ty == Tpointer && exp.e1.type.isintegral())
11935 result = scaleFactor(exp, sc);
11936 return;
11939 if (tb1.ty == Tpointer && tb2.ty == Tpointer)
11941 result = exp.incompatibleTypes();
11942 return;
11945 if (Expression ex = typeCombine(exp, sc))
11947 result = ex;
11948 return;
11951 Type tb = exp.type.toBasetype();
11952 if (tb.ty == Tarray || tb.ty == Tsarray)
11954 if (!isArrayOpValid(exp))
11956 result = arrayOpInvalidError(exp);
11957 return;
11959 result = exp;
11960 return;
11963 tb1 = exp.e1.type.toBasetype();
11964 if (!target.isVectorOpSupported(tb1, exp.op, tb2))
11966 result = exp.incompatibleTypes();
11967 return;
11969 if ((tb1.isreal() && exp.e2.type.isimaginary()) || (tb1.isimaginary() && exp.e2.type.isreal()))
11971 switch (exp.type.toBasetype().ty)
11973 case Tfloat32:
11974 case Timaginary32:
11975 exp.type = Type.tcomplex32;
11976 break;
11978 case Tfloat64:
11979 case Timaginary64:
11980 exp.type = Type.tcomplex64;
11981 break;
11983 case Tfloat80:
11984 case Timaginary80:
11985 exp.type = Type.tcomplex80;
11986 break;
11988 default:
11989 assert(0);
11992 result = exp;
11995 override void visit(MinExp exp)
11997 static if (LOGSEMANTIC)
11999 printf("MinExp::semantic('%s')\n", exp.toChars());
12001 if (exp.type)
12003 result = exp;
12004 return;
12007 if (Expression ex = binSemanticProp(exp, sc))
12009 result = ex;
12010 return;
12012 Expression e = exp.op_overload(sc);
12013 if (e)
12015 result = e;
12016 return;
12019 /* ImportC: convert arrays to pointers, functions to pointers to functions
12021 exp.e1 = exp.e1.arrayFuncConv(sc);
12022 exp.e2 = exp.e2.arrayFuncConv(sc);
12024 Type t1 = exp.e1.type.toBasetype();
12025 Type t2 = exp.e2.type.toBasetype();
12027 bool err = false;
12028 if (t1.ty == Tdelegate || t1.isPtrToFunction())
12030 err |= exp.e1.checkArithmetic(exp.op) || exp.e1.checkSharedAccess(sc);
12032 if (t2.ty == Tdelegate || t2.isPtrToFunction())
12034 err |= exp.e2.checkArithmetic(exp.op) || exp.e2.checkSharedAccess(sc);
12036 if (err)
12037 return setError();
12039 if (t1.ty == Tpointer)
12041 if (t2.ty == Tpointer)
12043 // https://dlang.org/spec/expression.html#add_expressions
12044 // "If both operands are pointers, and the operator is -, the pointers are
12045 // subtracted and the result is divided by the size of the type pointed to
12046 // by the operands. It is an error if the pointers point to different types."
12047 Type p1 = t1.nextOf();
12048 Type p2 = t2.nextOf();
12050 if (!p1.equivalent(p2))
12052 // Deprecation to remain for at least a year, after which this should be
12053 // changed to an error
12054 // See https://github.com/dlang/dmd/pull/7332
12055 deprecation(exp.loc,
12056 "cannot subtract pointers to different types: `%s` and `%s`.",
12057 t1.toChars(), t2.toChars());
12060 // Need to divide the result by the stride
12061 // Replace (ptr - ptr) with (ptr - ptr) / stride
12062 long stride;
12064 // make sure pointer types are compatible
12065 if (Expression ex = typeCombine(exp, sc))
12067 result = ex;
12068 return;
12071 exp.type = Type.tptrdiff_t;
12072 stride = t2.nextOf().size();
12073 if (stride == 0)
12075 e = new IntegerExp(exp.loc, 0, Type.tptrdiff_t);
12077 else if (stride == cast(long)SIZE_INVALID)
12078 e = ErrorExp.get();
12079 else
12081 e = new DivExp(exp.loc, exp, new IntegerExp(Loc.initial, stride, Type.tptrdiff_t));
12082 e.type = Type.tptrdiff_t;
12085 else if (t2.isintegral())
12086 e = scaleFactor(exp, sc);
12087 else
12089 error(exp.loc, "can't subtract `%s` from pointer", t2.toChars());
12090 e = ErrorExp.get();
12092 result = e;
12093 return;
12095 if (t2.ty == Tpointer)
12097 exp.type = exp.e2.type;
12098 error(exp.loc, "can't subtract pointer from `%s`", exp.e1.type.toChars());
12099 return setError();
12102 if (Expression ex = typeCombine(exp, sc))
12104 result = ex;
12105 return;
12108 Type tb = exp.type.toBasetype();
12109 if (tb.ty == Tarray || tb.ty == Tsarray)
12111 if (!isArrayOpValid(exp))
12113 result = arrayOpInvalidError(exp);
12114 return;
12116 result = exp;
12117 return;
12120 t1 = exp.e1.type.toBasetype();
12121 t2 = exp.e2.type.toBasetype();
12122 if (!target.isVectorOpSupported(t1, exp.op, t2))
12124 result = exp.incompatibleTypes();
12125 return;
12127 if ((t1.isreal() && t2.isimaginary()) || (t1.isimaginary() && t2.isreal()))
12129 switch (exp.type.ty)
12131 case Tfloat32:
12132 case Timaginary32:
12133 exp.type = Type.tcomplex32;
12134 break;
12136 case Tfloat64:
12137 case Timaginary64:
12138 exp.type = Type.tcomplex64;
12139 break;
12141 case Tfloat80:
12142 case Timaginary80:
12143 exp.type = Type.tcomplex80;
12144 break;
12146 default:
12147 assert(0);
12150 result = exp;
12151 return;
12155 * If the given expression is a `CatExp`, the function tries to lower it to
12156 * `_d_arraycatnTX`.
12158 * Params:
12159 * ee = the `CatExp` to lower
12160 * Returns:
12161 * `_d_arraycatnTX(e1, e2, ..., en)` if `ee` is `e1 ~ e2 ~ ... en`
12162 * `ee` otherwise
12164 private Expression lowerToArrayCat(CatExp exp)
12166 // String literals are concatenated by the compiler. No lowering is needed.
12167 if ((exp.e1.isStringExp() && (exp.e2.isIntegerExp() || exp.e2.isStringExp())) ||
12168 (exp.e2.isStringExp() && (exp.e1.isIntegerExp() || exp.e1.isStringExp())))
12169 return exp;
12171 bool useTraceGCHook = global.params.tracegc && sc.needsCodegen();
12173 Identifier hook = useTraceGCHook ? Id._d_arraycatnTXTrace : Id._d_arraycatnTX;
12174 if (!verifyHookExist(exp.loc, *sc, hook, "concatenating arrays"))
12176 setError();
12177 return result;
12180 void handleCatArgument(Expressions *arguments, Expression e)
12182 if (auto ce = e.isCatExp())
12184 Expression lowering = ce.lowering;
12186 /* Skip `file`, `line`, and `funcname` if the hook of the parent
12187 * `CatExp` is `_d_arraycatnTXTrace`.
12189 if (auto callExp = isRuntimeHook(lowering, hook))
12191 if (hook == Id._d_arraycatnTX)
12192 arguments.pushSlice((*callExp.arguments)[]);
12193 else
12194 arguments.pushSlice((*callExp.arguments)[3 .. $]);
12197 else
12198 arguments.push(e);
12201 auto arguments = new Expressions();
12202 if (useTraceGCHook)
12204 auto funcname = (sc.callsc && sc.callsc.func) ?
12205 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
12206 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
12207 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
12208 arguments.push(new StringExp(exp.loc, funcname.toDString()));
12211 handleCatArgument(arguments, exp.e1);
12212 handleCatArgument(arguments, exp.e2);
12214 Expression id = new IdentifierExp(exp.loc, Id.empty);
12215 id = new DotIdExp(exp.loc, id, Id.object);
12217 auto tiargs = new Objects();
12218 tiargs.push(exp.type);
12219 id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs);
12220 id = new CallExp(exp.loc, id, arguments);
12221 return id.expressionSemantic(sc);
12224 void trySetCatExpLowering(Expression exp)
12226 /* `_d_arraycatnTX` canot be used with `-betterC`, but `CatExp`s may be
12227 * used with `-betterC`, but only during CTFE.
12229 if (!global.params.useGC)
12230 return;
12232 if (auto ce = exp.isCatExp())
12233 ce.lowering = lowerToArrayCat(ce);
12236 override void visit(CatExp exp)
12238 // https://dlang.org/spec/expression.html#cat_expressions
12239 //printf("CatExp.semantic() %s\n", toChars());
12240 if (exp.type)
12242 result = exp;
12243 return;
12246 if (Expression ex = binSemanticProp(exp, sc))
12248 result = ex;
12249 return;
12251 Expression e = exp.op_overload(sc);
12252 if (e)
12254 result = e;
12255 return;
12258 Type tb1 = exp.e1.type.toBasetype();
12259 Type tb2 = exp.e2.type.toBasetype();
12261 auto f1 = checkNonAssignmentArrayOp(exp.e1);
12262 auto f2 = checkNonAssignmentArrayOp(exp.e2);
12263 if (f1 || f2)
12264 return setError();
12266 Type tb1next = tb1.nextOf();
12267 Type tb2next = tb2.nextOf();
12269 // Check for: array ~ array
12270 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)))
12272 /* https://issues.dlang.org/show_bug.cgi?id=9248
12273 * Here to avoid the case of:
12274 * void*[] a = [cast(void*)1];
12275 * void*[] b = [cast(void*)2];
12276 * a ~ b;
12277 * becoming:
12278 * a ~ [cast(void*)b];
12281 /* https://issues.dlang.org/show_bug.cgi?id=14682
12282 * Also to avoid the case of:
12283 * int[][] a;
12284 * a ~ [];
12285 * becoming:
12286 * a ~ cast(int[])[];
12288 goto Lpeer;
12291 // Check for: array ~ element
12292 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && tb2.ty != Tvoid)
12294 if (exp.e1.op == EXP.arrayLiteral)
12296 exp.e2 = doCopyOrMove(sc, exp.e2);
12297 // https://issues.dlang.org/show_bug.cgi?id=14686
12298 // Postblit call appears in AST, and this is
12299 // finally translated to an ArrayLiteralExp in below optimize().
12301 else if (exp.e1.op == EXP.string_)
12303 // No postblit call exists on character (integer) value.
12305 else
12307 if (tb2.checkPostblit(exp.e2.loc, sc))
12308 return setError();
12309 // Postblit call will be done in runtime helper function
12312 if (exp.e1.op == EXP.arrayLiteral && exp.e1.implicitConvTo(tb2.arrayOf()))
12314 exp.e1 = exp.e1.implicitCastTo(sc, tb2.arrayOf());
12315 exp.type = tb2.arrayOf();
12316 goto L2elem;
12318 if (exp.e2.implicitConvTo(tb1next) >= MATCH.convert)
12320 exp.e2 = exp.e2.implicitCastTo(sc, tb1next);
12321 exp.type = tb1next.arrayOf();
12322 L2elem:
12323 if (checkNewEscape(sc, exp.e2, false))
12324 return setError();
12325 result = exp.optimize(WANTvalue);
12326 trySetCatExpLowering(result);
12327 return;
12330 // Check for: element ~ array
12331 if ((tb2.ty == Tsarray || tb2.ty == Tarray) && tb1.ty != Tvoid)
12333 if (exp.e2.op == EXP.arrayLiteral)
12335 exp.e1 = doCopyOrMove(sc, exp.e1);
12337 else if (exp.e2.op == EXP.string_)
12340 else
12342 if (tb1.checkPostblit(exp.e1.loc, sc))
12343 return setError();
12346 if (exp.e2.op == EXP.arrayLiteral && exp.e2.implicitConvTo(tb1.arrayOf()))
12348 exp.e2 = exp.e2.implicitCastTo(sc, tb1.arrayOf());
12349 exp.type = tb1.arrayOf();
12350 goto L1elem;
12352 if (exp.e1.implicitConvTo(tb2next) >= MATCH.convert)
12354 exp.e1 = exp.e1.implicitCastTo(sc, tb2next);
12355 exp.type = tb2next.arrayOf();
12356 L1elem:
12357 if (checkNewEscape(sc, exp.e1, false))
12358 return setError();
12359 result = exp.optimize(WANTvalue);
12360 trySetCatExpLowering(result);
12361 return;
12365 Lpeer:
12366 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && (tb2.ty == Tsarray || tb2.ty == Tarray) && (tb1next.mod || tb2next.mod) && (tb1next.mod != tb2next.mod))
12368 Type t1 = tb1next.mutableOf().constOf().arrayOf();
12369 Type t2 = tb2next.mutableOf().constOf().arrayOf();
12370 if (exp.e1.op == EXP.string_ && !(cast(StringExp)exp.e1).committed)
12371 exp.e1.type = t1;
12372 else
12373 exp.e1 = exp.e1.castTo(sc, t1);
12374 if (exp.e2.op == EXP.string_ && !(cast(StringExp)exp.e2).committed)
12375 exp.e2.type = t2;
12376 else
12377 exp.e2 = exp.e2.castTo(sc, t2);
12380 if (Expression ex = typeCombine(exp, sc))
12382 result = ex;
12383 trySetCatExpLowering(result);
12384 return;
12386 exp.type = exp.type.toHeadMutable();
12388 Type tb = exp.type.toBasetype();
12389 if (tb.ty == Tsarray)
12390 exp.type = tb.nextOf().arrayOf();
12391 if (exp.type.ty == Tarray && tb1next && tb2next && tb1next.mod != tb2next.mod)
12393 exp.type = exp.type.nextOf().toHeadMutable().arrayOf();
12395 if (Type tbn = tb.nextOf())
12397 if (tbn.checkPostblit(exp.loc, sc))
12398 return setError();
12400 Type t1 = exp.e1.type.toBasetype();
12401 Type t2 = exp.e2.type.toBasetype();
12402 if ((t1.ty == Tarray || t1.ty == Tsarray) &&
12403 (t2.ty == Tarray || t2.ty == Tsarray))
12405 // Normalize to ArrayLiteralExp or StringExp as far as possible
12406 e = exp.optimize(WANTvalue);
12408 else
12410 //printf("(%s) ~ (%s)\n", e1.toChars(), e2.toChars());
12411 result = exp.incompatibleTypes();
12412 return;
12415 result = e;
12416 trySetCatExpLowering(result);
12419 override void visit(MulExp exp)
12421 version (none)
12423 printf("MulExp::semantic() %s\n", exp.toChars());
12425 if (exp.type)
12427 result = exp;
12428 return;
12431 if (Expression ex = binSemanticProp(exp, sc))
12433 result = ex;
12434 return;
12436 Expression e = exp.op_overload(sc);
12437 if (e)
12439 result = e;
12440 return;
12443 if (Expression ex = typeCombine(exp, sc))
12445 result = ex;
12446 return;
12449 Type tb = exp.type.toBasetype();
12450 if (tb.ty == Tarray || tb.ty == Tsarray)
12452 if (!isArrayOpValid(exp))
12454 result = arrayOpInvalidError(exp);
12455 return;
12457 result = exp;
12458 return;
12461 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
12462 return setError();
12464 if (exp.type.isfloating())
12466 Type t1 = exp.e1.type;
12467 Type t2 = exp.e2.type;
12469 if (t1.isreal())
12471 exp.type = t2;
12473 else if (t2.isreal())
12475 exp.type = t1;
12477 else if (t1.isimaginary())
12479 if (t2.isimaginary())
12481 switch (t1.toBasetype().ty)
12483 case Timaginary32:
12484 exp.type = Type.tfloat32;
12485 break;
12487 case Timaginary64:
12488 exp.type = Type.tfloat64;
12489 break;
12491 case Timaginary80:
12492 exp.type = Type.tfloat80;
12493 break;
12495 default:
12496 assert(0);
12499 // iy * iv = -yv
12500 exp.e1.type = exp.type;
12501 exp.e2.type = exp.type;
12502 e = new NegExp(exp.loc, exp);
12503 e = e.expressionSemantic(sc);
12504 result = e;
12505 return;
12507 else
12508 exp.type = t2; // t2 is complex
12510 else if (t2.isimaginary())
12512 exp.type = t1; // t1 is complex
12515 else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12517 result = exp.incompatibleTypes();
12518 return;
12520 result = exp;
12523 override void visit(DivExp exp)
12525 if (exp.type)
12527 result = exp;
12528 return;
12531 if (Expression ex = binSemanticProp(exp, sc))
12533 result = ex;
12534 return;
12536 Expression e = exp.op_overload(sc);
12537 if (e)
12539 result = e;
12540 return;
12543 if (Expression ex = typeCombine(exp, sc))
12545 result = ex;
12546 return;
12549 Type tb = exp.type.toBasetype();
12550 if (tb.ty == Tarray || tb.ty == Tsarray)
12552 if (!isArrayOpValid(exp))
12554 result = arrayOpInvalidError(exp);
12555 return;
12557 result = exp;
12558 return;
12561 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
12562 return setError();
12564 if (exp.type.isfloating())
12566 Type t1 = exp.e1.type;
12567 Type t2 = exp.e2.type;
12569 if (t1.isreal())
12571 exp.type = t2;
12572 if (t2.isimaginary())
12574 // x/iv = i(-x/v)
12575 exp.e2.type = t1;
12576 e = new NegExp(exp.loc, exp);
12577 e = e.expressionSemantic(sc);
12578 result = e;
12579 return;
12582 else if (t2.isreal())
12584 exp.type = t1;
12586 else if (t1.isimaginary())
12588 if (t2.isimaginary())
12590 switch (t1.toBasetype().ty)
12592 case Timaginary32:
12593 exp.type = Type.tfloat32;
12594 break;
12596 case Timaginary64:
12597 exp.type = Type.tfloat64;
12598 break;
12600 case Timaginary80:
12601 exp.type = Type.tfloat80;
12602 break;
12604 default:
12605 assert(0);
12608 else
12609 exp.type = t2; // t2 is complex
12611 else if (t2.isimaginary())
12613 exp.type = t1; // t1 is complex
12616 else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12618 result = exp.incompatibleTypes();
12619 return;
12621 result = exp;
12624 override void visit(ModExp exp)
12626 if (exp.type)
12628 result = exp;
12629 return;
12632 if (Expression ex = binSemanticProp(exp, sc))
12634 result = ex;
12635 return;
12637 Expression e = exp.op_overload(sc);
12638 if (e)
12640 result = e;
12641 return;
12644 if (Expression ex = typeCombine(exp, sc))
12646 result = ex;
12647 return;
12650 Type tb = exp.type.toBasetype();
12651 if (tb.ty == Tarray || tb.ty == Tsarray)
12653 if (!isArrayOpValid(exp))
12655 result = arrayOpInvalidError(exp);
12656 return;
12658 result = exp;
12659 return;
12661 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12663 result = exp.incompatibleTypes();
12664 return;
12667 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
12668 return setError();
12670 if (exp.type.isfloating())
12672 exp.type = exp.e1.type;
12673 if (exp.e2.type.iscomplex())
12675 error(exp.loc, "cannot perform modulo complex arithmetic");
12676 return setError();
12679 result = exp;
12682 override void visit(PowExp exp)
12684 if (exp.type)
12686 result = exp;
12687 return;
12690 //printf("PowExp::semantic() %s\n", toChars());
12691 if (Expression ex = binSemanticProp(exp, sc))
12693 result = ex;
12694 return;
12696 Expression e = exp.op_overload(sc);
12697 if (e)
12699 result = e;
12700 return;
12703 if (Expression ex = typeCombine(exp, sc))
12705 result = ex;
12706 return;
12709 Type tb = exp.type.toBasetype();
12710 if (tb.ty == Tarray || tb.ty == Tsarray)
12712 if (!isArrayOpValid(exp))
12714 result = arrayOpInvalidError(exp);
12715 return;
12717 result = exp;
12718 return;
12721 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
12722 return setError();
12724 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12726 result = exp.incompatibleTypes();
12727 return;
12730 // First, attempt to fold the expression.
12731 e = exp.optimize(WANTvalue);
12732 if (e.op != EXP.pow)
12734 e = e.expressionSemantic(sc);
12735 result = e;
12736 return;
12739 Module mmath = Module.loadStdMath();
12740 if (!mmath)
12742 error(e.loc, "`%s` requires `std.math` for `^^` operators", e.toChars());
12743 return setError();
12745 e = new ScopeExp(exp.loc, mmath);
12747 if (exp.e2.op == EXP.float64 && exp.e2.toReal() == CTFloat.half)
12749 // Replace e1 ^^ 0.5 with .std.math.sqrt(e1)
12750 e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._sqrt), exp.e1);
12752 else
12754 // Replace e1 ^^ e2 with .std.math.pow(e1, e2)
12755 e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._pow), exp.e1, exp.e2);
12757 e = e.expressionSemantic(sc);
12758 result = e;
12759 return;
12762 override void visit(ShlExp exp)
12764 //printf("ShlExp::semantic(), type = %p\n", type);
12765 if (exp.type)
12767 result = exp;
12768 return;
12771 if (Expression ex = binSemanticProp(exp, sc))
12773 result = ex;
12774 return;
12776 Expression e = exp.op_overload(sc);
12777 if (e)
12779 result = e;
12780 return;
12783 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
12784 return setError();
12786 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
12788 result = exp.incompatibleTypes();
12789 return;
12791 exp.e1 = integralPromotions(exp.e1, sc);
12792 if (exp.e2.type.toBasetype().ty != Tvector)
12793 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
12795 exp.type = exp.e1.type;
12796 result = exp;
12799 override void visit(ShrExp exp)
12801 if (exp.type)
12803 result = exp;
12804 return;
12807 if (Expression ex = binSemanticProp(exp, sc))
12809 result = ex;
12810 return;
12812 Expression e = exp.op_overload(sc);
12813 if (e)
12815 result = e;
12816 return;
12819 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
12820 return setError();
12822 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
12824 result = exp.incompatibleTypes();
12825 return;
12827 exp.e1 = integralPromotions(exp.e1, sc);
12828 if (exp.e2.type.toBasetype().ty != Tvector)
12829 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
12831 exp.type = exp.e1.type;
12832 result = exp;
12835 override void visit(UshrExp exp)
12837 if (exp.type)
12839 result = exp;
12840 return;
12843 if (Expression ex = binSemanticProp(exp, sc))
12845 result = ex;
12846 return;
12848 Expression e = exp.op_overload(sc);
12849 if (e)
12851 result = e;
12852 return;
12855 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
12856 return setError();
12858 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
12860 result = exp.incompatibleTypes();
12861 return;
12863 exp.e1 = integralPromotions(exp.e1, sc);
12864 if (exp.e2.type.toBasetype().ty != Tvector)
12865 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
12867 exp.type = exp.e1.type;
12868 result = exp;
12871 override void visit(AndExp exp)
12873 if (exp.type)
12875 result = exp;
12876 return;
12879 if (Expression ex = binSemanticProp(exp, sc))
12881 result = ex;
12882 return;
12884 Expression e = exp.op_overload(sc);
12885 if (e)
12887 result = e;
12888 return;
12891 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
12893 exp.type = exp.e1.type;
12894 result = exp;
12895 return;
12898 if (Expression ex = typeCombine(exp, sc))
12900 result = ex;
12901 return;
12904 Type tb = exp.type.toBasetype();
12905 if (tb.ty == Tarray || tb.ty == Tsarray)
12907 if (!isArrayOpValid(exp))
12909 result = arrayOpInvalidError(exp);
12910 return;
12912 result = exp;
12913 return;
12915 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12917 result = exp.incompatibleTypes();
12918 return;
12920 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
12921 return setError();
12923 result = exp;
12926 override void visit(OrExp exp)
12928 if (exp.type)
12930 result = exp;
12931 return;
12934 if (Expression ex = binSemanticProp(exp, sc))
12936 result = ex;
12937 return;
12939 Expression e = exp.op_overload(sc);
12940 if (e)
12942 result = e;
12943 return;
12946 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
12948 exp.type = exp.e1.type;
12949 result = exp;
12950 return;
12953 if (Expression ex = typeCombine(exp, sc))
12955 result = ex;
12956 return;
12959 Type tb = exp.type.toBasetype();
12960 if (tb.ty == Tarray || tb.ty == Tsarray)
12962 if (!isArrayOpValid(exp))
12964 result = arrayOpInvalidError(exp);
12965 return;
12967 result = exp;
12968 return;
12970 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12972 result = exp.incompatibleTypes();
12973 return;
12975 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
12976 return setError();
12978 result = exp;
12981 override void visit(XorExp exp)
12983 if (exp.type)
12985 result = exp;
12986 return;
12989 if (Expression ex = binSemanticProp(exp, sc))
12991 result = ex;
12992 return;
12994 Expression e = exp.op_overload(sc);
12995 if (e)
12997 result = e;
12998 return;
13001 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
13003 exp.type = exp.e1.type;
13004 result = exp;
13005 return;
13008 if (Expression ex = typeCombine(exp, sc))
13010 result = ex;
13011 return;
13014 Type tb = exp.type.toBasetype();
13015 if (tb.ty == Tarray || tb.ty == Tsarray)
13017 if (!isArrayOpValid(exp))
13019 result = arrayOpInvalidError(exp);
13020 return;
13022 result = exp;
13023 return;
13025 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
13027 result = exp.incompatibleTypes();
13028 return;
13030 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
13031 return setError();
13033 result = exp;
13036 override void visit(LogicalExp exp)
13038 static if (LOGSEMANTIC)
13040 printf("LogicalExp::semantic() %s\n", exp.toChars());
13043 if (exp.type)
13045 result = exp;
13046 return;
13049 exp.setNoderefOperands();
13051 Expression e1x = exp.e1.expressionSemantic(sc);
13053 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
13054 if (e1x.op == EXP.type)
13055 e1x = resolveAliasThis(sc, e1x);
13057 e1x = resolveProperties(sc, e1x);
13058 e1x = e1x.toBoolean(sc);
13060 if (sc.flags & SCOPE.condition)
13062 /* If in static if, don't evaluate e2 if we don't have to.
13064 e1x = e1x.optimize(WANTvalue);
13065 if (e1x.toBool().hasValue(exp.op == EXP.orOr))
13067 if (sc.flags & SCOPE.Cfile)
13068 result = new IntegerExp(exp.op == EXP.orOr);
13069 else
13070 result = IntegerExp.createBool(exp.op == EXP.orOr);
13071 return;
13075 CtorFlow ctorflow = sc.ctorflow.clone();
13076 Expression e2x = exp.e2.expressionSemantic(sc);
13077 sc.merge(exp.loc, ctorflow);
13078 ctorflow.freeFieldinit();
13080 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
13081 if (e2x.op == EXP.type)
13082 e2x = resolveAliasThis(sc, e2x);
13084 e2x = resolveProperties(sc, e2x);
13086 auto f1 = checkNonAssignmentArrayOp(e1x);
13087 auto f2 = checkNonAssignmentArrayOp(e2x);
13088 if (f1 || f2)
13089 return setError();
13091 // Unless the right operand is 'void', the expression is converted to 'bool'.
13092 if (e2x.type.ty != Tvoid)
13093 e2x = e2x.toBoolean(sc);
13095 if (e2x.op == EXP.type || e2x.op == EXP.scope_)
13097 error(exp.loc, "`%s` is not an expression", exp.e2.toChars());
13098 return setError();
13100 if (e1x.op == EXP.error || e1x.type.ty == Tnoreturn)
13102 result = e1x;
13103 return;
13105 if (e2x.op == EXP.error)
13107 result = e2x;
13108 return;
13111 // The result type is 'bool', unless the right operand has type 'void'.
13112 if (e2x.type.ty == Tvoid)
13113 exp.type = Type.tvoid;
13114 else
13115 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
13117 exp.e1 = e1x;
13118 exp.e2 = e2x;
13119 result = exp;
13123 override void visit(CmpExp exp)
13125 static if (LOGSEMANTIC)
13127 printf("CmpExp::semantic('%s')\n", exp.toChars());
13129 if (exp.type)
13131 result = exp;
13132 return;
13135 exp.setNoderefOperands();
13137 if (Expression ex = binSemanticProp(exp, sc))
13139 result = ex;
13140 return;
13142 Type t1 = exp.e1.type.toBasetype();
13143 Type t2 = exp.e2.type.toBasetype();
13144 if (t1.ty == Tclass && exp.e2.op == EXP.null_ || t2.ty == Tclass && exp.e1.op == EXP.null_)
13146 error(exp.loc, "do not use `null` when comparing class types");
13147 return setError();
13151 EXP cmpop = exp.op;
13152 if (auto e = exp.op_overload(sc, &cmpop))
13154 if (!e.type.isscalar() && e.type.equals(exp.e1.type))
13156 error(exp.loc, "recursive `opCmp` expansion");
13157 return setError();
13159 if (e.op == EXP.call)
13162 if (t1.ty == Tclass && t2.ty == Tclass)
13164 // Lower to object.__cmp(e1, e2)
13165 Expression cl = new IdentifierExp(exp.loc, Id.empty);
13166 cl = new DotIdExp(exp.loc, cl, Id.object);
13167 cl = new DotIdExp(exp.loc, cl, Id.__cmp);
13168 cl = cl.expressionSemantic(sc);
13170 auto arguments = new Expressions();
13171 // Check if op_overload found a better match by calling e2.opCmp(e1)
13172 // If the operands were swapped, then the result must be reversed
13173 // e1.opCmp(e2) == -e2.opCmp(e1)
13174 // cmpop takes care of this
13175 if (exp.op == cmpop)
13177 arguments.push(exp.e1);
13178 arguments.push(exp.e2);
13180 else
13182 // Use better match found by op_overload
13183 arguments.push(exp.e2);
13184 arguments.push(exp.e1);
13187 cl = new CallExp(exp.loc, cl, arguments);
13188 cl = new CmpExp(cmpop, exp.loc, cl, new IntegerExp(0));
13189 result = cl.expressionSemantic(sc);
13190 return;
13193 e = new CmpExp(cmpop, exp.loc, e, IntegerExp.literal!0);
13194 e = e.expressionSemantic(sc);
13196 result = e;
13197 return;
13201 if (Expression ex = typeCombine(exp, sc))
13203 result = ex;
13204 return;
13207 auto f1 = checkNonAssignmentArrayOp(exp.e1);
13208 auto f2 = checkNonAssignmentArrayOp(exp.e2);
13209 if (f1 || f2)
13210 return setError();
13212 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
13214 // Special handling for array comparisons
13215 Expression arrayLowering = null;
13216 t1 = exp.e1.type.toBasetype();
13217 t2 = exp.e2.type.toBasetype();
13218 if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && (t2.ty == Tarray || t2.ty == Tsarray || t2.ty == Tpointer))
13220 Type t1next = t1.nextOf();
13221 Type t2next = t2.nextOf();
13222 if (t1next.implicitConvTo(t2next) < MATCH.constant && t2next.implicitConvTo(t1next) < MATCH.constant && (t1next.ty != Tvoid && t2next.ty != Tvoid))
13224 error(exp.loc, "array comparison type mismatch, `%s` vs `%s`", t1next.toChars(), t2next.toChars());
13225 return setError();
13228 if ((t1.ty == Tarray || t1.ty == Tsarray) &&
13229 (t2.ty == Tarray || t2.ty == Tsarray))
13231 if (!verifyHookExist(exp.loc, *sc, Id.__cmp, "comparing arrays"))
13232 return setError();
13234 // Lower to object.__cmp(e1, e2)
13235 Expression al = new IdentifierExp(exp.loc, Id.empty);
13236 al = new DotIdExp(exp.loc, al, Id.object);
13237 al = new DotIdExp(exp.loc, al, Id.__cmp);
13238 al = al.expressionSemantic(sc);
13240 auto arguments = new Expressions(2);
13241 (*arguments)[0] = exp.e1;
13242 (*arguments)[1] = exp.e2;
13244 al = new CallExp(exp.loc, al, arguments);
13245 al = new CmpExp(exp.op, exp.loc, al, IntegerExp.literal!0);
13247 arrayLowering = al;
13250 else if (t1.ty == Tstruct || t2.ty == Tstruct || (t1.ty == Tclass && t2.ty == Tclass))
13252 if (t2.ty == Tstruct)
13253 error(exp.loc, "need member function `opCmp()` for %s `%s` to compare", t2.toDsymbol(sc).kind(), t2.toChars());
13254 else
13255 error(exp.loc, "need member function `opCmp()` for %s `%s` to compare", t1.toDsymbol(sc).kind(), t1.toChars());
13256 return setError();
13258 else if (t1.iscomplex() || t2.iscomplex())
13260 error(exp.loc, "compare not defined for complex operands");
13261 return setError();
13263 else if (t1.ty == Taarray || t2.ty == Taarray)
13265 error(exp.loc, "`%s` is not defined for associative arrays", EXPtoString(exp.op).ptr);
13266 return setError();
13268 else if (!target.isVectorOpSupported(t1, exp.op, t2))
13270 result = exp.incompatibleTypes();
13271 return;
13273 else
13275 bool r1 = exp.e1.checkValue() || exp.e1.checkSharedAccess(sc);
13276 bool r2 = exp.e2.checkValue() || exp.e2.checkSharedAccess(sc);
13277 if (r1 || r2)
13278 return setError();
13281 //printf("CmpExp: %s, type = %s\n", e.toChars(), e.type.toChars());
13282 if (arrayLowering)
13284 arrayLowering = arrayLowering.expressionSemantic(sc);
13285 result = arrayLowering;
13286 return;
13289 if (auto tv = t1.isTypeVector())
13290 exp.type = tv.toBooleanVector();
13292 result = exp;
13293 return;
13296 override void visit(InExp exp)
13298 if (exp.type)
13300 result = exp;
13301 return;
13304 if (Expression ex = binSemanticProp(exp, sc))
13306 result = ex;
13307 return;
13309 Expression e = exp.op_overload(sc);
13310 if (e)
13312 result = e;
13313 return;
13316 Type t2b = exp.e2.type.toBasetype();
13317 switch (t2b.ty)
13319 case Taarray:
13321 TypeAArray ta = cast(TypeAArray)t2b;
13323 // Special handling for array keys
13324 if (!arrayTypeCompatibleWithoutCasting(exp.e1.type, ta.index))
13326 // Convert key to type of key
13327 exp.e1 = exp.e1.implicitCastTo(sc, ta.index);
13330 semanticTypeInfo(sc, ta.index);
13332 // Return type is pointer to value
13333 exp.type = ta.nextOf().pointerTo();
13334 break;
13337 case Terror:
13338 return setError();
13340 case Tarray, Tsarray:
13341 result = exp.incompatibleTypes();
13342 errorSupplemental(exp.loc, "`in` is only allowed on associative arrays");
13343 const(char)* slice = (t2b.ty == Tsarray) ? "[]" : "";
13344 errorSupplemental(exp.loc, "perhaps use `std.algorithm.find(%s, %s%s)` instead",
13345 exp.e1.toChars(), exp.e2.toChars(), slice);
13346 return;
13348 default:
13349 result = exp.incompatibleTypes();
13350 return;
13352 result = exp;
13355 override void visit(RemoveExp e)
13357 if (Expression ex = binSemantic(e, sc))
13359 result = ex;
13360 return;
13362 result = e;
13365 override void visit(EqualExp exp)
13367 //printf("EqualExp::semantic('%s')\n", exp.toChars());
13368 if (exp.type)
13370 result = exp;
13371 return;
13374 exp.setNoderefOperands();
13376 if (auto e = binSemanticProp(exp, sc))
13378 result = e;
13379 return;
13381 if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
13383 /* https://issues.dlang.org/show_bug.cgi?id=12520
13384 * empty tuples are represented as types so special cases are added
13385 * so that they can be compared for equality with tuples of values.
13387 static auto extractTypeTupAndExpTup(Expression e)
13389 static struct Result { bool ttEmpty; bool te; }
13390 auto tt = e.op == EXP.type ? e.isTypeExp().type.isTypeTuple() : null;
13391 return Result(tt && (!tt.arguments || !tt.arguments.length), e.isTupleExp() !is null);
13393 auto tups1 = extractTypeTupAndExpTup(exp.e1);
13394 auto tups2 = extractTypeTupAndExpTup(exp.e2);
13395 // AliasSeq!() == AliasSeq!(<at least a value>)
13396 if (tups1.ttEmpty && tups2.te)
13398 result = IntegerExp.createBool(exp.op != EXP.equal);
13399 return;
13401 // AliasSeq!(<at least a value>) == AliasSeq!()
13402 else if (tups1.te && tups2.ttEmpty)
13404 result = IntegerExp.createBool(exp.op != EXP.equal);
13405 return;
13407 // AliasSeq!() == AliasSeq!()
13408 else if (tups1.ttEmpty && tups2.ttEmpty)
13410 result = IntegerExp.createBool(exp.op == EXP.equal);
13411 return;
13413 // otherwise, two types are really not comparable
13414 result = exp.incompatibleTypes();
13415 return;
13419 auto t1 = exp.e1.type;
13420 auto t2 = exp.e2.type;
13421 if (t1.ty == Tenum && t2.ty == Tenum && !t1.equivalent(t2))
13422 error(exp.loc, "comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`",
13423 t1.toChars(), t2.toChars());
13426 /* Before checking for operator overloading, check to see if we're
13427 * comparing the addresses of two statics. If so, we can just see
13428 * if they are the same symbol.
13430 if (exp.e1.op == EXP.address && exp.e2.op == EXP.address)
13432 AddrExp ae1 = cast(AddrExp)exp.e1;
13433 AddrExp ae2 = cast(AddrExp)exp.e2;
13434 if (ae1.e1.op == EXP.variable && ae2.e1.op == EXP.variable)
13436 VarExp ve1 = cast(VarExp)ae1.e1;
13437 VarExp ve2 = cast(VarExp)ae2.e1;
13438 if (ve1.var == ve2.var)
13440 // They are the same, result is 'true' for ==, 'false' for !=
13441 result = IntegerExp.createBool(exp.op == EXP.equal);
13442 return;
13447 Type t1 = exp.e1.type.toBasetype();
13448 Type t2 = exp.e2.type.toBasetype();
13450 // Indicates whether the comparison of the 2 specified array types
13451 // requires an object.__equals() lowering.
13452 static bool needsDirectEq(Type t1, Type t2, Scope* sc)
13454 Type t1n = t1.nextOf().toBasetype();
13455 Type t2n = t2.nextOf().toBasetype();
13456 if ((t1n.ty.isSomeChar && t2n.ty.isSomeChar) ||
13457 (t1n.ty == Tvoid || t2n.ty == Tvoid))
13459 return false;
13461 if (t1n.constOf() != t2n.constOf())
13462 return true;
13464 Type t = t1n;
13465 while (t.toBasetype().nextOf())
13466 t = t.nextOf().toBasetype();
13467 if (auto ts = t.isTypeStruct())
13469 // semanticTypeInfo() makes sure hasIdentityEquals has been computed
13470 if (global.params.useTypeInfo && Type.dtypeinfo)
13471 semanticTypeInfo(sc, ts);
13473 return ts.sym.hasIdentityEquals; // has custom opEquals
13476 return false;
13479 if (auto e = exp.op_overload(sc))
13481 result = e;
13482 return;
13486 const isArrayComparison = (t1.ty == Tarray || t1.ty == Tsarray) &&
13487 (t2.ty == Tarray || t2.ty == Tsarray);
13488 const needsArrayLowering = isArrayComparison && needsDirectEq(t1, t2, sc);
13490 if (!needsArrayLowering)
13492 // https://issues.dlang.org/show_bug.cgi?id=23783
13493 if (exp.e1.checkSharedAccess(sc) || exp.e2.checkSharedAccess(sc))
13494 return setError();
13495 if (auto e = typeCombine(exp, sc))
13497 result = e;
13498 return;
13502 auto f1 = checkNonAssignmentArrayOp(exp.e1);
13503 auto f2 = checkNonAssignmentArrayOp(exp.e2);
13504 if (f1 || f2)
13505 return setError();
13507 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
13509 if (!isArrayComparison)
13511 if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
13513 // Cast both to complex
13514 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
13515 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80);
13519 // lower some array comparisons to object.__equals(e1, e2)
13520 if (needsArrayLowering || (t1.ty == Tarray && t2.ty == Tarray))
13522 //printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars());
13524 // https://issues.dlang.org/show_bug.cgi?id=22390
13525 // Equality comparison between array of noreturns simply lowers to length equality comparison
13526 if (t1.nextOf.isTypeNoreturn() && t2.nextOf.isTypeNoreturn())
13528 Expression exp_l1 = new DotIdExp(exp.e1.loc, exp.e1, Id.length);
13529 Expression exp_l2 = new DotIdExp(exp.e2.loc, exp.e2, Id.length);
13530 auto e = new EqualExp(EXP.equal, exp.loc, exp_l1, exp_l2);
13531 result = e.expressionSemantic(sc);
13532 return;
13535 if (!verifyHookExist(exp.loc, *sc, Id.__equals, "equal checks on arrays"))
13536 return setError();
13538 Expression __equals = new IdentifierExp(exp.loc, Id.empty);
13539 Identifier id = Identifier.idPool("__equals");
13540 __equals = new DotIdExp(exp.loc, __equals, Id.object);
13541 __equals = new DotIdExp(exp.loc, __equals, id);
13543 /* https://issues.dlang.org/show_bug.cgi?id=23674
13545 * Optimize before creating the call expression to the
13546 * druntime hook as the optimizer may output errors
13547 * that will get swallowed otherwise.
13549 exp.e1 = exp.e1.optimize(WANTvalue);
13550 exp.e2 = exp.e2.optimize(WANTvalue);
13552 auto arguments = new Expressions(2);
13553 (*arguments)[0] = exp.e1;
13554 (*arguments)[1] = exp.e2;
13556 __equals = new CallExp(exp.loc, __equals, arguments);
13557 if (exp.op == EXP.notEqual)
13559 __equals = new NotExp(exp.loc, __equals);
13561 __equals = __equals.trySemantic(sc); // for better error message
13562 if (!__equals)
13564 error(exp.loc, "incompatible types for array comparison: `%s` and `%s`",
13565 exp.e1.type.toChars(), exp.e2.type.toChars());
13566 __equals = ErrorExp.get();
13569 result = __equals;
13570 return;
13573 if (exp.e1.type.toBasetype().ty == Taarray)
13574 semanticTypeInfo(sc, exp.e1.type.toBasetype());
13577 if (!target.isVectorOpSupported(t1, exp.op, t2))
13579 result = exp.incompatibleTypes();
13580 return;
13583 if (auto tv = t1.isTypeVector())
13584 exp.type = tv.toBooleanVector();
13586 result = exp;
13589 override void visit(IdentityExp exp)
13591 if (exp.type)
13593 result = exp;
13594 return;
13597 exp.setNoderefOperands();
13599 if (auto e = binSemanticProp(exp, sc))
13601 result = e;
13602 return;
13605 if (auto e = typeCombine(exp, sc))
13607 result = e;
13608 return;
13611 auto f1 = checkNonAssignmentArrayOp(exp.e1);
13612 auto f2 = checkNonAssignmentArrayOp(exp.e2);
13613 if (f1 || f2)
13614 return setError();
13616 if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
13618 result = exp.incompatibleTypes();
13619 return;
13622 exp.type = Type.tbool;
13624 if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
13626 // Cast both to complex
13627 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
13628 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80);
13631 auto tb1 = exp.e1.type.toBasetype();
13632 auto tb2 = exp.e2.type.toBasetype();
13633 if (!target.isVectorOpSupported(tb1, exp.op, tb2))
13635 result = exp.incompatibleTypes();
13636 return;
13639 if (exp.e1.op == EXP.call)
13640 exp.e1 = (cast(CallExp)exp.e1).addDtorHook(sc);
13641 if (exp.e2.op == EXP.call)
13642 exp.e2 = (cast(CallExp)exp.e2).addDtorHook(sc);
13644 if (exp.e1.type.toBasetype().ty == Tsarray ||
13645 exp.e2.type.toBasetype().ty == Tsarray)
13646 deprecation(exp.loc, "identity comparison of static arrays "
13647 ~ "implicitly coerces them to slices, "
13648 ~ "which are compared by reference");
13650 result = exp;
13653 override void visit(CondExp exp)
13655 static if (LOGSEMANTIC)
13657 printf("CondExp::semantic('%s')\n", exp.toChars());
13659 if (exp.type)
13661 result = exp;
13662 return;
13665 if (auto die = exp.econd.isDotIdExp())
13666 die.noderef = true;
13668 Expression ec = exp.econd.expressionSemantic(sc);
13669 ec = resolveProperties(sc, ec);
13670 ec = ec.toBoolean(sc);
13672 CtorFlow ctorflow_root = sc.ctorflow.clone();
13673 Expression e1x = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
13674 e1x = resolveProperties(sc, e1x);
13676 CtorFlow ctorflow1 = sc.ctorflow;
13677 sc.ctorflow = ctorflow_root;
13678 Expression e2x = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
13679 e2x = resolveProperties(sc, e2x);
13681 sc.merge(exp.loc, ctorflow1);
13682 ctorflow1.freeFieldinit();
13684 if (ec.op == EXP.error)
13686 result = ec;
13687 return;
13689 if (ec.type == Type.terror)
13690 return setError();
13691 exp.econd = ec;
13693 if (e1x.op == EXP.error)
13695 result = e1x;
13696 return;
13698 if (e1x.type == Type.terror)
13699 return setError();
13700 exp.e1 = e1x;
13702 if (e2x.op == EXP.error)
13704 result = e2x;
13705 return;
13707 if (e2x.type == Type.terror)
13708 return setError();
13709 exp.e2 = e2x;
13711 auto f0 = checkNonAssignmentArrayOp(exp.econd);
13712 auto f1 = checkNonAssignmentArrayOp(exp.e1);
13713 auto f2 = checkNonAssignmentArrayOp(exp.e2);
13714 if (f0 || f1 || f2)
13715 return setError();
13717 Type t1 = exp.e1.type;
13718 Type t2 = exp.e2.type;
13720 // https://issues.dlang.org/show_bug.cgi?id=23767
13721 // `cast(void*) 0` should be treated as `null` so the ternary expression
13722 // gets the pointer type of the other branch
13723 if (sc.flags & SCOPE.Cfile)
13725 static void rewriteCNull(ref Expression e, ref Type t)
13727 if (!t.isTypePointer())
13728 return;
13729 if (auto ie = e.optimize(WANTvalue).isIntegerExp())
13731 if (ie.getInteger() == 0)
13733 e = new NullExp(e.loc, Type.tnull);
13734 t = Type.tnull;
13738 rewriteCNull(exp.e1, t1);
13739 rewriteCNull(exp.e2, t2);
13742 if (t1.ty == Tnoreturn)
13744 exp.type = t2;
13745 exp.e1 = specialNoreturnCast(exp.e1, exp.type);
13747 else if (t2.ty == Tnoreturn)
13749 exp.type = t1;
13750 exp.e2 = specialNoreturnCast(exp.e2, exp.type);
13752 // If either operand is void the result is void, we have to cast both
13753 // the expression to void so that we explicitly discard the expression
13754 // value if any
13755 // https://issues.dlang.org/show_bug.cgi?id=16598
13756 else if (t1.ty == Tvoid || t2.ty == Tvoid)
13758 exp.type = Type.tvoid;
13759 exp.e1 = exp.e1.castTo(sc, exp.type);
13760 exp.e2 = exp.e2.castTo(sc, exp.type);
13762 else if (t1 == t2)
13763 exp.type = t1;
13764 else
13766 if (Expression ex = typeCombine(exp, sc))
13768 result = ex;
13769 return;
13772 switch (exp.e1.type.toBasetype().ty)
13774 case Tcomplex32:
13775 case Tcomplex64:
13776 case Tcomplex80:
13777 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
13778 break;
13779 default:
13780 break;
13782 switch (exp.e2.type.toBasetype().ty)
13784 case Tcomplex32:
13785 case Tcomplex64:
13786 case Tcomplex80:
13787 exp.e1 = exp.e1.castTo(sc, exp.e2.type);
13788 break;
13789 default:
13790 break;
13792 if (exp.type.toBasetype().ty == Tarray)
13794 exp.e1 = exp.e1.castTo(sc, exp.type);
13795 exp.e2 = exp.e2.castTo(sc, exp.type);
13798 exp.type = exp.type.merge2();
13799 version (none)
13801 printf("res: %s\n", exp.type.toChars());
13802 printf("e1 : %s\n", exp.e1.type.toChars());
13803 printf("e2 : %s\n", exp.e2.type.toChars());
13806 /* https://issues.dlang.org/show_bug.cgi?id=14696
13807 * If either e1 or e2 contain temporaries which need dtor,
13808 * make them conditional.
13809 * Rewrite:
13810 * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2)
13811 * to:
13812 * (auto __cond = cond) ? (... __tmp1) : (... __tmp2)
13813 * and replace edtors of __tmp1 and __tmp2 with:
13814 * __tmp1.edtor --> __cond && __tmp1.dtor()
13815 * __tmp2.edtor --> __cond || __tmp2.dtor()
13817 exp.hookDtors(sc);
13819 result = exp;
13822 override void visit(GenericExp exp)
13824 static if (LOGSEMANTIC)
13826 printf("GenericExp::semantic('%s')\n", exp.toChars());
13828 // C11 6.5.1.1 Generic Selection
13830 auto ec = exp.cntlExp.expressionSemantic(sc).arrayFuncConv(sc);
13831 bool errors = ec.isErrorExp() !is null;
13832 auto tc = ec.type;
13834 auto types = (*exp.types)[];
13835 foreach (i, ref t; types)
13837 if (!t)
13838 continue; // `default:` case
13839 t = t.typeSemantic(ec.loc, sc);
13840 if (t.isTypeError())
13842 errors = true;
13843 continue;
13846 /* C11 6.5.1-2 duplicate check
13848 /* C11 distinguishes int, long, and long long. But D doesn't, so depending on the
13849 * C target, a long may have the same type as `int` in the D type system.
13850 * So, skip checks when this may be the case. Later pick the first match
13852 if (
13853 (t.ty == Tint32 || t.ty == Tuns32) && target.c.longsize == 4 ||
13854 (t.ty == Tint64 || t.ty == Tuns64) && target.c.longsize == 8 ||
13855 (t.ty == Tfloat64 || t.ty == Timaginary64 || t.ty == Tcomplex64) && target.c.long_doublesize == 8
13857 continue;
13859 foreach (t2; types[0 .. i])
13861 if (t2 && t2.equals(t))
13863 error(ec.loc, "generic association type `%s` can only appear once", t.toChars());
13864 errors = true;
13865 break;
13870 auto exps = (*exp.exps)[];
13871 foreach (ref e; exps)
13873 e = e.expressionSemantic(sc);
13874 if (e.isErrorExp())
13875 errors = true;
13878 if (errors)
13879 return setError();
13881 enum size_t None = ~0;
13882 size_t imatch = None;
13883 size_t idefault = None;
13884 foreach (const i, t; types)
13886 if (t)
13888 /* if tc is compatible with t, it's a match
13889 * C11 6.2.7 defines a compatible type as being the same type, including qualifiers
13891 if (tc.equals(t))
13893 assert(imatch == None);
13894 imatch = i;
13895 break; // pick first match
13898 else
13899 idefault = i; // multiple defaults are not allowed, and are caught by cparse
13902 if (imatch == None)
13903 imatch = idefault;
13904 if (imatch == None)
13906 error(exp.loc, "no compatible generic association type for controlling expression type `%s`", tc.toChars());
13907 return setError();
13910 result = exps[imatch];
13913 override void visit(FileInitExp e)
13915 //printf("FileInitExp::semantic()\n");
13916 e.type = Type.tstring;
13917 result = e;
13920 override void visit(LineInitExp e)
13922 e.type = Type.tint32;
13923 result = e;
13926 override void visit(ModuleInitExp e)
13928 //printf("ModuleInitExp::semantic()\n");
13929 e.type = Type.tstring;
13930 result = e;
13933 override void visit(FuncInitExp e)
13935 //printf("FuncInitExp::semantic()\n");
13936 e.type = Type.tstring;
13937 if (sc.func)
13939 result = e.resolveLoc(Loc.initial, sc);
13940 return;
13942 result = e;
13945 override void visit(PrettyFuncInitExp e)
13947 //printf("PrettyFuncInitExp::semantic()\n");
13948 e.type = Type.tstring;
13949 if (sc.func)
13951 result = e.resolveLoc(Loc.initial, sc);
13952 return;
13955 result = e;
13959 /**********************************
13960 * Try to run semantic routines.
13961 * If they fail, return NULL.
13963 Expression trySemantic(Expression exp, Scope* sc)
13965 //printf("+trySemantic(%s)\n", exp.toChars());
13966 uint errors = global.startGagging();
13967 Expression e = expressionSemantic(exp, sc);
13968 if (global.endGagging(errors))
13970 e = null;
13972 //printf("-trySemantic(%s)\n", exp.toChars());
13973 return e;
13976 /**************************
13977 * Helper function for easy error propagation.
13978 * If error occurs, returns ErrorExp. Otherwise returns NULL.
13980 Expression unaSemantic(UnaExp e, Scope* sc)
13982 static if (LOGSEMANTIC)
13984 printf("UnaExp::semantic('%s')\n", e.toChars());
13986 Expression e1x = e.e1.expressionSemantic(sc);
13987 if (e1x.op == EXP.error)
13988 return e1x;
13989 e.e1 = e1x;
13990 return null;
13993 /**************************
13994 * Helper function for easy error propagation.
13995 * If error occurs, returns ErrorExp. Otherwise returns NULL.
13997 Expression binSemantic(BinExp e, Scope* sc)
13999 static if (LOGSEMANTIC)
14001 printf("BinExp::semantic('%s')\n", e.toChars());
14003 Expression e1x = e.e1.expressionSemantic(sc);
14004 Expression e2x = e.e2.expressionSemantic(sc);
14006 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
14007 if (e1x.op == EXP.type)
14008 e1x = resolveAliasThis(sc, e1x);
14009 if (e2x.op == EXP.type)
14010 e2x = resolveAliasThis(sc, e2x);
14012 if (e1x.op == EXP.error)
14013 return e1x;
14014 if (e2x.op == EXP.error)
14015 return e2x;
14016 e.e1 = e1x;
14017 e.e2 = e2x;
14018 return null;
14021 Expression binSemanticProp(BinExp e, Scope* sc)
14023 if (Expression ex = binSemantic(e, sc))
14024 return ex;
14025 Expression e1x = resolveProperties(sc, e.e1);
14026 Expression e2x = resolveProperties(sc, e.e2);
14027 if (e1x.op == EXP.error)
14028 return e1x;
14029 if (e2x.op == EXP.error)
14030 return e2x;
14031 e.e1 = e1x;
14032 e.e2 = e2x;
14033 return null;
14036 // entrypoint for semantic ExpressionSemanticVisitor
14037 extern (C++) Expression expressionSemantic(Expression e, Scope* sc)
14039 scope v = new ExpressionSemanticVisitor(sc);
14040 e.accept(v);
14041 return v.result;
14044 private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc)
14046 //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars());
14047 if (Expression ex = unaSemantic(exp, sc))
14048 return ex;
14050 if (!(sc.flags & SCOPE.Cfile) && exp.ident == Id._mangleof)
14052 // symbol.mangleof
14054 // return mangleof as an Expression
14055 static Expression dotMangleof(const ref Loc loc, Scope* sc, Dsymbol ds)
14057 assert(ds);
14058 if (auto f = ds.isFuncDeclaration())
14060 if (f.checkForwardRef(loc))
14061 return ErrorExp.get();
14063 if (f.purityInprocess || f.safetyInprocess || f.nothrowInprocess || f.nogcInprocess)
14065 error(loc, "%s `%s` cannot retrieve its `.mangleof` while inferring attributes", f.kind, f.toPrettyChars);
14066 return ErrorExp.get();
14069 OutBuffer buf;
14070 mangleToBuffer(ds, buf);
14071 Expression e = new StringExp(loc, buf.extractSlice());
14072 return e.expressionSemantic(sc);
14075 Dsymbol ds;
14076 switch (exp.e1.op)
14078 case EXP.scope_: return dotMangleof(exp.loc, sc, exp.e1.isScopeExp().sds);
14079 case EXP.variable: return dotMangleof(exp.loc, sc, exp.e1.isVarExp().var);
14080 case EXP.dotVariable: return dotMangleof(exp.loc, sc, exp.e1.isDotVarExp().var);
14081 case EXP.overloadSet: return dotMangleof(exp.loc, sc, exp.e1.isOverExp().vars);
14082 case EXP.template_:
14084 TemplateExp te = exp.e1.isTemplateExp();
14085 return dotMangleof(exp.loc, sc, ds = te.fd ? te.fd.isDsymbol() : te.td);
14088 default:
14089 break;
14093 if (exp.e1.isVarExp() && exp.e1.type.toBasetype().isTypeSArray() && exp.ident == Id.length)
14095 // bypass checkPurity
14096 return exp.e1.type.dotExp(sc, exp.e1, exp.ident, cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref));
14099 if (!exp.e1.isDotExp())
14101 exp.e1 = resolvePropertiesX(sc, exp.e1);
14104 if (auto te = exp.e1.isTupleExp())
14106 if (exp.ident == Id.offsetof)
14108 /* 'distribute' the .offsetof to each of the tuple elements.
14110 auto exps = new Expressions(te.exps.length);
14111 foreach (i, e; (*te.exps)[])
14113 (*exps)[i] = new DotIdExp(e.loc, e, Id.offsetof);
14115 // Don't evaluate te.e0 in runtime
14116 Expression e = new TupleExp(exp.loc, null, exps);
14117 e = e.expressionSemantic(sc);
14118 return e;
14120 if (exp.ident == Id.length)
14122 // Don't evaluate te.e0 in runtime
14123 return new IntegerExp(exp.loc, te.exps.length, Type.tsize_t);
14127 // https://issues.dlang.org/show_bug.cgi?id=14416
14128 // Template has no built-in properties except for 'stringof'.
14129 if ((exp.e1.isDotTemplateExp() || exp.e1.isTemplateExp()) && exp.ident != Id.stringof)
14131 error(exp.loc, "template `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
14132 return ErrorExp.get();
14134 if (!exp.e1.type)
14136 error(exp.loc, "expression `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
14137 return ErrorExp.get();
14140 return exp;
14143 private bool checkDisabled(Dsymbol s, ref Loc loc, Scope* sc)
14145 if (auto d = s.isDeclaration())
14146 return d.checkDisabled(loc, sc);
14148 return false;
14151 /******************************
14152 * Resolve properties, i.e. `e1.ident`, without seeing UFCS.
14153 * Params:
14154 * exp = expression to resolve
14155 * sc = context
14156 * gag = do not emit error messages, just return `null`
14157 * Returns:
14158 * resolved expression, null if error
14160 Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
14162 //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars());
14164 //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
14166 const cfile = (sc.flags & SCOPE.Cfile) != 0;
14168 /* Special case: rewrite this.id and super.id
14169 * to be classtype.id and baseclasstype.id
14170 * if we have no this pointer.
14172 if ((exp.e1.isThisExp() || exp.e1.isSuperExp()) && !hasThis(sc))
14174 if (AggregateDeclaration ad = sc.getStructClassScope())
14176 if (exp.e1.isThisExp())
14178 exp.e1 = new TypeExp(exp.e1.loc, ad.type);
14180 else
14182 if (auto cd = ad.isClassDeclaration())
14184 if (cd.baseClass)
14185 exp.e1 = new TypeExp(exp.e1.loc, cd.baseClass.type);
14192 Expression e = dotIdSemanticPropX(exp, sc);
14193 if (e != exp)
14194 return e;
14197 Expression eleft;
14198 Expression eright;
14199 if (auto de = exp.e1.isDotExp())
14201 eleft = de.e1;
14202 eright = de.e2;
14204 else
14206 eleft = null;
14207 eright = exp.e1;
14210 Type t1b = exp.e1.type.toBasetype();
14212 if (auto ie = eright.isScopeExp()) // also used for template alias's
14214 SearchOptFlags flags = SearchOpt.localsOnly;
14215 /* Disable access to another module's private imports.
14216 * The check for 'is sds our current module' is because
14217 * the current module should have access to its own imports.
14219 if (ie.sds.isModule() && ie.sds != sc._module)
14220 flags |= SearchOpt.ignorePrivateImports;
14221 if (sc.flags & SCOPE.ignoresymbolvisibility)
14222 flags |= SearchOpt.ignoreVisibility;
14223 Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags);
14224 /* Check for visibility before resolving aliases because public
14225 * aliases to private symbols are public.
14227 if (s && !(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc._module, s))
14229 s = null;
14231 if (s)
14233 auto p = s.isPackage();
14234 if (p && checkAccess(sc, p))
14236 s = null;
14239 if (s)
14241 // if 's' is a tuple variable, the tuple is returned.
14242 s = s.toAlias();
14244 s.checkDeprecated(exp.loc, sc);
14245 s.checkDisabled(exp.loc, sc);
14247 if (auto em = s.isEnumMember())
14249 return em.getVarExp(exp.loc, sc);
14251 if (auto v = s.isVarDeclaration())
14253 //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars());
14254 if (!v.type ||
14255 !v.type.deco && v.inuse)
14257 if (v.inuse)
14258 error(exp.loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
14259 else
14260 error(exp.loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
14261 return ErrorExp.get();
14263 if (v.type.isTypeError())
14264 return ErrorExp.get();
14266 if ((v.storage_class & STC.manifest) && v._init && !exp.wantsym)
14268 /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2().
14269 * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably
14270 * be reverted. `wantsym` is the hack to work around the problem.
14272 if (v.inuse)
14274 error(exp.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
14275 return ErrorExp.get();
14277 auto e = v.expandInitializer(exp.loc);
14278 v.inuse++;
14279 e = e.expressionSemantic(sc);
14280 v.inuse--;
14281 return e;
14284 Expression e;
14285 if (v.needThis())
14287 if (!eleft)
14288 eleft = new ThisExp(exp.loc);
14289 e = new DotVarExp(exp.loc, eleft, v);
14290 e = e.expressionSemantic(sc);
14292 else
14294 e = new VarExp(exp.loc, v);
14295 if (eleft)
14297 e = new CommaExp(exp.loc, eleft, e);
14298 e.type = v.type;
14301 e = e.deref();
14302 return e.expressionSemantic(sc);
14305 if (auto f = s.isFuncDeclaration())
14307 //printf("it's a function\n");
14308 if (!f.functionSemantic())
14309 return ErrorExp.get();
14310 Expression e;
14311 if (f.needThis())
14313 if (!eleft)
14314 eleft = new ThisExp(exp.loc);
14315 e = new DotVarExp(exp.loc, eleft, f, true);
14316 e = e.expressionSemantic(sc);
14318 else
14320 e = new VarExp(exp.loc, f, true);
14321 if (eleft)
14323 e = new CommaExp(exp.loc, eleft, e);
14324 e.type = f.type;
14327 return e;
14329 if (auto td = s.isTemplateDeclaration())
14331 Expression e;
14332 if (eleft)
14333 e = new DotTemplateExp(exp.loc, eleft, td);
14334 else
14335 e = new TemplateExp(exp.loc, td);
14336 e = e.expressionSemantic(sc);
14337 return e;
14339 if (OverDeclaration od = s.isOverDeclaration())
14341 Expression e = new VarExp(exp.loc, od, true);
14342 if (eleft)
14344 e = new CommaExp(exp.loc, eleft, e);
14345 e.type = Type.tvoid; // ambiguous type?
14347 return e.expressionSemantic(sc);
14349 if (auto o = s.isOverloadSet())
14351 //printf("'%s' is an overload set\n", o.toChars());
14352 return new OverExp(exp.loc, o);
14355 if (auto t = s.getType())
14357 return (new TypeExp(exp.loc, t)).expressionSemantic(sc);
14360 if (auto tup = s.isTupleDeclaration())
14362 if (eleft)
14364 Expression e = new DotVarExp(exp.loc, eleft, tup);
14365 e = e.expressionSemantic(sc);
14366 return e;
14368 Expression e = new TupleExp(exp.loc, tup);
14369 e = e.expressionSemantic(sc);
14370 return e;
14373 if (auto sds = s.isScopeDsymbol())
14375 //printf("it's a ScopeDsymbol %s\n", ident.toChars());
14376 Expression e = new ScopeExp(exp.loc, sds);
14377 e = e.expressionSemantic(sc);
14378 if (eleft)
14379 e = new DotExp(exp.loc, eleft, e);
14380 return e;
14383 if (auto imp = s.isImport())
14385 Expression se = new ScopeExp(exp.loc, imp.pkg);
14386 return se.expressionSemantic(sc);
14389 if (auto attr = s.isAttribDeclaration())
14391 if (auto sm = ie.sds.search(exp.loc, exp.ident, flags))
14393 auto es = new DsymbolExp(exp.loc, sm);
14394 return es;
14398 // BUG: handle other cases like in IdentifierExp::semantic()
14399 debug
14401 printf("s = %p '%s', kind = '%s'\n", s, s.toChars(), s.kind());
14403 assert(0);
14405 else if (exp.ident == Id.stringof)
14407 Expression e = new StringExp(exp.loc, ie.toString());
14408 e = e.expressionSemantic(sc);
14409 return e;
14411 if (ie.sds.isPackage() || ie.sds.isImport() || ie.sds.isModule())
14413 gag = false;
14415 if (gag)
14416 return null;
14417 s = ie.sds.search_correct(exp.ident);
14418 if (s && symbolIsVisible(sc, s))
14420 if (s.isPackage())
14421 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());
14422 else
14423 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());
14425 else
14426 error(exp.loc, "undefined identifier `%s` in %s `%s`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars());
14427 return ErrorExp.get();
14429 else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum &&
14431 exp.ident == Id.__sizeof ||
14432 exp.ident == Id.__xalignof ||
14433 !cfile &&
14434 (exp.ident == Id._mangleof ||
14435 exp.ident == Id.offsetof ||
14436 exp.ident == Id._init ||
14437 exp.ident == Id.stringof)
14440 Type t1bn = t1b.nextOf();
14441 if (gag)
14443 if (AggregateDeclaration ad = isAggregate(t1bn))
14445 if (!ad.members) // https://issues.dlang.org/show_bug.cgi?id=11312
14446 return null;
14450 /* Rewrite:
14451 * p.ident
14452 * as:
14453 * (*p).ident
14455 if (gag && t1bn.ty == Tvoid)
14456 return null;
14457 Expression e = new PtrExp(exp.loc, exp.e1);
14458 e = e.expressionSemantic(sc);
14459 const newFlag = cast(DotExpFlag) (gag * DotExpFlag.gag | exp.noderef * DotExpFlag.noDeref);
14460 return e.type.dotExp(sc, e, exp.ident, newFlag);
14462 else if (exp.ident == Id.__xalignof &&
14463 exp.e1.isVarExp() &&
14464 exp.e1.isVarExp().var.isVarDeclaration() &&
14465 !exp.e1.isVarExp().var.isVarDeclaration().alignment.isUnknown())
14467 // For `x.alignof` get the alignment of the variable, not the alignment of its type
14468 const explicitAlignment = exp.e1.isVarExp().var.isVarDeclaration().alignment;
14469 const naturalAlignment = exp.e1.type.alignsize();
14470 const actualAlignment = explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get();
14471 Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
14472 return e;
14474 else if ((exp.ident == Id.max || exp.ident == Id.min) &&
14475 exp.e1.isVarExp() &&
14476 exp.e1.isVarExp().var.isBitFieldDeclaration())
14478 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
14479 auto bf = exp.e1.isVarExp().var.isBitFieldDeclaration();
14480 return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type);
14482 else if ((exp.ident == Id.max || exp.ident == Id.min) &&
14483 exp.e1.isDotVarExp() &&
14484 exp.e1.isDotVarExp().var.isBitFieldDeclaration())
14486 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
14487 auto bf = exp.e1.isDotVarExp().var.isBitFieldDeclaration();
14488 return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type);
14490 else
14492 if (exp.e1.isTypeExp() || exp.e1.isTemplateExp())
14493 gag = false;
14495 const flag = cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref | gag * DotExpFlag.gag);
14497 Expression e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag);
14498 if (e)
14500 e = e.expressionSemantic(sc);
14502 return e;
14507 * Resolve `e1.ident!tiargs` without seeing UFCS.
14508 * Params:
14509 * exp = the `DotTemplateInstanceExp` to resolve
14510 * sc = the semantic scope
14511 * gag = stop "not a property" error and return `null`.
14512 * Returns:
14513 * `null` if error or not found, or the resolved expression.
14515 Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, bool gag)
14517 static if (LOGSEMANTIC)
14519 printf("DotTemplateInstanceExpY::semantic('%s')\n", exp.toChars());
14522 static Expression errorExp()
14524 return ErrorExp.get();
14527 Expression e1 = exp.e1;
14529 if (exp.ti.tempdecl && exp.ti.tempdecl.parent && exp.ti.tempdecl.parent.isTemplateMixin())
14531 // if 'ti.tempdecl' happens to be found in a mixin template don't lose that info
14532 // and do the symbol search in that context (Issue: 19476)
14533 auto tm = cast(TemplateMixin)exp.ti.tempdecl.parent;
14534 e1 = new DotExp(exp.e1.loc, exp.e1, new ScopeExp(tm.loc, tm));
14537 auto die = new DotIdExp(exp.loc, e1, exp.ti.name);
14539 Expression e = die.dotIdSemanticPropX(sc);
14540 if (e == die)
14542 exp.e1 = die.e1; // take back
14543 Type t1b = exp.e1.type.toBasetype();
14544 if (t1b.ty == Tarray || t1b.ty == Tsarray || t1b.ty == Taarray || t1b.ty == Tnull || (t1b.isTypeBasic() && t1b.ty != Tvoid))
14546 /* No built-in type has templatized properties, so do shortcut.
14547 * It is necessary in: 1024.max!"a < b"
14549 if (gag)
14550 return null;
14552 e = die.dotIdSemanticProp(sc, gag);
14553 if (gag)
14555 if (!e ||
14556 isDotOpDispatch(e))
14558 /* opDispatch!tiargs would be a function template that needs IFTI,
14559 * so it's not a template
14561 return null;
14565 assert(e);
14567 if (e.op == EXP.error)
14568 return e;
14569 if (DotVarExp dve = e.isDotVarExp())
14571 if (FuncDeclaration fd = dve.var.isFuncDeclaration())
14573 if (TemplateDeclaration td = fd.findTemplateDeclRoot())
14575 e = new DotTemplateExp(dve.loc, dve.e1, td);
14576 e = e.expressionSemantic(sc);
14579 else if (OverDeclaration od = dve.var.isOverDeclaration())
14581 exp.e1 = dve.e1; // pull semantic() result
14583 if (!exp.findTempDecl(sc))
14584 goto Lerr;
14585 if (exp.ti.needsTypeInference(sc))
14586 return exp;
14587 exp.ti.dsymbolSemantic(sc);
14588 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
14589 return errorExp();
14591 if (Declaration v = exp.ti.toAlias().isDeclaration())
14593 if (v.type && !v.type.deco)
14594 v.type = v.type.typeSemantic(v.loc, sc);
14595 return new DotVarExp(exp.loc, exp.e1, v)
14596 .expressionSemantic(sc);
14598 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
14599 .expressionSemantic(sc);
14602 else if (e.op == EXP.variable)
14604 VarExp ve = cast(VarExp)e;
14605 if (FuncDeclaration fd = ve.var.isFuncDeclaration())
14607 if (TemplateDeclaration td = fd.findTemplateDeclRoot())
14609 e = new TemplateExp(ve.loc, td)
14610 .expressionSemantic(sc);
14613 else if (OverDeclaration od = ve.var.isOverDeclaration())
14615 exp.ti.tempdecl = od;
14616 return new ScopeExp(exp.loc, exp.ti)
14617 .expressionSemantic(sc);
14621 if (DotTemplateExp dte = e.isDotTemplateExp())
14623 exp.e1 = dte.e1; // pull semantic() result
14625 exp.ti.tempdecl = dte.td;
14626 if (!exp.ti.semanticTiargs(sc))
14627 return errorExp();
14628 if (exp.ti.needsTypeInference(sc))
14629 return exp;
14630 exp.ti.dsymbolSemantic(sc);
14631 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
14632 return errorExp();
14634 if (Declaration v = exp.ti.toAlias().isDeclaration())
14636 return new DotVarExp(exp.loc, exp.e1, v)
14637 .expressionSemantic(sc);
14639 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
14640 .expressionSemantic(sc);
14642 else if (e.op == EXP.template_)
14644 exp.ti.tempdecl = (cast(TemplateExp)e).td;
14645 return new ScopeExp(exp.loc, exp.ti)
14646 .expressionSemantic(sc);
14648 else if (DotExp de = e.isDotExp())
14650 if (de.e2.op == EXP.overloadSet)
14652 if (!exp.findTempDecl(sc) || !exp.ti.semanticTiargs(sc))
14654 return errorExp();
14656 if (exp.ti.needsTypeInference(sc))
14657 return exp;
14658 exp.ti.dsymbolSemantic(sc);
14659 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
14660 return errorExp();
14662 if (Declaration v = exp.ti.toAlias().isDeclaration())
14664 if (v.type && !v.type.deco)
14665 v.type = v.type.typeSemantic(v.loc, sc);
14666 return new DotVarExp(exp.loc, exp.e1, v)
14667 .expressionSemantic(sc);
14669 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
14670 .expressionSemantic(sc);
14673 else if (OverExp oe = e.isOverExp())
14675 exp.ti.tempdecl = oe.vars;
14676 return new ScopeExp(exp.loc, exp.ti)
14677 .expressionSemantic(sc);
14680 Lerr:
14681 error(exp.loc, "`%s` isn't a template", e.toChars());
14682 return errorExp();
14685 MATCH matchType(FuncExp funcExp, Type to, Scope* sc, FuncExp* presult, ErrorSink eSink)
14687 auto loc = funcExp.loc;
14688 auto tok = funcExp.tok;
14689 auto td = funcExp.td;
14690 auto fd = funcExp.fd;
14691 auto type = funcExp.type;
14693 MATCH cannotInfer()
14695 eSink.error(loc, "cannot infer parameter types from `%s`", to.toChars());
14696 return MATCH.nomatch;
14699 //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars());
14700 if (presult)
14701 *presult = null;
14703 TypeFunction tof = null;
14704 if (to.ty == Tdelegate)
14706 if (tok == TOK.function_)
14708 eSink.error(loc, "cannot match function literal to delegate type `%s`", to.toChars());
14709 return MATCH.nomatch;
14711 tof = cast(TypeFunction)to.nextOf();
14713 else if (to.ty == Tpointer && (tof = to.nextOf().isTypeFunction()) !is null)
14715 if (tok == TOK.delegate_)
14717 eSink.error(loc, "cannot match delegate literal to function pointer type `%s`", to.toChars());
14718 return MATCH.nomatch;
14722 if (td)
14724 if (!tof)
14726 return cannotInfer();
14729 // Parameter types inference from 'tof'
14730 assert(td._scope);
14731 TypeFunction tf = fd.type.isTypeFunction();
14732 //printf("\ttof = %s\n", tof.toChars());
14733 //printf("\ttf = %s\n", tf.toChars());
14734 const dim = tf.parameterList.length;
14736 if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs)
14737 return cannotInfer();
14739 auto tiargs = new Objects();
14740 tiargs.reserve(td.parameters.length);
14742 foreach (tp; *td.parameters)
14744 size_t u = 0;
14745 foreach (i, p; tf.parameterList)
14747 if (auto ti = p.type.isTypeIdentifier())
14748 if (ti && ti.ident == tp.ident)
14749 break;
14751 ++u;
14753 assert(u < dim);
14754 Parameter pto = tof.parameterList[u];
14755 Type t = pto.type;
14756 if (t.ty == Terror)
14757 return cannotInfer();
14758 tf.parameterList[u].storageClass = tof.parameterList[u].storageClass;
14759 tiargs.push(t);
14762 // Set target of return type inference
14763 if (!tf.next && tof.next)
14764 fd.treq = to;
14766 auto ti = new TemplateInstance(loc, td, tiargs);
14767 Expression ex = (new ScopeExp(loc, ti)).expressionSemantic(td._scope);
14769 // Reset inference target for the later re-semantic
14770 fd.treq = null;
14772 if (ex.op == EXP.error)
14773 return MATCH.nomatch;
14774 if (auto ef = ex.isFuncExp())
14775 return ef.matchType(to, sc, presult, eSink);
14776 else
14777 return cannotInfer();
14780 if (!tof || !tof.next)
14781 return MATCH.nomatch;
14783 assert(type && type != Type.tvoid);
14784 if (fd.type.ty == Terror)
14785 return MATCH.nomatch;
14786 auto tfx = fd.type.isTypeFunction();
14787 bool convertMatch = (type.ty != to.ty);
14789 if (fd.inferRetType && tfx.next.implicitConvTo(tof.next) == MATCH.convert)
14791 /* If return type is inferred and covariant return,
14792 * tweak return statements to required return type.
14794 * interface I {}
14795 * class C : Object, I{}
14797 * I delegate() dg = delegate() { return new class C(); }
14799 convertMatch = true;
14801 auto tfy = new TypeFunction(tfx.parameterList, tof.next,
14802 tfx.linkage, STC.undefined_);
14803 tfy.mod = tfx.mod;
14804 tfy.trust = tfx.trust;
14805 tfy.isnothrow = tfx.isnothrow;
14806 tfy.isnogc = tfx.isnogc;
14807 tfy.purity = tfx.purity;
14808 tfy.isproperty = tfx.isproperty;
14809 tfy.isref = tfx.isref;
14810 tfy.isInOutParam = tfx.isInOutParam;
14811 tfy.isInOutQual = tfx.isInOutQual;
14812 tfy.deco = tfy.merge().deco;
14814 tfx = tfy;
14816 Type tx;
14817 if (tok == TOK.delegate_ ||
14818 tok == TOK.reserved && (type.ty == Tdelegate || type.ty == Tpointer && to.ty == Tdelegate))
14820 // Allow conversion from implicit function pointer to delegate
14821 tx = new TypeDelegate(tfx);
14822 tx.deco = tx.merge().deco;
14824 else
14826 assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer || fd.errors);
14827 tx = tfx.pointerTo();
14829 //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars());
14831 MATCH m = tx.implicitConvTo(to);
14832 if (m > MATCH.nomatch)
14834 // MATCH.exact: exact type match
14835 // MATCH.constant: covairiant type match (eg. attributes difference)
14836 // MATCH.convert: context conversion
14837 m = convertMatch ? MATCH.convert : tx.equals(to) ? MATCH.exact : MATCH.constant;
14839 if (presult)
14841 (*presult) = cast(FuncExp)funcExp.copy();
14842 (*presult).type = to;
14844 // https://issues.dlang.org/show_bug.cgi?id=12508
14845 // Tweak function body for covariant returns.
14846 (*presult).fd.modifyReturns(sc, tof.next);
14849 else if (!cast(ErrorSinkNull)eSink)
14851 auto ts = toAutoQualChars(tx, to);
14852 eSink.error(loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
14853 funcExp.toChars(), ts[0], ts[1]);
14855 return m;
14858 private bool checkSharedAccessBin(BinExp binExp, Scope* sc)
14860 const r1 = binExp.e1.checkSharedAccess(sc);
14861 const r2 = binExp.e2.checkSharedAccess(sc);
14862 return (r1 || r2);
14865 /***************************************
14866 * If expression is shared, check that we can access it.
14867 * Give error message if not.
14869 * Params:
14870 * e = expression to check
14871 * sc = context
14872 * returnRef = Whether this expression is for a `return` statement
14873 * off a `ref` function, in which case a single level
14874 * of dereference is allowed (e.g. `shared(int)*`).
14875 * Returns:
14876 * true on error
14878 bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
14880 if (global.params.noSharedAccess != FeatureState.enabled ||
14881 !sc ||
14882 sc.intypeof ||
14883 sc.flags & SCOPE.ctfe)
14885 return false;
14888 //printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef);
14890 bool check(Expression e, bool allowRef)
14892 bool sharedError(Expression e)
14894 // https://dlang.org/phobos/core_atomic.html
14895 error(e.loc, "direct access to shared `%s` is not allowed, see `core.atomic`", e.toChars());
14896 return true;
14899 // Error by default
14900 bool visit(Expression e)
14902 // https://issues.dlang.org/show_bug.cgi?id=23639
14903 // Should be able to cast(shared)
14904 if (!e.isCastExp() && e.type.isShared())
14905 return sharedError(e);
14906 return false;
14909 bool visitNew(NewExp e)
14911 if (e.thisexp)
14912 check(e.thisexp, false);
14913 return false;
14916 bool visitVar(VarExp e)
14918 // https://issues.dlang.org/show_bug.cgi?id=20908
14919 // direct access to init symbols is ok as they
14920 // cannot be modified.
14921 if (e.var.isSymbolDeclaration())
14922 return false;
14924 // https://issues.dlang.org/show_bug.cgi?id=22626
14925 // Synchronized functions don't need to use core.atomic
14926 // when accessing `this`.
14927 if (sc.func && sc.func.isSynchronized())
14929 if (e.var.isThisDeclaration())
14930 return false;
14931 else
14932 return sharedError(e);
14934 else if (!allowRef && e.var.type.isShared())
14935 return sharedError(e);
14937 return false;
14940 bool visitAddr(AddrExp e)
14942 return check(e.e1, true);
14945 bool visitPtr(PtrExp e)
14947 if (!allowRef && e.type.isShared())
14948 return sharedError(e);
14950 if (e.e1.type.isShared())
14951 return sharedError(e);
14953 return check(e.e1, false);
14956 bool visitDotVar(DotVarExp e)
14958 //printf("dotvarexp = %s\n", e.toChars());
14959 if (e.type.isShared())
14961 if (e.e1.isThisExp())
14963 // https://issues.dlang.org/show_bug.cgi?id=22626
14964 if (sc.func && sc.func.isSynchronized())
14965 return false;
14967 // https://issues.dlang.org/show_bug.cgi?id=23790
14968 if (e.e1.type.isTypeStruct())
14969 return false;
14972 auto fd = e.var.isFuncDeclaration();
14973 const sharedFunc = fd && fd.type.isShared;
14974 if (!allowRef && !sharedFunc)
14975 return sharedError(e);
14977 // Allow using `DotVarExp` within value types
14978 if (e.e1.type.isTypeSArray() || e.e1.type.isTypeStruct())
14979 return check(e.e1, allowRef);
14981 // If we end up with a single `VarExp`, it might be a `ref` param
14982 // `shared ref T` param == `shared(T)*`.
14983 if (auto ve = e.e1.isVarExp())
14985 return check(e.e1, allowRef && (ve.var.storage_class & STC.ref_));
14988 return sharedError(e);
14991 return check(e.e1, false);
14994 bool visitIndex(IndexExp e)
14996 if (!allowRef && e.type.isShared())
14997 return sharedError(e);
14999 if (e.e1.type.isShared())
15000 return sharedError(e);
15002 return check(e.e1, false);
15005 bool visitComma(CommaExp e)
15007 // Cannot be `return ref` since we can't use the return,
15008 // but it's better to show that error than an unrelated `shared` one
15009 return check(e.e2, true);
15012 switch (e.op)
15014 default: return visit(e);
15016 // Those have no indirections / can be ignored
15017 case EXP.call:
15018 case EXP.error:
15019 case EXP.complex80:
15020 case EXP.int64:
15021 case EXP.null_: return false;
15023 case EXP.variable: return visitVar(e.isVarExp());
15024 case EXP.new_: return visitNew(e.isNewExp());
15025 case EXP.address: return visitAddr(e.isAddrExp());
15026 case EXP.star: return visitPtr(e.isPtrExp());
15027 case EXP.dotVariable: return visitDotVar(e.isDotVarExp());
15028 case EXP.index: return visitIndex(e.isIndexExp());
15032 return check(e, returnRef);
15035 /****************************************
15036 * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE_FULL_PATH__ to loc.
15038 Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
15040 Expression visit(Expression exp)
15042 if (auto unaExp = exp.isUnaExp())
15044 unaExp.e1 = unaExp.e1.resolveLoc(loc, sc);
15045 return unaExp;
15047 exp.loc = loc;
15048 return exp;
15051 Expression visitCat(CatExp exp)
15053 exp.e1 = exp.e1.resolveLoc(loc, sc);
15054 exp.e2 = exp.e2.resolveLoc(loc, sc);
15055 return exp;
15058 Expression visitFileInit(FileInitExp exp)
15060 //printf("FileInitExp::resolve() %s\n", exp.toChars());
15061 const(char)* s;
15062 if (exp.op == EXP.fileFullPath)
15063 s = FileName.toAbsolute(loc.isValid() ? loc.filename : sc._module.srcfile.toChars());
15064 else
15065 s = loc.isValid() ? loc.filename : sc._module.ident.toChars();
15067 Expression e = new StringExp(loc, s.toDString());
15068 return e.expressionSemantic(sc);
15071 Expression visitLineInit(LineInitExp _)
15073 Expression e = new IntegerExp(loc, loc.linnum, Type.tint32);
15074 return e.expressionSemantic(sc);
15077 Expression visitModuleInit(ModuleInitExp _)
15079 const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString();
15080 Expression e = new StringExp(loc, s);
15081 return e.expressionSemantic(sc);
15084 Expression visitFuncInit(FuncInitExp _)
15086 const(char)* s;
15087 if (sc.callsc && sc.callsc.func)
15088 s = sc.callsc.func.Dsymbol.toPrettyChars();
15089 else if (sc.func)
15090 s = sc.func.Dsymbol.toPrettyChars();
15091 else
15092 s = "";
15093 Expression e = new StringExp(loc, s.toDString());
15094 return e.expressionSemantic(sc);
15097 Expression visitPrettyFunc(PrettyFuncInitExp _)
15099 FuncDeclaration fd = (sc.callsc && sc.callsc.func)
15100 ? sc.callsc.func
15101 : sc.func;
15103 const(char)* s;
15104 if (fd)
15106 const funcStr = fd.Dsymbol.toPrettyChars();
15107 OutBuffer buf;
15108 functionToBufferWithIdent(fd.type.isTypeFunction(), buf, funcStr, fd.isStatic);
15109 s = buf.extractChars();
15111 else
15113 s = "";
15116 Expression e = new StringExp(loc, s.toDString());
15117 e = e.expressionSemantic(sc);
15118 e.type = Type.tstring;
15119 return e;
15122 switch(exp.op)
15124 default: return visit(exp);
15125 case EXP.concatenate: return visitCat(exp.isCatExp());
15126 case EXP.file:
15127 case EXP.fileFullPath: return visitFileInit(exp.isFileInitExp());
15128 case EXP.line: return visitLineInit(exp.isLineInitExp);
15129 case EXP.moduleString: return visitModuleInit(exp.isModuleInitExp());
15130 case EXP.functionString: return visitFuncInit(exp.isFuncInitExp());
15131 case EXP.prettyFunction: return visitPrettyFunc(exp.isPrettyFuncInitExp());
15135 /************************************************
15136 * Destructors are attached to VarDeclarations.
15137 * Hence, if expression returns a temp that needs a destructor,
15138 * make sure and create a VarDeclaration for that temp.
15140 Expression addDtorHook(Expression e, Scope* sc)
15142 Expression visit(Expression exp)
15144 return exp;
15147 Expression visitStructLiteral(StructLiteralExp exp)
15149 auto sd = exp.sd;
15150 /* If struct requires a destructor, rewrite as:
15151 * (S tmp = S()),tmp
15152 * so that the destructor can be hung on tmp.
15154 if (sd.dtor && sc.func)
15156 /* Make an identifier for the temporary of the form:
15157 * __sl%s%d, where %s is the struct name
15159 char[10] buf = void;
15160 const prefix = "__sl";
15161 const ident = sd.ident.toString;
15162 const fullLen = prefix.length + ident.length;
15163 const len = fullLen < buf.length ? fullLen : buf.length;
15164 buf[0 .. prefix.length] = prefix;
15165 buf[prefix.length .. len] = ident[0 .. len - prefix.length];
15167 auto tmp = copyToTemp(0, buf[0 .. len], exp);
15168 Expression ae = new DeclarationExp(exp.loc, tmp);
15169 Expression e = new CommaExp(exp.loc, ae, new VarExp(exp.loc, tmp));
15170 e = e.expressionSemantic(sc);
15171 return e;
15174 return exp;
15177 Expression visitCall(CallExp exp)
15179 auto e1 = exp.e1;
15180 auto type = exp.type;
15181 /* Only need to add dtor hook if it's a type that needs destruction.
15182 * Use same logic as VarDeclaration::callScopeDtor()
15185 if (auto tf = e1.type.isTypeFunction())
15187 if (tf.isref)
15188 return exp;
15191 Type tv = type.baseElemOf();
15192 if (auto ts = tv.isTypeStruct())
15194 StructDeclaration sd = ts.sym;
15195 if (sd.dtor)
15197 /* Type needs destruction, so declare a tmp
15198 * which the back end will recognize and call dtor on
15200 auto tmp = copyToTemp(0, Id.__tmpfordtor.toString(), exp);
15201 auto de = new DeclarationExp(exp.loc, tmp);
15202 auto ve = new VarExp(exp.loc, tmp);
15203 Expression e = new CommaExp(exp.loc, de, ve);
15204 e = e.expressionSemantic(sc);
15205 return e;
15209 return exp;
15212 Expression visitCast(CastExp exp)
15214 if (exp.to.toBasetype().ty == Tvoid) // look past the cast(void)
15215 exp.e1 = exp.e1.addDtorHook(sc);
15216 return exp;
15219 Expression visitComma(CommaExp exp)
15221 exp.e2 = exp.e2.addDtorHook(sc);
15222 return exp;
15225 switch(e.op)
15227 default: return visit(e);
15229 case EXP.structLiteral: return visitStructLiteral(e.isStructLiteralExp());
15230 case EXP.call: return visitCall(e.isCallExp());
15231 case EXP.cast_: return visitCast(e.isCastExp());
15232 case EXP.comma: return visitComma(e.isCommaExp());
15236 /*******************************
15237 * Try to convert an expression to be an lvalue.
15239 * Give error if we're not an lvalue.
15240 * Params:
15241 * _this = expression to convert
15242 * sc = scope
15243 * action = for error messages, what the lvalue is needed for (e.g. take address of for `&x`, modify for `x++`)
15244 * Returns: converted expression, or `ErrorExp` on error
15246 extern(C++) Expression toLvalue(Expression _this, Scope* sc, const(char)* action)
15248 return toLvalueImpl(_this, sc, action, _this);
15251 // e = original un-lowered expression for error messages, in case of recursive calls
15252 private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action, Expression e)
15254 if (!action)
15255 action = "create lvalue of";
15257 assert(e);
15258 Expression visit(Expression _this)
15260 // BinaryAssignExp does not have an EXP associated
15261 // so it's treated on the default path.
15262 // Lvalue-ness will be handled in glue :layer.
15263 if (_this.isBinAssignExp())
15264 return _this;
15265 if (!_this.loc.isValid())
15266 _this.loc = e.loc;
15268 if (e.op == EXP.type)
15269 error(_this.loc, "cannot %s type `%s`", action, e.type.toChars());
15270 else if (e.op == EXP.template_)
15271 error(_this.loc, "cannot %s template `%s`, perhaps instantiate it first", action, e.toChars());
15272 else
15273 error(_this.loc, "cannot %s expression `%s` because it is not an lvalue", action, e.toChars());
15275 return ErrorExp.get();
15278 Expression visitInteger(IntegerExp _this)
15280 if (!_this.loc.isValid())
15281 _this.loc = e.loc;
15282 error(e.loc, "cannot %s constant `%s`", action, e.toChars());
15283 return ErrorExp.get();
15286 Expression visitThis(ThisExp _this)
15288 if (_this.type.toBasetype().ty == Tclass)
15290 // Class `this` is an rvalue; struct `this` is an lvalue.
15291 return visit(_this);
15294 return _this;
15297 Expression visitString(StringExp _this)
15299 //printf("StringExp::toLvalue(%s) type = %s\n", _this.toChars(), _this.type ? _this.type.toChars() : NULL);
15300 return (_this.type && _this.type.toBasetype().ty == Tsarray) ? _this : visit(_this);
15303 Expression visitStructLiteral(StructLiteralExp _this)
15305 if (sc.flags & SCOPE.Cfile)
15306 return _this; // C struct literals are lvalues
15307 else
15308 return visit(_this);
15311 Expression visitTemplate(TemplateExp _this)
15313 if (!_this.fd)
15314 return visit(_this);
15316 assert(sc);
15317 return symbolToExp(_this.fd, _this.loc, sc, true);
15321 Expression visitVar(VarExp _this)
15323 auto var = _this.var;
15324 if (var.storage_class & STC.manifest)
15326 error(_this.loc, "cannot %s manifest constant `%s`", action, var.toChars());
15327 return ErrorExp.get();
15329 if (var.storage_class & STC.lazy_ && !_this.delegateWasExtracted)
15331 error(_this.loc, "cannot %s lazy variable `%s`", action, var.toChars());
15332 return ErrorExp.get();
15334 if (var.ident == Id.ctfe)
15336 error(_this.loc, "cannot %s compiler-generated variable `__ctfe`", action);
15337 return ErrorExp.get();
15339 if (var.ident == Id.dollar) // https://issues.dlang.org/show_bug.cgi?id=13574
15341 error(_this.loc, "cannot %s operator `$`", action);
15342 return ErrorExp.get();
15344 return _this;
15347 Expression visitDotVar(DotVarExp _this)
15349 auto e1 = _this.e1;
15350 auto var = _this.var;
15351 //printf("DotVarExp::toLvalue(%s)\n", toChars());
15352 if (sc && sc.flags & SCOPE.Cfile)
15354 /* C11 6.5.2.3-3: A postfix expression followed by the '.' or '->' operator
15355 * is an lvalue if the first expression is an lvalue.
15357 if (!e1.isLvalue())
15358 return visit(_this);
15360 if (!_this.isLvalue())
15361 return visit(_this);
15362 if (e1.op == EXP.this_ && sc.ctorflow.fieldinit.length && !(sc.ctorflow.callSuper & CSX.any_ctor))
15364 if (VarDeclaration vd = var.isVarDeclaration())
15366 auto ad = vd.isMember2();
15367 if (ad && ad.fields.length == sc.ctorflow.fieldinit.length)
15369 foreach (i, f; ad.fields)
15371 if (f == vd)
15373 if (!(sc.ctorflow.fieldinit[i].csx & CSX.this_ctor))
15375 /* If the address of vd is taken, assume it is thereby initialized
15376 * https://issues.dlang.org/show_bug.cgi?id=15869
15378 modifyFieldVar(_this.loc, sc, vd, e1);
15380 break;
15386 return _this;
15389 Expression visitCall(CallExp _this)
15391 if (_this.isLvalue())
15392 return _this;
15393 return visit(_this);
15396 Expression visitCast(CastExp _this)
15398 if (sc && sc.flags & SCOPE.Cfile)
15400 /* C11 6.5.4-5: A cast does not yield an lvalue.
15402 return visit(_this);
15404 if (_this.isLvalue())
15405 return _this;
15406 return visit(_this);
15409 Expression visitVectorArray(VectorArrayExp _this)
15411 _this.e1 = _this.e1.toLvalueImpl(sc, action, e);
15412 return _this;
15415 Expression visitSlice(SliceExp _this)
15417 //printf("SliceExp::toLvalue(%s) _this.type = %s\n", _this.toChars(), _this.type ? _this.type.toChars() : NULL);
15418 return (_this.type && _this.type.toBasetype().ty == Tsarray) ? _this : visit(_this);
15421 Expression visitArray(ArrayExp _this)
15423 if (_this.type && _this.type.toBasetype().ty == Tvoid)
15424 error(_this.loc, "`void`s have no value");
15425 return _this;
15428 Expression visitComma(CommaExp _this)
15430 _this.e2 = _this.e2.toLvalue(sc, action);
15431 return _this;
15434 Expression visitDelegatePointer(DelegatePtrExp _this)
15436 _this.e1 = _this.e1.toLvalueImpl(sc, action, e);
15437 return _this;
15440 Expression visitDelegateFuncptr(DelegateFuncptrExp _this)
15442 _this.e1 = _this.e1.toLvalueImpl(sc, action, e);
15443 return _this;
15446 Expression visitIndex(IndexExp _this)
15448 if (_this.isLvalue())
15449 return _this;
15450 return visit(_this);
15453 Expression visitAssign(AssignExp _this)
15455 if (_this.e1.op == EXP.slice || _this.e1.op == EXP.arrayLength)
15457 return visit(_this);
15460 /* In front-end level, AssignExp should make an lvalue of e1.
15461 * Taking the address of e1 will be handled in low level layer,
15462 * so this function does nothing.
15464 return _this;
15467 Expression visitCond(CondExp _this)
15469 // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
15470 CondExp e = cast(CondExp)(_this.copy());
15471 e.e1 = _this.e1.toLvalue(sc, action).addressOf();
15472 e.e2 = _this.e2.toLvalue(sc, action).addressOf();
15473 e.type = _this.type.pointerTo();
15474 return new PtrExp(_this.loc, e, _this.type);
15478 switch(_this.op)
15480 default: return visit(_this);
15482 case EXP.int64: return visitInteger(_this.isIntegerExp());
15483 case EXP.error: return _this;
15484 case EXP.identifier: return _this;
15485 case EXP.dSymbol: return _this;
15486 case EXP.this_: return visitThis(_this.isThisExp());
15487 case EXP.super_: return visitThis(_this.isSuperExp());
15488 case EXP.string_: return visitString(_this.isStringExp());
15489 case EXP.structLiteral: return visitStructLiteral(_this.isStructLiteralExp());
15490 case EXP.template_: return visitTemplate(_this.isTemplateExp());
15491 case EXP.variable: return visitVar(_this.isVarExp());
15492 case EXP.overloadSet: return _this;
15493 case EXP.dotVariable: return visitDotVar(_this.isDotVarExp());
15494 case EXP.call: return visitCall(_this.isCallExp());
15495 case EXP.star: return _this;
15496 case EXP.cast_: return visitCast(_this.isCastExp());
15497 case EXP.vectorArray: return visitVectorArray(_this.isVectorArrayExp());
15498 case EXP.slice: return visitSlice(_this.isSliceExp());
15499 case EXP.array: return visitArray(_this.isArrayExp());
15500 case EXP.comma: return visitComma(_this.isCommaExp());
15501 case EXP.delegatePointer: return visitDelegatePointer(_this.isDelegatePtrExp());
15502 case EXP.delegateFunctionPointer: return visitDelegateFuncptr(_this.isDelegateFuncptrExp());
15503 case EXP.index: return visitIndex(_this.isIndexExp());
15504 case EXP.construct: return visitAssign(_this.isConstructExp());
15505 case EXP.loweredAssignExp: return visitAssign(_this.isLoweredAssignExp());
15506 case EXP.blit: return visitAssign(_this.isBlitExp());
15507 case EXP.assign: return visitAssign(_this.isAssignExp());
15508 case EXP.question: return visitCond(_this.isCondExp());
15512 /***************************************
15513 * Parameters:
15514 * sc: scope
15515 * flag: 1: do not issue error message for invalid modification
15516 2: the exp is a DotVarExp and a subfield of the leftmost
15517 variable is modified
15518 * Returns:
15519 * Whether the type is modifiable
15521 Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag = ModifyFlags.none)
15523 switch(exp.op)
15525 case EXP.variable:
15526 auto varExp = cast(VarExp)exp;
15528 //printf("VarExp::checkModifiable %s", varExp.toChars());
15529 assert(varExp.type);
15530 return varExp.var.checkModify(varExp.loc, sc, null, flag);
15532 case EXP.dotVariable:
15533 auto dotVarExp = cast(DotVarExp)exp;
15535 //printf("DotVarExp::checkModifiable %s %s\n", dotVarExp.toChars(), dotVarExp.type.toChars());
15536 if (dotVarExp.e1.op == EXP.this_)
15537 return dotVarExp.var.checkModify(dotVarExp.loc, sc, dotVarExp.e1, flag);
15539 /* https://issues.dlang.org/show_bug.cgi?id=12764
15540 * If inside a constructor and an expression of type `this.field.var`
15541 * is encountered, where `field` is a struct declaration with
15542 * default construction disabled, we must make sure that
15543 * assigning to `var` does not imply that `field` was initialized
15545 if (sc.func && sc.func.isCtorDeclaration())
15547 // if inside a constructor scope and e1 of this DotVarExp
15548 // is another DotVarExp, then check if the leftmost expression is a `this` identifier
15549 if (auto dve = dotVarExp.e1.isDotVarExp())
15551 // Iterate the chain of DotVarExp to find `this`
15552 // Keep track whether access to fields was limited to union members
15553 // s.t. one can initialize an entire struct inside nested unions
15554 // (but not its members)
15555 bool onlyUnion = true;
15556 while (true)
15558 auto v = dve.var.isVarDeclaration();
15559 assert(v);
15561 // Accessing union member?
15562 auto t = v.type.isTypeStruct();
15563 if (!t || !t.sym.isUnionDeclaration())
15564 onlyUnion = false;
15566 // Another DotVarExp left?
15567 if (!dve.e1 || dve.e1.op != EXP.dotVariable)
15568 break;
15570 dve = cast(DotVarExp) dve.e1;
15573 if (dve.e1.op == EXP.this_)
15575 scope v = dve.var.isVarDeclaration();
15576 /* if v is a struct member field with no initializer, no default construction
15577 * and v wasn't intialized before
15579 if (v && v.isField() && !v._init && !v.ctorinit)
15581 if (auto ts = v.type.isTypeStruct())
15583 if (ts.sym.noDefaultCtor)
15585 /* checkModify will consider that this is an initialization
15586 * of v while it is actually an assignment of a field of v
15588 scope modifyLevel = v.checkModify(dotVarExp.loc, sc, dve.e1, !onlyUnion ? (flag | ModifyFlags.fieldAssign) : flag);
15589 if (modifyLevel == Modifiable.initialization)
15591 // https://issues.dlang.org/show_bug.cgi?id=22118
15592 // v is a union type field that was assigned
15593 // a variable, therefore it counts as initialization
15594 if (v.ctorinit)
15595 return Modifiable.initialization;
15597 return Modifiable.yes;
15599 return modifyLevel;
15607 //printf("\te1 = %s\n", e1.toChars());
15608 return dotVarExp.e1.checkModifiable(sc, flag);
15610 case EXP.star:
15611 auto ptrExp = cast(PtrExp)exp;
15612 if (auto se = ptrExp.e1.isSymOffExp())
15614 return se.var.checkModify(ptrExp.loc, sc, null, flag);
15616 else if (auto ae = ptrExp.e1.isAddrExp())
15618 return ae.e1.checkModifiable(sc, flag);
15620 return Modifiable.yes;
15622 case EXP.slice:
15623 auto sliceExp = cast(SliceExp)exp;
15625 //printf("SliceExp::checkModifiable %s\n", sliceExp.toChars());
15626 auto e1 = sliceExp.e1;
15627 if (e1.type.ty == Tsarray || (e1.op == EXP.index && e1.type.ty != Tarray) || e1.op == EXP.slice)
15629 return e1.checkModifiable(sc, flag);
15631 return Modifiable.yes;
15633 case EXP.comma:
15634 return (cast(CommaExp)exp).e2.checkModifiable(sc, flag);
15636 case EXP.index:
15637 auto indexExp = cast(IndexExp)exp;
15638 auto e1 = indexExp.e1;
15639 if (e1.type.ty == Tsarray ||
15640 e1.type.ty == Taarray ||
15641 (e1.op == EXP.index && e1.type.ty != Tarray) ||
15642 e1.op == EXP.slice)
15644 return e1.checkModifiable(sc, flag);
15646 return Modifiable.yes;
15648 case EXP.question:
15649 auto condExp = cast(CondExp)exp;
15650 if (condExp.e1.checkModifiable(sc, flag) != Modifiable.no
15651 && condExp.e2.checkModifiable(sc, flag) != Modifiable.no)
15652 return Modifiable.yes;
15653 return Modifiable.no;
15655 default:
15656 return exp.type ? Modifiable.yes : Modifiable.no; // default modifiable
15661 * Similar to `toLvalue`, but also enforce it is mutable or raise an error.
15662 * Params:
15663 * _this = Expression to convert
15664 * sc = scope
15665 * Returns: `_this` converted to an lvalue, or an `ErrorExp`
15667 extern(C++) Expression modifiableLvalue(Expression _this, Scope* sc)
15669 return modifiableLvalueImpl(_this, sc, _this);
15672 // e = original / un-lowered expression to print in error messages
15673 private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression e)
15675 assert(e);
15676 Expression visit(Expression exp)
15678 //printf("Expression::modifiableLvalue() %s, type = %s\n", exp.toChars(), exp.type.toChars());
15679 // See if this expression is a modifiable lvalue (i.e. not const)
15680 if (exp.isBinAssignExp())
15681 return exp.toLvalue(sc, "modify");
15683 auto type = exp.type;
15684 if (checkModifiable(exp, sc) == Modifiable.yes)
15686 assert(type);
15687 if (!type.isMutable())
15689 if (auto dve = exp.isDotVarExp())
15691 if (isNeedThisScope(sc, dve.var))
15692 for (Dsymbol s = sc.func; s; s = s.toParentLocal())
15694 FuncDeclaration ff = s.isFuncDeclaration();
15695 if (!ff)
15696 break;
15697 if (!ff.type.isMutable)
15699 error(exp.loc, "cannot modify `%s` in `%s` function", exp.toChars(), MODtoChars(type.mod));
15700 return ErrorExp.get();
15704 error(exp.loc, "cannot modify `%s` expression `%s`", MODtoChars(type.mod), exp.toChars());
15705 return ErrorExp.get();
15707 else if (!type.isAssignable())
15709 error(exp.loc, "cannot modify struct instance `%s` of type `%s` because it contains `const` or `immutable` members",
15710 exp.toChars(), type.toChars());
15711 return ErrorExp.get();
15714 return exp.toLvalueImpl(sc, "modify", e);
15717 Expression visitString(StringExp exp)
15719 error(exp.loc, "cannot modify string literal `%s`", exp.toChars());
15720 return ErrorExp.get();
15723 Expression visitVar(VarExp exp)
15725 //printf("VarExp::modifiableLvalue('%s')\n", exp.var.toChars());
15726 if (exp.var.storage_class & STC.manifest)
15728 error(exp.loc, "cannot modify manifest constant `%s`", exp.toChars());
15729 return ErrorExp.get();
15731 // See if this expression is a modifiable lvalue (i.e. not const)
15732 return visit(exp);
15735 Expression visitPtr(PtrExp exp)
15737 //printf("PtrExp::modifiableLvalue() %s, type %s\n", exp.toChars(), exp.type.toChars());
15738 Declaration var;
15739 auto e1 = exp.e1;
15740 if (auto se = e1.isSymOffExp())
15741 var = se.var;
15742 else if (auto ve = e1.isVarExp())
15743 var = ve.var;
15744 if (var && var.type.isFunction_Delegate_PtrToFunction())
15746 if (var.type.isTypeFunction())
15747 error(exp.loc, "function `%s` is not an lvalue and cannot be modified", var.toChars());
15748 else
15749 error(exp.loc, "function pointed to by `%s` is not an lvalue and cannot be modified", var.toChars());
15750 return ErrorExp.get();
15752 return visit(exp);
15755 Expression visitSlice(SliceExp exp)
15757 error(exp.loc, "slice expression `%s` is not a modifiable lvalue", exp.toChars());
15758 return exp;
15761 Expression visitComma(CommaExp exp)
15763 exp.e2 = exp.e2.modifiableLvalueImpl(sc, e);
15764 return exp;
15767 Expression visitDelegatePtr(DelegatePtrExp exp)
15769 if (sc.setUnsafe(false, exp.loc, "cannot modify delegate pointer in `@safe` code `%s`", exp))
15771 return ErrorExp.get();
15773 return visit(exp);
15776 Expression visitDelegateFuncptr(DelegateFuncptrExp exp)
15778 if (sc.setUnsafe(false, exp.loc, "cannot modify delegate function pointer in `@safe` code `%s`", exp))
15780 return ErrorExp.get();
15782 return visit(exp);
15785 Expression visitIndex(IndexExp exp)
15787 //printf("IndexExp::modifiableLvalue(%s)\n", exp.toChars());
15788 Expression ex = exp.markSettingAAElem();
15789 if (ex.op == EXP.error)
15790 return ex;
15792 return visit(exp);
15795 Expression visitCond(CondExp exp)
15797 if (!exp.e1.isLvalue() && !exp.e2.isLvalue())
15799 error(exp.loc, "conditional expression `%s` is not a modifiable lvalue", exp.toChars());
15800 return ErrorExp.get();
15802 exp.e1 = exp.e1.modifiableLvalue(sc);
15803 exp.e2 = exp.e2.modifiableLvalue(sc);
15804 return exp.toLvalue(sc, "modify");
15807 switch(_this.op)
15809 default: return visit(_this);
15810 case EXP.string_: return visitString(_this.isStringExp());
15811 case EXP.variable: return visitVar(_this.isVarExp());
15812 case EXP.star: return visitPtr(_this.isPtrExp());
15813 case EXP.slice: return visitSlice(_this.isSliceExp());
15814 case EXP.comma: return visitComma(_this.isCommaExp());
15815 case EXP.delegatePointer: return visitDelegatePtr(_this.isDelegatePtrExp());
15816 case EXP.delegateFunctionPointer: return visitDelegateFuncptr(_this.isDelegateFuncptrExp());
15817 case EXP.index: return visitIndex(_this.isIndexExp());
15818 case EXP.question: return visitCond(_this.isCondExp());
15823 /****************************************************
15824 * Determine if `exp`, which gets its address taken, can do so safely.
15825 * Params:
15826 * sc = context
15827 * exp = expression having its address taken
15828 * v = the variable getting its address taken
15829 * Returns:
15830 * `true` if ok, `false` for error
15832 bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
15834 //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars());
15835 if (v is null)
15836 return true;
15838 if (!v.canTakeAddressOf())
15840 error(exp.loc, "cannot take address of `%s`", exp.toChars());
15841 return false;
15843 if (sc.func && !sc.intypeof && !v.isDataseg())
15845 if (sc.useDIP1000 != FeatureState.enabled &&
15846 !(v.storage_class & STC.temp) &&
15847 sc.setUnsafe(false, exp.loc, "cannot take address of local `%s` in `@safe` function `%s`", v, sc.func))
15849 return false;
15852 return true;
15855 /**************************************
15856 * This check ensures that the object in `exp` can have its address taken, or
15857 * issue a diagnostic error.
15858 * Params:
15859 * e = expression to check
15860 * sc = context
15861 * Returns:
15862 * true if the expression is addressable
15864 bool checkAddressable(Expression e, Scope* sc)
15866 Expression ex = e;
15867 while (true)
15869 switch (ex.op)
15871 case EXP.dotVariable:
15872 // https://issues.dlang.org/show_bug.cgi?id=22749
15873 // Error about taking address of any bit-field, regardless of
15874 // whether SCOPE.Cfile is set.
15875 if (auto bf = ex.isDotVarExp().var.isBitFieldDeclaration())
15877 error(e.loc, "cannot take address of bit-field `%s`", bf.toChars());
15878 return false;
15880 goto case EXP.cast_;
15882 case EXP.index:
15883 ex = ex.isBinExp().e1;
15884 continue;
15886 case EXP.address:
15887 case EXP.array:
15888 case EXP.cast_:
15889 ex = ex.isUnaExp().e1;
15890 continue;
15892 case EXP.variable:
15893 if (sc.flags & SCOPE.Cfile)
15895 // C11 6.5.3.2: A variable that has its address taken cannot be
15896 // stored in a register.
15897 // C11 6.3.2.1: An array that has its address computed with `[]`
15898 // or cast to an lvalue pointer cannot be stored in a register.
15899 if (ex.isVarExp().var.storage_class & STC.register)
15901 if (e.isIndexExp())
15902 error(e.loc, "cannot index through register variable `%s`", ex.toChars());
15903 else
15904 error(e.loc, "cannot take address of register variable `%s`", ex.toChars());
15905 return false;
15908 break;
15910 default:
15911 break;
15913 break;
15915 return true;
15919 /*******************************
15920 * Checks the attributes of a function.
15921 * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`)
15922 * and usage of `deprecated` and `@disabled`-ed symbols are checked.
15924 * Params:
15925 * exp = expression to check attributes for
15926 * sc = scope of the function
15927 * f = function to be checked
15928 * Returns: `true` if error occur.
15930 private bool checkFunctionAttributes(Expression exp, Scope* sc, FuncDeclaration f)
15932 bool error = f.checkDisabled(exp.loc, sc);
15933 error |= f.checkDeprecated(exp.loc, sc);
15934 error |= f.checkPurity(exp.loc, sc);
15935 error |= f.checkSafety(exp.loc, sc);
15936 error |= f.checkNogc(exp.loc, sc);
15937 return error;
15940 /*******************************
15941 * Helper function for `getRightThis()`.
15942 * Gets `this` of the next outer aggregate.
15943 * Params:
15944 * loc = location to use for error messages
15945 * sc = context
15946 * s = the parent symbol of the existing `this`
15947 * ad = struct or class we need the correct `this` for
15948 * e1 = existing `this`
15949 * t = type of the existing `this`
15950 * var = the specific member of ad we're accessing
15951 * flag = if true, return `null` instead of throwing an error
15952 * Returns:
15953 * Expression representing the `this` for the var
15955 Expression getThisSkipNestedFuncs(const ref Loc loc, Scope* sc, Dsymbol s, AggregateDeclaration ad, Expression e1, Type t, Dsymbol var, bool flag = false)
15957 int n = 0;
15958 while (s && s.isFuncDeclaration())
15960 FuncDeclaration f = s.isFuncDeclaration();
15961 if (f.vthis)
15963 n++;
15964 e1 = new VarExp(loc, f.vthis);
15965 if (f.hasDualContext())
15967 // (*__this)[i]
15968 if (n > 1)
15969 e1 = e1.expressionSemantic(sc);
15970 e1 = new PtrExp(loc, e1);
15971 uint i = f.followInstantiationContext(ad);
15972 e1 = new IndexExp(loc, e1, new IntegerExp(i));
15973 s = f.toParentP(ad);
15974 continue;
15977 else
15979 if (flag)
15980 return null;
15981 error(e1.loc, "need `this` of type `%s` to access member `%s` from static function `%s`", ad.toChars(), var.toChars(), f.toChars());
15982 e1 = ErrorExp.get();
15983 return e1;
15985 s = s.toParent2();
15987 if (n > 1 || e1.op == EXP.index)
15988 e1 = e1.expressionSemantic(sc);
15989 if (s && e1.type.equivalent(Type.tvoidptr))
15991 if (auto sad = s.isAggregateDeclaration())
15993 Type ta = sad.handleType();
15994 if (ta.ty == Tstruct)
15995 ta = ta.pointerTo();
15996 e1.type = ta;
15999 e1.type = e1.type.addMod(t.mod);
16000 return e1;
16003 /*******************************
16004 * Make a dual-context container for use as a `this` argument.
16005 * Params:
16006 * loc = location to use for error messages
16007 * sc = current scope
16008 * fd = target function that will take the `this` argument
16009 * Returns:
16010 * Temporary closure variable.
16011 * Note:
16012 * The function `fd` is added to the nested references of the
16013 * newly created variable such that a closure is made for the variable when
16014 * the address of `fd` is taken.
16016 VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration fd)
16018 Type tthis2 = Type.tvoidptr.sarrayOf(2);
16019 VarDeclaration vthis2 = new VarDeclaration(loc, tthis2, Identifier.generateId("__this"), null);
16020 vthis2.storage_class |= STC.temp;
16021 vthis2.dsymbolSemantic(sc);
16022 vthis2.parent = sc.parent;
16023 // make it a closure var
16024 assert(sc.func);
16025 sc.func.closureVars.push(vthis2);
16026 // add `fd` to the nested refs
16027 vthis2.nestedrefs.push(fd);
16028 return vthis2;
16031 /*******************************
16032 * Make sure that the runtime hook `id` exists.
16033 * Params:
16034 * loc = location to use for error messages
16035 * sc = current scope
16036 * id = the hook identifier
16037 * description = what the hook does
16038 * module_ = what module the hook is located in
16039 * Returns:
16040 * a `bool` indicating if the hook is present.
16042 bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string description, Identifier module_ = Id.object)
16044 Dsymbol pscopesym;
16045 auto rootSymbol = sc.search(loc, Id.empty, pscopesym);
16046 if (auto moduleSymbol = rootSymbol.search(loc, module_))
16047 if (moduleSymbol.search(loc, id))
16048 return true;
16049 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);
16050 return false;
16053 /***************************************
16054 * Fit elements[] to the corresponding types of the `sd`'s fields.
16056 * Params:
16057 * sd = the struct declaration
16058 * loc = location to use for error messages
16059 * sc = context
16060 * elements = explicit arguments used to construct object
16061 * stype = the constructed object type.
16062 * Returns:
16063 * false if any errors occur,
16064 * otherwise true and elements[] are rewritten for the output.
16066 private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions* elements, Type stype)
16068 if (!elements)
16069 return true;
16071 const nfields = sd.nonHiddenFields();
16072 size_t offset = 0;
16073 for (size_t i = 0; i < elements.length; i++)
16075 Expression e = (*elements)[i];
16076 if (!e)
16077 continue;
16079 e = resolveProperties(sc, e);
16080 if (i >= nfields)
16082 if (i < sd.fields.length && e.op == EXP.null_)
16084 // CTFE sometimes creates null as hidden pointer; we'll allow this.
16085 continue;
16087 .error(loc, "more initializers than fields (%llu) of `%s`", cast(ulong)nfields, sd.toChars());
16088 return false;
16090 VarDeclaration v = sd.fields[i];
16091 if (v.offset < offset)
16093 .error(loc, "overlapping initialization for `%s`", v.toChars());
16094 if (!sd.isUnionDeclaration())
16096 enum errorMsg = "`struct` initializers that contain anonymous unions" ~
16097 " must initialize only the first member of a `union`. All subsequent" ~
16098 " non-overlapping fields are default initialized";
16099 .errorSupplemental(loc, errorMsg);
16101 return false;
16103 const vsize = v.type.size();
16104 if (vsize == SIZE_INVALID)
16105 return false;
16106 offset = cast(uint)(v.offset + vsize);
16108 Type t = v.type;
16109 if (stype)
16110 t = t.addMod(stype.mod);
16111 Type origType = t;
16112 Type tb = t.toBasetype();
16114 const hasPointers = tb.hasPointers();
16115 if (hasPointers)
16117 if ((!stype.alignment.isDefault() && stype.alignment.get() < target.ptrsize ||
16118 (v.offset & (target.ptrsize - 1))) &&
16119 (sc.setUnsafe(false, loc,
16120 "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, v)))
16122 return false;
16126 /* Look for case of initializing a static array with a too-short
16127 * string literal, such as:
16128 * char[5] foo = "abc";
16129 * Allow this by doing an explicit cast, which will lengthen the string
16130 * literal.
16132 if (e.op == EXP.string_ && tb.ty == Tsarray)
16134 StringExp se = cast(StringExp)e;
16135 Type typeb = se.type.toBasetype();
16136 TY tynto = tb.nextOf().ty;
16137 if (!se.committed &&
16138 (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar &&
16139 se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger())
16141 e = se.castTo(sc, t);
16142 goto L1;
16146 while (!e.implicitConvTo(t) && tb.ty == Tsarray)
16148 /* Static array initialization, as in:
16149 * T[3][5] = e;
16151 t = tb.nextOf();
16152 tb = t.toBasetype();
16154 if (!e.implicitConvTo(t))
16155 t = origType; // restore type for better diagnostic
16157 e = e.implicitCastTo(sc, t);
16159 if (e.op == EXP.error)
16160 return false;
16162 (*elements)[i] = doCopyOrMove(sc, e);
16164 return true;
16169 * Returns `em` as a VariableExp
16170 * Params:
16171 * em = the EnumMember to wrap
16172 * loc = location of use of em
16173 * sc = scope of use of em
16174 * Returns:
16175 * VarExp referenceing `em` or ErrorExp if `em` if disabled/deprecated
16177 Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc)
16179 dsymbolSemantic(em, sc);
16180 if (em.errors)
16181 return ErrorExp.get();
16182 em.checkDisabled(loc, sc);
16184 if (em.depdecl && !em.depdecl._scope)
16185 em.depdecl._scope = sc;
16186 em.checkDeprecated(loc, sc);
16188 if (em.errors)
16189 return ErrorExp.get();
16190 Expression e = new VarExp(loc, em);
16191 e = e.expressionSemantic(sc);
16192 if (!(sc.flags & SCOPE.Cfile) && em.isCsymbol())
16194 /* C11 types them as int. But if in D file,
16195 * type qualified names as the enum
16197 e.type = em.parent.isEnumDeclaration().type;
16198 assert(e.type);
16200 return e;
16204 /*****************************
16205 * Try to treat `exp` as a boolean,
16206 * Params:
16207 * exp = the expression
16208 * sc = scope to evalute `exp` in
16209 * Returns:
16210 * Modified expression on success, ErrorExp on error
16212 Expression toBoolean(Expression exp, Scope* sc)
16214 switch(exp.op)
16216 case EXP.delete_:
16217 error(exp.loc, "`delete` does not give a boolean result");
16218 return ErrorExp.get();
16220 case EXP.comma:
16221 auto ce = exp.isCommaExp();
16222 auto ex2 = ce.e2.toBoolean(sc);
16223 if (ex2.op == EXP.error)
16224 return ex2;
16225 ce.e2 = ex2;
16226 ce.type = ce.e2.type;
16227 return ce;
16229 case EXP.assign:
16230 case EXP.construct:
16231 case EXP.blit:
16232 case EXP.loweredAssignExp:
16233 if (sc.flags & SCOPE.Cfile)
16234 return exp;
16235 // Things like:
16236 // if (a = b) ...
16237 // are usually mistakes.
16238 error(exp.loc, "assignment cannot be used as a condition, perhaps `==` was meant?");
16239 return ErrorExp.get();
16241 //LogicalExp
16242 case EXP.andAnd:
16243 case EXP.orOr:
16244 auto le = exp.isLogicalExp();
16245 auto ex2 = le.e2.toBoolean(sc);
16246 if (ex2.op == EXP.error)
16247 return ex2;
16248 le.e2 = ex2;
16249 return le;
16251 case EXP.question:
16252 auto ce = exp.isCondExp();
16253 auto ex1 = ce.e1.toBoolean(sc);
16254 auto ex2 = ce.e2.toBoolean(sc);
16255 if (ex1.op == EXP.error)
16256 return ex1;
16257 if (ex2.op == EXP.error)
16258 return ex2;
16259 ce.e1 = ex1;
16260 ce.e2 = ex2;
16261 return ce;
16264 default:
16265 // Default is 'yes' - do nothing
16266 Expression e = arrayFuncConv(exp, sc);
16267 Type t = e.type;
16268 Type tb = t.toBasetype();
16269 Type att = null;
16271 while (1)
16273 // Structs can be converted to bool using opCast(bool)()
16274 if (auto ts = tb.isTypeStruct())
16276 AggregateDeclaration ad = ts.sym;
16277 /* Don't really need to check for opCast first, but by doing so we
16278 * get better error messages if it isn't there.
16280 if (Dsymbol fd = search_function(ad, Id._cast))
16282 e = new CastExp(exp.loc, e, Type.tbool);
16283 e = e.expressionSemantic(sc);
16284 return e;
16287 // Forward to aliasthis.
16288 if (ad.aliasthis && !isRecursiveAliasThis(att, tb))
16290 e = resolveAliasThis(sc, e);
16291 t = e.type;
16292 tb = e.type.toBasetype();
16293 continue;
16296 break;
16299 if (!t.isBoolean())
16301 if (tb != Type.terror)
16302 error(exp.loc, "expression `%s` of type `%s` does not have a boolean value",
16303 exp.toChars(), t.toChars());
16304 return ErrorExp.get();
16306 return e;