Refine splitters related to "combine vpcmpuw + zero_extend to vpcmpuw"
[official-gcc.git] / gcc / d / dmd / expressionsem.d
blob7ae7f400d1661ba52c1e6af0d6f25a72466a5038
1 /**
2 * Semantic analysis of expressions.
4 * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions)
6 * Copyright: Copyright (C) 1999-2024 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.enumsem;
46 import dmd.escape;
47 import dmd.expression;
48 import dmd.file_manager;
49 import dmd.func;
50 import dmd.funcsem;
51 import dmd.globals;
52 import dmd.hdrgen;
53 import dmd.id;
54 import dmd.identifier;
55 import dmd.imphint;
56 import dmd.importc;
57 import dmd.init;
58 import dmd.initsem;
59 import dmd.inline;
60 import dmd.intrange;
61 import dmd.location;
62 import dmd.mtype;
63 import dmd.mustuse;
64 import dmd.nspace;
65 import dmd.objc;
66 import dmd.opover;
67 import dmd.optimize;
68 import dmd.parse;
69 import dmd.printast;
70 import dmd.postordervisitor;
71 import dmd.root.array;
72 import dmd.root.ctfloat;
73 import dmd.root.filename;
74 import dmd.common.outbuffer;
75 import dmd.rootobject;
76 import dmd.root.string;
77 import dmd.root.utf;
78 import dmd.semantic2;
79 import dmd.semantic3;
80 import dmd.sideeffect;
81 import dmd.safe;
82 import dmd.target;
83 import dmd.tokens;
84 import dmd.traits;
85 import dmd.typesem;
86 import dmd.typinf;
87 import dmd.utils;
88 import dmd.utils : arrayCastBigEndian;
89 import dmd.visitor;
91 enum LOGSEMANTIC = false;
93 /***********************************
94 * Determine if a `this` is needed to access `d`.
95 * Params:
96 * sc = context
97 * d = declaration to check
98 * Returns:
99 * true means a `this` is needed
101 private bool isNeedThisScope(Scope* sc, Declaration d)
103 if (sc.intypeof == 1)
104 return false;
106 AggregateDeclaration ad = d.isThis();
107 if (!ad)
108 return false;
109 //printf("d = %s, ad = %s\n", d.toChars(), ad.toChars());
111 for (Dsymbol s = sc.parent; s; s = s.toParentLocal())
113 //printf("\ts = %s %s, toParent2() = %p\n", s.kind(), s.toChars(), s.toParent2());
114 if (AggregateDeclaration ad2 = s.isAggregateDeclaration())
116 if (ad2 == ad)
117 return false;
118 else if (ad2.isNested())
119 continue;
120 else
121 return true;
123 if (FuncDeclaration f = s.isFuncDeclaration())
125 if (f.isMemberLocal())
126 break;
129 return true;
133 /********************************************************
134 * Perform semantic analysis and CTFE on expressions to produce
135 * a string.
136 * Params:
137 * buf = append generated string to buffer
138 * sc = context
139 * exps = array of Expressions
140 * Returns:
141 * true on error
143 bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps)
145 if (!exps)
146 return false;
148 foreach (ex; *exps)
150 if (!ex)
151 continue;
152 auto sc2 = sc.startCTFE();
153 sc2.tinst = null;
154 sc2.minst = null; // prevents emission of any instantiated templates to object file
155 auto e2 = ex.expressionSemantic(sc2);
156 auto e3 = resolveProperties(sc2, e2);
157 sc2.endCTFE();
159 // allowed to contain types as well as expressions
160 auto e4 = ctfeInterpretForPragmaMsg(e3);
161 if (!e4 || e4.op == EXP.error)
162 return true;
164 // expand tuple
165 if (auto te = e4.isTupleExp())
167 if (expressionsToString(buf, sc, te.exps))
168 return true;
169 continue;
171 // char literals exp `.toStringExp` return `null` but we cant override it
172 // because in most contexts we don't want the conversion to succeed.
173 IntegerExp ie = e4.isIntegerExp();
174 const ty = (ie && ie.type) ? ie.type.ty : Terror;
175 if (ty.isSomeChar)
177 auto tsa = new TypeSArray(ie.type, IntegerExp.literal!1);
178 e4 = new ArrayLiteralExp(ex.loc, tsa, ie);
181 if (StringExp se = e4.toStringExp())
182 buf.writestring(se.toUTF8(sc).peekString());
183 else
184 buf.writestring(e4.toString());
186 return false;
189 /*****************************************
190 * Determine if `this` is available by walking up the enclosing
191 * scopes until a function is found.
193 * Params:
194 * sc = where to start looking for the enclosing function
195 * Returns:
196 * Found function if it satisfies `isThis()`, otherwise `null`
198 FuncDeclaration hasThis(Scope* sc)
200 //printf("hasThis()\n");
201 Dsymbol p = sc.parent;
202 while (p && p.isTemplateMixin())
203 p = p.parent;
204 FuncDeclaration fdthis = p ? p.isFuncDeclaration() : null;
205 //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis.toChars() : "");
207 // Go upwards until we find the enclosing member function
208 FuncDeclaration fd = fdthis;
209 while (1)
211 if (!fd)
213 return null;
215 if (!fd.isNested() || fd.isThis() || (fd.hasDualContext() && fd.isMember2()))
216 break;
218 Dsymbol parent = fd.parent;
219 while (1)
221 if (!parent)
222 return null;
223 TemplateInstance ti = parent.isTemplateInstance();
224 if (ti)
225 parent = ti.parent;
226 else
227 break;
229 fd = parent.isFuncDeclaration();
232 if (!fd.isThis() && !(fd.hasDualContext() && fd.isMember2()))
234 return null;
237 assert(fd.vthis);
238 return fd;
242 extern (D) bool findTempDecl(DotTemplateInstanceExp exp, Scope* sc)
244 auto ti = exp.ti;
245 auto e1 = exp.e1;
246 static if (LOGSEMANTIC)
248 printf("DotTemplateInstanceExp::findTempDecl('%s')\n", exp.toChars());
250 if (ti.tempdecl)
251 return true;
253 Expression e = new DotIdExp(exp.loc, e1, ti.name);
254 e = e.expressionSemantic(sc);
255 if (e.op == EXP.dot)
256 e = (cast(DotExp)e).e2;
258 Dsymbol s = null;
259 switch (e.op)
261 case EXP.overloadSet:
262 s = (cast(OverExp)e).vars;
263 break;
265 case EXP.dotTemplateDeclaration:
266 s = (cast(DotTemplateExp)e).td;
267 break;
269 case EXP.scope_:
270 s = (cast(ScopeExp)e).sds;
271 break;
273 case EXP.dotVariable:
274 s = (cast(DotVarExp)e).var;
275 break;
277 case EXP.variable:
278 s = (cast(VarExp)e).var;
279 break;
281 default:
282 return false;
284 return ti.updateTempDecl(sc, s);
287 /***********************************************************
288 * Resolve `exp` as a compile-time known string.
289 * Params:
290 * sc = scope
291 * exp = Expression which expected as a string
292 * s = What the string is expected for, will be used in error diagnostic.
293 * Returns:
294 * String literal, or `null` if error happens.
296 StringExp semanticString(Scope *sc, Expression exp, const char* s)
298 sc = sc.startCTFE();
299 exp = exp.expressionSemantic(sc);
300 exp = resolveProperties(sc, exp);
301 sc = sc.endCTFE();
303 if (exp.op == EXP.error)
304 return null;
306 auto e = exp;
307 if (exp.type.isString())
309 e = e.ctfeInterpret();
310 if (e.op == EXP.error)
311 return null;
314 auto se = e.toStringExp();
315 if (!se)
317 error(exp.loc, "`string` expected for %s, not `(%s)` of type `%s`",
318 s, exp.toChars(), exp.type.toChars());
319 return null;
321 return se;
324 /****************************************
325 * Convert string to char[].
327 StringExp toUTF8(StringExp se, Scope* sc)
329 if (se.sz != 1)
331 // Convert to UTF-8 string
332 se.committed = false;
333 Expression e = castTo(se, sc, Type.tchar.arrayOf());
334 e = e.optimize(WANTvalue);
335 auto result = e.isStringExp();
336 assert(result.sz == 1);
337 return result;
339 return se;
342 private Expression reorderSettingAAElem(BinExp exp, Scope* sc)
344 BinExp be = exp;
346 auto ie = be.e1.isIndexExp();
347 if (!ie)
348 return be;
349 if (ie.e1.type.toBasetype().ty != Taarray)
350 return be;
352 /* Fix evaluation order of setting AA element
353 * https://issues.dlang.org/show_bug.cgi?id=3825
354 * Rewrite:
355 * aa[k1][k2][k3] op= val;
356 * as:
357 * auto ref __aatmp = aa;
358 * auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3;
359 * auto ref __aaval = val;
360 * __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval; // assignment
363 Expression e0;
364 while (1)
366 Expression de;
367 ie.e2 = extractSideEffect(sc, "__aakey", de, ie.e2);
368 e0 = Expression.combine(de, e0);
370 auto ie1 = ie.e1.isIndexExp();
371 if (!ie1 ||
372 ie1.e1.type.toBasetype().ty != Taarray)
374 break;
376 ie = ie1;
378 assert(ie.e1.type.toBasetype().ty == Taarray);
380 Expression de;
381 ie.e1 = extractSideEffect(sc, "__aatmp", de, ie.e1);
382 e0 = Expression.combine(de, e0);
384 be.e2 = extractSideEffect(sc, "__aaval", e0, be.e2, true);
386 //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars());
387 return Expression.combine(e0, be);
390 private Expression checkOpAssignTypes(BinExp binExp, Scope* sc)
392 auto e1 = binExp.e1;
393 auto e2 = binExp.e2;
394 auto op = binExp.op;
395 auto type = binExp.type;
396 auto loc = binExp.loc;
398 // At that point t1 and t2 are the merged types. type is the original type of the lhs.
399 Type t1 = e1.type;
400 Type t2 = e2.type;
402 // T opAssign floating yields a floating. Prevent truncating conversions (float to int).
403 // See https://issues.dlang.org/show_bug.cgi?id=3841.
404 // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ?
405 if (op == EXP.addAssign || op == EXP.minAssign ||
406 op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign ||
407 op == EXP.powAssign)
409 if ((type.isintegral() && t2.isfloating()))
411 warning(loc, "`%s %s %s` is performing truncating conversion", type.toChars(), EXPtoString(op).ptr, t2.toChars());
415 // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
416 if (op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign)
418 // Any multiplication by an imaginary or complex number yields a complex result.
419 // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
420 const(char)* opstr = EXPtoString(op).ptr;
421 if (t1.isreal() && t2.iscomplex())
423 error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
424 return ErrorExp.get();
426 else if (t1.isimaginary() && t2.iscomplex())
428 error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
429 return ErrorExp.get();
431 else if ((t1.isreal() || t1.isimaginary()) && t2.isimaginary())
433 error(loc, "`%s %s %s` is an undefined operation", t1.toChars(), opstr, t2.toChars());
434 return ErrorExp.get();
438 // generate an error if this is a nonsensical += or -=, eg real += imaginary
439 if (op == EXP.addAssign || op == EXP.minAssign)
441 // Addition or subtraction of a real and an imaginary is a complex result.
442 // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
443 if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex())))
445 error(loc, "`%s %s %s` is undefined (result is complex)", t1.toChars(), EXPtoString(op).ptr, t2.toChars());
446 return ErrorExp.get();
448 if (type.isreal() || type.isimaginary())
450 assert(global.errors || t2.isfloating());
451 e2 = e2.castTo(sc, t1);
454 if (op == EXP.mulAssign)
456 if (t2.isfloating())
458 if (t1.isreal())
460 if (t2.isimaginary() || t2.iscomplex())
462 e2 = e2.castTo(sc, t1);
465 else if (t1.isimaginary())
467 if (t2.isimaginary() || t2.iscomplex())
469 switch (t1.ty)
471 case Timaginary32:
472 t2 = Type.tfloat32;
473 break;
475 case Timaginary64:
476 t2 = Type.tfloat64;
477 break;
479 case Timaginary80:
480 t2 = Type.tfloat80;
481 break;
483 default:
484 assert(0);
486 e2 = e2.castTo(sc, t2);
491 else if (op == EXP.divAssign)
493 if (t2.isimaginary())
495 if (t1.isreal())
497 // x/iv = i(-x/v)
498 // Therefore, the result is 0
499 e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1));
500 e2.type = t1;
501 Expression e = new AssignExp(loc, e1, e2);
502 e.type = t1;
503 return e;
505 else if (t1.isimaginary())
507 Type t3;
508 switch (t1.ty)
510 case Timaginary32:
511 t3 = Type.tfloat32;
512 break;
514 case Timaginary64:
515 t3 = Type.tfloat64;
516 break;
518 case Timaginary80:
519 t3 = Type.tfloat80;
520 break;
522 default:
523 assert(0);
525 e2 = e2.castTo(sc, t3);
526 Expression e = new AssignExp(loc, e1, e2);
527 e.type = t1;
528 return e;
532 else if (op == EXP.modAssign)
534 if (t2.iscomplex())
536 error(loc, "cannot perform modulo complex arithmetic");
537 return ErrorExp.get();
540 return binExp;
543 private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue)
545 Expression e0;
546 Expression e1 = Expression.extractLast(ue.e1, e0);
547 // https://issues.dlang.org/show_bug.cgi?id=12585
548 // Extract the side effect part if ue.e1 is comma.
550 if ((sc.flags & SCOPE.ctfe) ? hasSideEffect(e1) : !isTrivialExp(e1)) // match logic in extractSideEffect()
552 /* Even if opDollar is needed, 'e1' should be evaluate only once. So
553 * Rewrite:
554 * e1.opIndex( ... use of $ ... )
555 * e1.opSlice( ... use of $ ... )
556 * as:
557 * (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...)
558 * (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
560 e1 = extractSideEffect(sc, "__dop", e0, e1, false);
561 assert(e1.isVarExp());
562 e1.isVarExp().var.storage_class |= STC.exptemp; // lifetime limited to expression
564 ue.e1 = e1;
565 return e0;
568 /****************************************
569 * Expand alias this tuples.
571 TupleDeclaration isAliasThisTuple(Expression e)
573 if (!e.type)
574 return null;
576 Type t = e.type.toBasetype();
577 while (true)
579 if (Dsymbol s = t.toDsymbol(null))
581 if (auto ad = s.isAggregateDeclaration())
583 s = ad.aliasthis ? ad.aliasthis.sym : null;
584 if (s && s.isVarDeclaration())
586 TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration();
587 if (td && td.isexp)
588 return td;
590 if (Type att = t.aliasthisOf())
592 t = att;
593 continue;
597 return null;
601 /**************************************
602 * Runs semantic on ae.arguments. Declares temporary variables
603 * if '$' was used.
605 Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0)
607 assert(!ae.lengthVar);
608 *pe0 = null;
609 AggregateDeclaration ad = isAggregate(ae.e1.type);
610 Dsymbol slice = search_function(ad, Id.slice);
611 //printf("slice = %s %s\n", slice.kind(), slice.toChars());
612 foreach (i, e; *ae.arguments)
614 if (i == 0)
615 *pe0 = extractOpDollarSideEffect(sc, ae);
617 if (e.op == EXP.interval && !(slice && slice.isTemplateDeclaration()))
619 Lfallback:
620 if (ae.arguments.length == 1)
621 return null;
622 error(ae.loc, "multi-dimensional slicing requires template `opSlice`");
623 return ErrorExp.get();
625 //printf("[%d] e = %s\n", i, e.toChars());
627 // Create scope for '$' variable for this dimension
628 auto sym = new ArrayScopeSymbol(sc, ae);
629 sym.parent = sc.scopesym;
630 sc = sc.push(sym);
631 ae.lengthVar = null; // Create it only if required
632 ae.currentDimension = i; // Dimension for $, if required
634 e = e.expressionSemantic(sc);
635 e = resolveProperties(sc, e);
637 if (ae.lengthVar && sc.func)
639 // If $ was used, declare it now
640 Expression de = new DeclarationExp(ae.loc, ae.lengthVar);
641 de = de.expressionSemantic(sc);
642 *pe0 = Expression.combine(*pe0, de);
644 sc = sc.pop();
646 if (auto ie = e.isIntervalExp())
648 auto tiargs = new Objects();
649 Expression edim = new IntegerExp(ae.loc, i, Type.tsize_t);
650 edim = edim.expressionSemantic(sc);
651 tiargs.push(edim);
653 auto fargs = new Expressions(2);
654 (*fargs)[0] = ie.lwr;
655 (*fargs)[1] = ie.upr;
657 uint xerrors = global.startGagging();
658 sc = sc.push();
659 FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, ArgumentList(fargs), FuncResolveFlag.quiet);
660 sc = sc.pop();
661 global.endGagging(xerrors);
662 if (!fslice)
663 goto Lfallback;
665 e = new DotTemplateInstanceExp(ae.loc, ae.e1, slice.ident, tiargs);
666 e = new CallExp(ae.loc, e, fargs);
667 e = e.expressionSemantic(sc);
670 if (!e.type)
672 error(ae.loc, "`%s` has no value", e.toChars());
673 e = ErrorExp.get();
675 if (e.op == EXP.error)
676 return e;
678 (*ae.arguments)[i] = e;
680 return ae;
683 /**************************************
684 * Runs semantic on se.lwr and se.upr. Declares a temporary variable
685 * if '$' was used.
686 * Returns:
687 * ae, or ErrorExp if errors occurred
689 Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* pe0)
691 //assert(!ae.lengthVar);
692 if (!ie)
693 return ae;
695 VarDeclaration lengthVar = ae.lengthVar;
696 bool errors = false;
698 // create scope for '$'
699 auto sym = new ArrayScopeSymbol(sc, ae);
700 sym.parent = sc.scopesym;
701 sc = sc.push(sym);
703 Expression sem(Expression e)
705 e = e.expressionSemantic(sc);
706 e = resolveProperties(sc, e);
707 if (!e.type)
709 error(ae.loc, "`%s` has no value", e.toChars());
710 errors = true;
712 return e;
715 ie.lwr = sem(ie.lwr);
716 ie.upr = sem(ie.upr);
718 if (ie.lwr.isErrorExp() || ie.upr.isErrorExp())
719 errors = true;
721 if (lengthVar != ae.lengthVar && sc.func)
723 // If $ was used, declare it now
724 Expression de = new DeclarationExp(ae.loc, ae.lengthVar);
725 de = de.expressionSemantic(sc);
726 *pe0 = Expression.combine(*pe0, de);
729 sc = sc.pop();
731 return errors ? ErrorExp.get() : ae;
734 /******************************
735 * Perform semantic() on an array of Expressions.
737 extern(D) bool arrayExpressionSemantic(
738 Expression[] exps, Scope* sc, bool preserveErrors = false)
740 bool err = false;
741 foreach (ref e; exps)
743 if (e is null) continue;
744 auto e2 = e.expressionSemantic(sc);
745 if (e2.op == EXP.error)
746 err = true;
747 if (preserveErrors || e2.op != EXP.error)
748 e = e2;
750 return err;
753 /************************************************
754 * Handle the postblit call on lvalue, or the move of rvalue.
756 * Params:
757 * sc = the scope where the expression is encountered
758 * e = the expression the needs to be moved or copied (source)
759 * t = if the struct defines a copy constructor, the type of the destination
761 * Returns:
762 * The expression that copy constructs or moves the value.
764 extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t = null)
766 if (auto ce = e.isCondExp())
768 ce.e1 = doCopyOrMove(sc, ce.e1);
769 ce.e2 = doCopyOrMove(sc, ce.e2);
771 else
773 e = e.isLvalue() ? callCpCtor(sc, e, t) : valueNoDtor(e);
775 return e;
778 /*********************************************
779 * If e is an instance of a struct, and that struct has a copy constructor,
780 * rewrite e as:
781 * (tmp = e),tmp
782 * Input:
783 * sc = just used to specify the scope of created temporary variable
784 * destinationType = the type of the object on which the copy constructor is called;
785 * may be null if the struct defines a postblit
787 private Expression callCpCtor(Scope* sc, Expression e, Type destinationType)
789 if (auto ts = e.type.baseElemOf().isTypeStruct())
791 StructDeclaration sd = ts.sym;
792 if (sd.postblit || sd.hasCopyCtor)
794 /* Create a variable tmp, and replace the argument e with:
795 * (tmp = e),tmp
796 * and let AssignExp() handle the construction.
797 * This is not the most efficient, ideally tmp would be constructed
798 * directly onto the stack.
800 auto tmp = copyToTemp(STC.rvalue, "__copytmp", e);
801 if (sd.hasCopyCtor && destinationType)
803 // https://issues.dlang.org/show_bug.cgi?id=22619
804 // If the destination type is inout we can preserve it
805 // only if inside an inout function; if we are not inside
806 // an inout function, then we will preserve the type of
807 // the source
808 if (destinationType.hasWild && !(sc.func.storage_class & STC.wild))
809 tmp.type = e.type;
810 else
811 tmp.type = destinationType;
813 tmp.storage_class |= STC.nodtor;
814 tmp.dsymbolSemantic(sc);
815 Expression de = new DeclarationExp(e.loc, tmp);
816 Expression ve = new VarExp(e.loc, tmp);
817 de.type = Type.tvoid;
818 ve.type = e.type;
819 return Expression.combine(de, ve);
822 return e;
825 /************************************************
826 * If we want the value of this expression, but do not want to call
827 * the destructor on it.
829 Expression valueNoDtor(Expression e)
831 auto ex = lastComma(e);
833 if (auto ce = ex.isCallExp())
835 /* The struct value returned from the function is transferred
836 * so do not call the destructor on it.
837 * Recognize:
838 * ((S _ctmp = S.init), _ctmp).this(...)
839 * and make sure the destructor is not called on _ctmp
840 * BUG: if ex is a CommaExp, we should go down the right side.
842 if (auto dve = ce.e1.isDotVarExp())
844 if (dve.var.isCtorDeclaration())
846 // It's a constructor call
847 if (auto comma = dve.e1.isCommaExp())
849 if (auto ve = comma.e2.isVarExp())
851 VarDeclaration ctmp = ve.var.isVarDeclaration();
852 if (ctmp)
854 ctmp.storage_class |= STC.nodtor;
855 assert(!ce.isLvalue());
862 else if (auto ve = ex.isVarExp())
864 auto vtmp = ve.var.isVarDeclaration();
865 if (vtmp && (vtmp.storage_class & STC.rvalue))
867 vtmp.storage_class |= STC.nodtor;
870 return e;
874 Checks if `exp` contains a direct access to a `noreturn`
875 variable. If that is the case, an `assert(0)` expression
876 is generated and returned. This function should be called
877 only after semantic analysis has been performed on `exp`.
879 Params:
880 exp = expression that is checked
882 Returns:
883 An `assert(0)` expression if `exp` contains a `noreturn`
884 variable access, `exp` otherwise.
887 Expression checkNoreturnVarAccess(Expression exp)
889 assert(exp.type);
891 Expression result = exp;
892 if (exp.type.isTypeNoreturn() && !exp.isAssertExp() &&
893 !exp.isThrowExp() && !exp.isCallExp())
895 auto msg = new StringExp(exp.loc, "Accessed expression of type `noreturn`");
896 msg.type = Type.tstring;
897 result = new AssertExp(exp.loc, IntegerExp.literal!0, msg);
898 result.type = exp.type;
901 return result;
904 /******************************
905 * Find symbol in accordance with the UFCS name look up rule
907 private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
909 //printf("searchUFCS(ident = %s)\n", ident.toChars());
910 Loc loc = ue.loc;
912 // TODO: merge with Scope.search.searchScopes()
913 Dsymbol searchScopes(SearchOptFlags flags)
915 Dsymbol s = null;
916 for (Scope* scx = sc; scx; scx = scx.enclosing)
918 if (!scx.scopesym)
919 continue;
920 if (scx.scopesym.isModule())
921 flags |= SearchOpt.unqualifiedModule; // tell Module.search() that SearchOpt.localsOnly is to be obeyed
922 s = scx.scopesym.search(loc, ident, flags);
923 if (s)
925 // overload set contains only module scope symbols.
926 if (s.isOverloadSet())
927 break;
928 // selective/renamed imports also be picked up
929 if (AliasDeclaration ad = s.isAliasDeclaration())
931 if (ad._import)
932 break;
934 // See only module scope symbols for UFCS target.
935 Dsymbol p = s.toParent2();
936 if (p && p.isModule())
937 break;
939 s = null;
941 // Stop when we hit a module, but keep going if that is not just under the global scope
942 if (scx.scopesym.isModule() && !(scx.enclosing && !scx.enclosing.enclosing))
943 break;
945 return s;
948 SearchOptFlags flags = SearchOpt.all;
949 Dsymbol s;
951 if (sc.flags & SCOPE.ignoresymbolvisibility)
952 flags |= SearchOpt.ignoreVisibility;
954 // First look in local scopes
955 s = searchScopes(flags | SearchOpt.localsOnly);
956 if (!s)
958 // Second look in imported modules
959 s = searchScopes(flags | SearchOpt.importsOnly);
962 if (!s)
963 return ue.e1.type.getProperty(sc, loc, ident, 0, ue.e1);
965 FuncDeclaration f = s.isFuncDeclaration();
966 if (f)
968 TemplateDeclaration td = getFuncTemplateDecl(f);
969 if (td)
971 if (td.overroot)
972 td = td.overroot;
973 s = td;
977 if (auto dti = ue.isDotTemplateInstanceExp())
979 // https://issues.dlang.org/show_bug.cgi?id=23968
980 // Typically, deprecated alias declarations are caught
981 // when `TemplateInstance.findTempDecl` is called,
982 // however, in this case the tempdecl field is updated
983 // therefore `findTempDecl` will return immediately
984 // and not get the chance to issue the deprecation.
985 if (s.isAliasDeclaration())
986 s.checkDeprecated(ue.loc, sc);
988 auto ti = new TemplateInstance(loc, s.ident, dti.ti.tiargs);
989 if (!ti.updateTempDecl(sc, s))
990 return ErrorExp.get();
991 return new ScopeExp(loc, ti);
993 else
995 //printf("-searchUFCS() %s\n", s.toChars());
996 return new DsymbolExp(loc, s);
1000 /******************************
1001 * check e is exp.opDispatch!(tiargs) or not
1002 * It's used to switch to UFCS the semantic analysis path
1004 private bool isDotOpDispatch(Expression e)
1006 if (auto dtie = e.isDotTemplateInstanceExp())
1007 return dtie.ti.name == Id.opDispatch;
1008 return false;
1011 private void hookDtors(CondExp ce, Scope* sc)
1013 extern (C++) final class DtorVisitor : StoppableVisitor
1015 alias visit = typeof(super).visit;
1016 public:
1017 Scope* sc;
1018 CondExp ce;
1019 VarDeclaration vcond;
1020 bool isThen;
1022 extern (D) this(Scope* sc, CondExp ce) @safe
1024 this.sc = sc;
1025 this.ce = ce;
1028 override void visit(Expression e)
1030 //printf("(e = %s)\n", e.toChars());
1033 override void visit(DeclarationExp e)
1035 auto v = e.declaration.isVarDeclaration();
1036 if (v && !v.isDataseg())
1038 if (v._init)
1040 if (auto ei = v._init.isExpInitializer())
1041 walkPostorder(ei.exp, this);
1044 if (v.edtor)
1045 walkPostorder(v.edtor, this);
1047 if (v.needsScopeDtor())
1049 if (!vcond)
1051 vcond = copyToTemp(STC.volatile_ | STC.const_, "__cond", ce.econd);
1052 vcond.dsymbolSemantic(sc);
1054 Expression de = new DeclarationExp(ce.econd.loc, vcond);
1055 de = de.expressionSemantic(sc);
1057 Expression ve = new VarExp(ce.econd.loc, vcond);
1058 ce.econd = Expression.combine(de, ve);
1061 //printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
1062 Expression ve = new VarExp(vcond.loc, vcond);
1063 if (isThen)
1064 v.edtor = new LogicalExp(v.edtor.loc, EXP.andAnd, ve, v.edtor);
1065 else
1066 v.edtor = new LogicalExp(v.edtor.loc, EXP.orOr, ve, v.edtor);
1067 v.edtor = v.edtor.expressionSemantic(sc);
1068 //printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
1074 scope DtorVisitor v = new DtorVisitor(sc, ce);
1075 //printf("+%s\n", toChars());
1076 v.isThen = true;
1077 walkPostorder(ce.e1, v);
1078 v.isThen = false;
1079 walkPostorder(ce.e2, v);
1080 //printf("-%s\n", toChars());
1084 /******************************
1085 * Pull out callable entity with UFCS.
1087 private Expression resolveUFCS(Scope* sc, CallExp ce)
1089 Loc loc = ce.loc;
1090 Expression eleft;
1091 Expression e;
1093 if (auto die = ce.e1.isDotIdExp())
1095 Identifier ident = die.ident;
1097 Expression ex = die.dotIdSemanticPropX(sc);
1098 if (ex != die)
1100 ce.e1 = ex;
1101 return null;
1103 eleft = die.e1;
1105 Type t = eleft.type.toBasetype();
1106 if (t.ty == Tarray || t.ty == Tsarray || t.ty == Tnull || (t.isTypeBasic() && t.ty != Tvoid))
1108 /* Built-in types and arrays have no callable properties, so do shortcut.
1109 * It is necessary in: e.init()
1112 else if (t.ty == Taarray)
1114 if (ident == Id.remove)
1116 /* Transform:
1117 * aa.remove(arg) into delete aa[arg]
1119 if (!ce.arguments || ce.arguments.length != 1)
1121 error(ce.loc, "expected key as argument to `aa.remove()`");
1122 return ErrorExp.get();
1124 if (!eleft.type.isMutable())
1126 error(ce.loc, "cannot remove key from `%s` associative array `%s`", MODtoChars(t.mod), eleft.toChars());
1127 return ErrorExp.get();
1129 Expression key = (*ce.arguments)[0];
1130 key = key.expressionSemantic(sc);
1131 key = resolveProperties(sc, key);
1133 TypeAArray taa = t.isTypeAArray();
1134 key = key.implicitCastTo(sc, taa.index);
1136 if (key.checkValue() || key.checkSharedAccess(sc))
1137 return ErrorExp.get();
1139 semanticTypeInfo(sc, taa.index);
1141 return new RemoveExp(loc, eleft, key);
1144 else
1146 if (Expression ey = die.dotIdSemanticProp(sc, 1))
1148 if (ey.op == EXP.error)
1149 return ey;
1150 ce.e1 = ey;
1151 if (isDotOpDispatch(ey))
1153 // even opDispatch and UFCS must have valid arguments,
1154 // so now that we've seen indication of a problem,
1155 // check them for issues.
1156 Expressions* originalArguments = Expression.arraySyntaxCopy(ce.arguments);
1158 uint errors = global.startGagging();
1159 e = ce.expressionSemantic(sc);
1160 if (!global.endGagging(errors))
1161 return e;
1163 if (arrayExpressionSemantic(originalArguments.peekSlice(), sc))
1164 return ErrorExp.get();
1166 /* fall down to UFCS */
1168 else
1169 return null;
1173 /* https://issues.dlang.org/show_bug.cgi?id=13953
1175 * If a struct has an alias this to an associative array
1176 * and remove is used on a struct instance, we have to
1177 * check first if there is a remove function that can be called
1178 * on the struct. If not we must check the alias this.
1180 * struct A
1182 * string[string] a;
1183 * alias a this;
1186 * void fun()
1188 * A s;
1189 * s.remove("foo");
1192 const errors = global.startGagging();
1193 e = searchUFCS(sc, die, ident);
1194 // if there were any errors and the identifier was remove
1195 if (global.endGagging(errors))
1197 if (ident == Id.remove)
1199 // check alias this
1200 Expression alias_e = resolveAliasThis(sc, die.e1, 1);
1201 if (alias_e && alias_e != die.e1)
1203 die.e1 = alias_e;
1204 CallExp ce2 = ce.syntaxCopy();
1205 ce2.e1 = die;
1206 e = ce2.isCallExp().trySemantic(sc);
1207 if (e)
1208 return e;
1211 // if alias this did not work out, print the initial errors
1212 searchUFCS(sc, die, ident);
1215 else if (auto dti = ce.e1.isDotTemplateInstanceExp())
1217 if (Expression ey = dti.dotTemplateSemanticProp(sc, DotExpFlag.gag))
1219 ce.e1 = ey;
1220 return null;
1222 eleft = dti.e1;
1223 e = searchUFCS(sc, dti, dti.ti.name);
1225 else
1226 return null;
1228 // Rewrite
1229 ce.e1 = e;
1230 if (!ce.arguments)
1231 ce.arguments = new Expressions();
1232 ce.arguments.shift(eleft);
1233 if (!ce.names)
1234 ce.names = new Identifiers();
1235 ce.names.shift(null);
1236 ce.isUfcsRewrite = true;
1237 return null;
1240 int expandAliasThisTuples(Expressions* exps, size_t starti = 0)
1242 if (!exps || exps.length == 0)
1243 return -1;
1245 for (size_t u = starti; u < exps.length; u++)
1247 Expression exp = (*exps)[u];
1248 if (TupleDeclaration td = exp.isAliasThisTuple)
1250 exps.remove(u);
1251 size_t i;
1252 td.foreachVar((s)
1254 auto d = s.isDeclaration();
1255 auto e = new DotVarExp(exp.loc, exp, d);
1256 assert(d.type);
1257 e.type = d.type;
1258 exps.insert(u + i, e);
1259 ++i;
1261 version (none)
1263 printf("expansion ->\n");
1264 foreach (e; exps)
1266 printf("\texps[%d] e = %s %s\n", i, EXPtoString(e.op), e.toChars());
1269 return cast(int)u;
1272 return -1;
1275 /******************************
1276 * Pull out property with UFCS.
1278 private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2 = null)
1280 Loc loc = e1.loc;
1281 Expression eleft;
1282 Expression e;
1284 if (auto die = e1.isDotIdExp())
1286 eleft = die.e1;
1287 e = searchUFCS(sc, die, die.ident);
1289 else if (auto dti = e1.isDotTemplateInstanceExp())
1291 eleft = dti.e1;
1292 e = searchUFCS(sc, dti, dti.ti.name);
1294 else
1295 return null;
1297 if (e is null)
1298 return null;
1300 // Rewrite
1301 if (e2)
1303 // run semantic without gagging
1304 e2 = e2.expressionSemantic(sc);
1306 /* f(e1) = e2
1308 Expression ex = e.copy();
1309 auto a1 = new Expressions(1);
1310 (*a1)[0] = eleft;
1311 ex = new CallExp(loc, ex, a1);
1312 auto e1PassSemantic = ex.trySemantic(sc);
1314 /* f(e1, e2)
1316 auto a2 = new Expressions(2);
1317 (*a2)[0] = eleft;
1318 (*a2)[1] = e2;
1319 e = new CallExp(loc, e, a2);
1320 e = e.trySemantic(sc);
1321 if (!e1PassSemantic && !e)
1323 /* https://issues.dlang.org/show_bug.cgi?id=20448
1325 * If both versions have failed to pass semantic,
1326 * f(e1) = e2 gets priority in error printing
1327 * because f might be a templated function that
1328 * failed to instantiate and we have to print
1329 * the instantiation errors.
1331 return e1.expressionSemantic(sc);
1333 else if (ex && !e)
1335 ex = new AssignExp(loc, ex, e2);
1336 return ex.expressionSemantic(sc);
1338 else
1340 // strict setter prints errors if fails
1341 e = e.expressionSemantic(sc);
1343 return e;
1345 else
1347 /* f(e1)
1349 auto arguments = new Expressions(1);
1350 (*arguments)[0] = eleft;
1351 e = new CallExp(loc, e, arguments);
1353 // https://issues.dlang.org/show_bug.cgi?id=24017
1354 if (sc.flags & SCOPE.debug_)
1355 e.isCallExp().inDebugStatement = true;
1357 e = e.expressionSemantic(sc);
1358 return e;
1362 /******************************
1363 * If e1 is a property function (template), resolve it.
1365 Expression resolvePropertiesOnly(Scope* sc, Expression e1)
1367 //printf("e1 = %s %s\n", Token.toChars(e1.op), e1.toChars());
1369 Expression handleOverloadSet(OverloadSet os)
1371 assert(os);
1372 foreach (s; os.a)
1374 auto fd = s.isFuncDeclaration();
1375 auto td = s.isTemplateDeclaration();
1376 if (fd)
1378 if (fd.type.isTypeFunction().isproperty)
1379 return resolveProperties(sc, e1);
1381 else if (td && td.onemember && (fd = td.onemember.isFuncDeclaration()) !is null)
1383 if (fd.type.isTypeFunction().isproperty ||
1384 (fd.storage_class2 & STC.property) ||
1385 (td._scope.stc & STC.property))
1386 return resolveProperties(sc, e1);
1389 return e1;
1392 Expression handleTemplateDecl(TemplateDeclaration td)
1394 assert(td);
1395 if (td.onemember)
1397 if (auto fd = td.onemember.isFuncDeclaration())
1399 if (fd.type.isTypeFunction().isproperty ||
1400 (fd.storage_class2 & STC.property) ||
1401 (td._scope.stc & STC.property))
1402 return resolveProperties(sc, e1);
1405 return e1;
1408 Expression handleFuncDecl(FuncDeclaration fd)
1410 assert(fd);
1411 if (fd.type.isTypeFunction().isproperty)
1412 return resolveProperties(sc, e1);
1413 return e1;
1416 if (auto de = e1.isDotExp())
1418 if (auto os = de.e2.isOverExp())
1419 return handleOverloadSet(os.vars);
1421 else if (auto oe = e1.isOverExp())
1422 return handleOverloadSet(oe.vars);
1423 else if (auto dti = e1.isDotTemplateInstanceExp())
1425 if (dti.ti.tempdecl)
1426 if (auto td = dti.ti.tempdecl.isTemplateDeclaration())
1427 return handleTemplateDecl(td);
1429 else if (auto dte = e1.isDotTemplateExp())
1430 return handleTemplateDecl(dte.td);
1431 else if (auto se = e1.isScopeExp())
1433 Dsymbol s = se.sds;
1434 TemplateInstance ti = s.isTemplateInstance();
1435 if (ti && !ti.semanticRun && ti.tempdecl)
1436 if (auto td = ti.tempdecl.isTemplateDeclaration())
1437 return handleTemplateDecl(td);
1439 else if (auto et = e1.isTemplateExp())
1440 return handleTemplateDecl(et.td);
1441 else if (e1.isDotVarExp() && e1.type.isTypeFunction())
1443 DotVarExp dve = e1.isDotVarExp();
1444 return handleFuncDecl(dve.var.isFuncDeclaration());
1446 else if (e1.isVarExp() && e1.type && e1.type.isTypeFunction() && (sc.intypeof || !e1.isVarExp().var.needThis()))
1447 return handleFuncDecl(e1.isVarExp().var.isFuncDeclaration());
1448 return e1;
1451 /****************************************
1452 * Turn symbol `s` into the expression it represents.
1454 * Params:
1455 * s = symbol to resolve
1456 * loc = location of use of `s`
1457 * sc = context
1458 * hasOverloads = applies if `s` represents a function.
1459 * true means it's overloaded and will be resolved later,
1460 * false means it's the exact function symbol.
1461 * Returns:
1462 * `s` turned into an expression, `ErrorExp` if an error occurred
1464 Expression symbolToExp(Dsymbol s, const ref Loc loc, Scope *sc, bool hasOverloads)
1466 static if (LOGSEMANTIC)
1468 printf("DsymbolExp::resolve(%s %s)\n", s.kind(), s.toChars());
1471 Lagain:
1472 Expression e;
1474 //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars());
1475 //printf("s = '%s', s.kind = '%s'\n", s.toChars(), s.kind());
1476 Dsymbol olds = s;
1477 Declaration d = s.isDeclaration();
1478 if (d && (d.storage_class & STC.templateparameter))
1480 s = s.toAlias();
1482 else
1484 // functions are checked after overloading
1485 // templates are checked after matching constraints
1486 if (!s.isFuncDeclaration() && !s.isTemplateDeclaration())
1488 s.checkDeprecated(loc, sc);
1489 if (d)
1490 d.checkDisabled(loc, sc);
1493 // https://issues.dlang.org/show_bug.cgi?id=12023
1494 // if 's' is a tuple variable, the tuple is returned.
1495 s = s.toAlias();
1497 //printf("s = '%s', s.kind = '%s', s.needThis() = %p\n", s.toChars(), s.kind(), s.needThis());
1498 if (s != olds && !s.isFuncDeclaration() && !s.isTemplateDeclaration())
1500 s.checkDeprecated(loc, sc);
1501 if (d)
1502 d.checkDisabled(loc, sc);
1505 if (auto sd = s.isDeclaration())
1507 if (sd.isSystem())
1509 if (sc.setUnsafePreview(global.params.systemVariables, false, loc,
1510 "cannot access `@system` variable `%s` in @safe code", sd))
1512 if (auto v = sd.isVarDeclaration())
1514 if (v.systemInferred)
1515 errorSupplemental(v.loc, "`%s` is inferred to be `@system` from its initializer here", v.toChars());
1516 else
1517 errorSupplemental(v.loc, "`%s` is declared here", v.toChars());
1519 return ErrorExp.get();
1525 if (auto em = s.isEnumMember())
1527 return em.getVarExp(loc, sc);
1529 if (auto v = s.isVarDeclaration())
1531 //printf("Identifier '%s' is a variable, type '%s'\n", s.toChars(), v.type.toChars());
1532 if (sc.intypeof == 1 && !v.inuse)
1533 v.dsymbolSemantic(sc);
1534 if (!v.type || // during variable type inference
1535 !v.type.deco && v.inuse) // during variable type semantic
1537 if (v.inuse) // variable type depends on the variable itself
1538 error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
1539 else // variable type cannot be determined
1540 error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
1541 return ErrorExp.get();
1543 if (v.type.ty == Terror)
1544 return ErrorExp.get();
1546 if ((v.storage_class & STC.manifest) && v._init)
1548 if (v.inuse)
1550 error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
1551 return ErrorExp.get();
1553 e = v.expandInitializer(loc);
1554 v.inuse++;
1555 e = e.expressionSemantic(sc);
1556 v.inuse--;
1557 return e;
1560 // We need to run semantics to correctly set 'STC.field' if it is a member variable
1561 // that could be forward referenced. This is needed for 'v.needThis()' to work
1562 if (v.isThis())
1563 v.dsymbolSemantic(sc);
1565 // Change the ancestor lambdas to delegate before hasThis(sc) call.
1566 if (v.checkNestedReference(sc, loc))
1567 return ErrorExp.get();
1569 if (v.needThis() && hasThis(sc))
1570 e = new DotVarExp(loc, new ThisExp(loc), v);
1571 else
1572 e = new VarExp(loc, v);
1573 e = e.expressionSemantic(sc);
1574 return e;
1576 if (auto fld = s.isFuncLiteralDeclaration())
1578 //printf("'%s' is a function literal\n", fld.toChars());
1579 e = new FuncExp(loc, fld);
1580 return e.expressionSemantic(sc);
1582 if (auto f = s.isFuncDeclaration())
1584 f = f.toAliasFunc();
1585 if (!functionSemantic(f))
1586 return ErrorExp.get();
1588 if (!hasOverloads && f.checkForwardRef(loc))
1589 return ErrorExp.get();
1591 auto fd = s.isFuncDeclaration();
1592 fd.type = f.type;
1593 return new VarExp(loc, fd, hasOverloads);
1595 if (OverDeclaration od = s.isOverDeclaration())
1597 e = new VarExp(loc, od, true);
1598 e.type = Type.tvoid;
1599 return e;
1601 if (OverloadSet o = s.isOverloadSet())
1603 //printf("'%s' is an overload set\n", o.toChars());
1604 return new OverExp(loc, o);
1607 if (Import imp = s.isImport())
1609 if (!imp.pkg)
1611 .error(loc, "forward reference of import `%s`", imp.toChars());
1612 return ErrorExp.get();
1614 auto ie = new ScopeExp(loc, imp.pkg);
1615 return ie.expressionSemantic(sc);
1617 if (Package pkg = s.isPackage())
1619 auto ie = new ScopeExp(loc, pkg);
1620 return ie.expressionSemantic(sc);
1622 if (Module mod = s.isModule())
1624 auto ie = new ScopeExp(loc, mod);
1625 return ie.expressionSemantic(sc);
1627 if (Nspace ns = s.isNspace())
1629 auto ie = new ScopeExp(loc, ns);
1630 return ie.expressionSemantic(sc);
1633 if (Type t = s.getType())
1635 return (new TypeExp(loc, t)).expressionSemantic(sc);
1638 if (TupleDeclaration tup = s.isTupleDeclaration())
1640 if (tup.needThis() && hasThis(sc))
1641 e = new DotVarExp(loc, new ThisExp(loc), tup);
1642 else
1643 e = new TupleExp(loc, tup);
1644 e = e.expressionSemantic(sc);
1645 return e;
1648 if (TemplateInstance ti = s.isTemplateInstance())
1650 ti.dsymbolSemantic(sc);
1651 if (!ti.inst || ti.errors)
1652 return ErrorExp.get();
1653 s = ti.toAlias();
1654 if (!s.isTemplateInstance())
1655 goto Lagain;
1656 e = new ScopeExp(loc, ti);
1657 e = e.expressionSemantic(sc);
1658 return e;
1660 if (TemplateDeclaration td = s.isTemplateDeclaration())
1662 Dsymbol p = td.toParentLocal();
1663 FuncDeclaration fdthis = hasThis(sc);
1664 AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null;
1665 if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0)
1667 e = new DotTemplateExp(loc, new ThisExp(loc), td);
1669 else
1670 e = new TemplateExp(loc, td);
1671 e = e.expressionSemantic(sc);
1672 return e;
1675 .error(loc, "%s `%s` is not a variable", s.kind(), s.toChars());
1676 return ErrorExp.get();
1679 /*************************************************************
1680 * Given var, get the
1681 * right `this` pointer if var is in an outer class, but our
1682 * existing `this` pointer is in an inner class.
1683 * Params:
1684 * loc = location to use for error messages
1685 * sc = context
1686 * ad = struct or class we need the correct `this` for
1687 * e1 = existing `this`
1688 * var = the specific member of ad we're accessing
1689 * flag = if true, return `null` instead of throwing an error
1690 * Returns:
1691 * Expression representing the `this` for the var
1693 private Expression getRightThis(const ref Loc loc, Scope* sc, AggregateDeclaration ad, Expression e1, Dsymbol var, int flag = 0)
1695 //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars());
1697 Type t = e1.type.toBasetype();
1698 //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars());
1700 if (e1.op == EXP.objcClassReference)
1702 // We already have an Objective-C class reference, just use that as 'this'.
1703 return e1;
1705 else if (ad && ad.isClassDeclaration && ad.isClassDeclaration.classKind == ClassKind.objc &&
1706 var.isFuncDeclaration && var.isFuncDeclaration.isStatic &&
1707 var.isFuncDeclaration.objc.selector)
1709 auto cls = ad.isClassDeclaration();
1710 auto classObj = new ObjcClassReferenceExp(e1.loc, cls);
1711 classObj.type = objc.getRuntimeMetaclass(cls).getType();
1712 return classObj;
1715 /* Access of a member which is a template parameter in dual-scope scenario
1716 * class A { inc(alias m)() { ++m; } } // `m` needs `this` of `B`
1717 * class B {int m; inc() { new A().inc!m(); } }
1719 if (e1.op == EXP.this_)
1721 FuncDeclaration f = hasThis(sc);
1722 if (f && f.hasDualContext())
1724 if (f.followInstantiationContext(ad))
1726 e1 = new VarExp(loc, f.vthis);
1727 e1 = new PtrExp(loc, e1);
1728 e1 = new IndexExp(loc, e1, IntegerExp.literal!1);
1729 e1 = getThisSkipNestedFuncs(loc, sc, f.toParent2(), ad, e1, t, var);
1730 if (e1.op == EXP.error)
1731 return e1;
1732 goto L1;
1737 /* If e1 is not the 'this' pointer for ad
1739 if (ad &&
1740 !(t.isTypePointer() && t.nextOf().isTypeStruct() && t.nextOf().isTypeStruct().sym == ad) &&
1741 !(t.isTypeStruct() && t.isTypeStruct().sym == ad))
1743 ClassDeclaration cd = ad.isClassDeclaration();
1744 ClassDeclaration tcd = t.isClassHandle();
1746 /* e1 is the right this if ad is a base class of e1
1748 if (!cd || !tcd || !(tcd == cd || cd.isBaseOf(tcd, null)))
1750 /* Only classes can be inner classes with an 'outer'
1751 * member pointing to the enclosing class instance
1753 if (tcd && tcd.isNested())
1755 /* e1 is the 'this' pointer for an inner class: tcd.
1756 * Rewrite it as the 'this' pointer for the outer class.
1758 auto vthis = tcd.followInstantiationContext(ad) ? tcd.vthis2 : tcd.vthis;
1759 e1 = new DotVarExp(loc, e1, vthis);
1760 e1.type = vthis.type;
1761 e1.type = e1.type.addMod(t.mod);
1762 // Do not call ensureStaticLinkTo()
1763 //e1 = e1.semantic(sc);
1765 // Skip up over nested functions, and get the enclosing
1766 // class type.
1767 e1 = getThisSkipNestedFuncs(loc, sc, tcd.toParentP(ad), ad, e1, t, var);
1768 if (e1.op == EXP.error)
1769 return e1;
1770 goto L1;
1773 /* Can't find a path from e1 to ad
1775 if (flag)
1776 return null;
1777 error(e1.loc, "`this` for `%s` needs to be type `%s` not type `%s`", var.toChars(), ad.toChars(), t.toChars());
1778 return ErrorExp.get();
1781 return e1;
1785 * Check whether `outerFunc` and `calledFunc` have the same `this`.
1786 * If `calledFunc` is the member of a base class of the class that contains
1787 * `outerFunc` we consider that they have the same this.
1789 * This function is used to test whether `this` needs to be prepended to
1790 * a function call or function symbol. For example:
1792 * struct X
1794 * void gun() {}
1796 * struct A
1798 * void fun() {}
1799 * void sun()
1801 * fun();
1802 * X.gun(); // error
1806 * When `fun` is called, `outerfunc` = `sun` and `calledFunc = `fun`.
1807 * `sun` is a member of `A` and `fun` is also a member of `A`, therefore
1808 * `this` can be prepended to `fun`. When `gun` is called (it will result
1809 * in an error, but that is not relevant here), which is a member of `X`,
1810 * no `this` is needed because the outer function does not have the same
1811 * `this` as `gun`.
1813 * Returns:
1814 * `true` if outerFunc and calledFunc may use the same `this` pointer.
1815 * `false` otherwise.
1817 private bool haveSameThis(FuncDeclaration outerFunc, FuncDeclaration calledFunc)
1819 // https://issues.dlang.org/show_bug.cgi?id=24013
1820 // traits(getOverloads) inserts an alias to select the overload.
1821 // When searching for the right this we need to use the aliased
1822 // overload/function, not the alias.
1823 outerFunc = outerFunc.toAliasFunc();
1824 calledFunc = calledFunc.toAliasFunc();
1826 auto thisAd = outerFunc.isMemberLocal();
1827 if (!thisAd)
1828 return false;
1830 auto requiredAd = calledFunc.isMemberLocal();
1831 if (!requiredAd)
1832 return false;
1834 if (thisAd == requiredAd)
1835 return true;
1837 // if outerfunc is the member of a nested aggregate, then let
1838 // getRightThis take care of this.
1839 if (thisAd.isNested())
1840 return true;
1842 // outerfunc is the member of a base class that contains calledFunc,
1843 // then we consider that they have the same this.
1844 auto cd = requiredAd.isClassDeclaration();
1845 if (!cd)
1846 return false;
1848 if (cd.isBaseOf2(thisAd.isClassDeclaration()))
1849 return true;
1851 return false;
1854 /*********************************************
1855 * Calling function f.
1856 * Check the purity, i.e. if we're in a pure function
1857 * we can only call other pure functions.
1858 * Returns true if error occurs.
1860 private bool checkPurity(FuncDeclaration f, const ref Loc loc, Scope* sc)
1862 if (!sc.func)
1863 return false;
1864 if (sc.func == f)
1865 return false;
1866 if (sc.intypeof == 1)
1867 return false;
1868 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1869 return false;
1871 // If the call has a pure parent, then the called func must be pure.
1872 if (!f.isPure() && checkImpure(sc, loc, null, f))
1874 error(loc, "`pure` %s `%s` cannot call impure %s `%s`",
1875 sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
1876 f.toPrettyChars());
1878 if (!f.isDtorDeclaration())
1879 errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.pure_);
1881 f.checkOverriddenDtor(sc, loc, dd => dd.type.toTypeFunction().purity != PURE.impure, "impure");
1882 return true;
1884 return false;
1888 * Checks whether `f` is a generated `DtorDeclaration` that hides a user-defined one
1889 * which passes `check` while `f` doesn't (e.g. when the user defined dtor is pure but
1890 * the generated dtor is not).
1891 * In that case the method will identify and print all members causing the attribute
1892 * missmatch.
1894 * Params:
1895 * f = potential `DtorDeclaration`
1896 * sc = scope
1897 * loc = location
1898 * check = current check (e.g. whether it's pure)
1899 * checkName = the kind of check (e.g. `"pure"`)
1901 void checkOverriddenDtor(FuncDeclaration f, Scope* sc, const ref Loc loc,
1902 scope bool function(DtorDeclaration) check, const string checkName)
1904 auto dd = f.isDtorDeclaration();
1905 if (!dd || !dd.isGenerated())
1906 return;
1908 // DtorDeclaration without parents should fail at an earlier stage
1909 auto ad = cast(AggregateDeclaration) f.toParent2();
1910 assert(ad);
1912 if (ad.userDtors.length)
1914 if (!check(ad.userDtors[0])) // doesn't match check (e.g. is impure as well)
1915 return;
1917 // Sanity check
1918 assert(!check(ad.fieldDtor));
1921 dd.loc.errorSupplemental("%s`%s.~this` is %.*s because of the following field's destructors:",
1922 dd.isGenerated() ? "generated " : "".ptr,
1923 ad.toChars,
1924 cast(int) checkName.length, checkName.ptr);
1926 // Search for the offending fields
1927 foreach (field; ad.fields)
1929 // Only structs may define automatically called destructors
1930 auto ts = field.type.isTypeStruct();
1931 if (!ts)
1933 // But they might be part of a static array
1934 auto ta = field.type.isTypeSArray();
1935 if (!ta)
1936 continue;
1938 ts = ta.baseElemOf().isTypeStruct();
1939 if (!ts)
1940 continue;
1943 auto fieldSym = ts.toDsymbol(sc);
1944 assert(fieldSym); // Resolving ts must succeed because missing defs. should error before
1946 auto fieldSd = fieldSym.isStructDeclaration();
1947 assert(fieldSd); // ts is a TypeStruct, this would imply a malformed ASR
1949 if (fieldSd.dtor && !check(fieldSd.dtor))
1951 field.loc.errorSupplemental(" - %s %s", field.type.toChars(), field.toChars());
1953 if (fieldSd.dtor.isGenerated())
1954 fieldSd.dtor.checkOverriddenDtor(sc, loc, check, checkName);
1955 else
1956 fieldSd.dtor.loc.errorSupplemental(" %.*s `%s.~this` is declared here",
1957 cast(int) checkName.length, checkName.ptr, fieldSd.toChars());
1962 /*******************************************
1963 * Accessing variable v.
1964 * Check for purity and safety violations.
1965 * Returns true if error occurs.
1967 private bool checkPurity(VarDeclaration v, const ref Loc loc, Scope* sc)
1969 //printf("v = %s %s\n", v.type.toChars(), v.toChars());
1970 /* Look for purity and safety violations when accessing variable v
1971 * from current function.
1973 if (!sc.func)
1974 return false;
1975 if (sc.intypeof == 1)
1976 return false; // allow violations inside typeof(expression)
1977 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1978 return false; // allow violations inside compile-time evaluated expressions and debug conditionals
1979 if (v.ident == Id.ctfe)
1980 return false; // magic variable never violates pure and safe
1981 if (v.isImmutable())
1982 return false; // always safe and pure to access immutables...
1983 if (v.isConst() && !v.isReference() && (v.isDataseg() || v.isParameter()) && v.type.implicitConvTo(v.type.immutableOf()))
1984 return false; // or const global/parameter values which have no mutable indirections
1985 if (v.storage_class & STC.manifest)
1986 return false; // ...or manifest constants
1988 // accessing empty structs is pure
1989 // https://issues.dlang.org/show_bug.cgi?id=18694
1990 // https://issues.dlang.org/show_bug.cgi?id=21464
1991 // https://issues.dlang.org/show_bug.cgi?id=23589
1992 if (v.type.ty == Tstruct)
1994 StructDeclaration sd = (cast(TypeStruct)v.type).sym;
1995 if (sd.members) // not opaque
1997 if (sd.semanticRun >= PASS.semanticdone)
1998 sd.determineSize(v.loc);
1999 if (sd.hasNoFields)
2000 return false;
2004 bool err = false;
2005 if (v.isDataseg())
2007 // https://issues.dlang.org/show_bug.cgi?id=7533
2008 // Accessing implicit generated __gate is pure.
2009 if (v.ident == Id.gate)
2010 return false;
2012 if (checkImpure(sc, loc, "`pure` %s `%s` cannot access mutable static data `%s`", v))
2014 error(loc, "`pure` %s `%s` cannot access mutable static data `%s`",
2015 sc.func.kind(), sc.func.toPrettyChars(), v.toChars());
2016 err = true;
2019 else
2021 /* Given:
2022 * void f() {
2023 * int fx;
2024 * pure void g() {
2025 * int gx;
2026 * /+pure+/ void h() {
2027 * int hx;
2028 * /+pure+/ void i() { }
2032 * i() can modify hx and gx but not fx
2035 Dsymbol vparent = v.toParent2();
2036 for (Dsymbol s = sc.func; !err && s; s = s.toParentP(vparent))
2038 if (s == vparent)
2039 break;
2041 if (AggregateDeclaration ad = s.isAggregateDeclaration())
2043 if (ad.isNested())
2044 continue;
2045 break;
2047 FuncDeclaration ff = s.isFuncDeclaration();
2048 if (!ff)
2049 break;
2050 if (ff.isNested() || ff.isThis())
2052 if (ff.type.isImmutable() ||
2053 ff.type.isShared() && !MODimplicitConv(ff.type.mod, v.type.mod))
2055 OutBuffer ffbuf;
2056 OutBuffer vbuf;
2057 MODMatchToBuffer(&ffbuf, ff.type.mod, v.type.mod);
2058 MODMatchToBuffer(&vbuf, v.type.mod, ff.type.mod);
2059 error(loc, "%s%s `%s` cannot access %sdata `%s`",
2060 ffbuf.peekChars(), ff.kind(), ff.toPrettyChars(), vbuf.peekChars(), v.toChars());
2061 err = true;
2062 break;
2064 continue;
2066 break;
2070 /* Do not allow safe functions to access __gshared data
2072 if (v.storage_class & STC.gshared)
2074 if (sc.setUnsafe(false, loc,
2075 "`@safe` function `%s` cannot access `__gshared` data `%s`", sc.func, v))
2077 err = true;
2081 return err;
2085 Check if sc.func is impure or can be made impure.
2086 Returns true on error, i.e. if sc.func is pure and cannot be made impure.
2088 private bool checkImpure(Scope* sc, Loc loc, const(char)* fmt, RootObject arg0)
2090 return sc.func && (isRootTraitsCompilesScope(sc)
2091 ? sc.func.isPureBypassingInference() >= PURE.weak
2092 : sc.func.setImpure(loc, fmt, arg0));
2095 /*********************************************
2096 * Calling function f.
2097 * Check the safety, i.e. if we're in a @safe function
2098 * we can only call @safe or @trusted functions.
2099 * Returns true if error occurs.
2101 private bool checkSafety(FuncDeclaration f, ref Loc loc, Scope* sc)
2103 if (sc.func == f)
2104 return false;
2105 if (sc.intypeof == 1)
2106 return false;
2107 if (sc.flags & SCOPE.debug_)
2108 return false;
2109 if ((sc.flags & SCOPE.ctfe) && sc.func)
2110 return false;
2112 if (!sc.func)
2114 if (sc.varDecl && !f.safetyInprocess && !f.isSafe() && !f.isTrusted())
2116 if (sc.varDecl.storage_class & STC.safe)
2118 error(loc, "`@safe` variable `%s` cannot be initialized by calling `@system` function `%s`",
2119 sc.varDecl.toChars(), f.toChars());
2120 return true;
2122 else
2124 sc.varDecl.storage_class |= STC.system;
2125 sc.varDecl.systemInferred = true;
2128 return false;
2131 if (!f.isSafe() && !f.isTrusted())
2133 if (isRootTraitsCompilesScope(sc) ? sc.func.isSafeBypassingInference() : sc.func.setUnsafeCall(f))
2135 if (!loc.isValid()) // e.g. implicitly generated dtor
2136 loc = sc.func.loc;
2138 const prettyChars = f.toPrettyChars();
2139 error(loc, "`@safe` %s `%s` cannot call `@system` %s `%s`",
2140 sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
2141 prettyChars);
2142 if (!f.isDtorDeclaration)
2143 errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.safe);
2144 .errorSupplemental(f.loc, "`%s` is declared here", prettyChars);
2146 f.checkOverriddenDtor(sc, loc, dd => dd.type.toTypeFunction().trust > TRUST.system, "@system");
2148 return true;
2151 else if (f.isSafe() && f.safetyViolation)
2153 // for dip1000 by default transition, print deprecations for calling functions that will become `@system`
2154 if (sc.func.isSafeBypassingInference())
2156 .deprecation(loc, "`@safe` function `%s` calling `%s`", sc.func.toChars(), f.toChars());
2157 errorSupplementalInferredAttr(f, 10, true, STC.safe);
2159 else if (!sc.func.safetyViolation)
2161 import dmd.func : AttributeViolation;
2162 sc.func.safetyViolation = new AttributeViolation(loc, null, f, null, null);
2165 return false;
2168 /*********************************************
2169 * Calling function f.
2170 * Check the @nogc-ness, i.e. if we're in a @nogc function
2171 * we can only call other @nogc functions.
2172 * Returns true if error occurs.
2174 private bool checkNogc(FuncDeclaration f, ref Loc loc, Scope* sc)
2176 if (!sc.func)
2177 return false;
2178 if (sc.func == f)
2179 return false;
2180 if (sc.intypeof == 1)
2181 return false;
2182 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
2183 return false;
2184 /* The original expressions (`new S(...)` or `new S[...]``) will be
2185 * verified instead. This is to keep errors related to the original code
2186 * and not the lowering.
2188 if (f.ident == Id._d_newitemT || f.ident == Id._d_newarrayT || f.ident == Id._d_newarraymTX)
2189 return false;
2191 if (!f.isNogc())
2193 if (isRootTraitsCompilesScope(sc) ? sc.func.isNogcBypassingInference() : sc.func.setGCCall(f))
2195 if (loc.linnum == 0) // e.g. implicitly generated dtor
2196 loc = sc.func.loc;
2198 // Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)),
2199 // so don't print anything to avoid double error messages.
2200 if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT
2201 || f.ident == Id._d_arrayappendT || f.ident == Id._d_arrayappendcTX
2202 || f.ident == Id._d_arraycatnTX || f.ident == Id._d_newclassT))
2204 error(loc, "`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
2205 sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars());
2207 if (!f.isDtorDeclaration)
2208 f.errorSupplementalInferredAttr(/*max depth*/ 10, /*deprecation*/ false, STC.nogc);
2211 f.checkOverriddenDtor(sc, loc, dd => dd.type.toTypeFunction().isnogc, "non-@nogc");
2213 return true;
2216 return false;
2219 /********************************************
2220 * Check that the postblit is callable if t is an array of structs.
2221 * Returns true if error happens.
2223 private bool checkPostblit(Type t, ref Loc loc, Scope* sc)
2225 if (auto ts = t.baseElemOf().isTypeStruct())
2227 if (global.params.useTypeInfo && Type.dtypeinfo)
2229 // https://issues.dlang.org/show_bug.cgi?id=11395
2230 // Require TypeInfo generation for array concatenation
2231 semanticTypeInfo(sc, t);
2234 StructDeclaration sd = ts.sym;
2235 if (sd.postblit)
2237 if (sd.postblit.checkDisabled(loc, sc))
2238 return true;
2240 //checkDeprecated(sc, sd.postblit); // necessary?
2241 sd.postblit.checkPurity(loc, sc);
2242 sd.postblit.checkSafety(loc, sc);
2243 sd.postblit.checkNogc(loc, sc);
2244 //checkAccess(sd, loc, sc, sd.postblit); // necessary?
2245 return false;
2248 return false;
2251 /***************************************
2252 * Pull out any properties.
2254 private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null, BinExp saveAtts = null)
2256 //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null);
2257 Loc loc = e1.loc;
2259 OverloadSet os;
2260 Dsymbol s;
2261 Objects* tiargs;
2262 Type tthis;
2263 if (auto de = e1.isDotExp())
2265 if (auto oe = de.e2.isOverExp())
2267 tiargs = null;
2268 tthis = de.e1.type;
2269 os = oe.vars;
2270 goto Los;
2273 else if (e1.isOverExp())
2275 tiargs = null;
2276 tthis = null;
2277 os = e1.isOverExp().vars;
2278 Los:
2279 assert(os);
2280 FuncDeclaration fd = null;
2281 if (e2)
2283 e2 = e2.expressionSemantic(sc);
2284 if (e2.op == EXP.error)
2285 return ErrorExp.get();
2286 e2 = resolveProperties(sc, e2);
2288 Expressions* a = new Expressions();
2289 a.push(e2);
2291 for (size_t i = 0; i < os.a.length; i++)
2293 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(a), FuncResolveFlag.quiet))
2295 if (f.errors)
2296 return ErrorExp.get();
2297 fd = f;
2298 assert(fd.type.ty == Tfunction);
2301 if (fd)
2303 Expression e = new CallExp(loc, e1, e2);
2304 return e.expressionSemantic(sc);
2308 for (size_t i = 0; i < os.a.length; i++)
2310 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet))
2312 if (f.errors)
2313 return ErrorExp.get();
2314 fd = f;
2315 assert(fd.type.ty == Tfunction);
2316 auto tf = fd.type.isTypeFunction();
2317 if (!tf.isref && e2)
2319 error(loc, "%s is not an lvalue", e1.toChars());
2320 return ErrorExp.get();
2324 if (fd)
2326 Expression e = new CallExp(loc, e1);
2327 if (e2)
2329 e = new AssignExp(loc, e, e2);
2330 if (saveAtts)
2332 (cast(BinExp)e).att1 = saveAtts.att1;
2333 (cast(BinExp)e).att2 = saveAtts.att2;
2336 return e.expressionSemantic(sc);
2339 if (e2)
2340 goto Leprop;
2342 else if (auto dti = e1.isDotTemplateInstanceExp())
2344 if (!dti.findTempDecl(sc))
2345 goto Leprop;
2346 if (!dti.ti.semanticTiargs(sc))
2347 goto Leprop;
2348 tiargs = dti.ti.tiargs;
2349 tthis = dti.e1.type;
2350 if ((os = dti.ti.tempdecl.isOverloadSet()) !is null)
2351 goto Los;
2352 if ((s = dti.ti.tempdecl) !is null)
2353 goto Lfd;
2355 else if (auto dte = e1.isDotTemplateExp())
2357 s = dte.td;
2358 tiargs = null;
2359 tthis = dte.e1.type;
2360 goto Lfd;
2362 else if (auto se = e1.isScopeExp())
2364 s = se.sds;
2365 TemplateInstance ti = s.isTemplateInstance();
2366 if (ti && !ti.semanticRun && ti.tempdecl)
2368 //assert(ti.needsTypeInference(sc));
2369 if (!ti.semanticTiargs(sc))
2370 goto Leprop;
2371 tiargs = ti.tiargs;
2372 tthis = null;
2373 if ((os = ti.tempdecl.isOverloadSet()) !is null)
2374 goto Los;
2375 if ((s = ti.tempdecl) !is null)
2376 goto Lfd;
2379 else if (auto te = e1.isTemplateExp())
2381 s = te.td;
2382 tiargs = null;
2383 tthis = null;
2384 goto Lfd;
2386 else if (e1.isDotVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isDotVarExp().var.isOverDeclaration()))
2388 DotVarExp dve = e1.isDotVarExp();
2389 s = dve.var;
2390 tiargs = null;
2391 tthis = dve.e1.type;
2392 goto Lfd;
2394 else if (sc && sc.flags & SCOPE.Cfile && e1.isVarExp() && !e2)
2396 // ImportC: do not implicitly call function if no ( ) are present
2398 else if (e1.isVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isVarExp().var.isOverDeclaration()))
2400 s = e1.isVarExp().var;
2401 tiargs = null;
2402 tthis = null;
2403 Lfd:
2404 assert(s);
2405 if (e2)
2407 e2 = e2.expressionSemantic(sc);
2408 if (e2.op == EXP.error)
2409 return ErrorExp.get();
2410 e2 = resolveProperties(sc, e2);
2412 Expressions* a = new Expressions();
2413 a.push(e2);
2415 FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(a), FuncResolveFlag.quiet);
2416 if (fd && fd.type)
2418 if (fd.errors)
2419 return ErrorExp.get();
2420 assert(fd.type.ty == Tfunction);
2421 Expression e = new CallExp(loc, e1, e2);
2422 return e.expressionSemantic(sc);
2426 FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet);
2427 if (fd && fd.type)
2429 if (fd.errors)
2430 return ErrorExp.get();
2431 TypeFunction tf = fd.type.isTypeFunction();
2432 if (!e2 || tf.isref)
2434 Expression e = new CallExp(loc, e1);
2435 if (e2)
2437 e = new AssignExp(loc, e, e2);
2438 if (saveAtts)
2440 (cast(BinExp)e).att1 = saveAtts.att1;
2441 (cast(BinExp)e).att2 = saveAtts.att2;
2444 return e.expressionSemantic(sc);
2448 if (FuncDeclaration fd = s.isFuncDeclaration())
2450 // Keep better diagnostic message for invalid property usage of functions
2451 assert(fd.type.ty == Tfunction);
2452 Expression e = new CallExp(loc, e1, e2);
2453 return e.expressionSemantic(sc);
2455 if (e2)
2456 goto Leprop;
2458 if (auto ve = e1.isVarExp())
2460 if (auto v = ve.var.isVarDeclaration())
2462 if (v.checkPurity(ve.loc, sc))
2463 return ErrorExp.get();
2466 if (e2)
2467 return null;
2469 if (e1.type && !e1.isTypeExp()) // function type is not a property
2471 /* Look for e1 being a lazy parameter; rewrite as delegate call
2472 * only if the symbol wasn't already treated as a delegate
2474 auto ve = e1.isVarExp();
2475 if (ve && ve.var.storage_class & STC.lazy_ && !ve.delegateWasExtracted)
2477 Expression e = new CallExp(loc, e1);
2478 return e.expressionSemantic(sc);
2480 else if (e1.isDotVarExp())
2482 // Check for reading overlapped pointer field in @safe code.
2483 if (checkUnsafeAccess(sc, e1, true, true))
2484 return ErrorExp.get();
2486 else if (auto ce = e1.isCallExp())
2488 // Check for reading overlapped pointer field in @safe code.
2489 if (checkUnsafeAccess(sc, ce.e1, true, true))
2490 return ErrorExp.get();
2494 if (!e1.type)
2496 error(loc, "cannot resolve type for %s", e1.toChars());
2497 e1 = ErrorExp.get();
2499 return e1;
2501 Leprop:
2502 error(loc, "not a property %s", e1.toChars());
2503 return ErrorExp.get();
2506 private bool checkRightThis(Expression e, Scope* sc)
2508 if (e.op == EXP.error)
2509 return true;
2510 if (e.op == EXP.variable && e.type.ty != Terror)
2512 VarExp ve = cast(VarExp)e;
2513 if (isNeedThisScope(sc, ve.var))
2515 //printf("checkRightThis sc.intypeof = %d, ad = %p, func = %p, fdthis = %p\n",
2516 // sc.intypeof, sc.getStructClassScope(), func, fdthis);
2517 auto t = ve.var.isThis();
2518 assert(t);
2519 error(e.loc, "accessing non-static variable `%s` requires an instance of `%s`", ve.var.toChars(), t.toChars());
2520 return true;
2523 return false;
2526 Expression resolveProperties(Scope* sc, Expression e)
2528 //printf("resolveProperties(%s)\n", e.toChars());
2529 e = resolvePropertiesX(sc, e);
2530 if (e.checkRightThis(sc))
2531 return ErrorExp.get();
2532 return e;
2535 /****************************************
2536 * The common type is determined by applying ?: to each pair.
2537 * Output:
2538 * exps[] properties resolved, implicitly cast to common type, rewritten in place
2539 * Returns:
2540 * The common type, or `null` if an error has occured
2542 private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
2544 /* Still have a problem with:
2545 * ubyte[][] = [ cast(ubyte[])"hello", [1]];
2546 * which works if the array literal is initialized top down with the ubyte[][]
2547 * type, but fails with this function doing bottom up typing.
2550 //printf("arrayExpressionToCommonType()\n");
2551 scope IntegerExp integerexp = IntegerExp.literal!0;
2552 scope CondExp condexp = new CondExp(Loc.initial, integerexp, null, null);
2554 Type t0 = null;
2555 Expression e0 = null;
2556 bool foundType;
2558 for (size_t i = 0; i < exps.length; i++)
2560 Expression e = exps[i];
2561 if (!e)
2562 continue;
2564 e = resolveProperties(sc, e);
2565 if (!e.type)
2567 error(e.loc, "`%s` has no value", e.toChars());
2568 t0 = Type.terror;
2569 continue;
2571 if (e.op == EXP.type)
2573 foundType = true; // do not break immediately, there might be more errors
2574 e.checkValue(); // report an error "type T has no value"
2575 t0 = Type.terror;
2576 continue;
2578 if (e.type.ty == Tvoid)
2580 // void expressions do not concur to the determination of the common
2581 // type.
2582 continue;
2584 if (checkNonAssignmentArrayOp(e))
2586 t0 = Type.terror;
2587 continue;
2590 e = doCopyOrMove(sc, e);
2592 if (!foundType && t0 && !t0.equals(e.type))
2594 /* This applies ?: to merge the types. It's backwards;
2595 * ?: should call this function to merge types.
2597 condexp.type = null;
2598 condexp.e1 = e0;
2599 condexp.e2 = e;
2600 condexp.loc = e.loc;
2601 Expression ex = condexp.expressionSemantic(sc);
2602 if (ex.op == EXP.error)
2603 e = ex;
2604 else
2606 // Convert to common type
2607 exps[i] = condexp.e1.castTo(sc, condexp.type);
2608 e = condexp.e2.castTo(sc, condexp.type);
2611 e0 = e;
2612 t0 = e.type;
2613 if (e.op != EXP.error)
2614 exps[i] = e;
2617 // [] is typed as void[]
2618 if (!t0)
2619 return Type.tvoid;
2621 // It's an error, don't do the cast
2622 if (t0.ty == Terror)
2623 return null;
2625 for (size_t i = 0; i < exps.length; i++)
2627 Expression e = exps[i];
2628 if (!e)
2629 continue;
2631 e = e.implicitCastTo(sc, t0);
2632 if (e.op == EXP.error)
2634 /* https://issues.dlang.org/show_bug.cgi?id=13024
2635 * a workaround for the bug in typeMerge -
2636 * it should paint e1 and e2 by deduced common type,
2637 * but doesn't in this particular case.
2639 return null;
2641 exps[i] = e;
2643 return t0;
2646 private Expression opAssignToOp(const ref Loc loc, EXP op, Expression e1, Expression e2) @safe
2648 Expression e;
2649 switch (op)
2651 case EXP.addAssign:
2652 e = new AddExp(loc, e1, e2);
2653 break;
2655 case EXP.minAssign:
2656 e = new MinExp(loc, e1, e2);
2657 break;
2659 case EXP.mulAssign:
2660 e = new MulExp(loc, e1, e2);
2661 break;
2663 case EXP.divAssign:
2664 e = new DivExp(loc, e1, e2);
2665 break;
2667 case EXP.modAssign:
2668 e = new ModExp(loc, e1, e2);
2669 break;
2671 case EXP.andAssign:
2672 e = new AndExp(loc, e1, e2);
2673 break;
2675 case EXP.orAssign:
2676 e = new OrExp(loc, e1, e2);
2677 break;
2679 case EXP.xorAssign:
2680 e = new XorExp(loc, e1, e2);
2681 break;
2683 case EXP.leftShiftAssign:
2684 e = new ShlExp(loc, e1, e2);
2685 break;
2687 case EXP.rightShiftAssign:
2688 e = new ShrExp(loc, e1, e2);
2689 break;
2691 case EXP.unsignedRightShiftAssign:
2692 e = new UshrExp(loc, e1, e2);
2693 break;
2695 default:
2696 assert(0);
2698 return e;
2701 /*********************
2702 * Rewrite:
2703 * array.length op= e2
2705 private Expression rewriteOpAssign(BinExp exp)
2707 ArrayLengthExp ale = exp.e1.isArrayLengthExp();
2708 if (ale.e1.isVarExp())
2710 // array.length = array.length op e2
2711 Expression e = opAssignToOp(exp.loc, exp.op, ale, exp.e2);
2712 e = new AssignExp(exp.loc, ale.syntaxCopy(), e);
2713 return e;
2715 else
2717 // (ref tmp = array;), tmp.length = tmp.length op e2
2718 auto tmp = copyToTemp(STC.ref_, "__arraylength", ale.e1);
2719 Expression e1 = new ArrayLengthExp(ale.loc, new VarExp(ale.loc, tmp));
2720 Expression elvalue = e1.syntaxCopy();
2721 Expression e = opAssignToOp(exp.loc, exp.op, e1, exp.e2);
2722 e = new AssignExp(exp.loc, elvalue, e);
2723 e = new CommaExp(exp.loc, new DeclarationExp(ale.loc, tmp), e);
2724 return e;
2728 /****************************************
2729 * Preprocess arguments to function.
2731 * Tuples in argumentList get expanded, properties resolved, rewritten in place
2733 * Params:
2734 * sc = scope
2735 * argumentList = arguments to function
2736 * reportErrors = whether or not to report errors here. Some callers are not
2737 * checking actual function params, so they'll do their own error reporting
2738 * Returns:
2739 * `true` when a semantic error occurred
2741 private bool preFunctionParameters(Scope* sc, ArgumentList argumentList, const bool reportErrors = true)
2743 Expressions* exps = argumentList.arguments;
2744 bool err = false;
2745 if (exps)
2747 expandTuples(exps, argumentList.names);
2749 for (size_t i = 0; i < exps.length; i++)
2751 Expression arg = (*exps)[i];
2752 arg = resolveProperties(sc, arg);
2753 arg = arg.arrayFuncConv(sc);
2754 if (arg.op == EXP.type)
2756 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
2757 arg = resolveAliasThis(sc, arg);
2759 if (arg.op == EXP.type)
2761 if (reportErrors)
2763 error(arg.loc, "cannot pass type `%s` as a function argument", arg.toChars());
2764 arg = ErrorExp.get();
2766 err = true;
2769 else if (arg.type.toBasetype().ty == Tfunction)
2771 if (reportErrors)
2773 error(arg.loc, "cannot pass function `%s` as a function argument", arg.toChars());
2774 arg = ErrorExp.get();
2776 err = true;
2778 else if (checkNonAssignmentArrayOp(arg))
2780 arg = ErrorExp.get();
2781 err = true;
2783 (*exps)[i] = arg;
2786 return err;
2789 /********************************************
2790 * Issue an error if default construction is disabled for type t.
2791 * Default construction is required for arrays and 'out' parameters.
2792 * Returns:
2793 * true an error was issued
2795 private bool checkDefCtor(Loc loc, Type t)
2797 if (auto ts = t.baseElemOf().isTypeStruct())
2799 StructDeclaration sd = ts.sym;
2800 if (sd.noDefaultCtor)
2802 .error(loc, "%s `%s` default construction is disabled", sd.kind, sd.toPrettyChars);
2803 return true;
2806 return false;
2809 /****************************************
2810 * Now that we know the exact type of the function we're calling,
2811 * the arguments[] need to be adjusted:
2812 * 1. implicitly convert argument to the corresponding parameter type
2813 * 2. add default arguments for any missing arguments
2814 * 3. do default promotions on arguments corresponding to ...
2815 * 4. add hidden _arguments[] argument
2816 * 5. call copy constructor for struct value arguments
2817 * Params:
2818 * loc = location of function call
2819 * sc = context
2820 * tf = type of the function
2821 * ethis = `this` argument, `null` if none or not known
2822 * tthis = type of `this` argument, `null` if no `this` argument
2823 * argumentsList = array of actual arguments to function call
2824 * fd = the function being called, `null` if called indirectly
2825 * prettype = set to return type of function
2826 * peprefix = set to expression to execute before `arguments[]` are evaluated, `null` if none
2827 * Returns:
2828 * true errors happened
2830 private bool functionParameters(const ref Loc loc, Scope* sc,
2831 TypeFunction tf, Expression ethis, Type tthis, ArgumentList argumentList, FuncDeclaration fd,
2832 Type* prettype, Expression* peprefix)
2834 Expressions* arguments = argumentList.arguments;
2835 //printf("functionParameters() %s\n", fd ? fd.toChars() : "");
2836 assert(arguments);
2837 assert(fd || tf.next);
2838 const size_t nparams = tf.parameterList.length;
2839 const olderrors = global.errors;
2840 bool err = false;
2841 Expression eprefix = null;
2842 *peprefix = null;
2844 if (argumentList.names)
2846 const(char)* msg = null;
2847 auto resolvedArgs = tf.resolveNamedArgs(argumentList, &msg);
2848 if (!resolvedArgs)
2850 // while errors are usually already caught by `tf.callMatch`,
2851 // this can happen when calling `typeof(freefunc)`
2852 if (msg)
2853 error(loc, "%s", msg);
2854 return true;
2856 // note: the argument list should be mutated with named arguments / default arguments,
2857 // so we can't simply change the pointer like `arguments = resolvedArgs;`
2858 arguments.setDim(0);
2859 arguments.pushSlice((*resolvedArgs)[]);
2861 size_t nargs = arguments ? arguments.length : 0;
2863 if (nargs > nparams && tf.parameterList.varargs == VarArg.none)
2865 error(loc, "expected %llu arguments, not %llu for non-variadic function type `%s`", cast(ulong)nparams, cast(ulong)nargs, tf.toChars());
2866 return true;
2869 // If inferring return type, and semantic3() needs to be run if not already run
2870 if (!tf.next && fd.inferRetType)
2872 functionSemantic(fd);
2874 else if (fd && fd.parent)
2876 TemplateInstance ti = fd.parent.isTemplateInstance();
2877 if (ti && ti.tempdecl)
2879 fd.functionSemantic3();
2883 /* If calling a pragma(inline, true) function,
2884 * set flag to later scan for inlines.
2886 if (fd && fd.inlining == PINLINE.always)
2888 if (sc._module)
2889 sc._module.hasAlwaysInlines = true;
2890 if (sc.func)
2891 sc.func.hasAlwaysInlines = true;
2894 const isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration();
2896 const size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams)
2898 /* If the function return type has wildcards in it, we'll need to figure out the actual type
2899 * based on the actual argument types.
2900 * Start with the `this` argument, later on merge into wildmatch the mod bits of the rest
2901 * of the arguments.
2903 MOD wildmatch = (tthis && !isCtorCall) ? tthis.Type.deduceWild(tf, false) : 0;
2905 bool done = false;
2906 foreach (const i; 0 .. n)
2908 Expression arg = (i < nargs) ? (*arguments)[i] : null;
2910 if (i < nparams)
2912 bool errorArgs()
2914 error(loc, "expected %llu function arguments, not %llu", cast(ulong)nparams, cast(ulong)nargs);
2915 return true;
2918 Parameter p = tf.parameterList[i];
2920 if (!arg)
2922 if (!p.defaultArg)
2924 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams)
2925 goto L2;
2926 return errorArgs();
2928 arg = p.defaultArg;
2929 if (!arg.type)
2930 arg = arg.expressionSemantic(sc);
2931 arg = inlineCopy(arg, sc);
2932 // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
2933 arg = arg.resolveLoc(loc, sc);
2934 if (i >= nargs)
2936 arguments.push(arg);
2937 nargs++;
2939 else
2940 (*arguments)[i] = arg;
2942 else
2944 if (arg.isDefaultInitExp())
2946 arg = arg.resolveLoc(loc, sc);
2947 (*arguments)[i] = arg;
2952 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams) // https://dlang.org/spec/function.html#variadic
2954 //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars());
2956 MATCH m;
2957 if ((m = arg.implicitConvTo(p.type)) > MATCH.nomatch)
2959 if (p.type.nextOf() && arg.implicitConvTo(p.type.nextOf()) >= m)
2960 goto L2;
2961 else if (nargs != nparams)
2962 return errorArgs();
2963 goto L1;
2967 Type tb = p.type.toBasetype();
2968 switch (tb.ty)
2970 case Tsarray:
2971 case Tarray:
2973 /* Create a static array variable v of type arg.type:
2974 * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
2976 * The array literal in the initializer of the hidden variable
2977 * is now optimized.
2978 * https://issues.dlang.org/show_bug.cgi?id=2356
2980 Type tbn = (cast(TypeArray)tb).next; // array element type
2981 Type tret = p.isLazyArray();
2983 auto elements = new Expressions(nargs - i);
2984 foreach (u; 0 .. elements.length)
2986 Expression a = (*arguments)[i + u];
2987 assert(a);
2988 if (tret && a.implicitConvTo(tret))
2990 // p is a lazy array of delegates, tret is return type of the delegates
2991 a = a.implicitCastTo(sc, tret)
2992 .optimize(WANTvalue)
2993 .toDelegate(tret, sc);
2995 else
2996 a = a.implicitCastTo(sc, tbn);
2997 a = a.addDtorHook(sc);
2998 (*elements)[u] = a;
3000 // https://issues.dlang.org/show_bug.cgi?id=14395
3001 // Convert to a static array literal, or its slice.
3002 arg = new ArrayLiteralExp(loc, tbn.sarrayOf(nargs - i), elements);
3003 if (tb.ty == Tarray)
3005 arg = new SliceExp(loc, arg, null, null);
3006 arg.type = p.type;
3008 break;
3010 case Tclass:
3012 /* Set arg to be:
3013 * new Tclass(arg0, arg1, ..., argn)
3015 auto args = new Expressions(nargs - i);
3016 foreach (u; i .. nargs)
3017 (*args)[u - i] = (*arguments)[u];
3018 arg = new NewExp(loc, null, p.type, args);
3019 break;
3021 default:
3022 if (!arg)
3024 error(loc, "not enough arguments");
3025 return true;
3027 break;
3029 arg = arg.expressionSemantic(sc);
3030 //printf("\targ = '%s'\n", arg.toChars());
3031 arguments.setDim(i + 1);
3032 (*arguments)[i] = arg;
3033 nargs = i + 1;
3034 done = true;
3038 if (!(p.isLazy() && p.type.ty == Tvoid))
3040 if (ubyte wm = arg.type.deduceWild(p.type, p.isReference()))
3042 wildmatch = wildmatch ? MODmerge(wildmatch, wm) : wm;
3043 //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p.type.toChars(), arg.type.toChars(), wm, wildmatch);
3047 if (done)
3048 break;
3050 if ((wildmatch == MODFlags.mutable || wildmatch == MODFlags.immutable_) &&
3051 tf.next && tf.next.hasWild() &&
3052 (tf.isref || !tf.next.implicitConvTo(tf.next.immutableOf())))
3054 bool errorInout(MOD wildmatch)
3056 const(char)* s = wildmatch == MODFlags.mutable ? "mutable" : MODtoChars(wildmatch);
3057 error(loc, "modify `inout` to `%s` is not allowed inside `inout` function", s);
3058 return true;
3061 if (fd)
3063 /* If the called function may return the reference to
3064 * outer inout data, it should be rejected.
3066 * void foo(ref inout(int) x) {
3067 * ref inout(int) bar(inout(int)) { return x; }
3068 * struct S {
3069 * ref inout(int) bar() inout { return x; }
3070 * ref inout(int) baz(alias a)() inout { return x; }
3072 * bar(int.init) = 1; // bad!
3073 * S().bar() = 1; // bad!
3075 * void test() {
3076 * int a;
3077 * auto s = foo(a);
3078 * s.baz!a() = 1; // bad!
3082 bool checkEnclosingWild(Dsymbol s)
3084 bool checkWild(Dsymbol s)
3086 if (!s)
3087 return false;
3088 if (auto ad = s.isAggregateDeclaration())
3090 if (ad.isNested())
3091 return checkEnclosingWild(s);
3093 else if (auto ff = s.isFuncDeclaration())
3095 if (ff.type.isTypeFunction().iswild)
3096 return errorInout(wildmatch);
3098 if (ff.isNested() || ff.isThis())
3099 return checkEnclosingWild(s);
3101 return false;
3104 Dsymbol ctx0 = s.toParent2();
3105 Dsymbol ctx1 = s.toParentLocal();
3106 if (checkWild(ctx0))
3107 return true;
3108 if (ctx0 != ctx1)
3109 return checkWild(ctx1);
3110 return false;
3112 if ((fd.isThis() || fd.isNested()) && checkEnclosingWild(fd))
3113 return true;
3115 else if (tf.isWild())
3116 return errorInout(wildmatch);
3119 Expression firstArg = null;
3120 final switch (returnParamDest(tf, tthis))
3122 case ReturnParamDest.returnVal:
3123 break;
3124 case ReturnParamDest.firstArg:
3125 firstArg = nargs > 0 ? (*arguments)[0] : null;
3126 break;
3127 case ReturnParamDest.this_:
3128 firstArg = ethis;
3129 break;
3132 assert(nargs >= nparams);
3133 foreach (const i, arg; (*arguments)[0 .. nargs])
3135 assert(arg);
3136 if (i < nparams)
3138 Parameter p = tf.parameterList[i];
3139 Type targ = arg.type; // keep original type for isCopyable() because alias this
3140 // resolution may hide an uncopyable type
3142 if (!(p.isLazy() && p.type.ty == Tvoid))
3144 Type tprm = p.type.hasWild()
3145 ? p.type.substWildTo(wildmatch)
3146 : p.type;
3148 const hasCopyCtor = arg.type.isTypeStruct() && arg.type.isTypeStruct().sym.hasCopyCtor;
3149 const typesMatch = arg.type.mutableOf().unSharedOf().equals(tprm.mutableOf().unSharedOf());
3150 if (!((hasCopyCtor && typesMatch) || tprm.equals(arg.type)))
3152 //printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars());
3153 arg = arg.implicitCastTo(sc, tprm);
3154 arg = arg.optimize(WANTvalue, p.isReference());
3158 // Support passing rvalue to `in` parameters
3159 if ((p.storageClass & (STC.in_ | STC.ref_)) == (STC.in_ | STC.ref_))
3161 if (!arg.isLvalue())
3163 auto v = copyToTemp(STC.exptemp, "__rvalue", arg);
3164 Expression ev = new DeclarationExp(arg.loc, v);
3165 ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
3166 arg = ev.expressionSemantic(sc);
3168 arg = arg.toLvalue(sc, "create `in` parameter from");
3170 // Look for mutable misaligned pointer, etc., in @safe mode
3171 err |= checkUnsafeAccess(sc, arg, false, true);
3173 else if (p.storageClass & STC.ref_)
3175 if (global.params.rvalueRefParam == FeatureState.enabled &&
3176 !arg.isLvalue() &&
3177 targ.isCopyable())
3178 { /* allow rvalues to be passed to ref parameters by copying
3179 * them to a temp, then pass the temp as the argument
3181 auto v = copyToTemp(0, "__rvalue", arg);
3182 Expression ev = new DeclarationExp(arg.loc, v);
3183 ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
3184 arg = ev.expressionSemantic(sc);
3186 arg = arg.toLvalue(sc, "create `ref` parameter from");
3188 // Look for mutable misaligned pointer, etc., in @safe mode
3189 err |= checkUnsafeAccess(sc, arg, false, true);
3191 else if (p.storageClass & STC.out_)
3193 Type t = arg.type;
3194 if (!t.isMutable() || !t.isAssignable()) // check blit assignable
3196 error(arg.loc, "cannot modify struct `%s` with immutable members", arg.toChars());
3197 err = true;
3199 else
3201 // Look for misaligned pointer, etc., in @safe mode
3202 err |= checkUnsafeAccess(sc, arg, false, true);
3203 err |= checkDefCtor(arg.loc, t); // t must be default constructible
3205 arg = arg.toLvalue(sc, "create `out` parameter from");
3207 else if (p.isLazy())
3209 // Convert lazy argument to a delegate
3210 auto t = (p.type.ty == Tvoid) ? p.type : arg.type;
3211 arg = toDelegate(arg, t, sc);
3213 //printf("arg: %s\n", arg.toChars());
3214 //printf("type: %s\n", arg.type.toChars());
3215 //printf("param: %s\n", p.toChars());
3217 const indirect = (fd is null) || (fd.isVirtual() && !fd.isFinal());
3218 const pStc = tf.parameterStorageClass(tthis, p, fd ? &fd.outerVars : null, indirect);
3220 if (firstArg && (pStc & STC.return_))
3222 /* Argument value can be assigned to firstArg.
3223 * Check arg to see if it matters.
3225 err |= checkParamArgumentReturn(sc, firstArg, arg, p, false);
3227 // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along
3228 // as lazy parameters to the next function, but that isn't escaping.
3229 // The arguments of `_d_arraycatnTX` are already handled in
3230 // expressionsem.d, via `checkNewEscape`. Without `-dip1000`, the
3231 // check does not return an error, so the lowering of `a ~ b` to
3232 // `_d_arraycatnTX(a, b)` still occurs.
3233 else if (!(pStc & STC.lazy_) && (!fd || fd.ident != Id._d_arraycatnTX))
3235 /* Argument value can escape from the called function.
3236 * Check arg to see if it matters.
3238 VarDeclaration vPar = fd ? (fd.parameters ? (*fd.parameters)[i] : null) : null;
3239 err |= checkParamArgumentEscape(sc, fd, p.ident, vPar, cast(STC) pStc, arg, false, false);
3242 // Turning heap allocations into stack allocations is dangerous without dip1000, since `scope` inference
3243 // may be unreliable when scope violations only manifest as deprecation warnings.
3244 // However, existing `@nogc` code may rely on it, so still do it when the parameter is explicitly marked `scope`
3245 const explicitScope = p.isLazy() ||
3246 ((p.storageClass & STC.scope_) && !(p.storageClass & STC.scopeinferred));
3247 if ((pStc & (STC.scope_ | STC.lazy_)) &&
3248 ((sc.useDIP1000 == FeatureState.enabled) || explicitScope) &&
3249 !(pStc & STC.return_))
3251 /* Argument value cannot escape from the called function.
3253 Expression a = arg;
3254 if (auto ce = a.isCastExp())
3255 a = ce.e1;
3257 ArrayLiteralExp ale;
3258 if (p.type.toBasetype().ty == Tarray &&
3259 (ale = a.isArrayLiteralExp()) !is null && ale.elements && ale.elements.length > 0)
3261 // allocate the array literal as temporary static array on the stack
3262 ale.type = ale.type.nextOf().sarrayOf(ale.elements.length);
3263 auto tmp = copyToTemp(0, "__arrayliteral_on_stack", ale);
3264 tmp.storage_class |= STC.exptemp;
3265 auto declareTmp = new DeclarationExp(ale.loc, tmp);
3266 auto castToSlice = new CastExp(ale.loc, new VarExp(ale.loc, tmp),
3267 p.type.substWildTo(MODFlags.mutable));
3268 arg = CommaExp.combine(declareTmp, castToSlice);
3269 arg = arg.expressionSemantic(sc);
3271 else if (auto fe = a.isFuncExp())
3273 /* Function literals can only appear once, so if this
3274 * appearance was scoped, there cannot be any others.
3276 fe.fd.tookAddressOf = 0;
3278 else if (auto de = a.isDelegateExp())
3280 /* For passing a delegate to a scoped parameter,
3281 * this doesn't count as taking the address of it.
3282 * We only worry about 'escaping' references to the function.
3284 if (auto ve = de.e1.isVarExp())
3286 if (auto f = ve.var.isFuncDeclaration())
3288 if (f.tookAddressOf)
3289 --f.tookAddressOf;
3290 //printf("--tookAddressOf = %d\n", f.tookAddressOf);
3295 if (!p.isReference())
3296 err |= arg.checkSharedAccess(sc);
3298 arg = arg.optimize(WANTvalue, p.isReference());
3300 else
3302 // These will be the trailing ... arguments
3303 // If not D linkage, do promotions
3304 if (tf.linkage != LINK.d)
3306 // Promote bytes, words, etc., to ints
3307 arg = integralPromotions(arg, sc);
3309 // Promote floats to doubles
3310 switch (arg.type.ty)
3312 case Tfloat32:
3313 arg = arg.castTo(sc, Type.tfloat64);
3314 break;
3316 case Timaginary32:
3317 arg = arg.castTo(sc, Type.timaginary64);
3318 break;
3320 default:
3321 break;
3323 if (tf.parameterList.varargs == VarArg.variadic ||
3324 tf.parameterList.varargs == VarArg.KRvariadic)
3326 const(char)* p = tf.linkage == LINK.c ? "extern(C)" : "extern(C++)";
3327 if (arg.type.ty == Tarray)
3329 error(arg.loc, "cannot pass dynamic arrays to `%s` vararg functions", p);
3330 err = true;
3332 if (arg.type.ty == Tsarray)
3334 error(arg.loc, "cannot pass static arrays to `%s` vararg functions", p);
3335 err = true;
3340 // Do not allow types that need destructors or copy constructors.
3341 if (arg.type.needsDestruction())
3343 error(arg.loc, "cannot pass types that need destruction as variadic arguments");
3344 err = true;
3346 if (arg.type.needsCopyOrPostblit())
3348 error(arg.loc, "cannot pass types with postblits or copy constructors as variadic arguments");
3349 err = true;
3352 // Convert static arrays to dynamic arrays
3353 // BUG: I don't think this is right for D2
3354 Type tb = arg.type.toBasetype();
3355 if (auto ts = tb.isTypeSArray())
3357 Type ta = ts.next.arrayOf();
3358 if (ts.size(arg.loc) == 0)
3359 arg = new NullExp(arg.loc, ta);
3360 else
3361 arg = arg.castTo(sc, ta);
3363 if (tb.ty == Tstruct)
3365 //arg = callCpCtor(sc, arg);
3367 // Give error for overloaded function addresses
3368 if (auto se = arg.isSymOffExp())
3370 if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique())
3372 error(arg.loc, "function `%s` is overloaded", arg.toChars());
3373 err = true;
3376 err |= arg.checkValue();
3377 err |= arg.checkSharedAccess(sc);
3378 err |= checkParamArgumentEscape(sc, fd, Id.dotdotdot, null, cast(STC) tf.parameterList.stc, arg, false, false);
3379 arg = arg.optimize(WANTvalue);
3381 (*arguments)[i] = arg;
3384 /* If calling C scanf(), printf(), or any variants, check the format string against the arguments
3386 const isVa_list = tf.parameterList.varargs == VarArg.none;
3387 if (fd && fd.printf)
3389 if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp())
3391 checkPrintfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list, sc.eSink);
3394 else if (fd && fd.scanf)
3396 if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp())
3398 checkScanfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list, sc.eSink);
3401 else
3403 // TODO: not checking the "v" functions yet (for those, check format string only, not args)
3406 /* Remaining problems:
3407 * 1. value structs (or static arrays of them) that need to be copy constructed
3408 * 2. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
3409 * function gets called.
3410 * 3. value structs need to be destructed after the function call for platforms where the caller destroys the arguments.
3411 * Those are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
3412 * up properly. Pushing arguments on the stack then cannot fail.
3415 /* Does Problem (3) apply?
3417 const bool callerDestroysArgs = !target.isCalleeDestroyingArgs(tf);
3419 /* Compute indices of last throwing argument and first arg needing destruction.
3420 * Used to not set up destructors unless an arg needs destruction on a throw
3421 * in a later argument.
3423 ptrdiff_t lastthrow = -1; // last argument that may throw
3424 ptrdiff_t firstdtor = -1; // first argument that needs destruction
3425 ptrdiff_t lastdtor = -1; // last argument that needs destruction
3426 for (ptrdiff_t i = 0; i != nargs; i++)
3428 Expression arg = (*arguments)[i];
3429 if (canThrow(arg, sc.func, null))
3430 lastthrow = i;
3431 if (arg.type.needsDestruction())
3433 Parameter p = (i >= nparams ? null : tf.parameterList[i]);
3434 if (!(p && (p.isLazy() || p.isReference())))
3436 if (firstdtor == -1)
3437 firstdtor = i;
3438 lastdtor = i;
3443 /* Do we need 'eprefix' for problems 2 or 3?
3445 const bool needsPrefix = callerDestroysArgs
3446 ? firstdtor >= 0 // true if any argument needs destruction
3447 : firstdtor >= 0 && lastthrow >= 0 &&
3448 (lastthrow - firstdtor) > 0; // last throw after first destruction
3449 const ptrdiff_t lastPrefix = callerDestroysArgs
3450 ? lastdtor // up to last argument requiring destruction
3451 : lastthrow; // up to last potentially throwing argument
3453 /* Problem 3: initialize 'eprefix' by declaring the gate
3455 VarDeclaration gate;
3456 if (needsPrefix && !callerDestroysArgs)
3458 // eprefix => bool __gate [= false]
3459 Identifier idtmp = Identifier.generateId("__gate");
3460 gate = new VarDeclaration(loc, Type.tbool, idtmp, null);
3461 gate.storage_class |= STC.temp | STC.ctfe | STC.volatile_;
3462 gate.dsymbolSemantic(sc);
3464 auto ae = new DeclarationExp(loc, gate);
3465 eprefix = ae.expressionSemantic(sc);
3468 foreach (ptrdiff_t i; 0 .. nargs)
3470 Expression arg = (*arguments)[i];
3471 //printf("arg[%d]: %s\n", cast(int)i, arg.toChars());
3473 Parameter parameter = i < nparams ? tf.parameterList[i] : null;
3474 const bool isRef = parameter && parameter.isReference();
3475 const bool isLazy = parameter && parameter.isLazy();
3477 /* Skip lazy parameters
3479 if (isLazy)
3480 continue;
3482 /* Do we have 'eprefix' and aren't past 'lastPrefix' yet?
3483 * Then declare a temporary variable for this arg and append that declaration
3484 * to 'eprefix', which will implicitly take care of potential problem 1) for
3485 * this arg.
3486 * 'eprefix' will therefore finally contain all args up to and including 'lastPrefix',
3487 * excluding all lazy parameters.
3489 if (needsPrefix && i <= lastPrefix)
3491 const bool needsDtor = !isRef && arg.type.needsDestruction() &&
3492 // Problem 3: last throwing arg doesn't require dtor patching
3493 (callerDestroysArgs || i != lastPrefix);
3495 /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
3497 auto tmp = copyToTemp(
3498 (parameter ? parameter.storageClass : tf.parameterList.stc) & (STC.return_ | STC.scope_),
3499 needsDtor ? "__pfx" : "__pfy",
3500 isRef ? arg.addressOf() : arg);
3501 tmp.dsymbolSemantic(sc);
3503 if (callerDestroysArgs)
3505 /* Problem 4: Normal temporary, destructed after the call
3507 if (needsDtor)
3508 tmp.isArgDtorVar = true; // mark it so that the backend passes it by ref to the function being called
3510 else
3512 /* Problem 2: Modify the destructor so it only runs if gate==false,
3513 * i.e., only if there was a throw while constructing the args
3515 if (needsDtor)
3517 // edtor => (__gate || edtor)
3518 assert(tmp.edtor);
3519 Expression e = tmp.edtor;
3520 e = new LogicalExp(e.loc, EXP.orOr, new VarExp(e.loc, gate), e);
3521 tmp.edtor = e.expressionSemantic(sc);
3522 //printf("edtor: %s\n", tmp.edtor.toChars());
3524 else
3526 if (tmp.edtor)
3528 assert(i == lastPrefix);
3529 tmp.edtor = null;
3534 // eprefix => (eprefix, auto __pfx/y = arg)
3535 auto ae = new DeclarationExp(loc, tmp);
3536 eprefix = Expression.combine(eprefix, ae.expressionSemantic(sc));
3538 // arg => __pfx/y
3539 arg = new VarExp(loc, tmp);
3540 arg = arg.expressionSemantic(sc);
3541 if (isRef)
3543 arg = new PtrExp(loc, arg);
3544 arg = arg.expressionSemantic(sc);
3547 /* Problem 2: Last throwing arg?
3548 * Then finalize eprefix => (eprefix, gate = true), i.e., disable the
3549 * dtors right after constructing the last throwing arg.
3550 * From now on, the callee will take care of destructing the args because
3551 * the args are implicitly moved into function parameters.
3553 if (!callerDestroysArgs && i == lastPrefix)
3555 auto e = new AssignExp(gate.loc, new VarExp(gate.loc, gate), IntegerExp.createBool(true));
3556 eprefix = Expression.combine(eprefix, e.expressionSemantic(sc));
3559 else // not part of 'eprefix'
3561 /* Handle problem 1) by calling the copy constructor for value structs
3562 * (or static arrays of them) if appropriate.
3564 Type tv = arg.type.baseElemOf();
3565 if (!isRef && tv.ty == Tstruct)
3566 arg = doCopyOrMove(sc, arg, parameter ? parameter.type : null);
3569 (*arguments)[i] = arg;
3572 //if (eprefix) printf("eprefix: %s\n", eprefix.toChars());
3574 /* Test compliance with DIP1021 Argument Ownership and Function Calls
3576 if (global.params.useDIP1021 && (tf.trust == TRUST.safe || tf.trust == TRUST.default_) ||
3577 tf.islive)
3578 err |= checkMutableArguments(sc, fd, tf, ethis, arguments, false);
3580 // If D linkage and variadic, add _arguments[] as first argument
3581 if (tf.isDstyleVariadic())
3583 assert(arguments.length >= nparams);
3585 auto args = new Parameters(arguments.length - nparams);
3586 for (size_t i = 0; i < arguments.length - nparams; i++)
3588 Expression earg = (*arguments)[nparams + i];
3589 auto arg = new Parameter(earg.loc, STC.in_, earg.type, null, null, null);
3590 (*args)[i] = arg;
3592 auto tup = new TypeTuple(args);
3593 Expression e = (new TypeidExp(loc, tup)).expressionSemantic(sc);
3594 arguments.insert(0, e);
3597 /* Determine function return type: tret
3599 Type tret = tf.next;
3600 if (isCtorCall)
3602 //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd.toChars(), fd.type.toChars(),
3603 // wildmatch, tf.isWild(), fd.isReturnIsolated());
3604 if (!tthis)
3606 assert(sc.intypeof || global.errors);
3607 tthis = fd.isThis().type.addMod(fd.type.mod);
3609 if (tf.isWild() && !fd.isReturnIsolated())
3611 if (wildmatch)
3612 tret = tret.substWildTo(wildmatch);
3613 int offset;
3614 if (!tret.implicitConvTo(tthis) && !(MODimplicitConv(tret.mod, tthis.mod) && tret.isBaseOf(tthis, &offset) && offset == 0))
3616 const(char)* s1 = tret.isNaked() ? " mutable" : tret.modToChars();
3617 const(char)* s2 = tthis.isNaked() ? " mutable" : tthis.modToChars();
3618 .error(loc, "`inout` constructor `%s` creates%s object, not%s", fd.toPrettyChars(), s1, s2);
3619 err = true;
3622 tret = tthis;
3624 else if (wildmatch && tret)
3626 /* Adjust function return type based on wildmatch
3628 //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret.toChars());
3629 tret = tret.substWildTo(wildmatch);
3632 *prettype = tret;
3633 *peprefix = eprefix;
3634 return (err || olderrors != global.errors);
3638 * Determines whether a symbol represents a module or package
3639 * (Used as a helper for is(type == module) and is(type == package))
3641 * Params:
3642 * sym = the symbol to be checked
3644 * Returns:
3645 * the symbol which `sym` represents (or `null` if it doesn't represent a `Package`)
3647 Package resolveIsPackage(Dsymbol sym)
3649 Package pkg;
3650 if (Import imp = sym.isImport())
3652 if (imp.pkg is null)
3654 .error(sym.loc, "internal compiler error: unable to process forward-referenced import `%s`",
3655 imp.toChars());
3656 assert(0);
3658 pkg = imp.pkg;
3660 else if (auto mod = sym.isModule())
3661 pkg = mod.isPackageFile ? mod.pkg : sym.isPackage();
3662 else
3663 pkg = sym.isPackage();
3664 if (pkg)
3665 pkg.resolvePKGunknown();
3666 return pkg;
3670 private extern (C++) final class ExpressionSemanticVisitor : Visitor
3672 alias visit = Visitor.visit;
3674 Scope* sc;
3675 Expression result;
3677 this(Scope* sc) scope @safe
3679 this.sc = sc;
3682 private void setError()
3684 result = ErrorExp.get();
3687 private void needThisError(Loc loc, FuncDeclaration f)
3689 auto t = f.isThis();
3690 assert(t);
3691 .error(loc, "calling non-static function `%s` requires an instance of type `%s`", f.toChars(), t.toChars());
3692 setError();
3695 /**************************
3696 * Semantically analyze Expression.
3697 * Determine types, fold constants, etc.
3699 override void visit(Expression e)
3701 static if (LOGSEMANTIC)
3703 printf("Expression::semantic() %s\n", e.toChars());
3705 if (e.type)
3706 e.type = e.type.typeSemantic(e.loc, sc);
3707 else
3708 e.type = Type.tvoid;
3709 result = e;
3712 override void visit(IntegerExp e)
3714 assert(e.type);
3715 if (e.type.ty == Terror)
3716 return setError();
3718 assert(e.type.deco);
3719 e.setInteger(e.getInteger());
3720 result = e;
3723 override void visit(RealExp e)
3725 if (!e.type)
3726 e.type = Type.tfloat64;
3727 else if (e.type.isimaginary && sc.flags & SCOPE.Cfile)
3729 /* Convert to core.stdc.config.complex
3731 Type t = getComplexLibraryType(e.loc, sc, e.type.ty);
3732 if (t.ty == Terror)
3733 return setError();
3735 Type tf;
3736 switch (e.type.ty)
3738 case Timaginary32: tf = Type.tfloat32; break;
3739 case Timaginary64: tf = Type.tfloat64; break;
3740 case Timaginary80: tf = Type.tfloat80; break;
3741 default:
3742 assert(0);
3745 /* Construct ts{re : 0.0, im : e}
3747 TypeStruct ts = t.isTypeStruct;
3748 Expressions* elements = new Expressions(2);
3749 (*elements)[0] = new RealExp(e.loc, CTFloat.zero, tf);
3750 (*elements)[1] = new RealExp(e.loc, e.toImaginary(), tf);
3751 Expression sle = new StructLiteralExp(e.loc, ts.sym, elements);
3752 result = sle.expressionSemantic(sc);
3753 return;
3755 else
3756 e.type = e.type.typeSemantic(e.loc, sc);
3757 result = e;
3760 override void visit(ComplexExp e)
3762 if (!e.type)
3763 e.type = Type.tcomplex80;
3764 else
3765 e.type = e.type.typeSemantic(e.loc, sc);
3766 result = e;
3769 override void visit(IdentifierExp exp)
3771 static if (LOGSEMANTIC)
3773 printf("IdentifierExp::semantic('%s')\n", exp.ident.toChars());
3775 if (exp.type) // This is used as the dummy expression
3777 result = exp;
3778 return;
3781 Dsymbol scopesym;
3782 Dsymbol s = sc.search(exp.loc, exp.ident, scopesym);
3783 if (s)
3785 if (s.errors)
3786 return setError();
3788 Expression e;
3790 /* See if the symbol was a member of an enclosing 'with'
3792 WithScopeSymbol withsym = scopesym.isWithScopeSymbol();
3793 if (withsym && withsym.withstate.wthis && symbolIsVisible(sc, s))
3795 /* Disallow shadowing
3797 // First find the scope of the with
3798 Scope* scwith = sc;
3799 while (scwith.scopesym != scopesym)
3801 scwith = scwith.enclosing;
3802 assert(scwith);
3804 // Look at enclosing scopes for symbols with the same name,
3805 // in the same function
3806 for (Scope* scx = scwith; scx && scx.func == scwith.func; scx = scx.enclosing)
3808 Dsymbol s2;
3809 if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2)
3811 error(exp.loc, "with symbol `%s` is shadowing local symbol `%s`", s.toPrettyChars(), s2.toPrettyChars());
3812 return setError();
3815 s = s.toAlias();
3817 // Same as wthis.ident
3818 // TODO: DotIdExp.semantic will find 'ident' from 'wthis' again.
3819 // The redudancy should be removed.
3820 e = new VarExp(exp.loc, withsym.withstate.wthis);
3821 e = new DotIdExp(exp.loc, e, exp.ident);
3822 e = e.expressionSemantic(sc);
3824 else
3826 if (withsym)
3828 if (withsym.withstate.exp.type.ty != Tvoid)
3830 // 'with (exp)' is a type expression
3831 // or 's' is not visible there (for error message)
3832 e = new TypeExp(exp.loc, withsym.withstate.exp.type);
3834 else
3836 // 'with (exp)' is a Package/Module
3837 e = withsym.withstate.exp;
3839 e = new DotIdExp(exp.loc, e, exp.ident);
3840 result = e.expressionSemantic(sc);
3841 return;
3844 /* If f is really a function template,
3845 * then replace f with the function template declaration.
3847 FuncDeclaration f = s.isFuncDeclaration();
3848 if (f)
3850 TemplateDeclaration td = getFuncTemplateDecl(f);
3851 if (td)
3853 if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
3854 td = td.overroot; // then get the start
3855 e = new TemplateExp(exp.loc, td, f);
3856 e = e.expressionSemantic(sc);
3857 result = e;
3858 return;
3862 if (global.params.fixAliasThis)
3864 ExpressionDsymbol expDsym = scopesym.isExpressionDsymbol();
3865 if (expDsym)
3867 //printf("expDsym = %s\n", expDsym.exp.toChars());
3868 result = expDsym.exp.expressionSemantic(sc);
3869 return;
3872 // Haven't done overload resolution yet, so pass 1
3873 e = symbolToExp(s, exp.loc, sc, true);
3875 result = e;
3876 return;
3879 if (!global.params.fixAliasThis && hasThis(sc))
3881 for (AggregateDeclaration ad = sc.getStructClassScope(); ad;)
3883 if (ad.aliasthis)
3885 Expression e;
3886 e = new ThisExp(exp.loc);
3887 e = new DotIdExp(exp.loc, e, ad.aliasthis.ident);
3888 e = new DotIdExp(exp.loc, e, exp.ident);
3889 e = e.trySemantic(sc);
3890 if (e)
3892 result = e;
3893 return;
3897 auto cd = ad.isClassDeclaration();
3898 if (cd && cd.baseClass && cd.baseClass != ClassDeclaration.object)
3900 ad = cd.baseClass;
3901 continue;
3903 break;
3907 if (exp.ident == Id.ctfe)
3909 if (sc.flags & SCOPE.ctfe)
3911 error(exp.loc, "variable `__ctfe` cannot be read at compile time");
3912 return setError();
3915 // Create the magic __ctfe bool variable
3916 auto vd = new VarDeclaration(exp.loc, Type.tbool, Id.ctfe, null);
3917 vd.storage_class |= STC.temp;
3918 vd.semanticRun = PASS.semanticdone;
3919 Expression e = new VarExp(exp.loc, vd);
3920 e = e.expressionSemantic(sc);
3921 result = e;
3922 return;
3925 // If we've reached this point and are inside a with() scope then we may
3926 // try one last attempt by checking whether the 'wthis' object supports
3927 // dynamic dispatching via opDispatch.
3928 // This is done by rewriting this expression as wthis.ident.
3929 // The innermost with() scope of the hierarchy to satisfy the condition
3930 // above wins.
3931 // https://issues.dlang.org/show_bug.cgi?id=6400
3932 for (Scope* sc2 = sc; sc2; sc2 = sc2.enclosing)
3934 if (!sc2.scopesym)
3935 continue;
3937 if (auto ss = sc2.scopesym.isWithScopeSymbol())
3939 if (ss.withstate.wthis)
3941 Expression e;
3942 e = new VarExp(exp.loc, ss.withstate.wthis);
3943 e = new DotIdExp(exp.loc, e, exp.ident);
3944 e = e.trySemantic(sc);
3945 if (e)
3947 result = e;
3948 return;
3951 // Try Type.opDispatch (so the static version)
3952 else if (ss.withstate.exp && ss.withstate.exp.op == EXP.type)
3954 if (Type t = ss.withstate.exp.isTypeExp().type)
3956 Expression e;
3957 e = new TypeExp(exp.loc, t);
3958 e = new DotIdExp(exp.loc, e, exp.ident);
3959 e = e.trySemantic(sc);
3960 if (e)
3962 result = e;
3963 return;
3970 /* Look for what user might have meant
3972 if (const n = importHint(exp.ident.toString()))
3973 error(exp.loc, "`%s` is not defined, perhaps `import %.*s;` is needed?", exp.ident.toChars(), cast(int)n.length, n.ptr);
3974 else if (auto s2 = sc.search_correct(exp.ident))
3975 error(exp.loc, "undefined identifier `%s`, did you mean %s `%s`?", exp.ident.toChars(), s2.kind(), s2.toChars());
3976 else if (const p = Scope.search_correct_C(exp.ident))
3977 error(exp.loc, "undefined identifier `%s`, did you mean `%s`?", exp.ident.toChars(), p);
3978 else if (exp.ident == Id.dollar)
3979 error(exp.loc, "undefined identifier `$`");
3980 else
3981 error(exp.loc, "undefined identifier `%s`", exp.ident.toChars());
3983 result = ErrorExp.get();
3986 override void visit(DsymbolExp e)
3988 result = symbolToExp(e.s, e.loc, sc, e.hasOverloads);
3991 override void visit(ThisExp e)
3993 static if (LOGSEMANTIC)
3995 printf("ThisExp::semantic()\n");
3997 if (e.type)
3999 result = e;
4000 return;
4003 FuncDeclaration fd = hasThis(sc); // fd is the uplevel function with the 'this' variable
4004 AggregateDeclaration ad;
4006 /* Special case for typeof(this) and typeof(super) since both
4007 * should work even if they are not inside a non-static member function
4009 if (!fd && sc.intypeof == 1)
4011 // Find enclosing struct or class
4012 for (Dsymbol s = sc.getStructClassScope(); 1; s = s.parent)
4014 if (!s)
4016 error(e.loc, "`%s` is not in a class or struct scope", e.toChars());
4017 return setError();
4019 ClassDeclaration cd = s.isClassDeclaration();
4020 if (cd)
4022 e.type = cd.type;
4023 result = e;
4024 return;
4026 StructDeclaration sd = s.isStructDeclaration();
4027 if (sd)
4029 e.type = sd.type;
4030 result = e;
4031 return;
4035 if (!fd)
4037 error(e.loc, "`this` is only defined in non-static member functions, not `%s`", sc.parent.toChars());
4038 return setError();
4041 assert(fd.vthis);
4042 e.var = fd.vthis;
4043 assert(e.var.parent);
4044 ad = fd.isMemberLocal();
4045 if (!ad)
4046 ad = fd.isMember2();
4047 assert(ad);
4048 e.type = ad.type.addMod(e.var.type.mod);
4050 if (e.var.checkNestedReference(sc, e.loc))
4051 return setError();
4053 result = e;
4056 override void visit(SuperExp e)
4058 static if (LOGSEMANTIC)
4060 printf("SuperExp::semantic('%s')\n", e.toChars());
4062 if (e.type)
4064 result = e;
4065 return;
4068 FuncDeclaration fd = hasThis(sc);
4069 ClassDeclaration cd;
4070 Dsymbol s;
4072 /* Special case for typeof(this) and typeof(super) since both
4073 * should work even if they are not inside a non-static member function
4075 if (!fd && sc.intypeof == 1)
4077 // Find enclosing class
4078 for (s = sc.getStructClassScope(); 1; s = s.parent)
4080 if (!s)
4082 error(e.loc, "`%s` is not in a class scope", e.toChars());
4083 return setError();
4085 cd = s.isClassDeclaration();
4086 if (cd)
4088 cd = cd.baseClass;
4089 if (!cd)
4091 error(e.loc, "class `%s` has no `super`", s.toChars());
4092 return setError();
4094 e.type = cd.type;
4095 result = e;
4096 return;
4100 if (!fd)
4101 goto Lerr;
4103 e.var = fd.vthis;
4104 assert(e.var && e.var.parent);
4106 s = fd.toParentDecl();
4107 if (s.isTemplateDeclaration()) // allow inside template constraint
4108 s = s.toParent();
4109 assert(s);
4110 cd = s.isClassDeclaration();
4111 //printf("parent is %s %s\n", fd.toParent().kind(), fd.toParent().toChars());
4112 if (!cd)
4113 goto Lerr;
4114 if (!cd.baseClass)
4116 error(e.loc, "no base class for `%s`", cd.toChars());
4117 e.type = cd.type.addMod(e.var.type.mod);
4119 else
4121 e.type = cd.baseClass.type;
4122 e.type = e.type.castMod(e.var.type.mod);
4125 if (e.var.checkNestedReference(sc, e.loc))
4126 return setError();
4128 result = e;
4129 return;
4131 Lerr:
4132 error(e.loc, "`super` is only allowed in non-static class member functions");
4133 result = ErrorExp.get();
4136 override void visit(NullExp e)
4138 static if (LOGSEMANTIC)
4140 printf("NullExp::semantic('%s')\n", e.toChars());
4142 // NULL is the same as (void *)0
4143 if (e.type)
4145 result = e;
4146 return;
4148 e.type = Type.tnull;
4149 result = e;
4152 override void visit(InterpExp e)
4154 // the lexer breaks up into an odd/even array of literals and expression code
4155 // we need to turn that into:
4157 tuple(
4158 .object.imported!"core.interpolation".InterpolationHeader(),
4160 .object.imported!"core.interpolation".InterpolationFooter()
4163 There the ... loops through them all, making the even ones
4164 .object.imported!"core.interpolation".InterpolatedLiteral!str()
4165 and making the odd ones
4166 .object.imported!"core.interpolation".InterpolatedExpression!str(),
4167 the code represented by str
4169 Empty string literals are skipped as they provide no additional information.
4172 if (e.postfix)
4173 error(e.loc, "String postfixes on interpolated expression sequences are not allowed.");
4175 Expression makeNonTemplateItem(Identifier which) {
4176 Expression id = new IdentifierExp(e.loc, Id.empty);
4177 id = new DotIdExp(e.loc, id, Id.object);
4178 auto moduleNameArgs = new Objects();
4179 moduleNameArgs.push(new StringExp(e.loc, "core.interpolation"));
4180 id = new DotTemplateInstanceExp(e.loc, id, Id.imported, moduleNameArgs);
4181 id = new DotIdExp(e.loc, id, which);
4182 id = new CallExp(e.loc, id, new Expressions());
4183 return id;
4186 Expression makeTemplateItem(Identifier which, string arg) {
4187 Expression id = new IdentifierExp(e.loc, Id.empty);
4188 id = new DotIdExp(e.loc, id, Id.object);
4189 auto moduleNameArgs = new Objects();
4190 moduleNameArgs.push(new StringExp(e.loc, "core.interpolation"));
4191 id = new DotTemplateInstanceExp(e.loc, id, Id.imported, moduleNameArgs);
4192 auto tiargs = new Objects();
4193 auto templateStringArg = new StringExp(e.loc, arg);
4194 // banning those instead of forwarding them
4195 // templateStringArg.postfix = e.postfix; // forward the postfix to these literals
4196 tiargs.push(templateStringArg);
4197 id = new DotTemplateInstanceExp(e.loc, id, which, tiargs);
4198 id = new CallExp(e.loc, id, new Expressions());
4199 return id;
4202 auto arguments = new Expressions();
4203 arguments.push(makeNonTemplateItem(Id.InterpolationHeader));
4205 foreach (idx, str; e.interpolatedSet.parts)
4207 if (idx % 2 == 0)
4209 if (str.length > 0)
4210 arguments.push(makeTemplateItem(Id.InterpolatedLiteral, str));
4212 else
4214 arguments.push(makeTemplateItem(Id.InterpolatedExpression, str));
4215 Expressions* mix = new Expressions();
4216 mix.push(new StringExp(e.loc, str));
4217 // FIXME: i'd rather not use MixinExp but idk how to do it lol
4218 arguments.push(new MixinExp(e.loc, mix));
4222 arguments.push(makeNonTemplateItem(Id.InterpolationFooter));
4224 auto loweredTo = new TupleExp(e.loc, arguments);
4225 visit(loweredTo);
4227 result = loweredTo;
4230 override void visit(StringExp e)
4232 static if (LOGSEMANTIC)
4234 printf("StringExp::semantic() %s\n", e.toChars());
4236 if (e.type)
4238 result = e;
4239 return;
4242 OutBuffer buffer;
4243 size_t newlen = 0;
4244 size_t u;
4245 dchar c;
4247 if (e.hexString)
4249 switch (e.postfix)
4251 case 'd':
4252 e.committed = true;
4253 e.sz = 4;
4254 e.type = Type.tdstring;
4255 break;
4256 case 'w':
4257 e.committed = true;
4258 e.sz = 2;
4259 e.type = Type.twstring;
4260 break;
4261 case 'c':
4262 e.committed = true;
4263 goto default;
4264 default:
4265 e.type = Type.tstring;
4266 e.sz = 1;
4267 break;
4269 if ((e.len % e.sz) != 0)
4270 error(e.loc, "hex string with `%s` type needs to be multiple of %d bytes, not %d",
4271 e.type.toChars(), e.sz, cast(int) e.len);
4273 e.setData(arrayCastBigEndian(e.peekData(), e.sz).ptr, e.len / e.sz, e.sz);
4275 else switch (e.postfix)
4277 case 'd':
4278 for (u = 0; u < e.len;)
4280 if (const p = utf_decodeChar(e.peekString(), u, c))
4282 error(e.loc, "%.*s", cast(int)p.length, p.ptr);
4283 return setError();
4285 else
4287 buffer.write4(c);
4288 newlen++;
4291 buffer.write4(0);
4292 e.setData(buffer.extractData(), newlen, 4);
4293 if (sc && sc.flags & SCOPE.Cfile)
4294 e.type = Type.tuns32.sarrayOf(e.len + 1);
4295 else
4296 e.type = Type.tdchar.immutableOf().arrayOf();
4297 e.committed = true;
4298 break;
4300 case 'w':
4301 for (u = 0; u < e.len;)
4303 if (const p = utf_decodeChar(e.peekString(), u, c))
4305 error(e.loc, "%.*s", cast(int)p.length, p.ptr);
4306 return setError();
4308 else
4310 buffer.writeUTF16(c);
4311 newlen++;
4312 if (c >= 0x10000)
4313 newlen++;
4316 buffer.writeUTF16(0);
4317 e.setData(buffer.extractData(), newlen, 2);
4318 if (sc && sc.flags & SCOPE.Cfile)
4319 e.type = Type.tuns16.sarrayOf(e.len + 1);
4320 else
4321 e.type = Type.twchar.immutableOf().arrayOf();
4322 e.committed = true;
4323 break;
4325 case 'c':
4326 e.committed = true;
4327 goto default;
4329 default:
4330 if (sc && sc.flags & SCOPE.Cfile)
4331 e.type = Type.tchar.sarrayOf(e.len + 1);
4332 else
4333 e.type = Type.tchar.immutableOf().arrayOf();
4334 break;
4336 e.type = e.type.typeSemantic(e.loc, sc);
4337 //type = type.immutableOf();
4338 //printf("type = %s\n", type.toChars());
4340 result = e;
4343 override void visit(TupleExp exp)
4345 static if (LOGSEMANTIC)
4347 printf("+TupleExp::semantic(%s)\n", exp.toChars());
4349 if (exp.type)
4351 result = exp;
4352 return;
4355 if (exp.e0)
4356 exp.e0 = exp.e0.expressionSemantic(sc);
4358 // Run semantic() on each argument
4359 bool err = false;
4360 for (size_t i = 0; i < exp.exps.length; i++)
4362 Expression e = (*exp.exps)[i];
4363 e = e.expressionSemantic(sc);
4364 if (!e.type)
4366 error(exp.loc, "`%s` has no value", e.toChars());
4367 err = true;
4369 else if (e.op == EXP.error)
4370 err = true;
4371 else
4372 (*exp.exps)[i] = e;
4374 if (err)
4375 return setError();
4377 expandTuples(exp.exps);
4379 exp.type = new TypeTuple(exp.exps);
4380 exp.type = exp.type.typeSemantic(exp.loc, sc);
4381 //printf("-TupleExp::semantic(%s)\n", toChars());
4382 result = exp;
4385 override void visit(ArrayLiteralExp e)
4387 static if (LOGSEMANTIC)
4389 printf("ArrayLiteralExp::semantic('%s')\n", e.toChars());
4391 if (e.type)
4393 result = e;
4394 return;
4397 /* Perhaps an empty array literal [ ] should be rewritten as null?
4400 if (e.basis)
4401 e.basis = e.basis.expressionSemantic(sc);
4402 if (arrayExpressionSemantic(e.elements.peekSlice(), sc) || (e.basis && e.basis.op == EXP.error))
4403 return setError();
4405 expandTuples(e.elements);
4407 if (e.basis)
4408 e.elements.push(e.basis);
4409 Type t0 = arrayExpressionToCommonType(sc, *e.elements);
4410 if (e.basis)
4411 e.basis = e.elements.pop();
4412 if (t0 is null)
4413 return setError();
4415 e.type = t0.arrayOf();
4416 e.type = e.type.typeSemantic(e.loc, sc);
4418 /* Disallow array literals of type void being used.
4420 if (e.elements.length > 0 && t0.ty == Tvoid)
4422 error(e.loc, "`%s` of type `%s` has no value", e.toChars(), e.type.toChars());
4423 return setError();
4426 if (global.params.useTypeInfo && Type.dtypeinfo)
4427 semanticTypeInfo(sc, e.type);
4429 result = e;
4432 override void visit(AssocArrayLiteralExp e)
4434 static if (LOGSEMANTIC)
4436 printf("AssocArrayLiteralExp::semantic('%s')\n", e.toChars());
4438 if (e.type)
4440 result = e;
4441 return;
4444 // Run semantic() on each element
4445 bool err_keys = arrayExpressionSemantic(e.keys.peekSlice(), sc);
4446 bool err_vals = arrayExpressionSemantic(e.values.peekSlice(), sc);
4447 if (err_keys || err_vals)
4448 return setError();
4450 expandTuples(e.keys);
4451 expandTuples(e.values);
4452 if (e.keys.length != e.values.length)
4454 error(e.loc, "number of keys is %llu, must match number of values %llu",
4455 cast(ulong) e.keys.length, cast(ulong) e.values.length);
4456 return setError();
4459 Type tkey = arrayExpressionToCommonType(sc, *e.keys);
4460 Type tvalue = arrayExpressionToCommonType(sc, *e.values);
4461 if (tkey is null || tvalue is null)
4462 return setError();
4464 e.type = new TypeAArray(tvalue, tkey);
4465 e.type = e.type.typeSemantic(e.loc, sc);
4467 semanticTypeInfo(sc, e.type);
4469 if (checkAssocArrayLiteralEscape(sc, e, false))
4470 return setError();
4472 result = e;
4475 override void visit(StructLiteralExp e)
4477 static if (LOGSEMANTIC)
4479 printf("StructLiteralExp::semantic('%s')\n", e.toChars());
4481 if (e.type)
4483 result = e;
4484 return;
4487 e.sd.size(e.loc);
4488 if (e.sd.sizeok != Sizeok.done)
4489 return setError();
4491 // run semantic() on each element
4492 if (arrayExpressionSemantic(e.elements.peekSlice(), sc))
4493 return setError();
4495 expandTuples(e.elements);
4497 /* Fit elements[] to the corresponding type of field[].
4499 if (!e.sd.fit(e.loc, sc, e.elements, e.stype))
4500 return setError();
4502 /* Fill out remainder of elements[] with default initializers for fields[]
4504 if (!e.sd.fill(e.loc, *e.elements, false))
4506 /* An error in the initializer needs to be recorded as an error
4507 * in the enclosing function or template, since the initializer
4508 * will be part of the stuct declaration.
4510 global.increaseErrorCount();
4511 return setError();
4514 if (checkFrameAccess(e.loc, sc, e.sd, e.elements.length))
4515 return setError();
4517 e.type = e.stype ? e.stype : e.sd.type;
4518 result = e;
4521 override void visit(CompoundLiteralExp cle)
4523 static if (LOGSEMANTIC)
4525 printf("CompoundLiteralExp::semantic('%s')\n", cle.toChars());
4527 Type t = cle.type.typeSemantic(cle.loc, sc);
4528 auto init = initializerSemantic(cle.initializer, sc, t, INITnointerpret);
4529 auto e = initializerToExpression(init, t, (sc.flags & SCOPE.Cfile) != 0);
4530 if (!e)
4532 error(cle.loc, "cannot convert initializer `%s` to expression", toChars(init));
4533 return setError();
4535 result = e;
4536 return;
4539 override void visit(TypeExp exp)
4541 if (exp.type.ty == Terror)
4542 return setError();
4544 //printf("TypeExp::semantic(%s)\n", exp.type.toChars());
4545 Expression e;
4546 Type t;
4547 Dsymbol s;
4549 dmd.typesem.resolve(exp.type, exp.loc, sc, e, t, s, true);
4550 if (e)
4552 // `(Type)` is actually `(var)` so if `(var)` is a member requiring `this`
4553 // then rewrite as `(this.var)` in case it would be followed by a DotVar
4554 // to fix https://issues.dlang.org/show_bug.cgi?id=9490
4555 VarExp ve = e.isVarExp();
4556 if (ve && ve.var && exp.parens && !ve.var.isStatic() && !(sc.stc & STC.static_) &&
4557 sc.func && sc.func.needThis && ve.var.isMember2())
4559 // printf("apply fix for bugzilla issue 9490: add `this.` to `%s`...\n", e.toChars());
4560 e = new DotVarExp(exp.loc, new ThisExp(exp.loc), ve.var, false);
4562 //printf("e = %s %s\n", Token.toChars(e.op), e.toChars());
4563 e = e.expressionSemantic(sc);
4565 else if (t)
4567 //printf("t = %d %s\n", t.ty, t.toChars());
4568 exp.type = t.typeSemantic(exp.loc, sc);
4569 e = exp;
4571 else if (s)
4573 //printf("s = %s %s\n", s.kind(), s.toChars());
4574 e = symbolToExp(s, exp.loc, sc, true);
4576 else
4577 assert(0);
4579 exp.type.checkComplexTransition(exp.loc, sc);
4581 result = e;
4584 override void visit(ScopeExp exp)
4586 static if (LOGSEMANTIC)
4588 printf("+ScopeExp::semantic(%p '%s')\n", exp, exp.toChars());
4590 if (exp.type)
4592 result = exp;
4593 return;
4596 ScopeDsymbol sds2 = exp.sds;
4597 TemplateInstance ti = sds2.isTemplateInstance();
4598 while (ti)
4600 WithScopeSymbol withsym;
4601 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc))
4602 return setError();
4603 if (withsym && withsym.withstate.wthis)
4605 Expression e = new VarExp(exp.loc, withsym.withstate.wthis);
4606 e = new DotTemplateInstanceExp(exp.loc, e, ti);
4607 result = e.expressionSemantic(sc);
4608 return;
4610 if (ti.needsTypeInference(sc))
4612 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
4614 Dsymbol p = td.toParentLocal();
4615 FuncDeclaration fdthis = hasThis(sc);
4616 AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null;
4617 if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0)
4619 Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti);
4620 result = e.expressionSemantic(sc);
4621 return;
4624 else if (OverloadSet os = ti.tempdecl.isOverloadSet())
4626 FuncDeclaration fdthis = hasThis(sc);
4627 AggregateDeclaration ad = os.parent.isAggregateDeclaration();
4628 if (fdthis && ad && fdthis.isMemberLocal() == ad)
4630 Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti);
4631 result = e.expressionSemantic(sc);
4632 return;
4635 // ti is an instance which requires IFTI.
4636 exp.sds = ti;
4637 exp.type = Type.tvoid;
4638 result = exp;
4639 return;
4641 ti.dsymbolSemantic(sc);
4642 if (!ti.inst || ti.errors)
4643 return setError();
4645 Dsymbol s = ti.toAlias();
4646 if (s == ti)
4648 exp.sds = ti;
4649 exp.type = Type.tvoid;
4650 result = exp;
4651 return;
4653 sds2 = s.isScopeDsymbol();
4654 if (sds2)
4656 ti = sds2.isTemplateInstance();
4657 //printf("+ sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
4658 continue;
4661 if (auto v = s.isVarDeclaration())
4663 if (!v.type)
4665 error(exp.loc, "forward reference of %s `%s`", v.kind(), v.toChars());
4666 return setError();
4668 if ((v.storage_class & STC.manifest) && v._init)
4670 /* When an instance that will be converted to a constant exists,
4671 * the instance representation "foo!tiargs" is treated like a
4672 * variable name, and its recursive appearance check (note that
4673 * it's equivalent with a recursive instantiation of foo) is done
4674 * separately from the circular initialization check for the
4675 * eponymous enum variable declaration.
4677 * template foo(T) {
4678 * enum bool foo = foo; // recursive definition check (v.inuse)
4680 * template bar(T) {
4681 * enum bool bar = bar!T; // recursive instantiation check (ti.inuse)
4684 if (ti.inuse)
4686 error(exp.loc, "recursive expansion of %s `%s`", ti.kind(), ti.toPrettyChars());
4687 return setError();
4689 v.checkDeprecated(exp.loc, sc);
4690 auto e = v.expandInitializer(exp.loc);
4691 ti.inuse++;
4692 e = e.expressionSemantic(sc);
4693 ti.inuse--;
4694 result = e;
4695 return;
4699 //printf("s = %s, '%s'\n", s.kind(), s.toChars());
4700 auto e = symbolToExp(s, exp.loc, sc, true);
4701 //printf("-1ScopeExp::semantic()\n");
4702 result = e;
4703 return;
4706 //printf("sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
4707 //printf("\tparent = '%s'\n", sds2.parent.toChars());
4708 sds2.dsymbolSemantic(sc);
4710 // (Aggregate|Enum)Declaration
4711 if (auto t = sds2.getType())
4713 result = (new TypeExp(exp.loc, t)).expressionSemantic(sc);
4714 return;
4717 if (auto td = sds2.isTemplateDeclaration())
4719 result = (new TemplateExp(exp.loc, td)).expressionSemantic(sc);
4720 return;
4723 exp.sds = sds2;
4724 exp.type = Type.tvoid;
4725 //printf("-2ScopeExp::semantic() %s\n", toChars());
4726 result = exp;
4730 * Sets the `lowering` field of a `NewExp` to a call to `_d_newitemT` unless
4731 * compiling with `-betterC` or within `__traits(compiles)`.
4733 * Params:
4734 * ne = the `NewExp` to lower
4736 private void tryLowerToNewItem(NewExp ne)
4738 if (!global.params.useGC || !sc.needsCodegen())
4739 return;
4741 auto hook = global.params.tracegc ? Id._d_newitemTTrace : Id._d_newitemT;
4742 if (!verifyHookExist(ne.loc, *sc, hook, "new struct"))
4743 return;
4745 /* Lower the memory allocation and initialization of `new T()` to
4746 * `_d_newitemT!T()`.
4748 Expression id = new IdentifierExp(ne.loc, Id.empty);
4749 id = new DotIdExp(ne.loc, id, Id.object);
4750 auto tiargs = new Objects();
4752 * Remove `inout`, `const`, `immutable` and `shared` to reduce the
4753 * number of generated `_d_newitemT` instances.
4755 auto t = ne.type.nextOf.unqualify(MODFlags.wild | MODFlags.const_ |
4756 MODFlags.immutable_ | MODFlags.shared_);
4757 tiargs.push(t);
4758 id = new DotTemplateInstanceExp(ne.loc, id, hook, tiargs);
4760 auto arguments = new Expressions();
4761 if (global.params.tracegc)
4763 auto funcname = (sc.callsc && sc.callsc.func) ?
4764 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
4765 arguments.push(new StringExp(ne.loc, ne.loc.filename.toDString()));
4766 arguments.push(new IntegerExp(ne.loc, ne.loc.linnum, Type.tint32));
4767 arguments.push(new StringExp(ne.loc, funcname.toDString()));
4769 id = new CallExp(ne.loc, id, arguments);
4771 ne.lowering = id.expressionSemantic(sc);
4774 override void visit(NewExp exp)
4776 static if (LOGSEMANTIC)
4778 printf("NewExp::semantic() %s\n", exp.toChars());
4779 if (exp.thisexp)
4780 printf("\tthisexp = %s\n", exp.thisexp.toChars());
4781 printf("\tnewtype: %s\n", exp.newtype.toChars());
4783 if (exp.type) // if semantic() already run
4785 result = exp;
4786 return;
4789 //for error messages if the argument in [] is not convertible to size_t
4790 const originalNewtype = exp.newtype;
4792 // https://issues.dlang.org/show_bug.cgi?id=11581
4793 // With the syntax `new T[edim]` or `thisexp.new T[edim]`,
4794 // T should be analyzed first and edim should go into arguments iff it's
4795 // not a tuple.
4796 Expression edim = null;
4797 if (!exp.arguments && exp.newtype.isTypeSArray())
4799 auto ts = exp.newtype.isTypeSArray();
4800 // check `new Value[Key]`
4801 ts.dim = ts.dim.expressionSemantic(sc);
4802 if (ts.dim.op == EXP.type)
4804 exp.newtype = new TypeAArray(ts.next, ts.dim.isTypeExp().type);
4806 else
4808 edim = ts.dim;
4809 exp.newtype = ts.next;
4813 ClassDeclaration cdthis = null;
4814 if (exp.thisexp)
4816 exp.thisexp = exp.thisexp.expressionSemantic(sc);
4817 if (exp.thisexp.op == EXP.error)
4818 return setError();
4820 cdthis = exp.thisexp.type.isClassHandle();
4821 if (!cdthis)
4823 error(exp.loc, "`this` for nested class must be a class type, not `%s`", exp.thisexp.type.toChars());
4824 return setError();
4827 sc = sc.push(cdthis);
4828 exp.type = exp.newtype.typeSemantic(exp.loc, sc);
4829 sc = sc.pop();
4831 else
4833 exp.type = exp.newtype.typeSemantic(exp.loc, sc);
4835 if (exp.type.ty == Terror)
4836 return setError();
4838 if (edim)
4840 if (exp.type.toBasetype().ty == Ttuple)
4842 // --> new T[edim]
4843 exp.type = new TypeSArray(exp.type, edim);
4844 exp.type = exp.type.typeSemantic(exp.loc, sc);
4845 if (exp.type.ty == Terror)
4846 return setError();
4848 else
4850 // --> new T[](edim)
4851 exp.arguments = new Expressions();
4852 exp.arguments.push(edim);
4853 exp.type = exp.type.arrayOf();
4857 exp.newtype = exp.type; // in case type gets cast to something else
4858 Type tb = exp.type.toBasetype();
4859 //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco);
4860 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc))
4862 return setError();
4864 if (preFunctionParameters(sc, exp.argumentList))
4866 return setError();
4869 if (exp.thisexp && tb.ty != Tclass)
4871 error(exp.loc, "`.new` is only for allocating nested classes, not `%s`", tb.toChars());
4872 return setError();
4875 const size_t nargs = exp.arguments ? exp.arguments.length : 0;
4876 Expression newprefix = null;
4878 if (auto tc = tb.isTypeClass())
4880 auto cd = tc.sym;
4881 if (cd.errors)
4882 return setError();
4883 cd.size(exp.loc);
4884 if (cd.sizeok != Sizeok.done)
4885 return setError();
4886 if (!cd.ctor)
4887 cd.ctor = cd.searchCtor();
4888 if (cd.noDefaultCtor && !nargs && !cd.defaultCtor)
4890 error(exp.loc, "default construction is disabled for type `%s`", cd.type.toChars());
4891 return setError();
4894 if (cd.isInterfaceDeclaration())
4896 error(exp.loc, "cannot create instance of interface `%s`", cd.toChars());
4897 return setError();
4900 if (cd.isAbstract())
4902 error(exp.loc, "cannot create instance of abstract class `%s`", cd.toChars());
4903 errorSupplemental(cd.loc, "class `%s` is declared here", cd.toChars());
4904 for (size_t i = 0; i < cd.vtbl.length; i++)
4906 FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration();
4907 if (fd && fd.isAbstract())
4909 errorSupplemental(fd.loc, "function `%s` is not implemented",
4910 fd.toFullSignature());
4913 return setError();
4915 // checkDeprecated() is already done in newtype.typeSemantic().
4917 if (cd.isNested())
4919 /* We need a 'this' pointer for the nested class.
4920 * Ensure we have the right one.
4922 Dsymbol s = cd.toParentLocal();
4924 //printf("cd isNested, parent = %s '%s'\n", s.kind(), s.toPrettyChars());
4925 if (auto cdn = s.isClassDeclaration())
4927 if (!cdthis)
4929 void noReferenceToOuterClass()
4931 if (cd.isAnonymous)
4932 error(exp.loc, "cannot construct anonymous nested class because no implicit `this` reference to outer class is available");
4933 else
4934 error(exp.loc, "cannot construct nested class `%s` because no implicit `this` reference to outer class `%s` is available",
4935 cd.toChars(), cdn.toChars());
4936 return setError();
4939 if (!sc.hasThis)
4940 return noReferenceToOuterClass();
4942 // Supply an implicit 'this' and try again
4943 exp.thisexp = new ThisExp(exp.loc);
4944 for (Dsymbol sp = sc.parent; 1; sp = sp.toParentLocal())
4946 if (!sp)
4947 return noReferenceToOuterClass();
4948 ClassDeclaration cdp = sp.isClassDeclaration();
4949 if (!cdp)
4950 continue;
4951 if (cdp == cdn || cdn.isBaseOf(cdp, null))
4952 break;
4953 // Add a '.outer' and try again
4954 exp.thisexp = new DotIdExp(exp.loc, exp.thisexp, Id.outer);
4957 exp.thisexp = exp.thisexp.expressionSemantic(sc);
4958 if (exp.thisexp.op == EXP.error)
4959 return setError();
4960 cdthis = exp.thisexp.type.isClassHandle();
4962 if (cdthis != cdn && !cdn.isBaseOf(cdthis, null))
4964 //printf("cdthis = %s\n", cdthis.toChars());
4965 error(exp.loc, "`this` for nested class must be of type `%s`, not `%s`",
4966 cdn.toChars(), exp.thisexp.type.toChars());
4967 return setError();
4969 if (!MODimplicitConv(exp.thisexp.type.mod, exp.newtype.mod))
4971 error(exp.loc, "nested type `%s` should have the same or weaker constancy as enclosing type `%s`",
4972 exp.newtype.toChars(), exp.thisexp.type.toChars());
4973 return setError();
4976 else if (exp.thisexp)
4978 error(exp.loc, "`.new` is only for allocating nested classes");
4979 return setError();
4981 else if (auto fdn = s.isFuncDeclaration())
4983 // make sure the parent context fdn of cd is reachable from sc
4984 if (!ensureStaticLinkTo(sc.parent, fdn))
4986 error(exp.loc, "outer function context of `%s` is needed to `new` nested class `%s`",
4987 fdn.toPrettyChars(), cd.toPrettyChars());
4988 return setError();
4991 else
4992 assert(0);
4994 else if (exp.thisexp)
4996 error(exp.loc, "`.new` is only for allocating nested classes");
4997 return setError();
5000 if (cd.vthis2)
5002 if (AggregateDeclaration ad2 = cd.isMember2())
5004 Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
5005 if (te.op != EXP.error)
5006 te = getRightThis(exp.loc, sc, ad2, te, cd);
5007 if (te.op == EXP.error)
5009 error(exp.loc, "need `this` of type `%s` needed to `new` nested class `%s`", ad2.toChars(), cd.toChars());
5010 return setError();
5015 if (cd.disableNew && !exp.onstack)
5017 error(exp.loc, "cannot allocate `class %s` with `new` because it is annotated with `@disable new()`",
5018 originalNewtype.toChars());
5019 return setError();
5022 if (cd.ctor)
5024 FuncDeclaration f = resolveFuncCall(exp.loc, sc, cd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard);
5025 if (!f || f.errors)
5026 return setError();
5028 checkFunctionAttributes(exp, sc, f);
5029 if (!checkSymbolAccess(sc, f))
5031 error(exp.loc, "%s `%s` is not accessible from module `%s`",
5032 f.kind(), f.toPrettyChars(), sc._module.toChars);
5033 return setError();
5036 TypeFunction tf = f.type.isTypeFunction();
5037 if (!exp.arguments)
5038 exp.arguments = new Expressions();
5039 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix))
5040 return setError();
5042 exp.member = f.isCtorDeclaration();
5043 assert(exp.member);
5045 else
5047 if (nargs)
5049 error(exp.loc, "no constructor for `%s`", cd.toChars());
5050 return setError();
5053 // https://issues.dlang.org/show_bug.cgi?id=19941
5054 // Run semantic on all field initializers to resolve any forward
5055 // references. This is the same as done for structs in sd.fill().
5056 for (ClassDeclaration c = cd; c; c = c.baseClass)
5058 foreach (v; c.fields)
5060 if (v.inuse || v._scope is null || v._init is null ||
5061 v._init.isVoidInitializer() || v.semanticRun >= PASS.semantic2done)
5062 continue;
5063 v.inuse++;
5064 v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret);
5065 import dmd.semantic2 : lowerStaticAAs;
5066 lowerStaticAAs(v, sc);
5067 v.inuse--;
5072 // When using `@nogc` exception handling, lower `throw new E(args)` to
5073 // `throw (__tmp = _d_newThrowable!E(), __tmp.__ctor(args), __tmp)`.
5074 if (global.params.ehnogc && exp.thrownew &&
5075 !cd.isCOMclass() && !cd.isCPPclass())
5077 assert(cd.ctor);
5079 Expression id = new IdentifierExp(exp.loc, Id.empty);
5080 id = new DotIdExp(exp.loc, id, Id.object);
5082 auto tiargs = new Objects();
5083 tiargs.push(exp.newtype);
5084 id = new DotTemplateInstanceExp(exp.loc, id, Id._d_newThrowable, tiargs);
5085 id = new CallExp(exp.loc, id).expressionSemantic(sc);
5087 Expression idVal;
5088 Expression tmp = extractSideEffect(sc, "__tmpThrowable", idVal, id, true);
5089 // auto castTmp = new CastExp(exp.loc, tmp, exp.type);
5091 auto ctor = new DotIdExp(exp.loc, tmp, Id.ctor).expressionSemantic(sc);
5092 auto ctorCall = new CallExp(exp.loc, ctor, exp.arguments);
5094 id = Expression.combine(idVal, exp.argprefix).expressionSemantic(sc);
5095 id = Expression.combine(id, ctorCall).expressionSemantic(sc);
5096 // id = Expression.combine(id, castTmp).expressionSemantic(sc);
5098 result = id.expressionSemantic(sc);
5099 return;
5101 else if (sc.needsCodegen() && // interpreter doesn't need this lowered
5102 !exp.onstack && !exp.type.isscope()) // these won't use the GC
5104 /* replace `new T(arguments)` with `core.lifetime._d_newclassT!T(arguments)`
5105 * or `_d_newclassTTrace`
5107 auto hook = global.params.tracegc ? Id._d_newclassTTrace : Id._d_newclassT;
5108 if (!verifyHookExist(exp.loc, *sc, hook, "new class"))
5109 return setError();
5111 Expression id = new IdentifierExp(exp.loc, Id.empty);
5112 id = new DotIdExp(exp.loc, id, Id.object);
5114 auto tiargs = new Objects();
5115 auto t = exp.newtype.unqualify(MODFlags.wild); // remove `inout`
5116 tiargs.push(t);
5117 id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs);
5118 auto arguments = new Expressions();
5119 if (global.params.tracegc)
5121 auto funcname = (sc.callsc && sc.callsc.func) ?
5122 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
5123 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
5124 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
5125 arguments.push(new StringExp(exp.loc, funcname.toDString()));
5127 id = new CallExp(exp.loc, id, arguments);
5129 exp.lowering = id.expressionSemantic(sc);
5132 else if (auto ts = tb.isTypeStruct())
5134 auto sd = ts.sym;
5135 sd.size(exp.loc);
5136 if (sd.sizeok != Sizeok.done)
5137 return setError();
5138 if (!sd.ctor)
5139 sd.ctor = sd.searchCtor();
5140 if (sd.noDefaultCtor && !nargs)
5142 error(exp.loc, "default construction is disabled for type `%s`", sd.type.toChars());
5143 return setError();
5145 // checkDeprecated() is already done in newtype.typeSemantic().
5147 if (sd.disableNew)
5149 error(exp.loc, "cannot allocate `struct %s` with `new` because it is annotated with `@disable new()`",
5150 originalNewtype.toChars());
5151 return setError();
5154 // https://issues.dlang.org/show_bug.cgi?id=22639
5155 // If the new expression has arguments, we either should call a
5156 // regular constructor of a copy constructor if the first argument
5157 // is the same type as the struct
5158 if (nargs && (sd.hasRegularCtor() || (sd.ctor && (*exp.arguments)[0].type.mutableOf() == sd.type.mutableOf())))
5160 FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard);
5161 if (!f || f.errors)
5162 return setError();
5164 checkFunctionAttributes(exp, sc, f);
5165 checkAccess(sd, exp.loc, sc, f);
5167 TypeFunction tf = f.type.isTypeFunction();
5168 if (!exp.arguments)
5169 exp.arguments = new Expressions();
5170 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix))
5171 return setError();
5173 exp.member = f.isCtorDeclaration();
5174 assert(exp.member);
5176 if (checkFrameAccess(exp.loc, sc, sd, sd.fields.length))
5177 return setError();
5179 else
5181 if (exp.names)
5183 exp.arguments = resolveStructLiteralNamedArgs(sd, exp.type, sc, exp.loc,
5184 exp.names ? (*exp.names)[] : null,
5185 (size_t i, Type t) => (*exp.arguments)[i],
5186 i => (*exp.arguments)[i].loc
5188 if (!exp.arguments)
5189 return setError();
5191 else if (!exp.arguments)
5193 exp.arguments = new Expressions();
5196 if (!sd.fit(exp.loc, sc, exp.arguments, tb))
5197 return setError();
5199 if (!sd.fill(exp.loc, *exp.arguments, false))
5200 return setError();
5202 if (checkFrameAccess(exp.loc, sc, sd, exp.arguments ? exp.arguments.length : 0))
5203 return setError();
5205 /* Since a `new` allocation may escape, check each of the arguments for escaping
5207 foreach (arg; *exp.arguments)
5209 if (arg && checkNewEscape(sc, arg, false))
5210 return setError();
5214 exp.type = exp.type.pointerTo();
5215 tryLowerToNewItem(exp);
5217 else if (tb.ty == Tarray)
5219 if (!nargs)
5221 // https://issues.dlang.org/show_bug.cgi?id=20422
5222 // Without this check the compiler would give a misleading error
5223 error(exp.loc, "missing length argument for array");
5224 return setError();
5227 Type tn = tb.nextOf().baseElemOf();
5228 Dsymbol s = tn.toDsymbol(sc);
5229 AggregateDeclaration ad = s ? s.isAggregateDeclaration() : null;
5230 if (ad && ad.noDefaultCtor)
5232 error(exp.loc, "default construction is disabled for type `%s`", tb.nextOf().toChars());
5233 return setError();
5235 for (size_t i = 0; i < nargs; i++)
5237 if (tb.ty != Tarray)
5239 error(exp.loc, "too many arguments for array");
5240 return setError();
5243 Expression arg = (*exp.arguments)[i];
5244 if (exp.names && (*exp.names)[i])
5246 error(exp.loc, "no named argument `%s` allowed for array dimension", (*exp.names)[i].toChars());
5247 return setError();
5250 arg = resolveProperties(sc, arg);
5251 arg = arg.implicitCastTo(sc, Type.tsize_t);
5252 if (arg.op == EXP.error)
5253 return setError();
5254 arg = arg.optimize(WANTvalue);
5255 if (arg.op == EXP.int64 && (target.isLP64 ?
5256 cast(sinteger_t)arg.toInteger() : cast(int)arg.toInteger()) < 0)
5258 error(exp.loc, "negative array dimension `%s`", (*exp.arguments)[i].toChars());
5259 return setError();
5261 (*exp.arguments)[i] = arg;
5262 tb = tb.isTypeDArray().next.toBasetype();
5265 if (!global.params.useGC && sc.needsCodegen())
5267 version(IN_GCC)
5268 error(exp.loc, "expression `%s` allocates with the GC and cannot be used with switch `-fno-rtti`", exp.toChars());
5269 else
5270 error(exp.loc, "expression `%s` allocates with the GC and cannot be used with switch `-betterC`", exp.toChars());
5271 return setError();
5274 if (!sc.needsCodegen())
5275 goto LskipNewArrayLowering;
5277 /* Class types may inherit base classes that have errors.
5278 * This may leak errors from the base class to the derived one
5279 * and then to the hook. Semantic analysis is performed eagerly
5280 * to a void this.
5282 if (auto tc = exp.type.nextOf.isTypeClass())
5284 tc.sym.dsymbolSemantic(sc);
5285 if (tc.sym.errors)
5286 goto LskipNewArrayLowering;
5289 if (nargs == 1)
5291 auto hook = global.params.tracegc ? Id._d_newarrayTTrace : Id._d_newarrayT;
5292 if (!verifyHookExist(exp.loc, *sc, hook, "new array"))
5293 goto LskipNewArrayLowering;
5295 /* Lower the memory allocation and initialization of `new T[n]`
5296 * to `_d_newarrayT!T(n)`.
5298 Expression lowering = new IdentifierExp(exp.loc, Id.empty);
5299 lowering = new DotIdExp(exp.loc, lowering, Id.object);
5300 auto tiargs = new Objects();
5301 /* Remove `inout`, `const`, `immutable` and `shared` to reduce
5302 * the number of generated `_d_newarrayT` instances.
5304 const isShared = exp.type.nextOf.isShared();
5305 auto t = exp.type.nextOf.unqualify(MODFlags.wild | MODFlags.const_ |
5306 MODFlags.immutable_ | MODFlags.shared_);
5307 tiargs.push(t);
5308 lowering = new DotTemplateInstanceExp(exp.loc, lowering, hook, tiargs);
5310 auto arguments = new Expressions();
5311 if (global.params.tracegc)
5313 auto funcname = (sc.callsc && sc.callsc.func) ?
5314 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
5315 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
5316 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
5317 arguments.push(new StringExp(exp.loc, funcname.toDString()));
5319 arguments.push((*exp.arguments)[0]);
5320 arguments.push(new IntegerExp(exp.loc, isShared, Type.tbool));
5322 lowering = new CallExp(exp.loc, lowering, arguments);
5323 exp.lowering = lowering.expressionSemantic(sc);
5325 else
5327 auto hook = global.params.tracegc ? Id._d_newarraymTXTrace : Id._d_newarraymTX;
5328 if (!verifyHookExist(exp.loc, *sc, hook, "new multi-dimensional array"))
5329 goto LskipNewArrayLowering;
5331 /* Lower the memory allocation and initialization of `new T[][]...[](n1, n2, ...)`
5332 * to `_d_newarraymTX!(T[][]...[], T)([n1, n2, ...])`.
5334 Expression lowering = new IdentifierExp(exp.loc, Id.empty);
5335 lowering = new DotIdExp(exp.loc, lowering, Id.object);
5337 auto tbn = exp.type.nextOf();
5338 while (tbn.ty == Tarray)
5339 tbn = tbn.nextOf();
5340 auto unqualTbn = tbn.unqualify(MODFlags.wild | MODFlags.const_ |
5341 MODFlags.immutable_ | MODFlags.shared_);
5343 auto tiargs = new Objects();
5344 tiargs.push(exp.type);
5345 tiargs.push(unqualTbn);
5346 lowering = new DotTemplateInstanceExp(exp.loc, lowering, hook, tiargs);
5348 auto arguments = new Expressions();
5349 if (global.params.tracegc)
5351 auto funcname = (sc.callsc && sc.callsc.func) ?
5352 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
5353 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
5354 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
5355 arguments.push(new StringExp(exp.loc, funcname.toDString()));
5358 arguments.push(new ArrayLiteralExp(exp.loc, Type.tsize_t.sarrayOf(nargs), exp.arguments));
5359 arguments.push(new IntegerExp(exp.loc, tbn.isShared(), Type.tbool));
5361 lowering = new CallExp(exp.loc, lowering, arguments);
5362 exp.lowering = lowering.expressionSemantic(sc);
5365 else if (tb.isscalar())
5367 if (!nargs)
5370 else if (nargs == 1)
5372 if (exp.names && (*exp.names)[0])
5374 error(exp.loc, "no named argument `%s` allowed for scalar", (*exp.names)[0].toChars());
5375 return setError();
5377 Expression e = (*exp.arguments)[0];
5378 e = e.implicitCastTo(sc, tb);
5379 (*exp.arguments)[0] = e;
5381 else
5383 error(exp.loc, "more than one argument for construction of `%s`", exp.type.toChars());
5384 return setError();
5387 exp.type = exp.type.pointerTo();
5388 tryLowerToNewItem(exp);
5390 else if (tb.ty == Taarray)
5392 // e.g. `new Alias(args)`
5393 if (nargs)
5395 error(exp.loc, "`new` cannot take arguments for an associative array");
5396 return setError();
5399 else
5401 error(exp.loc, "cannot create a `%s` with `new`", exp.type.toChars());
5402 return setError();
5405 LskipNewArrayLowering:
5406 //printf("NewExp: '%s'\n", toChars());
5407 //printf("NewExp:type '%s'\n", type.toChars());
5408 semanticTypeInfo(sc, exp.type);
5410 if (newprefix)
5412 result = Expression.combine(newprefix, exp);
5413 return;
5415 result = exp;
5418 override void visit(NewAnonClassExp e)
5420 static if (LOGSEMANTIC)
5422 printf("NewAnonClassExp::semantic() %s\n", e.toChars());
5423 //printf("thisexp = %p\n", thisexp);
5424 //printf("type: %s\n", type.toChars());
5427 Expression d = new DeclarationExp(e.loc, e.cd);
5428 sc = sc.push(); // just create new scope
5429 sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
5430 d = d.expressionSemantic(sc);
5431 sc = sc.pop();
5433 if (!e.cd.errors && sc.intypeof && !sc.parent.inNonRoot())
5435 ScopeDsymbol sds = sc.tinst ? cast(ScopeDsymbol)sc.tinst : sc._module;
5436 if (!sds.members)
5437 sds.members = new Dsymbols();
5438 sds.members.push(e.cd);
5441 Expression n = new NewExp(e.loc, e.thisexp, e.cd.type, e.arguments);
5443 Expression c = new CommaExp(e.loc, d, n);
5444 result = c.expressionSemantic(sc);
5447 override void visit(SymOffExp e)
5449 static if (LOGSEMANTIC)
5451 printf("SymOffExp::semantic('%s')\n", e.toChars());
5453 //var.dsymbolSemantic(sc);
5454 if (!e.type)
5455 e.type = e.var.type.pointerTo();
5457 if (auto v = e.var.isVarDeclaration())
5459 if (v.checkNestedReference(sc, e.loc))
5460 return setError();
5462 else if (auto f = e.var.isFuncDeclaration())
5464 if (f.checkNestedReference(sc, e.loc))
5465 return setError();
5468 result = e;
5471 override void visit(VarExp e)
5473 static if (LOGSEMANTIC)
5475 printf("VarExp::semantic(%s)\n", e.toChars());
5478 auto vd = e.var.isVarDeclaration();
5479 auto fd = e.var.isFuncDeclaration();
5481 if (fd)
5483 //printf("L%d fd = %s\n", __LINE__, f.toChars());
5484 if (!functionSemantic(fd))
5485 return setError();
5488 if (!e.type)
5489 e.type = e.var.type;
5490 if (e.type && !e.type.deco)
5492 auto decl = e.var.isDeclaration();
5493 if (decl)
5494 decl.inuse++;
5495 e.type = e.type.typeSemantic(e.loc, sc);
5496 if (decl)
5497 decl.inuse--;
5500 /* Fix for 1161 doesn't work because it causes visibility
5501 * problems when instantiating imported templates passing private
5502 * variables as alias template parameters.
5504 //checkAccess(loc, sc, NULL, var);
5506 if (vd)
5508 if (vd.checkNestedReference(sc, e.loc))
5509 return setError();
5511 // https://issues.dlang.org/show_bug.cgi?id=12025
5512 // If the variable is not actually used in runtime code,
5513 // the purity violation error is redundant.
5514 //checkPurity(sc, vd);
5516 else if (fd)
5518 // TODO: If fd isn't yet resolved its overload, the checkNestedReference
5519 // call would cause incorrect validation.
5520 // Maybe here should be moved in CallExp, or AddrExp for functions.
5521 if (fd.checkNestedReference(sc, e.loc))
5522 return setError();
5524 else if (auto od = e.var.isOverDeclaration())
5526 e.type = Type.tvoid; // ambiguous type?
5529 result = e;
5532 private void genIdent(FuncExp exp, Scope* sc)
5534 if (exp.fd.ident == Id.empty)
5536 const(char)[] s;
5537 if (exp.fd.fes)
5538 s = "__foreachbody";
5539 else if (exp.fd.tok == TOK.reserved)
5540 s = "__lambda";
5541 else if (exp.fd.tok == TOK.delegate_)
5542 s = "__dgliteral";
5543 else
5544 s = "__funcliteral";
5546 DsymbolTable symtab;
5547 if (FuncDeclaration func = sc.parent.isFuncDeclaration())
5549 if (func.localsymtab is null)
5551 // Inside template constraint, symtab is not set yet.
5552 // Initialize it lazily.
5553 func.localsymtab = new DsymbolTable();
5555 symtab = func.localsymtab;
5557 else
5559 ScopeDsymbol sds = sc.parent.isScopeDsymbol();
5560 if (!sds.symtab)
5562 // Inside template constraint, symtab may not be set yet.
5563 // Initialize it lazily.
5564 assert(sds.isTemplateInstance());
5565 sds.symtab = new DsymbolTable();
5567 symtab = sds.symtab;
5569 assert(symtab);
5570 Identifier id = Identifier.generateId(s, symtab.length() + 1);
5571 exp.fd.ident = id;
5572 if (exp.td)
5573 exp.td.ident = id;
5574 symtab.insert(exp.td ? cast(Dsymbol)exp.td : cast(Dsymbol)exp.fd);
5578 override void visit(FuncExp exp)
5580 static if (LOGSEMANTIC)
5582 printf("FuncExp::semantic(%s)\n", exp.toChars());
5583 if (exp.fd.treq)
5584 printf(" treq = %s\n", exp.fd.treq.toChars());
5587 if (exp.type)
5589 result = exp;
5590 return;
5593 Expression e = exp;
5594 uint olderrors;
5596 sc = sc.push(); // just create new scope
5597 sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
5598 sc.visibility = Visibility(Visibility.Kind.public_); // https://issues.dlang.org/show_bug.cgi?id=12506
5600 /* fd.treq might be incomplete type,
5601 * so should not semantic it.
5602 * void foo(T)(T delegate(int) dg){}
5603 * foo(a=>a); // in IFTI, treq == T delegate(int)
5605 //if (fd.treq)
5606 // fd.treq = fd.treq.dsymbolSemantic(loc, sc);
5608 genIdent(exp, sc);
5610 // Set target of return type inference
5611 if (exp.fd.treq && !exp.fd.type.nextOf())
5613 TypeFunction tfv = null;
5614 if (exp.fd.treq.ty == Tdelegate || exp.fd.treq.isPtrToFunction())
5615 tfv = cast(TypeFunction)exp.fd.treq.nextOf();
5616 if (tfv)
5618 TypeFunction tfl = cast(TypeFunction)exp.fd.type;
5619 tfl.next = tfv.nextOf();
5623 //printf("td = %p, treq = %p\n", td, fd.treq);
5624 if (exp.td)
5626 assert(exp.td.parameters && exp.td.parameters.length);
5627 exp.td.dsymbolSemantic(sc);
5628 exp.type = Type.tvoid; // temporary type
5630 if (exp.fd.treq) // defer type determination
5632 FuncExp fe;
5633 if (exp.matchType(exp.fd.treq, sc, &fe, sc.eSink) > MATCH.nomatch)
5634 e = fe;
5635 else
5636 e = ErrorExp.get();
5638 goto Ldone;
5641 olderrors = global.errors;
5642 exp.fd.dsymbolSemantic(sc);
5643 if (olderrors == global.errors)
5645 exp.fd.semantic2(sc);
5646 if (olderrors == global.errors)
5647 exp.fd.semantic3(sc);
5649 if (olderrors != global.errors)
5651 if (exp.fd.type && exp.fd.type.ty == Tfunction && !exp.fd.type.nextOf())
5652 (cast(TypeFunction)exp.fd.type).next = Type.terror;
5653 e = ErrorExp.get();
5654 goto Ldone;
5657 // Type is a "delegate to" or "pointer to" the function literal
5658 if ((exp.fd.isNested() && exp.fd.tok == TOK.delegate_) || (exp.tok == TOK.reserved && exp.fd.treq && exp.fd.treq.ty == Tdelegate))
5660 // https://issues.dlang.org/show_bug.cgi?id=22686
5661 // if the delegate return type is an error
5662 // abort semantic of the FuncExp and propagate
5663 // the error
5664 if (exp.fd.type.isTypeError())
5666 e = ErrorExp.get();
5667 goto Ldone;
5669 exp.type = new TypeDelegate(exp.fd.type.isTypeFunction());
5670 exp.type = exp.type.typeSemantic(exp.loc, sc);
5672 exp.fd.tok = TOK.delegate_;
5674 else
5676 exp.type = new TypePointer(exp.fd.type);
5677 exp.type = exp.type.typeSemantic(exp.loc, sc);
5678 //type = fd.type.pointerTo();
5680 /* A lambda expression deduced to function pointer might become
5681 * to a delegate literal implicitly.
5683 * auto foo(void function() fp) { return 1; }
5684 * assert(foo({}) == 1);
5686 * So, should keep fd.tok == TOK.reserve if fd.treq == NULL.
5688 if (exp.fd.treq && exp.fd.treq.ty == Tpointer)
5690 // change to non-nested
5691 exp.fd.tok = TOK.function_;
5692 exp.fd.vthis = null;
5695 exp.fd.tookAddressOf++;
5697 Ldone:
5698 sc = sc.pop();
5699 result = e;
5703 * Perform semantic analysis on function literals
5705 * Test the following construct:
5706 * ---
5707 * (x, y, z) { return x + y + z; }(42, 84, 1992);
5708 * ---
5710 Expression callExpSemantic(FuncExp exp, Scope* sc, Expressions* arguments)
5712 if ((!exp.type || exp.type == Type.tvoid) && exp.td && arguments && arguments.length)
5714 for (size_t k = 0; k < arguments.length; k++)
5716 Expression checkarg = (*arguments)[k];
5717 if (checkarg.op == EXP.error)
5718 return checkarg;
5721 genIdent(exp, sc);
5723 assert(exp.td.parameters && exp.td.parameters.length);
5724 exp.td.dsymbolSemantic(sc);
5726 TypeFunction tfl = cast(TypeFunction)exp.fd.type;
5727 size_t dim = tfl.parameterList.length;
5728 if (arguments.length < dim)
5730 // Default arguments are always typed, so they don't need inference.
5731 Parameter p = tfl.parameterList[arguments.length];
5732 if (p.defaultArg)
5733 dim = arguments.length;
5736 if ((tfl.parameterList.varargs == VarArg.none && arguments.length > dim) ||
5737 arguments.length < dim)
5739 OutBuffer buf;
5740 foreach (idx, ref arg; *arguments)
5741 buf.printf("%s%s", (idx ? ", ".ptr : "".ptr), arg.type.toChars());
5742 error(exp.loc, "function literal `%s%s` is not callable using argument types `(%s)`",
5743 exp.fd.toChars(), parametersTypeToChars(tfl.parameterList),
5744 buf.peekChars());
5745 errorSupplemental(exp.loc, "too %s arguments, expected %d, got %d",
5746 arguments.length < dim ? "few".ptr : "many".ptr,
5747 cast(int)dim, cast(int)arguments.length);
5748 return ErrorExp.get();
5751 auto tiargs = new Objects();
5752 tiargs.reserve(exp.td.parameters.length);
5754 for (size_t i = 0; i < exp.td.parameters.length; i++)
5756 TemplateParameter tp = (*exp.td.parameters)[i];
5757 assert(dim <= tfl.parameterList.length);
5758 foreach (u, p; tfl.parameterList)
5760 if (u == dim)
5761 break;
5763 if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident)
5765 Expression e = (*arguments)[u];
5766 tiargs.push(e.type);
5767 break;
5772 auto ti = new TemplateInstance(exp.loc, exp.td, tiargs);
5773 return (new ScopeExp(exp.loc, ti)).expressionSemantic(sc);
5775 return exp.expressionSemantic(sc);
5778 override void visit(CallExp exp)
5780 static if (LOGSEMANTIC)
5782 printf("CallExp::semantic() %s\n", exp.toChars());
5784 if (exp.type)
5786 result = exp;
5787 return; // semantic() already run
5790 Objects* tiargs = null; // initial list of template arguments
5791 Expression ethis = null;
5792 Type tthis = null;
5793 Expression e1org = exp.e1;
5795 if (auto ce = exp.e1.isCommaExp())
5797 /* Rewrite (a,b)(args) as (a,(b(args)))
5799 exp.e1 = ce.e2;
5800 ce.e2 = exp;
5801 result = ce.expressionSemantic(sc);
5802 return;
5804 if (DelegateExp de = exp.e1.isDelegateExp())
5806 exp.e1 = new DotVarExp(de.loc, de.e1, de.func, de.hasOverloads);
5807 visit(exp);
5808 return;
5810 if (FuncExp fe = exp.e1.isFuncExp())
5812 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
5813 preFunctionParameters(sc, exp.argumentList))
5814 return setError();
5816 // Run e1 semantic even if arguments have any errors
5817 exp.e1 = callExpSemantic(fe, sc, exp.arguments);
5818 if (exp.e1.op == EXP.error)
5820 result = exp.e1;
5821 return;
5824 if (sc.flags & SCOPE.Cfile)
5826 /* See if need to rewrite the AST because of cast/call ambiguity
5828 if (auto e = castCallAmbiguity(exp, sc))
5830 result = expressionSemantic(e, sc);
5831 return;
5835 if (Expression ex = resolveUFCS(sc, exp))
5837 result = ex;
5838 return;
5841 /* This recognizes:
5842 * foo!(tiargs)(funcargs)
5844 if (ScopeExp se = exp.e1.isScopeExp())
5846 TemplateInstance ti = se.sds.isTemplateInstance();
5847 if (ti)
5849 /* Attempt to instantiate ti. If that works, go with it.
5850 * If not, go with partial explicit specialization.
5852 WithScopeSymbol withsym;
5853 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc))
5854 return setError();
5855 if (withsym && withsym.withstate.wthis)
5857 exp.e1 = new VarExp(exp.e1.loc, withsym.withstate.wthis);
5858 exp.e1 = new DotTemplateInstanceExp(exp.e1.loc, exp.e1, ti);
5859 goto Ldotti;
5861 if (ti.needsTypeInference(sc, 1))
5863 /* Go with partial explicit specialization
5865 tiargs = ti.tiargs;
5866 assert(ti.tempdecl);
5867 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
5868 exp.e1 = new TemplateExp(exp.loc, td);
5869 else if (OverDeclaration od = ti.tempdecl.isOverDeclaration())
5870 exp.e1 = new VarExp(exp.loc, od);
5871 else
5872 exp.e1 = new OverExp(exp.loc, ti.tempdecl.isOverloadSet());
5874 else
5876 Expression e1x = exp.e1.expressionSemantic(sc);
5877 if (e1x.op == EXP.error)
5879 result = e1x;
5880 return;
5882 exp.e1 = e1x;
5887 /* This recognizes:
5888 * expr.foo!(tiargs)(funcargs)
5890 Ldotti:
5891 if (DotTemplateInstanceExp se = exp.e1.isDotTemplateInstanceExp())
5893 TemplateInstance ti = se.ti;
5895 /* Attempt to instantiate ti. If that works, go with it.
5896 * If not, go with partial explicit specialization.
5898 if (!se.findTempDecl(sc) || !ti.semanticTiargs(sc))
5899 return setError();
5900 if (ti.needsTypeInference(sc, 1))
5902 /* Go with partial explicit specialization
5904 tiargs = ti.tiargs;
5905 assert(ti.tempdecl);
5906 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
5907 exp.e1 = new DotTemplateExp(exp.loc, se.e1, td);
5908 else if (OverDeclaration od = ti.tempdecl.isOverDeclaration())
5910 exp.e1 = new DotVarExp(exp.loc, se.e1, od, true);
5912 else
5913 exp.e1 = new DotExp(exp.loc, se.e1, new OverExp(exp.loc, ti.tempdecl.isOverloadSet()));
5915 else
5917 Expression e1x = exp.e1.expressionSemantic(sc);
5918 if (e1x.op == EXP.error)
5920 result = e1x;
5921 return;
5923 exp.e1 = e1x;
5928 Type att = null;
5929 Lagain:
5930 //printf("Lagain: %s\n", toChars());
5931 exp.f = null;
5932 if (exp.e1.op == EXP.this_ || exp.e1.op == EXP.super_)
5934 // semantic() run later for these
5936 else
5938 if (DotIdExp die = exp.e1.isDotIdExp())
5940 exp.e1 = die.expressionSemantic(sc);
5941 /* Look for e1 having been rewritten to expr.opDispatch!(string)
5942 * We handle such earlier, so go back.
5943 * Note that in the rewrite, we carefully did not run semantic() on e1
5945 if (exp.e1.op == EXP.dotTemplateInstance)
5947 goto Ldotti;
5950 else
5952 __gshared int nest;
5953 if (++nest > global.recursionLimit)
5955 error(exp.loc, "recursive evaluation of `%s`", exp.toChars());
5956 --nest;
5957 return setError();
5959 Expression ex = unaSemantic(exp, sc);
5960 --nest;
5961 if (ex)
5963 result = ex;
5964 return;
5968 /* Look for e1 being a lazy parameter
5970 if (VarExp ve = exp.e1.isVarExp())
5972 if (ve.var.storage_class & STC.lazy_)
5974 // lazy parameters can be called without violating purity and safety
5975 Type tw = ve.var.type;
5976 Type tc = ve.var.type.substWildTo(MODFlags.const_);
5977 auto tf = new TypeFunction(ParameterList(), tc, LINK.d, STC.safe | STC.pure_);
5978 (tf = cast(TypeFunction)tf.typeSemantic(exp.loc, sc)).next = tw; // hack for bug7757
5979 auto t = new TypeDelegate(tf);
5980 ve.type = t.typeSemantic(exp.loc, sc);
5982 VarDeclaration v = ve.var.isVarDeclaration();
5983 if (v && v.checkPurity(ve.loc, sc))
5984 return setError();
5987 if (exp.e1.op == EXP.symbolOffset && (cast(SymOffExp)exp.e1).hasOverloads)
5989 SymOffExp se = cast(SymOffExp)exp.e1;
5990 exp.e1 = new VarExp(se.loc, se.var, true);
5991 exp.e1 = exp.e1.expressionSemantic(sc);
5993 else if (DotExp de = exp.e1.isDotExp())
5995 if (de.e2.op == EXP.overloadSet)
5997 ethis = de.e1;
5998 tthis = de.e1.type;
5999 exp.e1 = de.e2;
6002 else if (exp.e1.op == EXP.star && exp.e1.type.ty == Tfunction)
6004 // Rewrite (*fp)(arguments) to fp(arguments)
6005 exp.e1 = (cast(PtrExp)exp.e1).e1;
6007 else if (exp.e1.op == EXP.type && (sc && sc.flags & SCOPE.Cfile))
6009 const numArgs = exp.arguments ? exp.arguments.length : 0;
6011 /* Ambiguous cases arise from CParser where there is not enough
6012 * information to determine if we have a function call or declaration.
6013 * type-name ( identifier ) ;
6014 * identifier ( identifier ) ;
6015 * If exp.e1 is a type-name, then this is a declaration. C11 does not
6016 * have type construction syntax, so don't convert this to a cast().
6018 if (numArgs == 1)
6020 Expression arg = (*exp.arguments)[0];
6021 if (auto ie = (*exp.arguments)[0].isIdentifierExp())
6023 TypeExp te = cast(TypeExp)exp.e1;
6024 auto initializer = new VoidInitializer(ie.loc);
6025 Dsymbol s = new VarDeclaration(ie.loc, te.type, ie.ident, initializer);
6026 auto decls = new Dsymbols(1);
6027 (*decls)[0] = s;
6028 s = new LinkDeclaration(s.loc, LINK.c, decls);
6029 result = new DeclarationExp(exp.loc, s);
6030 result = result.expressionSemantic(sc);
6032 else
6034 error(arg.loc, "identifier or `(` expected");
6035 result = ErrorExp.get();
6037 return;
6039 error(exp.loc, "identifier or `(` expected before `)`");
6040 result = ErrorExp.get();
6041 return;
6045 Type t1 = exp.e1.type ? exp.e1.type.toBasetype() : null;
6047 if (exp.e1.op == EXP.error)
6049 result = exp.e1;
6050 return;
6052 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
6053 preFunctionParameters(sc, exp.argumentList))
6054 return setError();
6056 // Check for call operator overload
6057 if (t1)
6059 if (t1.ty == Tstruct)
6061 auto sd = (cast(TypeStruct)t1).sym;
6062 sd.size(exp.loc); // Resolve forward references to construct object
6063 if (sd.sizeok != Sizeok.done)
6064 return setError();
6065 if (!sd.ctor)
6066 sd.ctor = sd.searchCtor();
6067 /* If `sd.ctor` is a generated copy constructor, this means that it
6068 is the single constructor that this struct has. In order to not
6069 disable default construction, the ctor is nullified. The side effect
6070 of this is that the generated copy constructor cannot be called
6071 explicitly, but that is ok, because when calling a constructor the
6072 default constructor should have priority over the generated copy
6073 constructor.
6075 if (sd.ctor)
6077 auto ctor = sd.ctor.isCtorDeclaration();
6078 if (ctor && ctor.isCpCtor && ctor.isGenerated())
6079 sd.ctor = null;
6082 // First look for constructor
6083 if (exp.e1.op == EXP.type && sd.ctor)
6085 if (!sd.noDefaultCtor && !(exp.arguments && exp.arguments.length))
6086 goto Lx;
6088 /* https://issues.dlang.org/show_bug.cgi?id=20695
6089 If all constructors are copy constructors, then
6090 try default construction.
6092 if (!sd.hasRegularCtor &&
6093 // https://issues.dlang.org/show_bug.cgi?id=22639
6094 // we might still have a copy constructor that could be called
6095 (*exp.arguments)[0].type.mutableOf != sd.type.mutableOf())
6096 goto Lx;
6098 auto sle = new StructLiteralExp(exp.loc, sd, null, exp.e1.type);
6099 if (!sd.fill(exp.loc, *sle.elements, true))
6100 return setError();
6101 if (checkFrameAccess(exp.loc, sc, sd, sle.elements.length))
6102 return setError();
6104 // https://issues.dlang.org/show_bug.cgi?id=14556
6105 // Set concrete type to avoid further redundant semantic().
6106 sle.type = exp.e1.type;
6108 /* Constructor takes a mutable object, so don't use
6109 * the immutable initializer symbol.
6111 sle.useStaticInit = false;
6113 Expression e = sle;
6114 if (auto cf = sd.ctor.isCtorDeclaration())
6116 e = new DotVarExp(exp.loc, e, cf, true);
6118 else if (auto td = sd.ctor.isTemplateDeclaration())
6120 e = new DotIdExp(exp.loc, e, td.ident);
6122 else if (auto os = sd.ctor.isOverloadSet())
6124 e = new DotExp(exp.loc, e, new OverExp(exp.loc, os));
6126 else
6127 assert(0);
6128 e = new CallExp(exp.loc, e, exp.arguments, exp.names);
6129 e = e.expressionSemantic(sc);
6130 result = e;
6131 return;
6133 // No constructor, look for overload of opCall
6134 if (search_function(sd, Id.call))
6135 goto L1;
6136 // overload of opCall, therefore it's a call
6137 if (exp.e1.op != EXP.type)
6139 if (sd.aliasthis && !isRecursiveAliasThis(att, exp.e1.type))
6141 exp.e1 = resolveAliasThis(sc, exp.e1);
6142 goto Lagain;
6144 error(exp.loc, "%s `%s` does not overload ()", sd.kind(), sd.toChars());
6145 return setError();
6148 /* It's a struct literal
6151 Expressions* resolvedArgs = exp.arguments;
6152 if (exp.names)
6154 resolvedArgs = resolveStructLiteralNamedArgs(sd, exp.e1.type, sc, exp.loc,
6155 (*exp.names)[],
6156 (size_t i, Type t) => (*exp.arguments)[i],
6157 i => (*exp.arguments)[i].loc
6159 if (!resolvedArgs)
6161 result = ErrorExp.get();
6162 return;
6166 Expression e = new StructLiteralExp(exp.loc, sd, resolvedArgs, exp.e1.type);
6167 e = e.expressionSemantic(sc);
6168 result = e;
6169 return;
6171 else if (t1.ty == Tclass)
6174 // Rewrite as e1.call(arguments)
6175 Expression e = new DotIdExp(exp.loc, exp.e1, Id.call);
6176 e = new CallExp(exp.loc, e, exp.arguments, exp.names);
6177 e = e.expressionSemantic(sc);
6178 result = e;
6179 return;
6181 else if (exp.e1.op == EXP.type && t1.isscalar())
6183 Expression e;
6185 // Make sure to use the enum type itself rather than its
6186 // base type
6187 // https://issues.dlang.org/show_bug.cgi?id=16346
6188 if (exp.e1.type.ty == Tenum)
6190 t1 = exp.e1.type;
6193 if (!exp.arguments || exp.arguments.length == 0)
6195 e = t1.defaultInitLiteral(exp.loc);
6197 else if (exp.arguments.length == 1)
6199 e = (*exp.arguments)[0];
6200 e = e.implicitCastTo(sc, t1);
6201 e = new CastExp(exp.loc, e, t1);
6203 else
6205 error(exp.loc, "more than one argument for construction of `%s`", t1.toChars());
6206 return setError();
6208 e = e.expressionSemantic(sc);
6209 result = e;
6210 return;
6214 FuncDeclaration resolveOverloadSet(Loc loc, Scope* sc,
6215 OverloadSet os, Objects* tiargs, Type tthis, ArgumentList argumentList)
6217 FuncDeclaration f = null;
6218 foreach (s; os.a)
6220 if (tiargs && s.isFuncDeclaration())
6221 continue;
6222 if (auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, argumentList, FuncResolveFlag.quiet))
6224 if (f2.errors)
6225 return null;
6226 if (f)
6228 /* Match in more than one overload set,
6229 * even if one is a 'better' match than the other.
6231 if (f.isCsymbol() && f2.isCsymbol())
6233 /* C has global name space, so just pick one, such as f.
6234 * If f and f2 are not compatible, that's how C rolls.
6237 else
6238 ScopeDsymbol.multiplyDefined(loc, f, f2); // issue error
6240 else
6241 f = f2;
6244 if (!f)
6246 .error(loc, "no overload matches for `%s`", exp.toChars());
6247 errorSupplemental(loc, "Candidates are:");
6248 foreach (s; os.a)
6250 overloadApply(s, (ds){
6251 if (auto fd = ds.isFuncDeclaration())
6252 .errorSupplemental(ds.loc, "%s%s", fd.toChars(),
6253 fd.type.toTypeFunction().parameterList.parametersTypeToChars());
6254 else
6255 .errorSupplemental(ds.loc, "%s", ds.toChars());
6256 return 0;
6260 else if (f.errors)
6261 f = null;
6262 return f;
6265 bool isSuper = false;
6266 if (exp.e1.op == EXP.dotVariable && t1.ty == Tfunction || exp.e1.op == EXP.dotTemplateDeclaration)
6268 UnaExp ue = cast(UnaExp)exp.e1;
6270 Expression ue1old = ue.e1; // need for 'right this' check
6271 DotVarExp dve;
6272 DotTemplateExp dte;
6273 Dsymbol s;
6274 if (exp.e1.op == EXP.dotVariable)
6276 dve = cast(DotVarExp)exp.e1;
6277 dte = null;
6278 s = dve.var;
6279 tiargs = null;
6281 else
6283 dve = null;
6284 dte = cast(DotTemplateExp)exp.e1;
6285 s = dte.td;
6288 // Do overload resolution
6289 exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, ue.e1.type, exp.argumentList, FuncResolveFlag.standard);
6290 if (!exp.f || exp.f.errors || exp.f.type.ty == Terror)
6291 return setError();
6293 if (exp.f.interfaceVirtual)
6295 /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent
6297 auto b = exp.f.interfaceVirtual;
6298 auto ad2 = b.sym;
6299 ue.e1 = ue.e1.castTo(sc, ad2.type.addMod(ue.e1.type.mod));
6300 ue.e1 = ue.e1.expressionSemantic(sc);
6301 auto vi = findVtblIndex(exp.f, ad2.vtbl[]);
6302 assert(vi >= 0);
6303 exp.f = ad2.vtbl[vi].isFuncDeclaration();
6304 assert(exp.f);
6306 if (exp.f.needThis())
6308 AggregateDeclaration ad = exp.f.isMemberLocal();
6309 ue.e1 = getRightThis(exp.loc, sc, ad, ue.e1, exp.f);
6310 if (ue.e1.op == EXP.error)
6312 result = ue.e1;
6313 return;
6315 ethis = ue.e1;
6316 tthis = ue.e1.type;
6317 if (!(exp.f.type.ty == Tfunction && (cast(TypeFunction)exp.f.type).isScopeQual))
6319 if (checkParamArgumentEscape(sc, exp.f, Id.This, exp.f.vthis, STC.undefined_, ethis, false, false))
6320 return setError();
6324 /* Cannot call public functions from inside invariant
6325 * (because then the invariant would have infinite recursion)
6327 if (sc.func && sc.func.isInvariantDeclaration() && ue.e1.op == EXP.this_ && exp.f.addPostInvariant())
6329 error(exp.loc, "cannot call `public`/`export` function `%s` from invariant", exp.f.toChars());
6330 return setError();
6333 if (!exp.ignoreAttributes)
6334 checkFunctionAttributes(exp, sc, exp.f);
6336 // Cut-down version of checkAccess() that doesn't use the "most visible" version of exp.f.
6337 // We've already selected an overload here.
6338 const parent = exp.f.toParent();
6339 if (parent && parent.isTemplateInstance())
6341 // already a deprecation
6343 else if (!checkSymbolAccess(sc, exp.f))
6345 error(exp.loc, "%s `%s` of type `%s` is not accessible from module `%s`",
6346 exp.f.kind(), exp.f.toPrettyChars(), exp.f.type.toChars(), sc._module.toChars);
6347 return setError();
6350 if (!exp.f.needThis())
6352 exp.e1 = Expression.combine(ue.e1, new VarExp(exp.loc, exp.f, false));
6354 else
6356 if (ue1old.checkRightThis(sc))
6357 return setError();
6358 if (exp.e1.op == EXP.dotVariable)
6360 dve.var = exp.f;
6361 exp.e1.type = exp.f.type;
6363 else
6365 exp.e1 = new DotVarExp(exp.loc, dte.e1, exp.f, false);
6366 exp.e1 = exp.e1.expressionSemantic(sc);
6367 if (exp.e1.op == EXP.error)
6368 return setError();
6369 ue = cast(UnaExp)exp.e1;
6371 version (none)
6373 printf("ue.e1 = %s\n", ue.e1.toChars());
6374 printf("f = %s\n", exp.f.toChars());
6375 printf("t1 = %s\n", t1.toChars());
6376 printf("e1 = %s\n", exp.e1.toChars());
6377 printf("e1.type = %s\n", exp.e1.type.toChars());
6380 // See if we need to adjust the 'this' pointer
6381 AggregateDeclaration ad = exp.f.isThis();
6382 ClassDeclaration cd = ue.e1.type.isClassHandle();
6383 if (ad && cd && ad.isClassDeclaration())
6385 if (ue.e1.op == EXP.dotType)
6387 ue.e1 = (cast(DotTypeExp)ue.e1).e1;
6388 exp.directcall = true;
6390 else if (ue.e1.op == EXP.super_)
6391 exp.directcall = true;
6392 else if ((cd.storage_class & STC.final_) != 0) // https://issues.dlang.org/show_bug.cgi?id=14211
6393 exp.directcall = true;
6395 if (ad != cd)
6397 ue.e1 = ue.e1.castTo(sc, ad.type.addMod(ue.e1.type.mod));
6398 ue.e1 = ue.e1.expressionSemantic(sc);
6402 // If we've got a pointer to a function then deference it
6403 // https://issues.dlang.org/show_bug.cgi?id=16483
6404 if (exp.e1.type.isPtrToFunction())
6406 Expression e = new PtrExp(exp.loc, exp.e1);
6407 e.type = exp.e1.type.nextOf();
6408 exp.e1 = e;
6410 t1 = exp.e1.type;
6412 else if (exp.e1.op == EXP.super_ || exp.e1.op == EXP.this_)
6414 auto ad = sc.func ? sc.func.isThis() : null;
6415 auto cd = ad ? ad.isClassDeclaration() : null;
6417 isSuper = exp.e1.op == EXP.super_;
6418 if (isSuper)
6420 // Base class constructor call
6421 if (!cd || !cd.baseClass || !sc.func.isCtorDeclaration())
6423 error(exp.loc, "super class constructor call must be in a constructor");
6424 return setError();
6426 if (!cd.baseClass.ctor)
6428 error(exp.loc, "no super class constructor for `%s`", cd.baseClass.toChars());
6429 return setError();
6432 else
6434 // `this` call expression must be inside a
6435 // constructor
6436 if (!ad || !sc.func.isCtorDeclaration())
6438 error(exp.loc, "constructor call must be in a constructor");
6439 return setError();
6442 // https://issues.dlang.org/show_bug.cgi?id=18719
6443 // If `exp` is a call expression to another constructor
6444 // then it means that all struct/class fields will be
6445 // initialized after this call.
6446 foreach (ref field; sc.ctorflow.fieldinit)
6448 field.csx |= CSX.this_ctor;
6452 if (!sc.intypeof && !(sc.ctorflow.callSuper & CSX.halt))
6454 if (sc.inLoop || sc.ctorflow.callSuper & CSX.label)
6455 error(exp.loc, "constructor calls not allowed in loops or after labels");
6456 if (sc.ctorflow.callSuper & (CSX.super_ctor | CSX.this_ctor))
6457 error(exp.loc, "multiple constructor calls");
6458 if ((sc.ctorflow.callSuper & CSX.return_) && !(sc.ctorflow.callSuper & CSX.any_ctor))
6459 error(exp.loc, "an earlier `return` statement skips constructor");
6460 sc.ctorflow.callSuper |= CSX.any_ctor | (isSuper ? CSX.super_ctor : CSX.this_ctor);
6463 tthis = ad.type.addMod(sc.func.type.mod);
6464 auto ctor = isSuper ? cd.baseClass.ctor : ad.ctor;
6465 if (auto os = ctor.isOverloadSet())
6466 exp.f = resolveOverloadSet(exp.loc, sc, os, null, tthis, exp.argumentList);
6467 else
6468 exp.f = resolveFuncCall(exp.loc, sc, ctor, null, tthis, exp.argumentList, FuncResolveFlag.standard);
6470 if (!exp.f || exp.f.errors)
6471 return setError();
6473 checkFunctionAttributes(exp, sc, exp.f);
6474 if (!checkSymbolAccess(sc, exp.f))
6476 error(exp.loc, "%s `%s` is not accessible from module `%s`",
6477 exp.f.kind(), exp.f.toPrettyChars(), sc._module.toChars);
6478 return setError();
6481 exp.e1 = new DotVarExp(exp.e1.loc, exp.e1, exp.f, false);
6482 exp.e1 = exp.e1.expressionSemantic(sc);
6483 // https://issues.dlang.org/show_bug.cgi?id=21095
6484 if (exp.e1.op == EXP.error)
6485 return setError();
6486 t1 = exp.e1.type;
6488 // BUG: this should really be done by checking the static
6489 // call graph
6490 if (exp.f == sc.func)
6492 error(exp.loc, "cyclic constructor call");
6493 return setError();
6496 else if (auto oe = exp.e1.isOverExp())
6498 exp.f = resolveOverloadSet(exp.loc, sc, oe.vars, tiargs, tthis, exp.argumentList);
6499 if (!exp.f)
6500 return setError();
6501 if (ethis)
6502 exp.e1 = new DotVarExp(exp.loc, ethis, exp.f, false);
6503 else
6504 exp.e1 = new VarExp(exp.loc, exp.f, false);
6505 goto Lagain;
6507 else if (!t1)
6509 error(exp.loc, "function expected before `()`, not `%s`", exp.e1.toChars());
6510 return setError();
6512 else if (t1.ty == Terror)
6514 return setError();
6516 else if (t1.ty != Tfunction)
6518 TypeFunction tf;
6519 const(char)* p;
6520 Dsymbol s;
6521 exp.f = null;
6522 if (auto fe = exp.e1.isFuncExp())
6524 // function literal that direct called is always inferred.
6525 assert(fe.fd);
6526 exp.f = fe.fd;
6527 tf = cast(TypeFunction)exp.f.type;
6528 p = "function literal";
6530 else if (t1.ty == Tdelegate)
6532 TypeDelegate td = cast(TypeDelegate)t1;
6533 assert(td.next.ty == Tfunction);
6534 tf = cast(TypeFunction)td.next;
6535 p = "delegate";
6537 else if (auto tfx = t1.isPtrToFunction())
6539 tf = tfx;
6540 p = "function pointer";
6542 else if (exp.e1.op == EXP.dotVariable && (cast(DotVarExp)exp.e1).var.isOverDeclaration())
6544 DotVarExp dve = cast(DotVarExp)exp.e1;
6545 exp.f = resolveFuncCall(exp.loc, sc, dve.var, tiargs, dve.e1.type, exp.argumentList, FuncResolveFlag.overloadOnly);
6546 if (!exp.f)
6547 return setError();
6548 if (exp.f.needThis())
6550 dve.var = exp.f;
6551 dve.type = exp.f.type;
6552 dve.hasOverloads = false;
6553 goto Lagain;
6555 exp.e1 = new VarExp(dve.loc, exp.f, false);
6556 Expression e = new CommaExp(exp.loc, dve.e1, exp);
6557 result = e.expressionSemantic(sc);
6558 return;
6560 else if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.isOverDeclaration())
6562 s = (cast(VarExp)exp.e1).var;
6563 goto L2;
6565 else if (exp.e1.op == EXP.template_)
6567 s = (cast(TemplateExp)exp.e1).td;
6569 exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, null, exp.argumentList,
6570 exp.isUfcsRewrite ? FuncResolveFlag.ufcs : FuncResolveFlag.standard);
6571 if (!exp.f || exp.f.errors)
6572 return setError();
6573 if (exp.f.needThis())
6575 if (hasThis(sc))
6577 // Supply an implicit 'this', as in
6578 // this.ident
6579 exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), exp.f, false);
6580 goto Lagain;
6582 else if (isNeedThisScope(sc, exp.f))
6584 return needThisError(exp.loc, exp.f);
6587 exp.e1 = new VarExp(exp.e1.loc, exp.f, false);
6588 goto Lagain;
6590 else
6592 error(exp.loc, "function expected before `()`, not `%s` of type `%s`", exp.e1.toChars(), exp.e1.type.toChars());
6593 return setError();
6596 void errorHelper(const(char)* failMessage) scope
6598 OutBuffer buf;
6599 buf.writeByte('(');
6600 argExpTypesToCBuffer(buf, exp.arguments);
6601 buf.writeByte(')');
6602 if (tthis)
6603 tthis.modToBuffer(buf);
6605 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
6606 .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`",
6607 p, exp.e1.toChars(), parametersTypeToChars(tf.parameterList), buf.peekChars());
6608 if (failMessage)
6609 errorSupplemental(exp.loc, "%s", failMessage);
6612 if (tf.callMatch(null, exp.argumentList, 0, &errorHelper, sc) == MATCH.nomatch)
6613 return setError();
6615 // Purity and safety check should run after testing arguments matching
6616 if (exp.f)
6618 exp.f.checkPurity(exp.loc, sc);
6619 exp.f.checkSafety(exp.loc, sc);
6620 exp.f.checkNogc(exp.loc, sc);
6621 if (exp.f.checkNestedReference(sc, exp.loc))
6622 return setError();
6624 else if (sc.func && sc.intypeof != 1 && !(sc.flags & (SCOPE.ctfe | SCOPE.debug_)))
6626 bool err = false;
6627 if (!tf.purity && sc.func.setImpure(exp.loc, "`pure` %s `%s` cannot call impure `%s`", exp.e1))
6629 error(exp.loc, "`pure` %s `%s` cannot call impure %s `%s`",
6630 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
6631 err = true;
6633 if (!tf.isnogc && sc.func.setGC(exp.loc, "`@nogc` %s `%s` cannot call non-@nogc `%s`", exp.e1))
6635 error(exp.loc, "`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
6636 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
6637 err = true;
6639 if (tf.trust <= TRUST.system && sc.setUnsafe(true, exp.loc,
6640 "`@safe` function `%s` cannot call `@system` `%s`", sc.func, exp.e1))
6642 error(exp.loc, "`@safe` %s `%s` cannot call `@system` %s `%s`",
6643 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
6644 err = true;
6646 if (err)
6647 return setError();
6650 if (t1.ty == Tpointer)
6652 Expression e = new PtrExp(exp.loc, exp.e1);
6653 e.type = tf;
6654 exp.e1 = e;
6656 t1 = tf;
6658 else if (VarExp ve = exp.e1.isVarExp())
6660 // Do overload resolution
6661 exp.f = ve.var.isFuncDeclaration();
6662 assert(exp.f);
6663 tiargs = null;
6665 if (ve.hasOverloads && exp.f.overnext)
6666 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.overloadOnly);
6667 else
6669 exp.f = exp.f.toAliasFunc();
6670 TypeFunction tf = cast(TypeFunction)exp.f.type;
6672 void errorHelper2(const(char)* failMessage) scope
6674 OutBuffer buf;
6675 buf.writeByte('(');
6676 argExpTypesToCBuffer(buf, exp.arguments);
6677 buf.writeByte(')');
6679 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
6680 if (exp.isUfcsRewrite)
6682 const arg = (*exp.argumentList.arguments)[0];
6683 .error(exp.loc, "no property `%s` for `%s` of type `%s`", exp.f.ident.toChars(), arg.toChars(), arg.type.toChars());
6684 .errorSupplemental(exp.loc, "the following error occured while looking for a UFCS match");
6687 .error(exp.loc, "%s `%s` is not callable using argument types `%s`",
6688 exp.f.kind(), exp.f.toChars(), buf.peekChars());
6689 if (failMessage)
6690 errorSupplemental(exp.loc, "%s", failMessage);
6691 .errorSupplemental(exp.f.loc, "`%s%s` declared here", exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList));
6692 exp.f = null;
6695 if (tf.callMatch(null, exp.argumentList, 0, &errorHelper2, sc) == MATCH.nomatch)
6696 exp.f = null;
6698 if (!exp.f || exp.f.errors)
6699 return setError();
6701 if (exp.f.needThis())
6703 // Change the ancestor lambdas to delegate before hasThis(sc) call.
6704 if (exp.f.checkNestedReference(sc, exp.loc))
6705 return setError();
6707 auto memberFunc = hasThis(sc);
6708 if (memberFunc && haveSameThis(memberFunc, exp.f))
6710 // Supply an implicit 'this', as in
6711 // this.ident
6712 exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), ve.var);
6713 // Note: we cannot use f directly, because further overload resolution
6714 // through the supplied 'this' may cause different result.
6715 goto Lagain;
6717 else if (isNeedThisScope(sc, exp.f))
6719 // At this point it is possible that `exp.f` had an ambiguity error that was
6720 // silenced because the previous call to `resolveFuncCall` was done using
6721 // `FuncResolveFlag.overloadOnly`. To make sure that a proper error message
6722 // is printed, redo the call with `FuncResolveFlag.standard`.
6724 // https://issues.dlang.org/show_bug.cgi?id=22157
6725 if (exp.f.overnext)
6726 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.standard);
6728 if (!exp.f || exp.f.errors)
6729 return setError();
6731 // If no error is printed, it means that `f` is the single matching overload
6732 // and it needs `this`.
6733 return needThisError(exp.loc, exp.f);
6737 checkFunctionAttributes(exp, sc, exp.f);
6738 checkAccess(exp.loc, sc, null, exp.f);
6739 if (exp.f.checkNestedReference(sc, exp.loc))
6740 return setError();
6742 ethis = null;
6743 tthis = null;
6745 if (ve.hasOverloads)
6747 exp.e1 = new VarExp(ve.loc, exp.f, false);
6748 exp.e1.type = exp.f.type;
6750 t1 = exp.f.type;
6752 assert(t1.ty == Tfunction);
6754 Expression argprefix;
6755 if (!exp.arguments)
6756 exp.arguments = new Expressions();
6757 if (functionParameters(exp.loc, sc, cast(TypeFunction)t1, ethis, tthis, exp.argumentList, exp.f, &exp.type, &argprefix))
6758 return setError();
6760 if (!exp.type)
6762 exp.e1 = e1org; // https://issues.dlang.org/show_bug.cgi?id=10922
6763 // avoid recursive expression printing
6764 error(exp.loc, "forward reference to inferred return type of function call `%s`", exp.toChars());
6765 return setError();
6768 if (exp.f && exp.f.tintro)
6770 Type t = exp.type;
6771 int offset = 0;
6772 TypeFunction tf = cast(TypeFunction)exp.f.tintro;
6773 if (tf.next.isBaseOf(t, &offset) && offset)
6775 exp.type = tf.next;
6776 result = Expression.combine(argprefix, exp.castTo(sc, t));
6777 return;
6781 // Handle the case of a direct lambda call
6782 if (exp.f && exp.f.isFuncLiteralDeclaration() && sc.func && !sc.intypeof)
6784 exp.f.tookAddressOf = 0;
6787 result = Expression.combine(argprefix, exp);
6789 if (isSuper)
6791 auto ad = sc.func ? sc.func.isThis() : null;
6792 auto cd = ad ? ad.isClassDeclaration() : null;
6793 if (cd && cd.classKind == ClassKind.cpp && exp.f && !exp.f.fbody)
6795 // if super is defined in C++, it sets the vtable pointer to the base class
6796 // so we have to restore it, but still return 'this' from super() call:
6797 // (auto __vptrTmp = this.__vptr, auto __superTmp = super()), (this.__vptr = __vptrTmp, __superTmp)
6798 Loc loc = exp.loc;
6800 auto vptr = new DotIdExp(loc, new ThisExp(loc), Id.__vptr);
6801 auto vptrTmpDecl = copyToTemp(0, "__vptrTmp", vptr);
6802 auto declareVptrTmp = new DeclarationExp(loc, vptrTmpDecl);
6804 auto superTmpDecl = copyToTemp(0, "__superTmp", result);
6805 auto declareSuperTmp = new DeclarationExp(loc, superTmpDecl);
6807 auto declareTmps = new CommaExp(loc, declareVptrTmp, declareSuperTmp);
6809 auto restoreVptr = new AssignExp(loc, vptr.syntaxCopy(), new VarExp(loc, vptrTmpDecl));
6811 Expression e = new CommaExp(loc, declareTmps, new CommaExp(loc, restoreVptr, new VarExp(loc, superTmpDecl)));
6812 result = e.expressionSemantic(sc);
6816 // `super.fun()` with fun being abstract and unimplemented
6817 auto supDotFun = exp.e1.isDotVarExp();
6818 if (supDotFun && supDotFun.e1.isSuperExp() && exp.f && exp.f.isAbstract() && !exp.f.fbody)
6820 error(exp.loc, "call to unimplemented abstract function `%s`", exp.f.toFullSignature());
6821 errorSupplemental(exp.loc, "declared here: %s", exp.f.loc.toChars());
6824 // declare dual-context container
6825 if (exp.f && exp.f.hasDualContext() && !sc.intypeof && sc.func)
6827 // check access to second `this`
6828 if (AggregateDeclaration ad2 = exp.f.isMember2())
6830 Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
6831 if (te.op != EXP.error)
6832 te = getRightThis(exp.loc, sc, ad2, te, exp.f);
6833 if (te.op == EXP.error)
6835 error(exp.loc, "need `this` of type `%s` to call function `%s`", ad2.toChars(), exp.f.toChars());
6836 return setError();
6839 exp.vthis2 = makeThis2Argument(exp.loc, sc, exp.f);
6840 Expression de = new DeclarationExp(exp.loc, exp.vthis2);
6841 result = Expression.combine(de, result);
6842 result = result.expressionSemantic(sc);
6846 override void visit(DeclarationExp e)
6848 if (e.type)
6850 result = e;
6851 return;
6853 static if (LOGSEMANTIC)
6855 printf("DeclarationExp::semantic() %s\n", e.toChars());
6858 uint olderrors = global.errors;
6860 /* This is here to support extern(linkage) declaration,
6861 * where the extern(linkage) winds up being an AttribDeclaration
6862 * wrapper.
6864 Dsymbol s = e.declaration;
6866 while (1)
6868 AttribDeclaration ad = s.isAttribDeclaration();
6869 if (ad)
6871 if (ad.decl && ad.decl.length == 1)
6873 s = (*ad.decl)[0];
6874 continue;
6877 break;
6880 //printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc);
6881 // Insert into both local scope and function scope.
6882 // Must be unique in both.
6883 if (s.ident)
6885 VarDeclaration v = s.isVarDeclaration();
6886 if (v)
6888 if (sc.flags & SCOPE.Cfile)
6890 /* Do semantic() on the type before inserting v into the symbol table
6892 if (!v.originalType)
6893 v.originalType = v.type.syntaxCopy();
6894 Scope* sc2 = sc.push();
6895 sc2.stc |= v.storage_class & STC.FUNCATTR;
6896 sc2.linkage = LINK.c; // account for the extern(C) in front of the declaration
6897 v.inuse++;
6898 v.type = v.type.typeSemantic(v.loc, sc2);
6899 v.inuse--;
6900 sc2.pop();
6902 else
6904 /* Do semantic() on initializer first so this will be illegal:
6905 * int a = a;
6907 e.declaration.dsymbolSemantic(sc);
6908 s.parent = sc.parent;
6912 if (!sc.insert(s))
6914 Dsymbol pscopesym;
6915 auto conflict = sc.search(Loc.initial, s.ident, pscopesym);
6916 error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
6917 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
6918 conflict.kind(), conflict.toChars());
6919 return setError();
6922 if (v && (sc.flags & SCOPE.Cfile))
6924 /* Do semantic() on initializer last so this will be legal:
6925 * int a = a;
6927 e.declaration.dsymbolSemantic(sc);
6928 s.parent = sc.parent;
6931 if (sc.func)
6933 // https://issues.dlang.org/show_bug.cgi?id=11720
6934 if ((s.isFuncDeclaration() ||
6935 s.isAggregateDeclaration() ||
6936 s.isEnumDeclaration() ||
6937 s.isTemplateDeclaration() ||
6939 ) && !sc.func.localsymtab.insert(s))
6941 // Get the previous symbol
6942 Dsymbol originalSymbol = sc.func.localsymtab.lookup(s.ident);
6944 // Perturb the name mangling so that the symbols can co-exist
6945 // instead of colliding
6946 s.localNum = cast(ushort)(originalSymbol.localNum + 1);
6947 // 65535 should be enough for anyone
6948 if (!s.localNum)
6950 error(e.loc, "more than 65535 symbols with name `%s` generated", s.ident.toChars());
6951 return setError();
6954 // Replace originalSymbol with s, which updates the localCount
6955 sc.func.localsymtab.update(s);
6957 // The mangling change only works for D mangling
6960 if (!(sc.flags & SCOPE.Cfile))
6962 /* https://issues.dlang.org/show_bug.cgi?id=21272
6963 * If we are in a foreach body we need to extract the
6964 * function containing the foreach
6966 FuncDeclaration fes_enclosing_func;
6967 if (sc.func && sc.func.fes)
6968 fes_enclosing_func = sc.enclosing.enclosing.func;
6970 // Disallow shadowing
6971 for (Scope* scx = sc.enclosing; scx && (scx.func == sc.func || (fes_enclosing_func && scx.func == fes_enclosing_func)); scx = scx.enclosing)
6973 Dsymbol s2;
6974 if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2)
6976 // allow STC.local symbols to be shadowed
6977 // TODO: not really an optimal design
6978 auto decl = s2.isDeclaration();
6979 if (!decl || !(decl.storage_class & STC.local))
6981 if (sc.func.fes)
6983 deprecation(e.loc, "%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
6984 deprecationSupplemental(s2.loc, "declared here");
6987 else
6989 error(e.loc, "%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
6990 errorSupplemental(s2.loc, "declared here");
6991 return setError();
6999 if (!s.isVarDeclaration())
7001 Scope* sc2 = sc;
7002 if (sc2.stc & (STC.pure_ | STC.nothrow_ | STC.nogc))
7003 sc2 = sc.push();
7004 sc2.stc &= ~(STC.pure_ | STC.nothrow_ | STC.nogc);
7005 e.declaration.dsymbolSemantic(sc2);
7006 if (sc2 != sc)
7007 sc2.pop();
7008 s.parent = sc.parent;
7010 if (global.errors == olderrors)
7012 e.declaration.semantic2(sc);
7013 if (global.errors == olderrors)
7015 e.declaration.semantic3(sc);
7018 // todo: error in declaration should be propagated.
7020 e.type = Type.tvoid;
7021 result = e;
7024 override void visit(TypeidExp exp)
7026 static if (LOGSEMANTIC)
7028 printf("TypeidExp::semantic() %s\n", exp.toChars());
7030 Type ta = isType(exp.obj);
7031 Expression ea = isExpression(exp.obj);
7032 Dsymbol sa = isDsymbol(exp.obj);
7033 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
7035 if (ta)
7037 dmd.typesem.resolve(ta, exp.loc, sc, ea, ta, sa, true);
7040 if (ea)
7042 if (auto sym = getDsymbol(ea))
7043 ea = symbolToExp(sym, exp.loc, sc, false);
7044 else
7045 ea = ea.expressionSemantic(sc);
7046 ea = resolveProperties(sc, ea);
7047 ta = ea.type;
7048 if (ea.op == EXP.type)
7049 ea = null;
7052 if (!ta)
7054 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
7055 error(exp.loc, "no type for `typeid(%s)`", ea ? ea.toChars() : (sa ? sa.toChars() : ""));
7056 return setError();
7059 ta.checkComplexTransition(exp.loc, sc);
7061 Expression e;
7062 auto tb = ta.toBasetype();
7063 if (ea && tb.ty == Tclass)
7065 if (tb.toDsymbol(sc).isClassDeclaration().classKind == ClassKind.cpp)
7067 error(exp.loc, "runtime type information is not supported for `extern(C++)` classes");
7068 e = ErrorExp.get();
7070 else if (!Type.typeinfoclass)
7072 error(exp.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
7073 e = ErrorExp.get();
7075 else
7077 /* Get the dynamic type, which is .classinfo
7079 ea = ea.expressionSemantic(sc);
7080 e = new TypeidExp(ea.loc, ea);
7081 e.type = Type.typeinfoclass.type;
7084 else if (ta.ty == Terror)
7086 e = ErrorExp.get();
7088 else
7090 // Handle this in the glue layer
7091 e = new TypeidExp(exp.loc, ta);
7093 bool genObjCode = true;
7095 // https://issues.dlang.org/show_bug.cgi?id=23650
7096 // We generate object code for typeinfo, required
7097 // by typeid, only if in non-speculative context
7098 if (sc.flags & SCOPE.compile)
7100 genObjCode = false;
7103 e.type = getTypeInfoType(exp.loc, ta, sc, genObjCode);
7104 semanticTypeInfo(sc, ta);
7106 if (ea)
7108 e = new CommaExp(exp.loc, ea, e); // execute ea
7109 e = e.expressionSemantic(sc);
7112 result = e;
7115 override void visit(TraitsExp e)
7117 result = semanticTraits(e, sc);
7120 override void visit(HaltExp e)
7122 static if (LOGSEMANTIC)
7124 printf("HaltExp::semantic()\n");
7126 e.type = Type.tnoreturn;
7127 result = e;
7130 override void visit(IsExp e)
7132 /* is(targ id tok tspec)
7133 * is(targ id : tok2)
7134 * is(targ id == tok2)
7136 Type tded = null;
7138 void yes()
7140 //printf("yes\n");
7141 if (!e.id)
7143 result = IntegerExp.createBool(true);
7144 return;
7147 Dsymbol s;
7148 Tuple tup = isTuple(tded);
7149 if (tup)
7150 s = new TupleDeclaration(e.loc, e.id, &tup.objects);
7151 else
7152 s = new AliasDeclaration(e.loc, e.id, tded);
7153 s.dsymbolSemantic(sc);
7155 /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there.
7156 * More investigation is needed.
7158 if (!tup && !sc.insert(s))
7160 Dsymbol pscopesym;
7161 auto conflict = sc.search(Loc.initial, s.ident, pscopesym);
7162 error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
7163 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
7164 conflict.kind(), conflict.toChars());
7167 unSpeculative(sc, s);
7169 result = IntegerExp.createBool(true);
7171 void no()
7173 result = IntegerExp.createBool(false);
7174 //printf("no\n");
7177 static if (LOGSEMANTIC)
7179 printf("IsExp::semantic(%s)\n", e.toChars());
7181 if (e.id && !(sc.flags & SCOPE.condition))
7183 error(e.loc, "can only declare type aliases within `static if` conditionals or `static assert`s");
7184 return setError();
7187 if (e.tok2 == TOK.package_ || e.tok2 == TOK.module_) // These is() expressions are special because they can work on modules, not just types.
7189 const oldErrors = global.startGagging();
7190 Dsymbol sym = e.targ.toDsymbol(sc);
7191 global.endGagging(oldErrors);
7193 if (sym is null)
7194 return no();
7195 Package p = resolveIsPackage(sym);
7196 if (p is null)
7197 return no();
7198 if (e.tok2 == TOK.package_ && p.isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module.
7199 return no();
7200 else if(e.tok2 == TOK.module_ && !(p.isModule() || p.isPackageMod()))
7201 return no();
7202 tded = e.targ;
7203 return yes();
7207 Scope* sc2 = sc.copy(); // keep sc.flags
7208 sc2.tinst = null;
7209 sc2.minst = null;
7210 sc2.flags |= SCOPE.fullinst;
7211 Type t = dmd.typesem.trySemantic(e.targ, e.loc, sc2);
7212 sc2.pop();
7213 if (!t) // errors, so condition is false
7214 return no();
7215 e.targ = t;
7218 if (e.tok2 != TOK.reserved)
7220 switch (e.tok2)
7222 case TOK.struct_:
7223 if (e.targ.ty != Tstruct)
7224 return no();
7225 if ((cast(TypeStruct)e.targ).sym.isUnionDeclaration())
7226 return no();
7227 tded = e.targ;
7228 break;
7230 case TOK.union_:
7231 if (e.targ.ty != Tstruct)
7232 return no();
7233 if (!(cast(TypeStruct)e.targ).sym.isUnionDeclaration())
7234 return no();
7235 tded = e.targ;
7236 break;
7238 case TOK.class_:
7239 if (e.targ.ty != Tclass)
7240 return no();
7241 if ((cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
7242 return no();
7243 tded = e.targ;
7244 break;
7246 case TOK.interface_:
7247 if (e.targ.ty != Tclass)
7248 return no();
7249 if (!(cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
7250 return no();
7251 tded = e.targ;
7252 break;
7254 case TOK.const_:
7255 if (!e.targ.isConst())
7256 return no();
7257 tded = e.targ;
7258 break;
7260 case TOK.immutable_:
7261 if (!e.targ.isImmutable())
7262 return no();
7263 tded = e.targ;
7264 break;
7266 case TOK.shared_:
7267 if (!e.targ.isShared())
7268 return no();
7269 tded = e.targ;
7270 break;
7272 case TOK.inout_:
7273 if (!e.targ.isWild())
7274 return no();
7275 tded = e.targ;
7276 break;
7278 case TOK.super_:
7279 // If class or interface, get the base class and interfaces
7280 if (e.targ.ty != Tclass)
7281 return no();
7282 else
7284 ClassDeclaration cd = (cast(TypeClass)e.targ).sym;
7285 auto args = new Parameters();
7286 args.reserve(cd.baseclasses.length);
7287 if (cd.semanticRun < PASS.semanticdone)
7288 cd.dsymbolSemantic(null);
7289 for (size_t i = 0; i < cd.baseclasses.length; i++)
7291 BaseClass* b = (*cd.baseclasses)[i];
7292 args.push(new Parameter(Loc.initial, STC.in_, b.type, null, null, null));
7294 tded = new TypeTuple(args);
7296 break;
7298 case TOK.enum_:
7299 if (e.targ.ty != Tenum)
7300 return no();
7301 if (e.id)
7302 tded = (cast(TypeEnum)e.targ).sym.getMemtype(e.loc);
7303 else
7304 tded = e.targ;
7306 if (tded.ty == Terror)
7307 return setError();
7308 break;
7310 case TOK.delegate_:
7311 if (e.targ.ty != Tdelegate)
7312 return no();
7313 tded = (cast(TypeDelegate)e.targ).next; // the underlying function type
7314 break;
7316 case TOK.function_:
7317 if (e.targ.ty != Tfunction)
7318 return no();
7319 goto case;
7320 case TOK.parameters:
7322 if (auto tf = e.targ.isFunction_Delegate_PtrToFunction())
7323 tded = tf;
7324 else
7325 return no();
7327 /* Generate tuple from function parameter types.
7329 auto args = new Parameters();
7330 foreach (i, arg; tded.isTypeFunction().parameterList)
7332 assert(arg && arg.type);
7333 /* If one of the default arguments was an error,
7334 don't return an invalid tuple
7336 if (e.tok2 == TOK.parameters && arg.defaultArg && arg.defaultArg.op == EXP.error)
7337 return setError();
7338 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));
7340 tded = new TypeTuple(args);
7341 break;
7343 case TOK.return_:
7344 /* Get the 'return type' for the function,
7345 * delegate, or pointer to function.
7347 if (auto tf = e.targ.isFunction_Delegate_PtrToFunction())
7348 tded = tf.next;
7349 else
7350 return no();
7351 break;
7353 case TOK.argumentTypes:
7354 /* Generate a type tuple of the equivalent types used to determine if a
7355 * function argument of this type can be passed in registers.
7356 * The results of this are highly platform dependent, and intended
7357 * primarly for use in implementing va_arg().
7359 tded = target.toArgTypes(e.targ);
7360 if (!tded)
7361 return no();
7362 // not valid for a parameter
7363 break;
7365 case TOK.vector:
7366 if (e.targ.ty != Tvector)
7367 return no();
7368 tded = (cast(TypeVector)e.targ).basetype;
7369 break;
7371 default:
7372 assert(0);
7375 // https://issues.dlang.org/show_bug.cgi?id=18753
7376 if (tded)
7377 return yes();
7378 return no();
7380 else if (e.tspec && !e.id && !(e.parameters && e.parameters.length))
7382 /* Evaluate to true if targ matches tspec
7383 * is(targ == tspec)
7384 * is(targ : tspec)
7386 e.tspec = e.tspec.typeSemantic(e.loc, sc);
7387 //printf("targ = %s, %s\n", e.targ.toChars(), e.targ.deco);
7388 //printf("tspec = %s, %s\n", e.tspec.toChars(), e.tspec.deco);
7390 if (e.tok == TOK.colon)
7392 // current scope is itself deprecated, or deprecations are not errors
7393 const bool deprecationAllowed = sc.isDeprecated
7394 || global.params.useDeprecated != DiagnosticReporting.error;
7395 const bool preventAliasThis = e.targ.hasDeprecatedAliasThis && !deprecationAllowed;
7397 if (preventAliasThis && e.targ.ty == Tstruct)
7399 if ((cast(TypeStruct) e.targ).implicitConvToWithoutAliasThis(e.tspec))
7400 return yes();
7401 else
7402 return no();
7404 else if (preventAliasThis && e.targ.ty == Tclass)
7406 if ((cast(TypeClass) e.targ).implicitConvToWithoutAliasThis(e.tspec))
7407 return yes();
7408 else
7409 return no();
7411 else if (e.targ.implicitConvTo(e.tspec))
7412 return yes();
7413 else
7414 return no();
7416 else /* == */
7418 if (e.targ.equals(e.tspec))
7419 return yes();
7420 else
7421 return no();
7424 else if (e.tspec)
7426 /* Evaluate to true if targ matches tspec.
7427 * If true, declare id as an alias for the specialized type.
7428 * is(targ == tspec, tpl)
7429 * is(targ : tspec, tpl)
7430 * is(targ id == tspec)
7431 * is(targ id : tspec)
7432 * is(targ id == tspec, tpl)
7433 * is(targ id : tspec, tpl)
7435 Identifier tid = e.id ? e.id : Identifier.generateId("__isexp_id");
7436 e.parameters.insert(0, new TemplateTypeParameter(e.loc, tid, null, null));
7438 Objects dedtypes = Objects(e.parameters.length);
7439 dedtypes.zero();
7441 MATCH m = deduceType(e.targ, sc, e.tspec, *e.parameters, dedtypes, null, 0, e.tok == TOK.equal);
7443 if (m == MATCH.nomatch || (m != MATCH.exact && e.tok == TOK.equal))
7445 return no();
7447 else
7449 tded = cast(Type)dedtypes[0];
7450 if (!tded)
7451 tded = e.targ;
7452 Objects tiargs = Objects(1);
7453 tiargs[0] = e.targ;
7455 /* Declare trailing parameters
7457 for (size_t i = 1; i < e.parameters.length; i++)
7459 TemplateParameter tp = (*e.parameters)[i];
7460 Declaration s = null;
7462 m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, dedtypes, &s);
7463 if (m == MATCH.nomatch)
7464 return no();
7465 s.dsymbolSemantic(sc);
7466 if (!sc.insert(s))
7468 Dsymbol pscopesym;
7469 auto conflict = sc.search(Loc.initial, s.ident, pscopesym);
7470 error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
7471 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
7472 conflict.kind(), conflict.toChars());
7475 unSpeculative(sc, s);
7477 return yes();
7480 else if (e.id)
7482 /* Declare id as an alias for type targ. Evaluate to true
7483 * is(targ id)
7485 tded = e.targ;
7487 return yes();
7490 override void visit(BinAssignExp exp)
7492 if (exp.type)
7494 result = exp;
7495 return;
7498 Expression e = exp.op_overload(sc);
7499 if (e)
7501 result = e;
7502 return;
7505 if (exp.e1.op == EXP.arrayLength)
7507 // arr.length op= e2;
7508 e = rewriteOpAssign(exp);
7509 e = e.expressionSemantic(sc);
7510 result = e;
7511 return;
7513 if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
7515 if (checkNonAssignmentArrayOp(exp.e1))
7516 return setError();
7518 if (exp.e1.op == EXP.slice)
7519 (cast(SliceExp)exp.e1).arrayop = true;
7521 // T[] op= ...
7522 if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
7524 // T[] op= T
7525 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
7527 else if (Expression ex = typeCombine(exp, sc))
7529 result = ex;
7530 return;
7532 exp.type = exp.e1.type;
7533 result = arrayOp(exp, sc);
7534 return;
7537 exp.e1 = exp.e1.expressionSemantic(sc);
7538 exp.e1 = exp.e1.modifiableLvalue(sc);
7539 exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
7540 exp.type = exp.e1.type;
7542 if (auto ad = isAggregate(exp.e1.type))
7544 if (const s = search_function(ad, Id.opOpAssign))
7546 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());
7547 return setError();
7550 if (exp.e1.checkScalar() ||
7551 exp.e1.checkReadModifyWrite(exp.op, exp.e2) ||
7552 exp.e1.checkSharedAccess(sc))
7553 return setError();
7555 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);
7556 int bitwise = (exp.op == EXP.andAssign || exp.op == EXP.orAssign || exp.op == EXP.xorAssign);
7557 int shift = (exp.op == EXP.leftShiftAssign || exp.op == EXP.rightShiftAssign || exp.op == EXP.unsignedRightShiftAssign);
7559 if (bitwise && exp.type.toBasetype().ty == Tbool)
7560 exp.e2 = exp.e2.implicitCastTo(sc, exp.type);
7561 else if (exp.checkNoBool())
7562 return setError();
7564 if ((exp.op == EXP.addAssign || exp.op == EXP.minAssign) && exp.e1.type.toBasetype().ty == Tpointer && exp.e2.type.toBasetype().isintegral())
7566 result = scaleFactor(exp, sc);
7567 return;
7570 if (Expression ex = typeCombine(exp, sc))
7572 result = ex;
7573 return;
7576 if (arith && (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)))
7577 return setError();
7578 if ((bitwise || shift) && (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)))
7579 return setError();
7581 if (shift)
7583 if (exp.e2.type.toBasetype().ty != Tvector)
7584 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
7587 if (!target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
7589 result = exp.incompatibleTypes();
7590 return;
7593 if (exp.e1.op == EXP.error || exp.e2.op == EXP.error)
7594 return setError();
7596 e = exp.checkOpAssignTypes(sc);
7597 if (e.op == EXP.error)
7599 result = e;
7600 return;
7603 assert(e.op == EXP.assign || e == exp);
7604 result = (cast(BinExp)e).reorderSettingAAElem(sc);
7607 private Expression compileIt(MixinExp exp, Scope *sc)
7609 OutBuffer buf;
7610 if (expressionsToString(buf, sc, exp.exps))
7611 return null;
7613 uint errors = global.errors;
7614 const len = buf.length;
7615 const str = buf.extractChars()[0 .. len];
7616 const bool doUnittests = global.params.parsingUnittestsRequired();
7617 auto loc = adjustLocForMixin(str, exp.loc, global.params.mixinOut);
7618 scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
7619 p.transitionIn = global.params.v.vin;
7620 p.nextToken();
7621 //printf("p.loc.linnum = %d\n", p.loc.linnum);
7623 Expression e = p.parseExpression();
7624 if (global.errors != errors)
7625 return null;
7627 if (p.token.value != TOK.endOfFile)
7629 error(e.loc, "unexpected token `%s` after %s expression",
7630 p.token.toChars(), EXPtoString(e.op).ptr);
7631 errorSupplemental(e.loc, "while parsing string mixin expression `%s`",
7632 str.ptr);
7633 return null;
7635 return e;
7638 override void visit(MixinExp exp)
7640 /* https://dlang.org/spec/expression.html#mixin_expressions
7643 static if (LOGSEMANTIC)
7645 printf("MixinExp::semantic('%s')\n", exp.toChars());
7648 // The expression is not treated as part of a default argument,
7649 // because it is evaluated at compile time.
7650 Scope* sc2 = sc.push();
7651 sc2.inDefaultArg = false;
7653 auto e = compileIt(exp, sc2);
7654 sc2.pop();
7655 if (!e)
7656 return setError();
7657 result = e.expressionSemantic(sc);
7660 override void visit(ImportExp e)
7662 static if (LOGSEMANTIC)
7664 printf("ImportExp::semantic('%s')\n", e.toChars());
7667 auto se = semanticString(sc, e.e1, "file name argument");
7668 if (!se)
7669 return setError();
7670 se = se.toUTF8(sc);
7672 auto namez = se.toStringz();
7673 if (!global.filePath.length)
7675 error(e.loc, "need `-J` switch to import text file `%s`", namez.ptr);
7676 return setError();
7679 /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
7680 * ('Path Traversal') attacks.
7681 * https://cwe.mitre.org/data/definitions/22.html
7684 if (FileName.absolute(namez))
7686 error(e.loc, "absolute path is not allowed in import expression: `%s`", se.toChars());
7687 return setError();
7690 auto idxReserved = FileName.findReservedChar(namez);
7691 if (idxReserved != size_t.max)
7693 error(e.loc, "`%s` is not a valid filename on this platform", se.toChars());
7694 errorSupplemental(e.loc, "Character `'%c'` is reserved and cannot be used", namez[idxReserved]);
7695 return setError();
7698 if (FileName.refersToParentDir(namez))
7700 error(e.loc, "path refers to parent (`..`) directory: `%s`", se.toChars());
7701 return setError();
7704 auto resolvedNamez = FileName.searchPath(global.filePath[], namez, false);
7705 if (!resolvedNamez)
7707 error(e.loc, "file `%s` cannot be found or not in a path specified with `-J`", se.toChars());
7708 errorSupplemental(e.loc, "Path(s) searched (as provided by `-J`):");
7709 foreach (idx, path; global.filePath[])
7711 const attr = FileName.exists(path);
7712 const(char)* err = attr == 2 ? "" :
7713 (attr == 1 ? " (not a directory)" : " (path not found)");
7714 errorSupplemental(e.loc, "[%llu]: `%s`%s", cast(ulong)idx, path, err);
7716 return setError();
7719 sc._module.contentImportedFiles.push(resolvedNamez.ptr);
7720 if (global.params.v.verbose)
7722 const slice = se.peekString();
7723 message("file %.*s\t(%s)", cast(int)slice.length, slice.ptr, resolvedNamez.ptr);
7725 if (global.params.moduleDeps.buffer !is null)
7727 OutBuffer* ob = global.params.moduleDeps.buffer;
7728 Module imod = sc._module;
7730 if (!global.params.moduleDeps.name)
7731 ob.writestring("depsFile ");
7732 ob.writestring(imod.toPrettyChars());
7733 ob.writestring(" (");
7734 escapePath(ob, imod.srcfile.toChars());
7735 ob.writestring(") : ");
7736 if (global.params.moduleDeps.name)
7737 ob.writestring("string : ");
7738 ob.write(se.peekString());
7739 ob.writestring(" (");
7740 escapePath(ob, resolvedNamez.ptr);
7741 ob.writestring(")");
7742 ob.writenl();
7744 if (global.params.makeDeps.doOutput)
7746 global.params.makeDeps.files.push(resolvedNamez.ptr);
7750 auto fileName = FileName(resolvedNamez);
7751 if (auto fmResult = global.fileManager.getFileContents(fileName))
7753 se = new StringExp(e.loc, fmResult);
7755 else
7757 error(e.loc, "cannot read file `%s`", resolvedNamez.ptr);
7758 return setError();
7761 result = se.expressionSemantic(sc);
7764 override void visit(AssertExp exp)
7766 // https://dlang.org/spec/expression.html#assert_expressions
7767 static if (LOGSEMANTIC)
7769 printf("AssertExp::semantic('%s')\n", exp.toChars());
7771 if (auto e = exp.e1.isStringExp())
7773 // deprecated in 2.107
7774 deprecation(e.loc, "assert condition cannot be a string literal");
7775 deprecationSupplemental(e.loc, "If intentional, use `%s !is null` instead to preserve behaviour",
7776 e.toChars());
7779 const generateMsg = !exp.msg &&
7780 sc.needsCodegen() && // let ctfe interpreter handle the error message
7781 global.params.checkAction == CHECKACTION.context &&
7782 global.params.useAssert == CHECKENABLE.on &&
7783 !((exp.e1.isIntegerExp() && (exp.e1.toInteger() == 0)) ||
7784 exp.e1.isNullExp());
7785 Expression temporariesPrefix;
7787 if (generateMsg)
7788 // no message - use assert expression as msg
7790 if (!verifyHookExist(exp.loc, *sc, Id._d_assert_fail, "generating assert messages"))
7791 return setError();
7795 auto a = e1, b = e2;
7796 assert(a == b, _d_assert_fail!"=="(a, b));
7801 Stores the result of an operand expression into a temporary
7802 if necessary, e.g. if it is an impure fuction call containing side
7803 effects as in https://issues.dlang.org/show_bug.cgi?id=20114
7805 Params:
7806 op = an expression which may require a temporary (added to
7807 `temporariesPrefix`: `auto tmp = op`) and will be replaced
7808 by `tmp` if necessary
7810 Returns: (possibly replaced) `op`
7812 Expression maybePromoteToTmp(ref Expression op)
7814 // https://issues.dlang.org/show_bug.cgi?id=20989
7815 // Flag that _d_assert_fail will never dereference `array.ptr` to avoid safety
7816 // errors for `assert(!array.ptr)` => `_d_assert_fail!"!"(array.ptr)`
7818 auto die = op.isDotIdExp();
7819 if (die && die.ident == Id.ptr)
7820 die.noderef = true;
7823 op = op.expressionSemantic(sc);
7824 op = resolveProperties(sc, op);
7826 // Detect assert's using static operator overloads (e.g. `"var" in environment`)
7827 if (auto te = op.isTypeExp())
7829 // Replace the TypeExp with it's textual representation
7830 // Including "..." in the error message isn't quite right but
7831 // proper solutions require more drastic changes, e.g. directly
7832 // using miniFormat and combine instead of calling _d_assert_fail
7833 auto name = new StringExp(te.loc, te.toString());
7834 return name.expressionSemantic(sc);
7837 // Create a temporary for expressions with side effects
7838 // Defensively assume that function calls may have side effects even
7839 // though it's not detected by hasSideEffect (e.g. `debug puts("Hello")` )
7840 // Rewriting CallExp's also avoids some issues with the inliner/debug generation
7841 if (op.hasSideEffect(true))
7843 // Don't create an invalid temporary for void-expressions
7844 // Further semantic will issue an appropriate error
7845 if (op.type.ty == Tvoid)
7846 return op;
7848 // https://issues.dlang.org/show_bug.cgi?id=21590
7849 // Don't create unnecessary temporaries and detect `assert(a = b)`
7850 if (op.isAssignExp() || op.isBinAssignExp())
7852 auto left = (cast(BinExp) op).e1;
7854 // Find leftmost expression to handle other rewrites,
7855 // e.g. --(++a) => a += 1 -= 1
7856 while (left.isAssignExp() || left.isBinAssignExp())
7857 left = (cast(BinExp) left).e1;
7859 // Only use the assignee if it's a variable and skip
7860 // other lvalues (e.g. ref's returned by functions)
7861 if (left.isVarExp())
7862 return left;
7864 // Sanity check that `op` can be converted to boolean
7865 // But don't raise errors for assignments enclosed in another expression
7866 if (op is exp.e1)
7867 op.toBoolean(sc);
7870 // Tuples with side-effects already receive a temporary during semantic
7871 if (op.type.isTypeTuple())
7873 auto te = op.isTupleExp();
7874 assert(te);
7876 // Create a new tuple without the associated temporary
7877 auto res = new TupleExp(op.loc, te.exps);
7878 return res.expressionSemantic(sc);
7881 const stc = op.isLvalue() ? STC.ref_ : 0;
7882 auto tmp = copyToTemp(stc, "__assertOp", op);
7883 tmp.dsymbolSemantic(sc);
7885 auto decl = new DeclarationExp(op.loc, tmp);
7886 temporariesPrefix = Expression.combine(temporariesPrefix, decl);
7888 op = new VarExp(op.loc, tmp);
7889 op = op.expressionSemantic(sc);
7891 return op;
7894 // if the assert condition is a mixin expression, try to compile it
7895 if (auto ce = exp.e1.isMixinExp())
7897 if (auto e1 = compileIt(ce, sc))
7898 exp.e1 = e1;
7901 Expressions* es;
7902 Objects* tiargs;
7903 Loc loc = exp.e1.loc;
7905 const op = exp.e1.op;
7906 bool isEqualsCallExpression;
7907 if (const callExp = exp.e1.isCallExp())
7909 // https://issues.dlang.org/show_bug.cgi?id=20331
7910 // callExp.f may be null if the assert contains a call to
7911 // a function pointer or literal
7912 if (const callExpFunc = callExp.f)
7914 const callExpIdent = callExpFunc.ident;
7915 isEqualsCallExpression = callExpIdent == Id.__equals ||
7916 callExpIdent == Id.eq;
7919 if (op == EXP.equal || op == EXP.notEqual ||
7920 op == EXP.lessThan || op == EXP.greaterThan ||
7921 op == EXP.lessOrEqual || op == EXP.greaterOrEqual ||
7922 op == EXP.identity || op == EXP.notIdentity ||
7923 op == EXP.in_ ||
7924 isEqualsCallExpression)
7926 es = new Expressions(3);
7927 tiargs = new Objects(1);
7929 if (isEqualsCallExpression)
7931 auto callExp = cast(CallExp) exp.e1;
7932 auto args = callExp.arguments;
7934 // structs with opEquals get rewritten to a DotVarExp:
7935 // a.opEquals(b)
7936 // https://issues.dlang.org/show_bug.cgi?id=20100
7937 if (args.length == 1)
7939 auto dv = callExp.e1.isDotVarExp();
7940 assert(dv);
7942 // runtime args
7943 (*es)[1] = maybePromoteToTmp(dv.e1);
7944 (*es)[2] = maybePromoteToTmp((*args)[0]);
7946 else
7948 // runtime args
7949 (*es)[1] = maybePromoteToTmp((*args)[0]);
7950 (*es)[2] = maybePromoteToTmp((*args)[1]);
7953 else
7955 auto binExp = cast(EqualExp) exp.e1;
7957 // runtime args
7958 (*es)[1] = maybePromoteToTmp(binExp.e1);
7959 (*es)[2] = maybePromoteToTmp(binExp.e2);
7962 // template args
7963 Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : EXPtoString(exp.e1.op));
7964 comp = comp.expressionSemantic(sc);
7965 (*es)[0] = comp;
7966 (*tiargs)[0] = (*es)[1].type;
7969 // Format exp.e1 before any additional boolean conversion
7970 // Ignore &&/|| because "assert(...) failed" is more informative than "false != true"
7971 else if (op != EXP.andAnd && op != EXP.orOr)
7973 es = new Expressions(2);
7974 tiargs = new Objects(1);
7976 if (auto ne = exp.e1.isNotExp())
7978 // Fetch the (potential non-bool) expression and fold
7979 // (n) negations into (n % 2) negations, e.g. !!a => a
7980 for (bool neg = true; ; neg = !neg)
7982 if (auto ne2 = ne.e1.isNotExp())
7983 ne = ne2;
7984 else
7986 (*es)[0] = new StringExp(loc, neg ? "!" : "");
7987 (*es)[1] = maybePromoteToTmp(ne.e1);
7988 break;
7992 else
7993 { // Simply format exp.e1
7994 (*es)[0] = new StringExp(loc, "");
7995 (*es)[1] = maybePromoteToTmp(exp.e1);
7998 (*tiargs)[0] = (*es)[1].type;
8000 // Passing __ctfe to auto ref infers ref and aborts compilation:
8001 // "cannot modify compiler-generated variable __ctfe"
8002 auto ve = (*es)[1].isVarExp();
8003 if (ve && ve.var.ident == Id.ctfe)
8005 exp.msg = new StringExp(loc, "assert(__ctfe) failed!");
8006 goto LSkip;
8009 else
8011 OutBuffer buf;
8012 buf.printf("`%s` failed", exp.toChars());
8013 exp.msg = new StringExp(Loc.initial, buf.extractSlice());
8014 goto LSkip;
8017 Expression __assertFail = new IdentifierExp(exp.loc, Id.empty);
8018 auto assertFail = new DotIdExp(loc, __assertFail, Id.object);
8020 auto dt = new DotTemplateInstanceExp(loc, assertFail, Id._d_assert_fail, tiargs);
8021 auto ec = CallExp.create(loc, dt, es);
8022 exp.msg = ec;
8025 LSkip:
8026 if (Expression ex = unaSemantic(exp, sc))
8028 result = ex;
8029 return;
8032 exp.e1 = resolveProperties(sc, exp.e1);
8033 // BUG: see if we can do compile time elimination of the Assert
8034 exp.e1 = exp.e1.optimize(WANTvalue);
8035 exp.e1 = exp.e1.toBoolean(sc);
8037 if (exp.e1.op == EXP.error)
8039 result = exp.e1;
8040 return;
8043 if (exp.msg)
8045 exp.msg = expressionSemantic(exp.msg, sc);
8046 exp.msg = resolveProperties(sc, exp.msg);
8047 exp.msg = exp.msg.implicitCastTo(sc, Type.tchar.constOf().arrayOf());
8048 exp.msg = exp.msg.optimize(WANTvalue);
8049 checkParamArgumentEscape(sc, null, null, null, STC.undefined_, exp.msg, true, false);
8052 if (exp.msg && exp.msg.op == EXP.error)
8054 result = exp.msg;
8055 return;
8058 auto f1 = checkNonAssignmentArrayOp(exp.e1);
8059 auto f2 = exp.msg && checkNonAssignmentArrayOp(exp.msg);
8060 if (f1 || f2)
8061 return setError();
8063 if (exp.e1.toBool().hasValue(false))
8065 /* This is an `assert(0)` which means halt program execution
8067 FuncDeclaration fd = sc.parent.isFuncDeclaration();
8068 if (fd)
8069 fd.hasReturnExp |= 4;
8070 sc.ctorflow.orCSX(CSX.halt);
8072 if (global.params.useAssert == CHECKENABLE.off)
8074 Expression e = new HaltExp(exp.loc);
8075 e = e.expressionSemantic(sc);
8076 result = e;
8077 return;
8080 // Only override the type when it isn't already some flavour of noreturn,
8081 // e.g. when this assert was generated by defaultInitLiteral
8082 if (!exp.type || !exp.type.isTypeNoreturn())
8083 exp.type = Type.tnoreturn;
8085 else
8086 exp.type = Type.tvoid;
8088 result = !temporariesPrefix
8089 ? exp
8090 : Expression.combine(temporariesPrefix, exp).expressionSemantic(sc);
8093 override void visit(ThrowExp te)
8095 import dmd.statementsem;
8097 if (throwSemantic(te.loc, te.e1, sc))
8098 result = te;
8099 else
8100 setError();
8103 override void visit(DotIdExp exp)
8105 static if (LOGSEMANTIC)
8107 printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars());
8108 //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op));
8111 if (sc.flags & SCOPE.Cfile)
8113 /* See if need to rewrite the AST because of cast/call ambiguity
8115 if (auto e = castCallAmbiguity(exp, sc))
8117 result = expressionSemantic(e, sc);
8118 return;
8121 if (exp.arrow) // ImportC only
8122 exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
8124 if (exp.ident == Id.__xalignof && exp.e1.isTypeExp())
8126 // C11 6.5.3 says _Alignof only applies to types
8127 Expression e;
8128 Type t;
8129 Dsymbol s;
8130 dmd.typesem.resolve(exp.e1.type, exp.e1.loc, sc, e, t, s, true);
8131 if (e)
8133 error(exp.e1.loc, "argument to `_Alignof` must be a type");
8134 return setError();
8136 else if (t)
8138 // Note similarity to getProperty() implementation of __xalignof
8139 const explicitAlignment = t.alignment();
8140 const naturalAlignment = t.alignsize();
8141 const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get());
8142 result = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
8144 else if (s)
8146 error(exp.e1.loc, "argument to `_Alignof` must be a type");
8147 return setError();
8149 else
8150 assert(0);
8151 return;
8154 if (exp.ident != Id.__sizeof)
8156 result = fieldLookup(exp.e1, sc, exp.ident, exp.arrow);
8157 return;
8161 Expression e = exp.dotIdSemanticProp(sc, 1);
8163 if (e && isDotOpDispatch(e))
8165 auto ode = e;
8166 uint errors = global.startGagging();
8167 e = resolvePropertiesX(sc, e);
8168 // Any error or if 'e' is not resolved, go to UFCS
8169 if (global.endGagging(errors) || e is ode)
8170 e = null; /* fall down to UFCS */
8171 else
8173 result = e;
8174 return;
8177 if (!e) // if failed to find the property
8179 /* If ident is not a valid property, rewrite:
8180 * e1.ident
8181 * as:
8182 * .ident(e1)
8184 e = resolveUFCSProperties(sc, exp);
8186 result = e;
8189 override void visit(DotTemplateExp e)
8191 if (e.type)
8193 result = e;
8194 return;
8196 if (Expression ex = unaSemantic(e, sc))
8198 result = ex;
8199 return;
8201 // 'void' like TemplateExp
8202 e.type = Type.tvoid;
8203 result = e;
8206 override void visit(DotVarExp exp)
8208 static if (LOGSEMANTIC)
8210 printf("DotVarExp::semantic('%s')\n", exp.toChars());
8212 if (exp.type)
8214 result = exp;
8215 return;
8218 exp.var = exp.var.toAlias().isDeclaration();
8220 exp.e1 = exp.e1.expressionSemantic(sc);
8222 if (auto tup = exp.var.isTupleDeclaration())
8224 /* Replace:
8225 * e1.tuple(a, b, c)
8226 * with:
8227 * tuple(e1.a, e1.b, e1.c)
8229 Expression e0;
8230 Expression ev = sc.func ? extractSideEffect(sc, "__tup", e0, exp.e1) : exp.e1;
8232 auto exps = new Expressions();
8233 exps.reserve(tup.objects.length);
8234 for (size_t i = 0; i < tup.objects.length; i++)
8236 RootObject o = (*tup.objects)[i];
8237 Expression e;
8238 Declaration var;
8239 switch (o.dyncast()) with (DYNCAST)
8241 case expression:
8242 e = cast(Expression)o;
8243 if (auto se = e.isDsymbolExp())
8244 var = se.s.isDeclaration();
8245 else if (auto ve = e.isVarExp())
8246 if (!ve.var.isFuncDeclaration())
8247 // Exempt functions for backwards compatibility reasons.
8248 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
8249 var = ve.var;
8250 break;
8251 case dsymbol:
8252 Dsymbol s = cast(Dsymbol) o;
8253 Declaration d = s.isDeclaration();
8254 if (!d || d.isFuncDeclaration())
8255 // Exempt functions for backwards compatibility reasons.
8256 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
8257 e = new DsymbolExp(exp.loc, s);
8258 else
8259 var = d;
8260 break;
8261 case type:
8262 e = new TypeExp(exp.loc, cast(Type)o);
8263 break;
8264 default:
8265 error(exp.loc, "`%s` is not an expression", o.toChars());
8266 return setError();
8268 if (var)
8269 e = new DotVarExp(exp.loc, ev, var);
8270 exps.push(e);
8273 Expression e = new TupleExp(exp.loc, e0, exps);
8274 e = e.expressionSemantic(sc);
8275 result = e;
8276 return;
8278 else if (auto ad = exp.var.isAliasDeclaration())
8280 if (auto t = ad.getType())
8282 result = new TypeExp(exp.loc, t).expressionSemantic(sc);
8283 return;
8287 exp.e1 = exp.e1.addDtorHook(sc);
8289 Type t1 = exp.e1.type;
8291 if (FuncDeclaration fd = exp.var.isFuncDeclaration())
8293 // for functions, do checks after overload resolution
8294 if (!functionSemantic(fd))
8295 return setError();
8297 /* https://issues.dlang.org/show_bug.cgi?id=13843
8298 * If fd obviously has no overloads, we should
8299 * normalize AST, and it will give a chance to wrap fd with FuncExp.
8301 if ((fd.isNested() && !fd.isThis()) || fd.isFuncLiteralDeclaration())
8303 // (e1, fd)
8304 auto e = symbolToExp(fd, exp.loc, sc, false);
8305 result = Expression.combine(exp.e1, e);
8306 return;
8309 exp.type = fd.type;
8310 assert(exp.type);
8312 else if (OverDeclaration od = exp.var.isOverDeclaration())
8314 exp.type = Type.tvoid; // ambiguous type?
8316 else
8318 exp.type = exp.var.type;
8319 if (!exp.type && global.errors) // var is goofed up, just return error.
8320 return setError();
8321 assert(exp.type);
8323 if (t1.ty == Tpointer)
8324 t1 = t1.nextOf();
8326 exp.type = exp.type.addMod(t1.mod);
8328 // https://issues.dlang.org/show_bug.cgi?id=23109
8329 // Run semantic on the DotVarExp type
8330 if (auto handle = exp.type.isClassHandle())
8332 if (handle.semanticRun < PASS.semanticdone && !handle.isBaseInfoComplete())
8333 handle.dsymbolSemantic(null);
8336 Dsymbol vparent = exp.var.toParent();
8337 AggregateDeclaration ad = vparent ? vparent.isAggregateDeclaration() : null;
8338 if (Expression e1x = getRightThis(exp.loc, sc, ad, exp.e1, exp.var, 1))
8339 exp.e1 = e1x;
8340 else
8342 /* Later checkRightThis will report correct error for invalid field variable access.
8344 Expression e = new VarExp(exp.loc, exp.var);
8345 e = e.expressionSemantic(sc);
8346 result = e;
8347 return;
8349 checkAccess(exp.loc, sc, exp.e1, exp.var);
8351 VarDeclaration v = exp.var.isVarDeclaration();
8352 if (v && (v.isDataseg() || (v.storage_class & STC.manifest)))
8354 Expression e = expandVar(WANTvalue, v);
8355 if (e)
8357 result = e;
8358 return;
8362 if (v && (v.isDataseg() || // fix https://issues.dlang.org/show_bug.cgi?id=8238
8363 (!v.needThis() && v.semanticRun > PASS.initial))) // fix https://issues.dlang.org/show_bug.cgi?id=17258
8365 // (e1, v)
8366 checkAccess(exp.loc, sc, exp.e1, v);
8367 Expression e = new VarExp(exp.loc, v);
8368 e = new CommaExp(exp.loc, exp.e1, e);
8369 e = e.expressionSemantic(sc);
8370 result = e;
8371 return;
8374 //printf("-DotVarExp::semantic('%s')\n", toChars());
8375 result = exp;
8378 override void visit(DotTemplateInstanceExp exp)
8380 static if (LOGSEMANTIC)
8382 printf("DotTemplateInstanceExp::semantic('%s')\n", exp.toChars());
8384 if (exp.type)
8386 result = exp;
8387 return;
8389 // Indicate we need to resolve by UFCS.
8390 Expression e = exp.dotTemplateSemanticProp(sc, DotExpFlag.gag);
8391 if (!e)
8392 e = resolveUFCSProperties(sc, exp);
8393 if (e is exp)
8394 e.type = Type.tvoid; // Unresolved type, because it needs inference
8395 result = e;
8398 override void visit(DelegateExp e)
8400 static if (LOGSEMANTIC)
8402 printf("DelegateExp::semantic('%s')\n", e.toChars());
8404 if (e.type)
8406 result = e;
8407 return;
8410 e.e1 = e.e1.expressionSemantic(sc);
8412 e.type = new TypeDelegate(e.func.type.isTypeFunction());
8413 e.type = e.type.typeSemantic(e.loc, sc);
8415 FuncDeclaration f = e.func.toAliasFunc();
8416 AggregateDeclaration ad = f.isMemberLocal();
8417 if (f.needThis())
8418 e.e1 = getRightThis(e.loc, sc, ad, e.e1, f);
8420 if (f.type.ty == Tfunction)
8422 TypeFunction tf = cast(TypeFunction)f.type;
8423 if (!MODmethodConv(e.e1.type.mod, f.type.mod))
8425 OutBuffer thisBuf, funcBuf;
8426 MODMatchToBuffer(&thisBuf, e.e1.type.mod, tf.mod);
8427 MODMatchToBuffer(&funcBuf, tf.mod, e.e1.type.mod);
8428 error(e.loc, "%smethod `%s` is not callable using a %s`%s`",
8429 funcBuf.peekChars(), f.toPrettyChars(), thisBuf.peekChars(), e.e1.toChars());
8430 return setError();
8433 if (ad && ad.isClassDeclaration() && ad.type != e.e1.type)
8435 // A downcast is required for interfaces
8436 // https://issues.dlang.org/show_bug.cgi?id=3706
8437 e.e1 = new CastExp(e.loc, e.e1, ad.type);
8438 e.e1 = e.e1.expressionSemantic(sc);
8440 result = e;
8441 // declare dual-context container
8442 if (f.hasDualContext() && !sc.intypeof && sc.func)
8444 // check access to second `this`
8445 if (AggregateDeclaration ad2 = f.isMember2())
8447 Expression te = new ThisExp(e.loc).expressionSemantic(sc);
8448 if (te.op != EXP.error)
8449 te = getRightThis(e.loc, sc, ad2, te, f);
8450 if (te.op == EXP.error)
8452 error(e.loc, "need `this` of type `%s` to make delegate from function `%s`", ad2.toChars(), f.toChars());
8453 return setError();
8456 VarDeclaration vthis2 = makeThis2Argument(e.loc, sc, f);
8457 e.vthis2 = vthis2;
8458 Expression de = new DeclarationExp(e.loc, vthis2);
8459 result = Expression.combine(de, result);
8460 result = result.expressionSemantic(sc);
8464 override void visit(DotTypeExp exp)
8466 static if (LOGSEMANTIC)
8468 printf("DotTypeExp::semantic('%s')\n", exp.toChars());
8470 if (exp.type)
8472 result = exp;
8473 return;
8476 if (auto e = unaSemantic(exp, sc))
8478 result = e;
8479 return;
8482 exp.type = exp.sym.getType().addMod(exp.e1.type.mod);
8483 result = exp;
8486 override void visit(AddrExp exp)
8488 static if (LOGSEMANTIC)
8490 printf("AddrExp::semantic('%s')\n", exp.toChars());
8492 if (exp.type)
8494 result = exp;
8495 return;
8498 if (Expression ex = unaSemantic(exp, sc))
8500 result = ex;
8501 return;
8504 if (sc.flags & SCOPE.Cfile)
8506 /* Special handling for &"string"/&(T[]){0, 1}
8507 * since C regards string/array literals as lvalues
8509 auto e = exp.e1;
8510 if(e.isStringExp() || e.isArrayLiteralExp())
8512 e.type = typeSemantic(e.type, Loc.initial, sc);
8513 // if type is already a pointer exp is an illegal expression of the form `&(&"")`
8514 if (!e.type.isTypePointer())
8516 e.type = e.type.pointerTo();
8517 result = e;
8518 return;
8520 else
8522 // `toLvalue` call further below is upon exp.e1, omitting & from the error message
8523 exp.toLvalue(sc, "take address of");
8524 return setError();
8529 int wasCond = exp.e1.op == EXP.question;
8531 if (exp.e1.op == EXP.dotTemplateInstance)
8533 DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)exp.e1;
8534 TemplateInstance ti = dti.ti;
8536 //assert(ti.needsTypeInference(sc));
8537 ti.dsymbolSemantic(sc);
8538 if (!ti.inst || ti.errors) // if template failed to expand
8539 return setError();
8541 Dsymbol s = ti.toAlias();
8542 FuncDeclaration f = s.isFuncDeclaration();
8543 if (f)
8545 exp.e1 = new DotVarExp(exp.e1.loc, dti.e1, f);
8546 exp.e1 = exp.e1.expressionSemantic(sc);
8550 else if (exp.e1.op == EXP.scope_)
8552 TemplateInstance ti = (cast(ScopeExp)exp.e1).sds.isTemplateInstance();
8553 if (ti)
8555 //assert(ti.needsTypeInference(sc));
8556 ti.dsymbolSemantic(sc);
8557 if (!ti.inst || ti.errors) // if template failed to expand
8558 return setError();
8560 Dsymbol s = ti.toAlias();
8561 FuncDeclaration f = s.isFuncDeclaration();
8562 if (f)
8564 exp.e1 = new VarExp(exp.e1.loc, f);
8565 exp.e1 = exp.e1.expressionSemantic(sc);
8569 /* https://issues.dlang.org/show_bug.cgi?id=809
8571 * If the address of a lazy variable is taken,
8572 * the expression is rewritten so that the type
8573 * of it is the delegate type. This means that
8574 * the symbol is not going to represent a call
8575 * to the delegate anymore, but rather, the
8576 * actual symbol.
8578 if (auto ve = exp.e1.isVarExp())
8580 if (ve.var.storage_class & STC.lazy_)
8582 exp.e1 = exp.e1.expressionSemantic(sc);
8583 exp.e1 = resolveProperties(sc, exp.e1);
8584 if (auto callExp = exp.e1.isCallExp())
8586 if (callExp.e1.type.toBasetype().ty == Tdelegate)
8588 /* https://issues.dlang.org/show_bug.cgi?id=20551
8590 * Cannot take address of lazy parameter in @safe code
8591 * because it might end up being a pointer to undefined
8592 * memory.
8594 if (1)
8596 if (sc.setUnsafe(false, exp.loc,
8597 "cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve, sc.func))
8599 setError();
8600 return;
8603 VarExp ve2 = callExp.e1.isVarExp();
8604 ve2.delegateWasExtracted = true;
8605 ve2.var.storage_class |= STC.scope_;
8606 result = ve2;
8607 return;
8613 exp.e1 = exp.e1.toLvalue(sc, "take address of");
8614 if (exp.e1.op == EXP.error)
8616 result = exp.e1;
8617 return;
8619 if (checkNonAssignmentArrayOp(exp.e1))
8620 return setError();
8622 if (!exp.e1.type)
8624 error(exp.loc, "cannot take address of `%s`", exp.e1.toChars());
8625 return setError();
8627 if (!checkAddressable(exp, sc))
8628 return setError();
8630 bool hasOverloads;
8631 if (auto f = isFuncAddress(exp, &hasOverloads))
8633 if (!hasOverloads && f.checkForwardRef(exp.loc))
8634 return setError();
8636 else if (!exp.e1.type.deco)
8638 // try to resolve the type
8639 exp.e1.type = exp.e1.type.typeSemantic(exp.e1.loc, sc);
8640 if (!exp.e1.type.deco) // still couldn't resolve it
8642 if (auto ve = exp.e1.isVarExp())
8644 Declaration d = ve.var;
8645 error(exp.loc, "forward reference to %s `%s`", d.kind(), d.toChars());
8647 else
8648 error(exp.loc, "forward reference to type `%s` of expression `%s`", exp.e1.type.toChars(), exp.e1.toChars());
8649 return setError();
8653 exp.type = exp.e1.type.pointerTo();
8655 // See if this should really be a delegate
8656 if (exp.e1.op == EXP.dotVariable)
8658 DotVarExp dve = cast(DotVarExp)exp.e1;
8659 FuncDeclaration f = dve.var.isFuncDeclaration();
8660 if (f)
8662 f = f.toAliasFunc(); // FIXME, should see overloads
8663 // https://issues.dlang.org/show_bug.cgi?id=1983
8664 if (!dve.hasOverloads)
8665 f.tookAddressOf++;
8667 Expression e;
8668 if (f.needThis())
8669 e = new DelegateExp(exp.loc, dve.e1, f, dve.hasOverloads);
8670 else // It is a function pointer. Convert &v.f() --> (v, &V.f())
8671 e = new CommaExp(exp.loc, dve.e1, new AddrExp(exp.loc, new VarExp(exp.loc, f, dve.hasOverloads)));
8672 e = e.expressionSemantic(sc);
8673 result = e;
8674 return;
8677 // Look for misaligned pointer in @safe mode
8678 if (checkUnsafeAccess(sc, dve, !exp.type.isMutable(), true))
8679 return setError();
8681 else if (exp.e1.op == EXP.variable)
8683 VarExp ve = cast(VarExp)exp.e1;
8684 VarDeclaration v = ve.var.isVarDeclaration();
8685 if (v)
8687 if (!checkAddressVar(sc, exp.e1, v))
8688 return setError();
8690 v.checkPurity(ve.loc, sc);
8692 FuncDeclaration f = ve.var.isFuncDeclaration();
8693 if (f)
8695 /* Because nested functions cannot be overloaded,
8696 * mark here that we took its address because castTo()
8697 * may not be called with an exact match.
8699 * https://issues.dlang.org/show_bug.cgi?id=19285 :
8700 * We also need to make sure we aren't inside a typeof. Ideally the compiler
8701 * would do typeof(...) semantic analysis speculatively then collect information
8702 * about what it used rather than relying on what are effectively semantically-global
8703 * variables but it doesn't.
8705 if (!sc.isFromSpeculativeSemanticContext() && (!ve.hasOverloads || (f.isNested() && !f.needThis())))
8707 // TODO: Refactor to use a proper interface that can keep track of causes.
8708 f.tookAddressOf++;
8711 if (f.isNested() && !f.needThis())
8713 if (f.isFuncLiteralDeclaration())
8715 if (!f.FuncDeclaration.isNested())
8717 /* Supply a 'null' for a this pointer if no this is available
8719 Expression e = new DelegateExp(exp.loc, new NullExp(exp.loc, Type.tnull), f, ve.hasOverloads);
8720 e = e.expressionSemantic(sc);
8721 result = e;
8722 return;
8725 Expression e = new DelegateExp(exp.loc, exp.e1, f, ve.hasOverloads);
8726 e = e.expressionSemantic(sc);
8727 result = e;
8728 return;
8730 if (f.needThis())
8732 auto memberFunc = hasThis(sc);
8733 if (memberFunc && haveSameThis(memberFunc, f))
8735 /* Should probably supply 'this' after overload resolution,
8736 * not before.
8738 Expression ethis = new ThisExp(exp.loc);
8739 Expression e = new DelegateExp(exp.loc, ethis, f, ve.hasOverloads);
8740 e = e.expressionSemantic(sc);
8741 result = e;
8742 return;
8744 if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_))
8746 sc.setUnsafe(false, exp.loc,
8747 "`this` reference necessary to take address of member `%s` in `@safe` function `%s`",
8748 f, sc.func);
8753 else if (exp.e1.op == EXP.index)
8755 /* For:
8756 * int[3] a;
8757 * &a[i]
8758 * check 'a' the same as for a regular variable
8760 if (VarDeclaration v = expToVariable(exp.e1))
8762 v.checkPurity(exp.e1.loc, sc);
8765 else if (wasCond)
8767 /* a ? b : c was transformed to *(a ? &b : &c), but we still
8768 * need to do safety checks
8770 assert(exp.e1.op == EXP.star);
8771 PtrExp pe = cast(PtrExp)exp.e1;
8772 assert(pe.e1.op == EXP.question);
8773 CondExp ce = cast(CondExp)pe.e1;
8774 assert(ce.e1.op == EXP.address);
8775 assert(ce.e2.op == EXP.address);
8777 // Re-run semantic on the address expressions only
8778 ce.e1.type = null;
8779 ce.e1 = ce.e1.expressionSemantic(sc);
8780 ce.e2.type = null;
8781 ce.e2 = ce.e2.expressionSemantic(sc);
8783 result = exp.optimize(WANTvalue);
8786 override void visit(PtrExp exp)
8788 static if (LOGSEMANTIC)
8790 printf("PtrExp::semantic('%s')\n", exp.toChars());
8792 if (exp.type)
8794 result = exp;
8795 return;
8798 Expression e = exp.op_overload(sc);
8799 if (e)
8801 result = e;
8802 return;
8805 exp.e1 = exp.e1.arrayFuncConv(sc);
8807 Type tb = exp.e1.type.toBasetype();
8808 switch (tb.ty)
8810 case Tpointer:
8811 exp.type = (cast(TypePointer)tb).next;
8812 break;
8814 case Tsarray:
8815 case Tarray:
8816 if (isNonAssignmentArrayOp(exp.e1))
8817 goto default;
8818 error(exp.loc, "using `*` on an array is no longer supported; use `*(%s).ptr` instead", exp.e1.toChars());
8819 exp.type = (cast(TypeArray)tb).next;
8820 exp.e1 = exp.e1.castTo(sc, exp.type.pointerTo());
8821 break;
8823 case Terror:
8824 return setError();
8826 case Tnull:
8827 exp.type = Type.tnoreturn; // typeof(*null) is bottom type
8828 break;
8830 default:
8831 error(exp.loc, "can only `*` a pointer, not a `%s`", exp.e1.type.toChars());
8832 goto case Terror;
8835 if (sc.flags & SCOPE.Cfile && exp.type && exp.type.toBasetype().ty == Tvoid)
8837 // https://issues.dlang.org/show_bug.cgi?id=23752
8838 // `&*((void*)(0))` is allowed in C
8839 result = exp;
8840 return;
8843 if (exp.checkValue())
8844 return setError();
8846 result = exp;
8849 override void visit(NegExp exp)
8851 static if (LOGSEMANTIC)
8853 printf("NegExp::semantic('%s')\n", exp.toChars());
8855 if (exp.type)
8857 result = exp;
8858 return;
8861 Expression e = exp.op_overload(sc);
8862 if (e)
8864 result = e;
8865 return;
8868 fix16997(sc, exp);
8869 exp.type = exp.e1.type;
8870 Type tb = exp.type.toBasetype();
8871 if (tb.ty == Tarray || tb.ty == Tsarray)
8873 if (!isArrayOpValid(exp.e1))
8875 result = arrayOpInvalidError(exp);
8876 return;
8878 result = exp;
8879 return;
8881 if (!target.isVectorOpSupported(tb, exp.op))
8883 result = exp.incompatibleTypes();
8884 return;
8886 if (exp.e1.checkNoBool())
8887 return setError();
8888 if (exp.e1.checkArithmetic(exp.op) ||
8889 exp.e1.checkSharedAccess(sc))
8890 return setError();
8892 result = exp;
8895 override void visit(UAddExp exp)
8897 static if (LOGSEMANTIC)
8899 printf("UAddExp::semantic('%s')\n", exp.toChars());
8901 assert(!exp.type);
8903 Expression e = exp.op_overload(sc);
8904 if (e)
8906 result = e;
8907 return;
8910 fix16997(sc, exp);
8911 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op))
8913 result = exp.incompatibleTypes();
8914 return;
8916 if (exp.e1.checkNoBool())
8917 return setError();
8918 if (exp.e1.checkArithmetic(exp.op))
8919 return setError();
8920 if (exp.e1.checkSharedAccess(sc))
8921 return setError();
8923 result = exp.e1;
8926 override void visit(ComExp exp)
8928 if (exp.type)
8930 result = exp;
8931 return;
8934 Expression e = exp.op_overload(sc);
8935 if (e)
8937 result = e;
8938 return;
8941 fix16997(sc, exp);
8942 exp.type = exp.e1.type;
8943 Type tb = exp.type.toBasetype();
8944 if (tb.ty == Tarray || tb.ty == Tsarray)
8946 if (!isArrayOpValid(exp.e1))
8948 result = arrayOpInvalidError(exp);
8949 return;
8951 result = exp;
8952 return;
8954 if (!target.isVectorOpSupported(tb, exp.op))
8956 result = exp.incompatibleTypes();
8957 return;
8959 if (exp.e1.checkNoBool())
8960 return setError();
8961 if (exp.e1.checkIntegral() ||
8962 exp.e1.checkSharedAccess(sc))
8963 return setError();
8965 result = exp;
8968 override void visit(NotExp e)
8970 if (e.type)
8972 result = e;
8973 return;
8976 e.setNoderefOperand();
8978 // Note there is no operator overload
8979 if (Expression ex = unaSemantic(e, sc))
8981 result = ex;
8982 return;
8985 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
8986 if (e.e1.op == EXP.type)
8987 e.e1 = resolveAliasThis(sc, e.e1);
8989 e.e1 = resolveProperties(sc, e.e1);
8990 e.e1 = e.e1.toBoolean(sc);
8991 if (e.e1.type == Type.terror)
8993 result = e.e1;
8994 return;
8997 if (!target.isVectorOpSupported(e.e1.type.toBasetype(), e.op))
8999 result = e.incompatibleTypes();
9001 // https://issues.dlang.org/show_bug.cgi?id=13910
9002 // Today NotExp can take an array as its operand.
9003 if (checkNonAssignmentArrayOp(e.e1))
9004 return setError();
9006 e.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
9007 result = e;
9010 override void visit(DeleteExp exp)
9012 // @@@DEPRECATED_2.109@@@
9013 // 1. Deprecated since 2.079
9014 // 2. Error since 2.099
9015 // 3. Removal of keyword, "delete" can be used for other identities
9016 if (!exp.isRAII)
9018 error(exp.loc, "the `delete` keyword is obsolete");
9019 errorSupplemental(exp.loc, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead");
9020 return setError();
9023 Expression e = exp;
9025 if (Expression ex = unaSemantic(exp, sc))
9027 result = ex;
9028 return;
9030 exp.e1 = resolveProperties(sc, exp.e1);
9031 exp.e1 = exp.e1.modifiableLvalue(sc);
9032 if (exp.e1.op == EXP.error)
9034 result = exp.e1;
9035 return;
9037 exp.type = Type.tvoid;
9039 Type tb = exp.e1.type.toBasetype();
9041 /* Now that `delete` in user code is an error, we only get here when
9042 * `isRAII` has been set to true for the deletion of a `scope class`. */
9043 if (tb.ty != Tclass)
9045 error(exp.loc, "cannot delete type `%s`", exp.e1.type.toChars());
9046 return setError();
9049 ClassDeclaration cd = (cast(TypeClass)tb).sym;
9050 if (cd.isCOMinterface())
9052 /* Because COM classes are deleted by IUnknown.Release()
9054 error(exp.loc, "cannot `delete` instance of COM interface `%s`", cd.toChars());
9055 return setError();
9058 bool err = false;
9059 if (cd.dtor)
9061 err |= !functionSemantic(cd.dtor);
9062 err |= cd.dtor.checkPurity(exp.loc, sc);
9063 err |= cd.dtor.checkSafety(exp.loc, sc);
9064 err |= cd.dtor.checkNogc(exp.loc, sc);
9066 if (err)
9067 return setError();
9069 result = e;
9072 override void visit(CastExp exp)
9074 static if (LOGSEMANTIC)
9076 printf("CastExp::semantic('%s')\n", exp.toChars());
9078 //static int x; assert(++x < 10);
9079 if (exp.type)
9081 result = exp;
9082 return;
9085 if ((sc && sc.flags & SCOPE.Cfile) &&
9086 exp.to && (exp.to.ty == Tident || exp.to.ty == Tsarray) &&
9087 (exp.e1.op == EXP.address || exp.e1.op == EXP.star ||
9088 exp.e1.op == EXP.uadd || exp.e1.op == EXP.negate))
9090 /* Ambiguous cases arise from CParser if type-name is just an identifier.
9091 * ( identifier ) cast-expression
9092 * ( identifier [expression]) cast-expression
9093 * If we determine that `identifier` is a variable, and cast-expression
9094 * is one of the unary operators (& * + -), then rewrite this cast
9095 * as a binary expression.
9097 Loc loc = exp.loc;
9098 Type t;
9099 Expression e;
9100 Dsymbol s;
9101 exp.to.resolve(loc, sc, e, t, s);
9102 if (e !is null)
9104 if (auto ex = exp.e1.isAddrExp()) // (ident) &exp -> (ident & exp)
9105 result = new AndExp(loc, e, ex.e1);
9106 else if (auto ex = exp.e1.isPtrExp()) // (ident) *exp -> (ident * exp)
9107 result = new MulExp(loc, e, ex.e1);
9108 else if (auto ex = exp.e1.isUAddExp()) // (ident) +exp -> (ident + exp)
9109 result = new AddExp(loc, e, ex.e1);
9110 else if (auto ex = exp.e1.isNegExp()) // (ident) -exp -> (ident - exp)
9111 result = new MinExp(loc, e, ex.e1);
9113 assert(result);
9114 result = result.expressionSemantic(sc);
9115 return;
9119 if (exp.to)
9121 exp.to = exp.to.typeSemantic(exp.loc, sc);
9122 if (exp.to == Type.terror)
9123 return setError();
9125 if (!exp.to.hasPointers())
9126 exp.setNoderefOperand();
9128 // When e1 is a template lambda, this cast may instantiate it with
9129 // the type 'to'.
9130 exp.e1 = inferType(exp.e1, exp.to);
9133 if (auto e = unaSemantic(exp, sc))
9135 result = e;
9136 return;
9139 if (exp.to && !exp.to.isTypeSArray() && !exp.to.isTypeFunction())
9140 exp.e1 = exp.e1.arrayFuncConv(sc);
9142 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
9143 if (exp.e1.op == EXP.type)
9144 exp.e1 = resolveAliasThis(sc, exp.e1);
9146 auto e1x = resolveProperties(sc, exp.e1);
9147 if (e1x.op == EXP.error)
9149 result = e1x;
9150 return;
9152 if (e1x.checkType())
9153 return setError();
9154 exp.e1 = e1x;
9156 if (!exp.e1.type)
9158 error(exp.loc, "cannot cast `%s`", exp.e1.toChars());
9159 return setError();
9162 // https://issues.dlang.org/show_bug.cgi?id=19954
9163 if (exp.e1.type.ty == Ttuple)
9165 if (exp.to)
9167 if (TypeTuple tt = exp.to.isTypeTuple())
9169 if (exp.e1.type.implicitConvTo(tt))
9171 result = exp.e1.castTo(sc, tt);
9172 return;
9176 TupleExp te = exp.e1.isTupleExp();
9177 if (te.exps.length == 1)
9178 exp.e1 = (*te.exps)[0];
9181 // only allow S(x) rewrite if cast specified S explicitly.
9182 // See https://issues.dlang.org/show_bug.cgi?id=18545
9183 const bool allowImplicitConstruction = exp.to !is null;
9185 if (!exp.to) // Handle cast(const) and cast(immutable), etc.
9187 exp.to = exp.e1.type.castMod(exp.mod);
9188 exp.to = exp.to.typeSemantic(exp.loc, sc);
9190 if (exp.to == Type.terror)
9191 return setError();
9194 if (exp.to.ty == Ttuple)
9196 error(exp.loc, "cannot cast `%s` of type `%s` to type sequence `%s`", exp.e1.toChars(), exp.e1.type.toChars(), exp.to.toChars());
9197 return setError();
9200 // cast(void) is used to mark e1 as unused, so it is safe
9201 if (exp.to.ty == Tvoid)
9203 exp.type = exp.to;
9204 result = exp;
9205 return;
9208 if (!exp.to.equals(exp.e1.type) && exp.mod == cast(ubyte)~0)
9210 if (Expression e = exp.op_overload(sc))
9212 result = e.implicitCastTo(sc, exp.to);
9213 return;
9217 Type t1b = exp.e1.type.toBasetype();
9218 Type tob = exp.to.toBasetype();
9220 if (allowImplicitConstruction && tob.ty == Tstruct && !tob.equals(t1b))
9222 /* Look to replace:
9223 * cast(S)t
9224 * with:
9225 * S(t)
9228 // Rewrite as to.call(e1)
9229 Expression e = new TypeExp(exp.loc, exp.to);
9230 e = new CallExp(exp.loc, e, exp.e1);
9231 e = e.trySemantic(sc);
9232 if (e)
9234 result = e;
9235 return;
9239 if (!t1b.equals(tob) && (t1b.ty == Tarray || t1b.ty == Tsarray))
9241 if (checkNonAssignmentArrayOp(exp.e1))
9242 return setError();
9245 Expression ex = exp.e1.castTo(sc, exp.to);
9246 if (ex.op == EXP.error)
9248 result = ex;
9249 return;
9252 // Check for unsafe casts
9253 if (!isSafeCast(ex, t1b, tob))
9255 if (sc.setUnsafe(false, exp.loc, "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to))
9257 return setError();
9261 // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built
9262 // to handle certain casts. Those casts which `object.__ArrayCast` does not support are filtered out.
9263 // See `e2ir.toElemCast` for other types of casts. If `object.__ArrayCast` is improved to support more
9264 // casts these conditions and potentially some logic in `e2ir.toElemCast` can be removed.
9265 if (tob.ty == Tarray)
9267 // https://issues.dlang.org/show_bug.cgi?id=19840
9268 if (auto ad = isAggregate(t1b))
9270 if (ad.aliasthis)
9272 Expression e = resolveAliasThis(sc, exp.e1);
9273 e = new CastExp(exp.loc, e, exp.to);
9274 result = e.expressionSemantic(sc);
9275 return;
9279 if(t1b.ty == Tarray && exp.e1.op != EXP.arrayLiteral && sc.needsCodegen())
9281 auto tFrom = t1b.nextOf();
9282 auto tTo = tob.nextOf();
9284 // https://issues.dlang.org/show_bug.cgi?id=20130
9285 if (exp.e1.op != EXP.string_ || !ex.isStringExp)
9287 const uint fromSize = cast(uint)tFrom.size();
9288 const uint toSize = cast(uint)tTo.size();
9289 if (fromSize == SIZE_INVALID || toSize == SIZE_INVALID)
9290 return setError();
9292 // If array element sizes do not match, we must adjust the dimensions
9293 if (fromSize != toSize)
9295 if (!verifyHookExist(exp.loc, *sc, Id.__ArrayCast, "casting array of structs"))
9296 return setError();
9298 // A runtime check is needed in case arrays don't line up. That check should
9299 // be done in the implementation of `object.__ArrayCast`
9300 if (toSize == 0 || (fromSize % toSize) != 0)
9302 // lower to `object.__ArrayCast!(TFrom, TTo)(from)`
9304 // fully qualify as `object.__ArrayCast`
9305 Expression id = new IdentifierExp(exp.loc, Id.empty);
9306 auto dotid = new DotIdExp(exp.loc, id, Id.object);
9308 auto tiargs = new Objects();
9309 tiargs.push(tFrom);
9310 tiargs.push(tTo);
9311 auto dt = new DotTemplateInstanceExp(exp.loc, dotid, Id.__ArrayCast, tiargs);
9313 auto arguments = new Expressions();
9314 arguments.push(exp.e1);
9315 Expression ce = new CallExp(exp.loc, dt, arguments);
9317 result = expressionSemantic(ce, sc);
9318 return;
9325 if (sc && sc.flags & SCOPE.Cfile)
9327 /* C11 6.5.4-5: A cast does not yield an lvalue.
9328 * So ensure that castTo does not strip away the cast so that this
9329 * can be enforced in other semantic visitor methods.
9331 if (!ex.isCastExp())
9333 ex = new CastExp(exp.loc, ex, exp.to);
9334 ex.type = exp.to;
9337 result = ex;
9340 override void visit(VectorExp exp)
9342 static if (LOGSEMANTIC)
9344 printf("VectorExp::semantic('%s')\n", exp.toChars());
9346 if (exp.type)
9348 result = exp;
9349 return;
9352 exp.e1 = exp.e1.expressionSemantic(sc);
9353 exp.type = exp.to.typeSemantic(exp.loc, sc);
9354 if (exp.e1.op == EXP.error || exp.type.ty == Terror)
9356 result = exp.e1;
9357 return;
9360 Type tb = exp.type.toBasetype();
9361 assert(tb.ty == Tvector);
9362 TypeVector tv = cast(TypeVector)tb;
9363 Type te = tv.elementType();
9364 exp.dim = cast(int)(tv.size(exp.loc) / te.size(exp.loc));
9366 bool checkElem(Expression elem)
9368 if (elem.isConst() == 1)
9369 return false;
9371 error(exp.loc, "constant expression expected, not `%s`", elem.toChars());
9372 return true;
9375 exp.e1 = exp.e1.optimize(WANTvalue);
9376 bool res;
9377 if (exp.e1.op == EXP.arrayLiteral)
9379 foreach (i; 0 .. exp.dim)
9381 // Do not stop on first error - check all AST nodes even if error found
9382 res |= checkElem(exp.e1.isArrayLiteralExp()[i]);
9385 else if (exp.e1.type.ty == Tvoid)
9386 checkElem(exp.e1);
9388 result = res ? ErrorExp.get() : exp;
9391 override void visit(VectorArrayExp e)
9393 static if (LOGSEMANTIC)
9395 printf("VectorArrayExp::semantic('%s')\n", e.toChars());
9397 if (!e.type)
9399 unaSemantic(e, sc);
9400 e.e1 = resolveProperties(sc, e.e1);
9402 if (e.e1.op == EXP.error)
9404 result = e.e1;
9405 return;
9407 assert(e.e1.type.ty == Tvector);
9408 e.type = e.e1.type.isTypeVector().basetype;
9410 result = e;
9413 override void visit(SliceExp exp)
9415 static if (LOGSEMANTIC)
9417 printf("SliceExp::semantic('%s')\n", exp.toChars());
9419 if (exp.type)
9421 result = exp;
9422 return;
9425 // operator overloading should be handled in ArrayExp already.
9426 if (Expression ex = unaSemantic(exp, sc))
9428 result = ex;
9429 return;
9431 exp.e1 = resolveProperties(sc, exp.e1);
9432 if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
9434 if (exp.lwr || exp.upr)
9436 error(exp.loc, "cannot slice type `%s`", exp.e1.toChars());
9437 return setError();
9439 Expression e = new TypeExp(exp.loc, exp.e1.type.arrayOf());
9440 result = e.expressionSemantic(sc);
9441 return;
9443 if (!exp.lwr && !exp.upr)
9445 if (exp.e1.op == EXP.arrayLiteral)
9447 // Convert [a,b,c][] to [a,b,c]
9448 Type t1b = exp.e1.type.toBasetype();
9449 Expression e = exp.e1;
9450 if (t1b.ty == Tsarray)
9452 e = e.copy();
9453 e.type = t1b.nextOf().arrayOf();
9455 result = e;
9456 return;
9458 if (exp.e1.op == EXP.slice)
9460 // Convert e[][] to e[]
9461 SliceExp se = cast(SliceExp)exp.e1;
9462 if (!se.lwr && !se.upr)
9464 result = se;
9465 return;
9468 if (isArrayOpOperand(exp.e1))
9470 // Convert (a[]+b[])[] to a[]+b[]
9471 result = exp.e1;
9472 return;
9475 if (exp.e1.op == EXP.error)
9477 result = exp.e1;
9478 return;
9480 if (exp.e1.type.ty == Terror)
9481 return setError();
9483 Type t1b = exp.e1.type.toBasetype();
9484 if (auto tp = t1b.isTypePointer())
9486 if (t1b.isPtrToFunction())
9488 error(exp.loc, "cannot slice function pointer `%s`", exp.e1.toChars());
9489 return setError();
9491 if (!exp.lwr || !exp.upr)
9493 error(exp.loc, "upper and lower bounds are needed to slice a pointer");
9494 if (auto ad = isAggregate(tp.next.toBasetype()))
9496 auto s = search_function(ad, Id.index);
9497 if (!s) s = search_function(ad, Id.slice);
9498 if (s)
9500 auto fd = s.isFuncDeclaration();
9501 if ((fd && !fd.getParameterList().length) || s.isTemplateDeclaration())
9503 errorSupplemental(exp.loc,
9504 "pointer `%s` points to an aggregate that defines an `%s`, perhaps you meant `(*%s)[]`",
9505 exp.e1.toChars(),
9506 s.ident.toChars(),
9507 exp.e1.toChars()
9514 return setError();
9516 if (sc.setUnsafe(false, exp.loc, "pointer slicing not allowed in safe functions"))
9517 return setError();
9519 else if (t1b.ty == Tarray)
9522 else if (t1b.ty == Tsarray)
9525 else if (t1b.ty == Ttuple)
9527 if (!exp.lwr && !exp.upr)
9529 result = exp.e1;
9530 return;
9532 if (!exp.lwr || !exp.upr)
9534 error(exp.loc, "need upper and lower bound to slice a sequence");
9535 return setError();
9538 else if (t1b.ty == Tvector && exp.e1.isLvalue())
9540 // Convert e1 to corresponding static array
9541 TypeVector tv1 = cast(TypeVector)t1b;
9542 t1b = tv1.basetype;
9543 t1b = t1b.castMod(tv1.mod);
9544 exp.e1.type = t1b;
9546 else
9548 error(exp.loc, "`%s` cannot be sliced with `[]`", t1b.ty == Tvoid ? exp.e1.toChars() : t1b.toChars());
9549 return setError();
9552 /* Run semantic on lwr and upr.
9554 Scope* scx = sc;
9555 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
9557 // Create scope for 'length' variable
9558 ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
9559 sym.parent = sc.scopesym;
9560 sc = sc.push(sym);
9562 if (exp.lwr)
9564 if (t1b.ty == Ttuple)
9565 sc = sc.startCTFE();
9566 exp.lwr = exp.lwr.expressionSemantic(sc);
9567 exp.lwr = resolveProperties(sc, exp.lwr);
9568 if (t1b.ty == Ttuple)
9569 sc = sc.endCTFE();
9570 exp.lwr = exp.lwr.implicitCastTo(sc, Type.tsize_t);
9572 if (exp.upr)
9574 if (t1b.ty == Ttuple)
9575 sc = sc.startCTFE();
9576 exp.upr = exp.upr.expressionSemantic(sc);
9577 exp.upr = resolveProperties(sc, exp.upr);
9578 if (t1b.ty == Ttuple)
9579 sc = sc.endCTFE();
9580 exp.upr = exp.upr.implicitCastTo(sc, Type.tsize_t);
9582 if (sc != scx)
9583 sc = sc.pop();
9584 if (exp.lwr && exp.lwr.type == Type.terror || exp.upr && exp.upr.type == Type.terror)
9585 return setError();
9587 if (t1b.ty == Ttuple)
9589 exp.lwr = exp.lwr.ctfeInterpret();
9590 exp.upr = exp.upr.ctfeInterpret();
9591 uinteger_t i1 = exp.lwr.toUInteger();
9592 uinteger_t i2 = exp.upr.toUInteger();
9594 TupleExp te;
9595 TypeTuple tup;
9596 size_t length;
9597 if (exp.e1.op == EXP.tuple) // slicing an expression tuple
9599 te = cast(TupleExp)exp.e1;
9600 tup = null;
9601 length = te.exps.length;
9603 else if (exp.e1.op == EXP.type) // slicing a type tuple
9605 te = null;
9606 tup = cast(TypeTuple)t1b;
9607 length = Parameter.dim(tup.arguments);
9609 else
9610 assert(0);
9612 if (i2 < i1 || length < i2)
9614 error(exp.loc, "string slice `[%llu .. %llu]` is out of bounds", i1, i2);
9615 return setError();
9618 size_t j1 = cast(size_t)i1;
9619 size_t j2 = cast(size_t)i2;
9620 Expression e;
9621 if (exp.e1.op == EXP.tuple)
9623 auto exps = new Expressions(j2 - j1);
9624 for (size_t i = 0; i < j2 - j1; i++)
9626 (*exps)[i] = (*te.exps)[j1 + i];
9628 e = new TupleExp(exp.loc, te.e0, exps);
9630 else
9632 auto args = new Parameters();
9633 args.reserve(j2 - j1);
9634 for (size_t i = j1; i < j2; i++)
9636 Parameter arg = Parameter.getNth(tup.arguments, i);
9637 args.push(arg);
9639 e = new TypeExp(exp.e1.loc, new TypeTuple(args));
9641 e = e.expressionSemantic(sc);
9642 result = e;
9643 return;
9646 exp.type = t1b.nextOf().arrayOf();
9647 // Allow typedef[] -> typedef[]
9648 if (exp.type.equals(t1b))
9649 exp.type = exp.e1.type;
9651 // We might know $ now
9652 setLengthVarIfKnown(exp.lengthVar, t1b);
9654 if (exp.lwr && exp.upr)
9656 exp.lwr = exp.lwr.optimize(WANTvalue);
9657 exp.upr = exp.upr.optimize(WANTvalue);
9659 IntRange lwrRange = getIntRange(exp.lwr);
9660 IntRange uprRange = getIntRange(exp.upr);
9662 if (t1b.ty == Tsarray || t1b.ty == Tarray)
9664 Expression el = new ArrayLengthExp(exp.loc, exp.e1);
9665 el = el.expressionSemantic(sc);
9666 el = el.optimize(WANTvalue);
9667 if (el.op == EXP.int64)
9669 // Array length is known at compile-time. Upper is in bounds if it fits length.
9670 dinteger_t length = el.toInteger();
9671 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length));
9672 exp.upperIsInBounds = bounds.contains(uprRange);
9674 else if (exp.upr.op == EXP.int64 && exp.upr.toInteger() == 0)
9676 // Upper slice expression is '0'. Value is always in bounds.
9677 exp.upperIsInBounds = true;
9679 else if (exp.upr.op == EXP.variable && (cast(VarExp)exp.upr).var.ident == Id.dollar)
9681 // Upper slice expression is '$'. Value is always in bounds.
9682 exp.upperIsInBounds = true;
9685 else if (t1b.ty == Tpointer)
9687 exp.upperIsInBounds = true;
9689 else
9690 assert(0);
9692 exp.lowerIsLessThanUpper = (lwrRange.imax <= uprRange.imin);
9694 //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", exp.upperIsInBounds, exp.lowerIsLessThanUpper);
9697 result = exp;
9700 override void visit(ArrayLengthExp e)
9702 static if (LOGSEMANTIC)
9704 printf("ArrayLengthExp::semantic('%s')\n", e.toChars());
9706 if (e.type)
9708 result = e;
9709 return;
9712 if (Expression ex = unaSemantic(e, sc))
9714 result = ex;
9715 return;
9717 e.e1 = resolveProperties(sc, e.e1);
9719 e.type = Type.tsize_t;
9720 result = e;
9723 override void visit(ArrayExp exp)
9725 static if (LOGSEMANTIC)
9727 printf("ArrayExp::semantic('%s')\n", exp.toChars());
9729 assert(!exp.type);
9731 if (sc.flags & SCOPE.Cfile)
9733 /* See if need to rewrite the AST because of cast/call ambiguity
9735 if (auto e = castCallAmbiguity(exp, sc))
9737 result = expressionSemantic(e, sc);
9738 return;
9742 result = exp.carraySemantic(sc); // C semantics
9743 if (result)
9744 return;
9746 Expression e = exp.op_overload(sc);
9747 if (e)
9749 result = e;
9750 return;
9753 if (isAggregate(exp.e1.type))
9754 error(exp.loc, "no `[]` operator overload for type `%s`", exp.e1.type.toChars());
9755 else if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
9756 error(exp.loc, "static array of `%s` with multiple lengths not allowed", exp.e1.type.toChars());
9757 else if (isIndexableNonAggregate(exp.e1.type))
9758 error(exp.loc, "only one index allowed to index `%s`", exp.e1.type.toChars());
9759 else
9760 error(exp.loc, "cannot use `[]` operator on expression of type `%s`", exp.e1.type.toChars());
9762 result = ErrorExp.get();
9765 override void visit(DotExp exp)
9767 static if (LOGSEMANTIC)
9769 printf("DotExp::semantic('%s')\n", exp.toChars());
9770 if (exp.type)
9771 printf("\ttype = %s\n", exp.type.toChars());
9773 exp.e1 = exp.e1.expressionSemantic(sc);
9774 exp.e2 = exp.e2.expressionSemantic(sc);
9776 if (exp.e1.op == EXP.type)
9778 result = exp.e2;
9779 return;
9781 if (exp.e2.op == EXP.type)
9783 result = exp.e2;
9784 return;
9786 if (auto te = exp.e2.isTemplateExp())
9788 Expression e = new DotTemplateExp(exp.loc, exp.e1, te.td);
9789 result = e.expressionSemantic(sc);
9790 return;
9792 if (!exp.type)
9793 exp.type = exp.e2.type;
9794 result = exp;
9797 override void visit(CommaExp e)
9799 //printf("Semantic.CommaExp() %s\n", e.toChars());
9800 if (e.type)
9802 result = e;
9803 return;
9806 // Allow `((a,b),(x,y))`
9807 if (e.allowCommaExp)
9809 CommaExp.allow(e.e1);
9810 CommaExp.allow(e.e2);
9813 if (Expression ex = binSemanticProp(e, sc))
9815 result = ex;
9816 return;
9818 e.e1 = e.e1.addDtorHook(sc);
9820 if (checkNonAssignmentArrayOp(e.e1))
9821 return setError();
9823 // Comma expressions trigger this conversion
9824 e.e2 = e.e2.arrayFuncConv(sc);
9826 e.type = e.e2.type;
9827 result = e;
9829 if (sc.flags & SCOPE.Cfile)
9830 return;
9832 if (e.type is Type.tvoid)
9834 checkMustUse(e.e1, sc);
9835 discardValue(e.e1);
9837 else if (!e.allowCommaExp && !e.isGenerated)
9838 error(e.loc, "using the result of a comma expression is not allowed");
9841 override void visit(IntervalExp e)
9843 static if (LOGSEMANTIC)
9845 printf("IntervalExp::semantic('%s')\n", e.toChars());
9847 if (e.type)
9849 result = e;
9850 return;
9853 Expression le = e.lwr;
9854 le = le.expressionSemantic(sc);
9855 le = resolveProperties(sc, le);
9857 Expression ue = e.upr;
9858 ue = ue.expressionSemantic(sc);
9859 ue = resolveProperties(sc, ue);
9861 if (le.op == EXP.error)
9863 result = le;
9864 return;
9866 if (ue.op == EXP.error)
9868 result = ue;
9869 return;
9872 e.lwr = le;
9873 e.upr = ue;
9875 e.type = Type.tvoid;
9876 result = e;
9879 override void visit(DelegatePtrExp e)
9881 static if (LOGSEMANTIC)
9883 printf("DelegatePtrExp::semantic('%s')\n", e.toChars());
9885 if (!e.type)
9887 unaSemantic(e, sc);
9888 e.e1 = resolveProperties(sc, e.e1);
9890 if (e.e1.op == EXP.error)
9892 result = e.e1;
9893 return;
9895 e.type = Type.tvoidptr;
9897 result = e;
9900 override void visit(DelegateFuncptrExp e)
9902 static if (LOGSEMANTIC)
9904 printf("DelegateFuncptrExp::semantic('%s')\n", e.toChars());
9906 if (!e.type)
9908 unaSemantic(e, sc);
9909 e.e1 = resolveProperties(sc, e.e1);
9910 if (e.e1.op == EXP.error)
9912 result = e.e1;
9913 return;
9915 e.type = e.e1.type.nextOf().pointerTo();
9917 result = e;
9920 override void visit(IndexExp exp)
9922 static if (LOGSEMANTIC)
9924 printf("IndexExp::semantic('%s')\n", exp.toChars());
9926 if (exp.type)
9928 result = exp;
9929 return;
9932 // operator overloading should be handled in ArrayExp already.
9933 if (!exp.e1.type)
9934 exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
9935 assert(exp.e1.type); // semantic() should already be run on it
9936 if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
9938 exp.e2 = exp.e2.expressionSemantic(sc);
9939 exp.e2 = resolveProperties(sc, exp.e2);
9940 Type nt;
9941 if (exp.e2.op == EXP.type)
9942 nt = new TypeAArray(exp.e1.type, exp.e2.type);
9943 else
9944 nt = new TypeSArray(exp.e1.type, exp.e2);
9945 Expression e = new TypeExp(exp.loc, nt);
9946 result = e.expressionSemantic(sc);
9947 return;
9949 if (exp.e1.op == EXP.error)
9951 result = exp.e1;
9952 return;
9954 if (exp.e1.type.ty == Terror)
9955 return setError();
9957 // Note that unlike C we do not implement the int[ptr]
9959 Type t1b = exp.e1.type.toBasetype();
9961 if (TypeVector tv1 = t1b.isTypeVector())
9963 // Convert e1 to corresponding static array
9964 t1b = tv1.basetype;
9965 t1b = t1b.castMod(tv1.mod);
9966 exp.e1 = exp.e1.castTo(sc, t1b);
9968 if (t1b.ty == Tsarray || t1b.ty == Tarray)
9970 if (!checkAddressable(exp, sc))
9971 return setError();
9974 /* Run semantic on e2
9976 Scope* scx = sc;
9977 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
9979 // Create scope for 'length' variable
9980 ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
9981 sym.parent = sc.scopesym;
9982 sc = sc.push(sym);
9984 if (t1b.ty == Ttuple)
9985 sc = sc.startCTFE();
9986 exp.e2 = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
9987 exp.e2 = resolveProperties(sc, exp.e2);
9988 if (t1b.ty == Ttuple)
9989 sc = sc.endCTFE();
9990 if (exp.e2.op == EXP.tuple)
9992 TupleExp te = cast(TupleExp)exp.e2;
9993 if (te.exps && te.exps.length == 1)
9994 exp.e2 = Expression.combine(te.e0, (*te.exps)[0]); // bug 4444 fix
9996 if (sc != scx)
9997 sc = sc.pop();
9998 if (exp.e2.type == Type.terror)
9999 return setError();
10001 if (checkNonAssignmentArrayOp(exp.e1))
10002 return setError();
10004 switch (t1b.ty)
10006 case Tpointer:
10007 if (t1b.isPtrToFunction())
10009 error(exp.loc, "cannot index function pointer `%s`", exp.e1.toChars());
10010 return setError();
10012 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
10013 if (exp.e2.type == Type.terror)
10014 return setError();
10015 exp.e2 = exp.e2.optimize(WANTvalue);
10016 if (exp.e2.op == EXP.int64 && exp.e2.toInteger() == 0)
10019 else if (sc.setUnsafe(false, exp.loc, "`@safe` function `%s` cannot index pointer `%s`", sc.func, exp.e1))
10021 return setError();
10023 exp.type = (cast(TypeNext)t1b).next;
10024 break;
10026 case Tarray:
10027 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
10028 if (exp.e2.type == Type.terror)
10029 return setError();
10030 exp.type = (cast(TypeNext)t1b).next;
10031 break;
10033 case Tsarray:
10035 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
10036 if (exp.e2.type == Type.terror)
10037 return setError();
10038 exp.type = t1b.nextOf();
10039 break;
10041 case Taarray:
10043 TypeAArray taa = cast(TypeAArray)t1b;
10044 /* We can skip the implicit conversion if they differ only by
10045 * constness
10046 * https://issues.dlang.org/show_bug.cgi?id=2684
10047 * see also bug https://issues.dlang.org/show_bug.cgi?id=2954 b
10049 if (!arrayTypeCompatibleWithoutCasting(exp.e2.type, taa.index))
10051 exp.e2 = exp.e2.implicitCastTo(sc, taa.index); // type checking
10052 if (exp.e2.type == Type.terror)
10053 return setError();
10056 semanticTypeInfo(sc, taa);
10057 checkNewEscape(sc, exp.e2, false);
10059 exp.type = taa.next;
10060 break;
10062 case Ttuple:
10064 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
10065 if (exp.e2.type == Type.terror)
10066 return setError();
10068 exp.e2 = exp.e2.ctfeInterpret();
10069 uinteger_t index = exp.e2.toUInteger();
10071 TupleExp te;
10072 TypeTuple tup;
10073 size_t length;
10074 if (exp.e1.op == EXP.tuple)
10076 te = cast(TupleExp)exp.e1;
10077 tup = null;
10078 length = te.exps.length;
10080 else if (exp.e1.op == EXP.type)
10082 te = null;
10083 tup = cast(TypeTuple)t1b;
10084 length = Parameter.dim(tup.arguments);
10086 else
10087 assert(0);
10089 if (length <= index)
10091 error(exp.loc, "array index `[%llu]` is outside array bounds `[0 .. %llu]`", index, cast(ulong)length);
10092 return setError();
10094 Expression e;
10095 if (exp.e1.op == EXP.tuple)
10097 e = (*te.exps)[cast(size_t)index];
10098 e = Expression.combine(te.e0, e);
10100 else
10101 e = new TypeExp(exp.e1.loc, Parameter.getNth(tup.arguments, cast(size_t)index).type);
10102 result = e;
10103 return;
10105 default:
10106 error(exp.loc, "`%s` must be an array or pointer type, not `%s`", exp.e1.toChars(), exp.e1.type.toChars());
10107 return setError();
10110 // We might know $ now
10111 setLengthVarIfKnown(exp.lengthVar, t1b);
10113 if (t1b.ty == Tsarray || t1b.ty == Tarray)
10115 Expression el = new ArrayLengthExp(exp.loc, exp.e1);
10116 el = el.expressionSemantic(sc);
10117 el = el.optimize(WANTvalue);
10118 if (el.op == EXP.int64)
10120 exp.e2 = exp.e2.optimize(WANTvalue);
10121 dinteger_t length = el.toInteger();
10122 if (length)
10124 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length - 1));
10125 // OR it in, because it might already be set for C array indexing
10126 exp.indexIsInBounds |= bounds.contains(getIntRange(exp.e2));
10128 else if (sc.flags & SCOPE.Cfile && t1b.ty == Tsarray)
10130 if (auto ve = exp.e1.isVarExp())
10132 /* Rewrite 0-length C array ve[exp.e2] as *(ve + exp.e2)
10134 auto vp = ve.castTo(sc, t1b.isTypeSArray().next.pointerTo());
10135 auto e = new AddExp(exp.loc, vp, exp.e2);
10136 auto pe = new PtrExp(exp.loc, e);
10137 result = pe.expressionSemantic(sc).optimize(WANTvalue);
10138 return;
10144 result = exp;
10147 override void visit(PostExp exp)
10149 static if (LOGSEMANTIC)
10151 printf("PostExp::semantic('%s')\n", exp.toChars());
10153 if (exp.type)
10155 result = exp;
10156 return;
10159 if (sc.flags & SCOPE.Cfile)
10161 /* See if need to rewrite the AST because of cast/call ambiguity
10163 if (auto e = castCallAmbiguity(exp, sc))
10165 result = expressionSemantic(e, sc);
10166 return;
10170 if (Expression ex = binSemantic(exp, sc))
10172 result = ex;
10173 return;
10175 Expression e1x = resolveProperties(sc, exp.e1);
10176 if (e1x.op == EXP.error)
10178 result = e1x;
10179 return;
10181 exp.e1 = e1x;
10183 Expression e = exp.op_overload(sc);
10184 if (e)
10186 result = e;
10187 return;
10190 if (exp.e1.checkReadModifyWrite(exp.op))
10191 return setError();
10193 if (exp.e1.op == EXP.slice)
10195 const(char)* s = exp.op == EXP.plusPlus ? "increment" : "decrement";
10196 error(exp.loc, "cannot post-%s array slice `%s`, use pre-%s instead", s, exp.e1.toChars(), s);
10197 return setError();
10200 Type t1 = exp.e1.type.toBasetype();
10201 if (t1.ty == Tclass || t1.ty == Tstruct || exp.e1.op == EXP.arrayLength)
10203 /* Check for operator overloading,
10204 * but rewrite in terms of ++e instead of e++
10207 /* If e1 is not trivial, take a reference to it
10209 Expression de = null;
10210 if (exp.e1.op != EXP.variable && exp.e1.op != EXP.arrayLength)
10212 // ref v = e1;
10213 auto v = copyToTemp(STC.ref_, "__postref", exp.e1);
10214 de = new DeclarationExp(exp.loc, v);
10215 exp.e1 = new VarExp(exp.e1.loc, v);
10218 /* Rewrite as:
10219 * auto tmp = e1; ++e1; tmp
10221 auto tmp = copyToTemp(0, "__pitmp", exp.e1);
10222 Expression ea = new DeclarationExp(exp.loc, tmp);
10224 Expression eb = exp.e1.syntaxCopy();
10225 eb = new PreExp(exp.op == EXP.plusPlus ? EXP.prePlusPlus : EXP.preMinusMinus, exp.loc, eb);
10227 Expression ec = new VarExp(exp.loc, tmp);
10229 // Combine de,ea,eb,ec
10230 if (de)
10231 ea = new CommaExp(exp.loc, de, ea);
10232 e = new CommaExp(exp.loc, ea, eb);
10233 e = new CommaExp(exp.loc, e, ec);
10234 e = e.expressionSemantic(sc);
10235 result = e;
10236 return;
10239 exp.e1 = exp.e1.modifiableLvalue(sc);
10240 exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
10242 e = exp;
10243 if (exp.e1.checkScalar() ||
10244 exp.e1.checkSharedAccess(sc))
10245 return setError();
10246 if (exp.e1.checkNoBool())
10247 return setError();
10249 if (exp.e1.type.ty == Tpointer)
10250 e = scaleFactor(exp, sc);
10251 else
10252 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
10253 e.type = exp.e1.type;
10254 result = e;
10257 override void visit(PreExp exp)
10259 Expression e = exp.op_overload(sc);
10260 // printf("PreExp::semantic('%s')\n", toChars());
10261 if (e)
10263 result = e;
10264 return;
10267 // Rewrite as e1+=1 or e1-=1
10268 if (exp.op == EXP.prePlusPlus)
10269 e = new AddAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
10270 else
10271 e = new MinAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
10272 result = e.expressionSemantic(sc);
10276 * Get the expression initializer for a specific struct
10278 * Params:
10279 * sd = the struct for which the expression initializer is needed
10280 * loc = the location of the initializer
10281 * sc = the scope where the expression is located
10282 * t = the type of the expression
10284 * Returns:
10285 * The expression initializer or error expression if any errors occured
10287 private Expression getInitExp(StructDeclaration sd, Loc loc, Scope* sc, Type t)
10289 if (sd.zeroInit && !sd.isNested())
10291 // https://issues.dlang.org/show_bug.cgi?id=14606
10292 // Always use BlitExp for the special expression: (struct = 0)
10293 return IntegerExp.literal!0;
10296 if (sd.isNested())
10298 auto sle = new StructLiteralExp(loc, sd, null, t);
10299 if (!sd.fill(loc, *sle.elements, true))
10300 return ErrorExp.get();
10301 if (checkFrameAccess(loc, sc, sd, sle.elements.length))
10302 return ErrorExp.get();
10304 sle.type = t;
10305 return sle;
10308 return t.defaultInit(loc);
10311 override void visit(AssignExp exp)
10313 static if (LOGSEMANTIC)
10315 if (exp.op == EXP.blit) printf("BlitExp.toElem('%s')\n", exp.toChars());
10316 if (exp.op == EXP.assign) printf("AssignExp.toElem('%s')\n", exp.toChars());
10317 if (exp.op == EXP.construct) printf("ConstructExp.toElem('%s')\n", exp.toChars());
10320 void setResult(Expression e, int line = __LINE__)
10322 //printf("line %d\n", line);
10323 result = e;
10326 if (exp.type)
10328 return setResult(exp);
10331 Expression e1old = exp.e1;
10333 if (auto e2comma = exp.e2.isCommaExp())
10335 if (!e2comma.isGenerated && !(sc.flags & SCOPE.Cfile))
10336 error(exp.loc, "using the result of a comma expression is not allowed");
10338 /* Rewrite to get rid of the comma from rvalue
10339 * e1=(e0,e2) => e0,(e1=e2)
10341 Expression e0;
10342 exp.e2 = Expression.extractLast(e2comma, e0);
10343 Expression e = Expression.combine(e0, exp);
10344 return setResult(e.expressionSemantic(sc));
10347 /* Look for operator overloading of a[arguments] = e2.
10348 * Do it before e1.expressionSemantic() otherwise the ArrayExp will have been
10349 * converted to unary operator overloading already.
10351 if (auto ae = exp.e1.isArrayExp())
10353 Expression res;
10355 ae.e1 = ae.e1.expressionSemantic(sc);
10356 ae.e1 = resolveProperties(sc, ae.e1);
10357 Expression ae1old = ae.e1;
10359 const(bool) maybeSlice =
10360 (ae.arguments.length == 0 ||
10361 ae.arguments.length == 1 && (*ae.arguments)[0].op == EXP.interval);
10363 IntervalExp ie = null;
10364 if (maybeSlice && ae.arguments.length)
10366 assert((*ae.arguments)[0].op == EXP.interval);
10367 ie = cast(IntervalExp)(*ae.arguments)[0];
10369 Type att = null; // first cyclic `alias this` type
10370 while (true)
10372 if (ae.e1.op == EXP.error)
10373 return setResult(ae.e1);
10375 Expression e0 = null;
10376 Expression ae1save = ae.e1;
10377 ae.lengthVar = null;
10379 Type t1b = ae.e1.type.toBasetype();
10380 AggregateDeclaration ad = isAggregate(t1b);
10381 if (!ad)
10382 break;
10383 if (search_function(ad, Id.indexass))
10385 // Deal with $
10386 res = resolveOpDollar(sc, ae, &e0);
10387 if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
10388 goto Lfallback;
10389 if (res.op == EXP.error)
10390 return setResult(res);
10392 res = exp.e2.expressionSemantic(sc);
10393 if (res.op == EXP.error)
10394 return setResult(res);
10395 exp.e2 = res;
10397 /* Rewrite (a[arguments] = e2) as:
10398 * a.opIndexAssign(e2, arguments)
10400 Expressions* a = ae.arguments.copy();
10401 a.insert(0, exp.e2);
10402 res = new DotIdExp(exp.loc, ae.e1, Id.indexass);
10403 res = new CallExp(exp.loc, res, a);
10404 if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2)
10405 res = res.trySemantic(sc);
10406 else
10407 res = res.expressionSemantic(sc);
10408 if (res)
10409 return setResult(Expression.combine(e0, res));
10412 Lfallback:
10413 if (maybeSlice && search_function(ad, Id.sliceass))
10415 // Deal with $
10416 res = resolveOpDollar(sc, ae, ie, &e0);
10417 if (res.op == EXP.error)
10418 return setResult(res);
10420 res = exp.e2.expressionSemantic(sc);
10421 if (res.op == EXP.error)
10422 return setResult(res);
10424 exp.e2 = res;
10426 /* Rewrite (a[i..j] = e2) as:
10427 * a.opSliceAssign(e2, i, j)
10429 auto a = new Expressions();
10430 a.push(exp.e2);
10431 if (ie)
10433 a.push(ie.lwr);
10434 a.push(ie.upr);
10436 res = new DotIdExp(exp.loc, ae.e1, Id.sliceass);
10437 res = new CallExp(exp.loc, res, a);
10438 res = res.expressionSemantic(sc);
10439 return setResult(Expression.combine(e0, res));
10442 // No operator overloading member function found yet, but
10443 // there might be an alias this to try.
10444 if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type))
10446 /* Rewrite (a[arguments] op e2) as:
10447 * a.aliasthis[arguments] op e2
10449 ae.e1 = resolveAliasThis(sc, ae1save, true);
10450 if (ae.e1)
10451 continue;
10453 break;
10455 ae.e1 = ae1old; // recovery
10456 ae.lengthVar = null;
10459 /* Run this.e1 semantic.
10462 Expression e1x = exp.e1;
10464 /* With UFCS, e.f = value
10465 * Could mean:
10466 * .f(e, value)
10467 * or:
10468 * .f(e) = value
10470 if (auto dti = e1x.isDotTemplateInstanceExp())
10472 Expression e = dti.dotTemplateSemanticProp(sc, DotExpFlag.gag);
10473 if (!e)
10475 return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
10478 e1x = e;
10480 else if (sc.flags & SCOPE.Cfile && e1x.isDotIdExp())
10482 auto die = e1x.isDotIdExp();
10483 e1x = fieldLookup(die.e1, sc, die.ident, die.arrow);
10485 else if (auto die = e1x.isDotIdExp())
10487 Expression e = die.dotIdSemanticProp(sc, 1);
10488 if (e && isDotOpDispatch(e))
10490 /* https://issues.dlang.org/show_bug.cgi?id=19687
10492 * On this branch, e2 is semantically analyzed in resolvePropertiesX,
10493 * but that call is done with gagged errors. That is the only time when
10494 * semantic gets ran on e2, that is why the error never gets to be printed.
10495 * In order to make sure that UFCS is tried with correct parameters, e2
10496 * needs to have semantic ran on it.
10498 auto ode = e;
10499 exp.e2 = exp.e2.expressionSemantic(sc);
10500 uint errors = global.startGagging();
10501 e = resolvePropertiesX(sc, e, exp.e2);
10502 // Any error or if 'e' is not resolved, go to UFCS
10503 if (global.endGagging(errors) || e is ode)
10504 e = null; /* fall down to UFCS */
10505 else
10506 return setResult(e);
10508 if (!e)
10509 return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
10510 e1x = e;
10512 else
10514 if (auto se = e1x.isSliceExp())
10515 se.arrayop = true;
10517 e1x = e1x.expressionSemantic(sc);
10520 /* We have f = value.
10521 * Could mean:
10522 * f(value)
10523 * or:
10524 * f() = value
10526 if (Expression e = resolvePropertiesX(sc, e1x, exp.e2, exp))
10527 return setResult(e);
10529 if (e1x.checkRightThis(sc))
10531 return setError();
10533 exp.e1 = e1x;
10534 assert(exp.e1.type);
10536 Type t1 = exp.e1.type.isTypeEnum() ? exp.e1.type : exp.e1.type.toBasetype();
10538 /* Run this.e2 semantic.
10539 * Different from other binary expressions, the analysis of e2
10540 * depends on the result of e1 in assignments.
10543 Expression e2x = inferType(exp.e2, t1.baseElemOf());
10544 e2x = e2x.expressionSemantic(sc);
10545 if (!t1.isTypeSArray())
10546 e2x = e2x.arrayFuncConv(sc);
10547 e2x = resolveProperties(sc, e2x);
10548 if (e2x.op == EXP.type)
10549 e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684
10550 if (e2x.op == EXP.error)
10551 return setResult(e2x);
10552 // We delay checking the value for structs/classes as these might have
10553 // an opAssign defined.
10554 if ((t1.ty != Tstruct && t1.ty != Tclass && e2x.checkValue()) ||
10555 e2x.checkSharedAccess(sc))
10556 return setError();
10558 auto etmp = checkNoreturnVarAccess(e2x);
10559 if (etmp != e2x)
10560 return setResult(etmp);
10562 exp.e2 = e2x;
10565 /* Rewrite tuple assignment as a tuple of assignments.
10568 Expression e2x = exp.e2;
10570 Ltupleassign:
10571 if (exp.e1.op == EXP.tuple && e2x.op == EXP.tuple)
10573 TupleExp tup1 = cast(TupleExp)exp.e1;
10574 TupleExp tup2 = cast(TupleExp)e2x;
10575 size_t dim = tup1.exps.length;
10576 Expression e = null;
10577 if (dim != tup2.exps.length)
10579 error(exp.loc, "mismatched sequence lengths, %d and %d", cast(int)dim, cast(int)tup2.exps.length);
10580 return setError();
10582 if (dim == 0)
10584 e = IntegerExp.literal!0;
10585 e = new CastExp(exp.loc, e, Type.tvoid); // avoid "has no effect" error
10586 e = Expression.combine(tup1.e0, tup2.e0, e);
10588 else
10590 auto exps = new Expressions(dim);
10591 for (size_t i = 0; i < dim; i++)
10593 Expression ex1 = (*tup1.exps)[i];
10594 Expression ex2 = (*tup2.exps)[i];
10595 (*exps)[i] = new AssignExp(exp.loc, ex1, ex2);
10597 e = new TupleExp(exp.loc, Expression.combine(tup1.e0, tup2.e0), exps);
10599 return setResult(e.expressionSemantic(sc));
10602 /* Look for form: e1 = e2.aliasthis.
10604 if (exp.e1.op == EXP.tuple)
10606 TupleDeclaration td = isAliasThisTuple(e2x);
10607 if (!td)
10608 goto Lnomatch;
10610 assert(exp.e1.type.ty == Ttuple);
10611 TypeTuple tt = cast(TypeTuple)exp.e1.type;
10613 Expression e0;
10614 Expression ev = extractSideEffect(sc, "__tup", e0, e2x);
10616 auto iexps = new Expressions();
10617 iexps.push(ev);
10618 for (size_t u = 0; u < iexps.length; u++)
10620 Lexpand:
10621 Expression e = (*iexps)[u];
10623 Parameter arg = Parameter.getNth(tt.arguments, u);
10624 //printf("[%d] iexps.length = %d, ", u, iexps.length);
10625 //printf("e = (%s %s, %s), ", Token.toChars[e.op], e.toChars(), e.type.toChars());
10626 //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
10628 if (!arg || !e.type.implicitConvTo(arg.type))
10630 // expand initializer to tuple
10631 if (expandAliasThisTuples(iexps, u) != -1)
10633 if (iexps.length <= u)
10634 break;
10635 goto Lexpand;
10637 goto Lnomatch;
10640 e2x = new TupleExp(e2x.loc, e0, iexps);
10641 e2x = e2x.expressionSemantic(sc);
10642 if (e2x.op == EXP.error)
10644 result = e2x;
10645 return;
10647 // Do not need to overwrite this.e2
10648 goto Ltupleassign;
10650 Lnomatch:
10653 /* Inside constructor, if this is the first assignment of object field,
10654 * rewrite this to initializing the field.
10656 if (exp.op == EXP.assign
10657 && exp.e1.checkModifiable(sc) == Modifiable.initialization)
10659 //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars());
10660 auto t = exp.type;
10661 exp = new ConstructExp(exp.loc, exp.e1, exp.e2);
10662 exp.type = t;
10664 // https://issues.dlang.org/show_bug.cgi?id=13515
10665 // set Index::modifiable flag for complex AA element initialization
10666 if (auto ie1 = exp.e1.isIndexExp())
10668 Expression e1x = ie1.markSettingAAElem();
10669 if (e1x.op == EXP.error)
10671 result = e1x;
10672 return;
10676 else if (exp.op == EXP.construct && exp.e1.op == EXP.variable &&
10677 (cast(VarExp)exp.e1).var.storage_class & (STC.out_ | STC.ref_))
10679 exp.memset = MemorySet.referenceInit;
10682 if (exp.op == EXP.assign) // skip EXP.blit and EXP.construct, which are initializations
10684 exp.e1.checkSharedAccess(sc);
10685 checkUnsafeAccess(sc, exp.e1, false, true);
10688 checkUnsafeAccess(sc, exp.e2, true, true); // Initializer must always be checked
10690 /* If it is an assignment from a 'foreign' type,
10691 * check for operator overloading.
10693 if (exp.memset == MemorySet.referenceInit)
10695 // If this is an initialization of a reference,
10696 // do nothing
10698 else if (t1.ty == Tstruct)
10700 auto e1x = exp.e1;
10701 auto e2x = exp.e2;
10702 auto sd = (cast(TypeStruct)t1).sym;
10704 if (exp.op == EXP.construct)
10706 Type t2 = e2x.type.toBasetype();
10707 if (t2.ty == Tstruct && sd == (cast(TypeStruct)t2).sym)
10709 sd.size(exp.loc);
10710 if (sd.sizeok != Sizeok.done)
10711 return setError();
10712 if (!sd.ctor)
10713 sd.ctor = sd.searchCtor();
10715 // https://issues.dlang.org/show_bug.cgi?id=15661
10716 // Look for the form from last of comma chain.
10717 auto e2y = lastComma(e2x);
10719 CallExp ce = (e2y.op == EXP.call) ? cast(CallExp)e2y : null;
10720 DotVarExp dve = (ce && ce.e1.op == EXP.dotVariable)
10721 ? cast(DotVarExp)ce.e1 : null;
10722 if (sd.ctor && ce && dve && dve.var.isCtorDeclaration() &&
10723 // https://issues.dlang.org/show_bug.cgi?id=19389
10724 dve.e1.op != EXP.dotVariable &&
10725 e2y.type.implicitConvTo(t1))
10727 /* Look for form of constructor call which is:
10728 * __ctmp.ctor(arguments...)
10731 /* Before calling the constructor, initialize
10732 * variable with a bit copy of the default
10733 * initializer
10735 Expression einit = getInitExp(sd, exp.loc, sc, t1);
10736 if (einit.op == EXP.error)
10738 result = einit;
10739 return;
10742 auto ae = new BlitExp(exp.loc, exp.e1, einit);
10743 ae.type = e1x.type;
10745 /* Replace __ctmp being constructed with e1.
10746 * We need to copy constructor call expression,
10747 * because it may be used in other place.
10749 auto dvx = cast(DotVarExp)dve.copy();
10750 dvx.e1 = e1x;
10751 auto cx = cast(CallExp)ce.copy();
10752 cx.e1 = dvx;
10753 if (checkConstructorEscape(sc, cx, false))
10754 return setError();
10756 Expression e0;
10757 Expression.extractLast(e2x, e0);
10759 auto e = Expression.combine(e0, ae, cx);
10760 e = e.expressionSemantic(sc);
10761 result = e;
10762 return;
10764 // https://issues.dlang.org/show_bug.cgi?id=21586
10765 // Rewrite CondExp or e1 will miss direct construction, e.g.
10766 // e1 = a ? S(1) : ...; -> AST: e1 = a ? (S(0)).this(1) : ...;
10767 // a temporary created and an extra destructor call.
10768 // AST will be rewritten to:
10769 // a ? e1 = 0, e1.this(1) : ...; -> blitting plus construction
10770 if (e2x.op == EXP.question)
10772 /* Rewrite as:
10773 * a ? e1 = b : e1 = c;
10775 CondExp econd = cast(CondExp)e2x;
10776 Expression ea1 = new ConstructExp(econd.e1.loc, e1x, econd.e1);
10777 Expression ea2 = new ConstructExp(econd.e2.loc, e1x, econd.e2);
10778 Expression e = new CondExp(exp.loc, econd.econd, ea1, ea2);
10779 result = e.expressionSemantic(sc);
10780 return;
10782 if (sd.postblit || sd.hasCopyCtor)
10784 /* We have a copy constructor for this
10787 if (e2x.isLvalue())
10789 if (sd.hasCopyCtor)
10791 /* Rewrite as:
10792 * e1 = init, e1.copyCtor(e2);
10794 Expression einit = new BlitExp(exp.loc, exp.e1, getInitExp(sd, exp.loc, sc, t1));
10795 einit.type = e1x.type;
10797 Expression e;
10798 e = new DotIdExp(exp.loc, e1x, Id.ctor);
10799 e = new CallExp(exp.loc, e, e2x);
10800 e = new CommaExp(exp.loc, einit, e);
10802 //printf("e: %s\n", e.toChars());
10804 result = e.expressionSemantic(sc);
10805 return;
10807 else
10809 if (!e2x.type.implicitConvTo(e1x.type))
10811 error(exp.loc, "conversion error from `%s` to `%s`",
10812 e2x.type.toChars(), e1x.type.toChars());
10813 return setError();
10816 /* Rewrite as:
10817 * (e1 = e2).postblit();
10819 * Blit assignment e1 = e2 returns a reference to the original e1,
10820 * then call the postblit on it.
10822 Expression e = e1x.copy();
10823 e.type = e.type.mutableOf();
10824 if (e.type.isShared && !sd.type.isShared)
10825 e.type = e.type.unSharedOf();
10826 e = new BlitExp(exp.loc, e, e2x);
10827 e = new DotVarExp(exp.loc, e, sd.postblit, false);
10828 e = new CallExp(exp.loc, e);
10829 result = e.expressionSemantic(sc);
10830 return;
10833 else
10835 /* The struct value returned from the function is transferred
10836 * so should not call the destructor on it.
10838 e2x = valueNoDtor(e2x);
10842 // https://issues.dlang.org/show_bug.cgi?id=19251
10843 // if e2 cannot be converted to e1.type, maybe there is an alias this
10844 if (!e2x.implicitConvTo(t1))
10846 AggregateDeclaration ad2 = isAggregate(e2x.type);
10847 if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
10849 /* Rewrite (e1 op e2) as:
10850 * (e1 op e2.aliasthis)
10852 exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
10853 result = exp.expressionSemantic(sc);
10854 return;
10858 else if (!e2x.implicitConvTo(t1))
10860 sd.size(exp.loc);
10861 if (sd.sizeok != Sizeok.done)
10862 return setError();
10863 if (!sd.ctor)
10864 sd.ctor = sd.searchCtor();
10866 if (sd.ctor)
10868 /* Look for implicit constructor call
10869 * Rewrite as:
10870 * e1 = init, e1.ctor(e2)
10873 /* Fix Issue 5153 : https://issues.dlang.org/show_bug.cgi?id=5153
10874 * Using `new` to initialize a struct object is a common mistake, but
10875 * the error message from the compiler is not very helpful in that
10876 * case. If exp.e2 is a NewExp and the type of new is the same as
10877 * the type as exp.e1 (struct in this case), then we know for sure
10878 * that the user wants to instantiate a struct. This is done to avoid
10879 * issuing an error when the user actually wants to call a constructor
10880 * which receives a class object.
10882 * Foo f = new Foo2(0); is a valid expression if Foo has a constructor
10883 * which receives an instance of a Foo2 class
10885 if (exp.e2.op == EXP.new_)
10887 auto newExp = cast(NewExp)(exp.e2);
10888 if (newExp.newtype && newExp.newtype == t1)
10890 error(exp.loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
10891 newExp.toChars(), newExp.type.toChars(), t1.toChars());
10892 errorSupplemental(exp.loc, "Perhaps remove the `new` keyword?");
10893 return setError();
10897 Expression einit = new BlitExp(exp.loc, e1x, getInitExp(sd, exp.loc, sc, t1));
10898 einit.type = e1x.type;
10900 Expression e;
10901 e = new DotIdExp(exp.loc, e1x, Id.ctor);
10902 e = new CallExp(exp.loc, e, e2x);
10903 e = new CommaExp(exp.loc, einit, e);
10904 e = e.expressionSemantic(sc);
10905 result = e;
10906 return;
10908 if (search_function(sd, Id.call))
10910 /* Look for static opCall
10911 * https://issues.dlang.org/show_bug.cgi?id=2702
10912 * Rewrite as:
10913 * e1 = typeof(e1).opCall(arguments)
10915 e2x = typeDotIdExp(e2x.loc, e1x.type, Id.call);
10916 e2x = new CallExp(exp.loc, e2x, exp.e2);
10918 e2x = e2x.expressionSemantic(sc);
10919 e2x = resolveProperties(sc, e2x);
10920 if (e2x.op == EXP.error)
10922 result = e2x;
10923 return;
10925 if (e2x.checkValue() || e2x.checkSharedAccess(sc))
10926 return setError();
10929 else // https://issues.dlang.org/show_bug.cgi?id=11355
10931 AggregateDeclaration ad2 = isAggregate(e2x.type);
10932 if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
10934 /* Rewrite (e1 op e2) as:
10935 * (e1 op e2.aliasthis)
10937 exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
10938 result = exp.expressionSemantic(sc);
10939 return;
10943 else if (exp.op == EXP.assign)
10945 if (e1x.op == EXP.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray)
10948 * Rewrite:
10949 * aa[key] = e2;
10950 * as:
10951 * ref __aatmp = aa;
10952 * ref __aakey = key;
10953 * ref __aaval = e2;
10954 * (__aakey in __aatmp
10955 * ? __aatmp[__aakey].opAssign(__aaval)
10956 * : ConstructExp(__aatmp[__aakey], __aaval));
10958 // ensure we keep the expr modifiable
10959 Expression esetting = (cast(IndexExp)e1x).markSettingAAElem();
10960 if (esetting.op == EXP.error)
10962 result = esetting;
10963 return;
10965 assert(esetting.op == EXP.index);
10966 IndexExp ie = cast(IndexExp) esetting;
10967 Type t2 = e2x.type.toBasetype();
10969 Expression e0 = null;
10970 Expression ea = extractSideEffect(sc, "__aatmp", e0, ie.e1);
10971 Expression ek = extractSideEffect(sc, "__aakey", e0, ie.e2);
10972 Expression ev = extractSideEffect(sc, "__aaval", e0, e2x);
10974 AssignExp ae = cast(AssignExp)exp.copy();
10975 ae.e1 = new IndexExp(exp.loc, ea, ek);
10976 ae.e1 = ae.e1.expressionSemantic(sc);
10977 ae.e1 = ae.e1.optimize(WANTvalue);
10978 ae.e2 = ev;
10979 Expression e = ae.op_overload(sc);
10980 if (e)
10982 Expression ey = null;
10983 if (t2.ty == Tstruct && sd == t2.toDsymbol(sc))
10985 ey = ev;
10987 else if (!ev.implicitConvTo(ie.type) && sd.ctor)
10989 // Look for implicit constructor call
10990 // Rewrite as S().ctor(e2)
10991 ey = new StructLiteralExp(exp.loc, sd, null);
10992 ey = new DotIdExp(exp.loc, ey, Id.ctor);
10993 ey = new CallExp(exp.loc, ey, ev);
10994 ey = ey.trySemantic(sc);
10996 if (ey)
10998 Expression ex;
10999 ex = new IndexExp(exp.loc, ea, ek);
11000 ex = ex.expressionSemantic(sc);
11001 ex = ex.modifiableLvalue(sc); // allocate new slot
11002 ex = ex.optimize(WANTvalue);
11004 ey = new ConstructExp(exp.loc, ex, ey);
11005 ey = ey.expressionSemantic(sc);
11006 if (ey.op == EXP.error)
11008 result = ey;
11009 return;
11011 ex = e;
11013 // https://issues.dlang.org/show_bug.cgi?id=14144
11014 // The whole expression should have the common type
11015 // of opAssign() return and assigned AA entry.
11016 // Even if there's no common type, expression should be typed as void.
11017 if (!typeMerge(sc, EXP.question, ex, ey))
11019 ex = new CastExp(ex.loc, ex, Type.tvoid);
11020 ey = new CastExp(ey.loc, ey, Type.tvoid);
11022 e = new CondExp(exp.loc, new InExp(exp.loc, ek, ea), ex, ey);
11024 e = Expression.combine(e0, e);
11025 e = e.expressionSemantic(sc);
11026 result = e;
11027 return;
11030 else
11032 Expression e = exp.op_overload(sc);
11033 if (e)
11035 result = e;
11036 return;
11040 else
11041 assert(exp.op == EXP.blit);
11043 if (e2x.checkValue())
11044 return setError();
11046 exp.e1 = e1x;
11047 exp.e2 = e2x;
11049 else if (t1.ty == Tclass)
11051 // Disallow assignment operator overloads for same type
11052 if (exp.op == EXP.assign && !exp.e2.implicitConvTo(exp.e1.type))
11054 Expression e = exp.op_overload(sc);
11055 if (e)
11057 result = e;
11058 return;
11061 if (exp.e2.checkValue())
11062 return setError();
11064 else if (t1.ty == Tsarray)
11066 // SliceExp cannot have static array type without context inference.
11067 assert(exp.e1.op != EXP.slice);
11068 Expression e1x = exp.e1;
11069 Expression e2x = exp.e2;
11071 /* C strings come through as static arrays. May need to adjust the size of the
11072 * string to match the size of e1.
11074 Type t2 = e2x.type.toBasetype();
11075 if (sc.flags & SCOPE.Cfile && e2x.isStringExp() && t2.isTypeSArray())
11077 uinteger_t dim1 = t1.isTypeSArray().dim.toInteger();
11078 uinteger_t dim2 = t2.isTypeSArray().dim.toInteger();
11079 if (dim1 + 1 == dim2 || dim2 < dim1)
11081 auto tsa2 = t2.isTypeSArray();
11082 auto newt = tsa2.next.sarrayOf(dim1).immutableOf();
11083 e2x = castTo(e2x, sc, newt);
11084 exp.e2 = e2x;
11088 if (e2x.implicitConvTo(e1x.type))
11090 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()))
11092 if (t1.checkPostblit(e1x.loc, sc))
11093 return setError();
11096 // e2 matches to t1 because of the implicit length match, so
11097 if (isUnaArrayOp(e2x.op) || isBinArrayOp(e2x.op))
11099 // convert e1 to e1[]
11100 // e.g. e1[] = a[] + b[];
11101 auto sle = new SliceExp(e1x.loc, e1x, null, null);
11102 sle.arrayop = true;
11103 e1x = sle.expressionSemantic(sc);
11105 else
11107 // convert e2 to t1 later
11108 // e.g. e1 = [1, 2, 3];
11111 else
11113 if (e2x.implicitConvTo(t1.nextOf().arrayOf()) > MATCH.nomatch)
11115 uinteger_t dim1 = (cast(TypeSArray)t1).dim.toInteger();
11116 uinteger_t dim2 = dim1;
11117 if (auto ale = e2x.isArrayLiteralExp())
11119 dim2 = ale.elements ? ale.elements.length : 0;
11121 else if (auto se = e2x.isSliceExp())
11123 Type tx = toStaticArrayType(se);
11124 if (tx)
11125 dim2 = (cast(TypeSArray)tx).dim.toInteger();
11127 if (dim1 != dim2)
11129 error(exp.loc, "mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2);
11130 return setError();
11134 // May be block or element-wise assignment, so
11135 // convert e1 to e1[]
11136 if (exp.op != EXP.assign)
11138 // If multidimensional static array, treat as one large array
11140 // Find the appropriate array type depending on the assignment, e.g.
11141 // int[3] = int => int[3]
11142 // int[3][2] = int => int[6]
11143 // int[3][2] = int[] => int[3][2]
11144 // int[3][2][4] + int => int[24]
11145 // int[3][2][4] + int[] => int[3][8]
11146 ulong dim = t1.isTypeSArray().dim.toUInteger();
11147 auto type = t1.nextOf();
11149 for (TypeSArray tsa; (tsa = type.isTypeSArray()) !is null; )
11151 import core.checkedint : mulu;
11153 // Accumulate skipped dimensions
11154 bool overflow = false;
11155 dim = mulu(dim, tsa.dim.toUInteger(), overflow);
11156 if (overflow || dim >= uint.max)
11158 // dym exceeds maximum array size
11159 error(exp.loc, "static array `%s` size overflowed to %llu",
11160 e1x.type.toChars(), cast(ulong) dim);
11161 return setError();
11164 // Move to the element type
11165 type = tsa.nextOf().toBasetype();
11167 // Rewrite ex1 as a static array if a matching type was found
11168 if (e2x.implicitConvTo(type) > MATCH.nomatch)
11170 e1x.type = type.sarrayOf(dim);
11171 break;
11175 auto sle = new SliceExp(e1x.loc, e1x, null, null);
11176 sle.arrayop = true;
11177 e1x = sle.expressionSemantic(sc);
11179 if (e1x.op == EXP.error)
11180 return setResult(e1x);
11181 if (e2x.op == EXP.error)
11182 return setResult(e2x);
11184 exp.e1 = e1x;
11185 exp.e2 = e2x;
11186 t1 = e1x.type.toBasetype();
11188 /* Check the mutability of e1.
11190 if (auto ale = exp.e1.isArrayLengthExp())
11192 // e1 is not an lvalue, but we let code generator handle it
11194 auto ale1x = ale.e1.modifiableLvalueImpl(sc, exp.e1);
11195 if (ale1x.op == EXP.error)
11196 return setResult(ale1x);
11197 ale.e1 = ale1x;
11199 Type tn = ale.e1.type.toBasetype().nextOf();
11200 checkDefCtor(ale.loc, tn);
11202 Identifier hook = global.params.tracegc ? Id._d_arraysetlengthTTrace : Id._d_arraysetlengthT;
11203 if (!verifyHookExist(exp.loc, *sc, Id._d_arraysetlengthTImpl, "resizing arrays"))
11204 return setError();
11206 exp.e2 = exp.e2.expressionSemantic(sc);
11207 auto lc = lastComma(exp.e2);
11208 lc = lc.optimize(WANTvalue);
11209 // use slice expression when arr.length = 0 to avoid runtime call
11210 if(lc.op == EXP.int64 && lc.toInteger() == 0)
11212 Expression se = new SliceExp(ale.loc, ale.e1, lc, lc);
11213 Expression as = new AssignExp(ale.loc, ale.e1, se);
11214 as = as.expressionSemantic(sc);
11215 auto res = Expression.combine(as, exp.e2);
11216 res.type = ale.type;
11217 return setResult(res);
11220 if (!sc.needsCodegen()) // if compile time creature only
11222 exp.type = Type.tsize_t;
11223 return setResult(exp);
11226 // Lower to object._d_arraysetlengthTImpl!(typeof(e1))._d_arraysetlengthT{,Trace}(e1, e2)
11227 Expression id = new IdentifierExp(ale.loc, Id.empty);
11228 id = new DotIdExp(ale.loc, id, Id.object);
11229 auto tiargs = new Objects();
11230 tiargs.push(ale.e1.type);
11231 id = new DotTemplateInstanceExp(ale.loc, id, Id._d_arraysetlengthTImpl, tiargs);
11232 id = new DotIdExp(ale.loc, id, hook);
11233 id = id.expressionSemantic(sc);
11235 auto arguments = new Expressions();
11236 arguments.reserve(5);
11237 if (global.params.tracegc)
11239 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
11240 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
11241 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
11242 arguments.push(new StringExp(exp.loc, funcname.toDString()));
11244 arguments.push(ale.e1);
11245 arguments.push(exp.e2);
11247 Expression ce = new CallExp(ale.loc, id, arguments).expressionSemantic(sc);
11248 auto res = new LoweredAssignExp(exp, ce);
11249 // if (global.params.verbose)
11250 // message("lowered %s =>\n %s", exp.toChars(), res.toChars());
11251 res.type = Type.tsize_t;
11252 return setResult(res);
11254 else if (auto se = exp.e1.isSliceExp())
11256 Type tn = se.type.nextOf();
11257 const fun = sc.func;
11258 if (exp.op == EXP.assign && !tn.isMutable() &&
11259 // allow modifiation in module ctor, see
11260 // https://issues.dlang.org/show_bug.cgi?id=9884
11261 (!fun || (fun && !fun.isStaticCtorDeclaration())))
11263 error(exp.loc, "slice `%s` is not mutable", se.toChars());
11264 return setError();
11267 if (exp.op == EXP.assign && !tn.baseElemOf().isAssignable())
11269 error(exp.loc, "slice `%s` is not mutable, struct `%s` has immutable members",
11270 exp.e1.toChars(), tn.baseElemOf().toChars());
11271 result = ErrorExp.get();
11272 return;
11275 // For conditional operator, both branches need conversion.
11276 while (se.e1.op == EXP.slice)
11277 se = cast(SliceExp)se.e1;
11278 if (se.e1.op == EXP.question && se.e1.type.toBasetype().ty == Tsarray)
11280 se.e1 = se.e1.modifiableLvalueImpl(sc, exp.e1);
11281 if (se.e1.op == EXP.error)
11282 return setResult(se.e1);
11285 else
11287 if (t1.ty == Tsarray && exp.op == EXP.assign)
11289 Type tn = exp.e1.type.nextOf();
11290 if (tn && !tn.baseElemOf().isAssignable())
11292 error(exp.loc, "array `%s` is not mutable, struct `%s` has immutable members",
11293 exp.e1.toChars(), tn.baseElemOf().toChars());
11294 result = ErrorExp.get();
11295 return;
11299 Expression e1x = exp.e1;
11301 // Try to do a decent error message with the expression
11302 // before it gets constant folded
11303 if (exp.op == EXP.assign)
11304 e1x = e1x.modifiableLvalueImpl(sc, e1old);
11306 e1x = e1x.optimize(WANTvalue, /*keepLvalue*/ true);
11308 if (e1x.op == EXP.error)
11310 result = e1x;
11311 return;
11313 exp.e1 = e1x;
11316 /* Tweak e2 based on the type of e1.
11318 Expression e2x = exp.e2;
11319 Type t2 = e2x.type.toBasetype();
11321 // If it is a array, get the element type. Note that it may be
11322 // multi-dimensional.
11323 Type telem = t1;
11324 while (telem.ty == Tarray)
11325 telem = telem.nextOf();
11327 if (exp.e1.op == EXP.slice && t1.nextOf() &&
11328 (telem.ty != Tvoid || e2x.op == EXP.null_) &&
11329 e2x.implicitConvTo(t1.nextOf()))
11331 // Check for block assignment. If it is of type void[], void[][], etc,
11332 // '= null' is the only allowable block assignment (Bug 7493)
11333 exp.memset = MemorySet.blockAssign; // make it easy for back end to tell what this is
11334 e2x = e2x.implicitCastTo(sc, t1.nextOf());
11335 if (exp.op != EXP.blit && e2x.isLvalue() && t1.nextOf.checkPostblit(exp.e1.loc, sc))
11336 return setError();
11338 else if (exp.e1.op == EXP.slice &&
11339 (t2.ty == Tarray || t2.ty == Tsarray) &&
11340 t2.nextOf().implicitConvTo(t1.nextOf()))
11342 // Check element-wise assignment.
11344 /* If assigned elements number is known at compile time,
11345 * check the mismatch.
11347 SliceExp se1 = cast(SliceExp)exp.e1;
11348 TypeSArray tsa1 = cast(TypeSArray)toStaticArrayType(se1);
11349 TypeSArray tsa2 = null;
11350 if (auto ale = e2x.isArrayLiteralExp())
11351 tsa2 = cast(TypeSArray)t2.nextOf().sarrayOf(ale.elements.length);
11352 else if (auto se = e2x.isSliceExp())
11353 tsa2 = cast(TypeSArray)toStaticArrayType(se);
11354 else
11355 tsa2 = t2.isTypeSArray();
11357 if (tsa1 && tsa2)
11359 uinteger_t dim1 = tsa1.dim.toInteger();
11360 uinteger_t dim2 = tsa2.dim.toInteger();
11361 if (dim1 != dim2)
11363 error(exp.loc, "mismatched array lengths %d and %d for assignment `%s`", cast(int)dim1, cast(int)dim2, exp.toChars());
11364 return setError();
11368 if (exp.op != EXP.blit &&
11369 (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() ||
11370 e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() ||
11371 e2x.op != EXP.slice && e2x.isLvalue()))
11373 if (t1.nextOf().checkPostblit(exp.e1.loc, sc))
11374 return setError();
11377 Type t2n = t2.nextOf();
11378 Type t1n = t1.nextOf();
11379 int offset;
11380 if (t2n.equivalent(t1n) ||
11381 t1n.isBaseOf(t2n, &offset) && offset == 0)
11383 /* Allow copy of distinct qualifier elements.
11384 * eg.
11385 * char[] dst; const(char)[] src;
11386 * dst[] = src;
11388 * class C {} class D : C {}
11389 * C[2] ca; D[] da;
11390 * ca[] = da;
11392 if (isArrayOpValid(e2x))
11394 // Don't add CastExp to keep AST for array operations
11395 e2x = e2x.copy();
11396 e2x.type = exp.e1.type.constOf();
11398 else
11399 e2x = e2x.castTo(sc, exp.e1.type.constOf());
11401 else
11403 /* https://issues.dlang.org/show_bug.cgi?id=15778
11404 * A string literal has an array type of immutable
11405 * elements by default, and normally it cannot be convertible to
11406 * array type of mutable elements. But for element-wise assignment,
11407 * elements need to be const at best. So we should give a chance
11408 * to change code unit size for polysemous string literal.
11410 if (e2x.op == EXP.string_)
11411 e2x = e2x.implicitCastTo(sc, exp.e1.type.constOf());
11412 else
11413 e2x = e2x.implicitCastTo(sc, exp.e1.type);
11415 if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid)
11417 if (sc.setUnsafe(false, exp.loc, "cannot copy `void[]` to `void[]` in `@safe` code"))
11418 return setError();
11421 else
11423 if (exp.op == EXP.blit)
11424 e2x = e2x.castTo(sc, exp.e1.type);
11425 else
11427 e2x = e2x.implicitCastTo(sc, exp.e1.type);
11429 // Fix Issue 13435: https://issues.dlang.org/show_bug.cgi?id=13435
11431 // If the implicit cast has failed and the assign expression is
11432 // the initialization of a struct member field
11433 if (e2x.op == EXP.error && exp.op == EXP.construct && t1.ty == Tstruct)
11435 scope sd = (cast(TypeStruct)t1).sym;
11436 Dsymbol opAssign = search_function(sd, Id.assign);
11438 // and the struct defines an opAssign
11439 if (opAssign)
11441 // offer more information about the cause of the problem
11442 errorSupplemental(exp.loc,
11443 "`%s` is the first assignment of `%s` therefore it represents its initialization",
11444 exp.toChars(), exp.e1.toChars());
11445 errorSupplemental(exp.loc,
11446 "`opAssign` methods are not used for initialization, but for subsequent assignments");
11451 if (e2x.op == EXP.error)
11453 result = e2x;
11454 return;
11456 exp.e2 = e2x;
11457 t2 = exp.e2.type.toBasetype();
11459 /* Look for array operations
11461 if ((t2.ty == Tarray || t2.ty == Tsarray) && isArrayOpValid(exp.e2))
11463 // Look for valid array operations
11464 if (exp.memset != MemorySet.blockAssign &&
11465 exp.e1.op == EXP.slice &&
11466 (isUnaArrayOp(exp.e2.op) || isBinArrayOp(exp.e2.op)))
11468 exp.type = exp.e1.type;
11469 if (exp.op == EXP.construct) // https://issues.dlang.org/show_bug.cgi?id=10282
11470 // tweak mutability of e1 element
11471 exp.e1.type = exp.e1.type.nextOf().mutableOf().arrayOf();
11472 result = arrayOp(exp, sc);
11473 return;
11476 // Drop invalid array operations in e2
11477 // d = a[] + b[], d = (a[] + b[])[0..2], etc
11478 if (checkNonAssignmentArrayOp(exp.e2, exp.memset != MemorySet.blockAssign && exp.op == EXP.assign))
11479 return setError();
11481 // Remains valid array assignments
11482 // d = d[], d = [1,2,3], etc
11485 /* Don't allow assignment to classes that were allocated on the stack with:
11486 * scope Class c = new Class();
11488 if (exp.e1.op == EXP.variable && exp.op == EXP.assign)
11490 VarExp ve = cast(VarExp)exp.e1;
11491 VarDeclaration vd = ve.var.isVarDeclaration();
11492 if (vd && vd.onstack)
11494 assert(t1.ty == Tclass);
11495 error(exp.loc, "cannot rebind scope variables");
11499 if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.ident == Id.ctfe)
11501 error(exp.loc, "cannot modify compiler-generated variable `__ctfe`");
11504 exp.type = exp.e1.type;
11505 assert(exp.type);
11506 auto assignElem = exp.e2;
11507 auto res = exp.op == EXP.assign ? exp.reorderSettingAAElem(sc) : exp;
11508 /* https://issues.dlang.org/show_bug.cgi?id=22366
11510 * `reorderSettingAAElem` creates a tree of comma expressions, however,
11511 * `checkAssignExp` expects only AssignExps.
11513 if (res == exp) // no `AA[k] = v` rewrite was performed
11514 checkAssignEscape(sc, res, false, false);
11515 else
11516 checkNewEscape(sc, assignElem, false); // assigning to AA puts it on heap
11518 if (auto ae = res.isConstructExp())
11520 Type t1b = ae.e1.type.toBasetype();
11521 if (t1b.ty != Tsarray && t1b.ty != Tarray)
11522 return setResult(res);
11524 // only non-trivial array constructions may need to be lowered (non-POD elements basically)
11525 Type t1e = t1b.nextOf();
11526 TypeStruct ts = t1e.baseElemOf().isTypeStruct();
11527 if (!ts || (!ts.sym.postblit && !ts.sym.hasCopyCtor && !ts.sym.dtor))
11528 return setResult(res);
11530 // don't lower ref-constructions etc.
11531 if (!(t1b.ty == Tsarray || ae.e1.isSliceExp) ||
11532 (ae.e1.isVarExp && ae.e1.isVarExp.var.isVarDeclaration.isReference))
11533 return setResult(res);
11535 // Construction from an equivalent other array?
11536 // Only lower with lvalue RHS elements; let the glue layer move rvalue elements.
11537 Type t2b = ae.e2.type.toBasetype();
11538 // skip over a (possibly implicit) cast of a static array RHS to a slice
11539 Expression rhs = ae.e2;
11540 Type rhsType = t2b;
11541 if (t2b.ty == Tarray)
11543 if (auto ce = rhs.isCastExp())
11545 auto ct = ce.e1.type.toBasetype();
11546 if (ct.ty == Tsarray)
11548 rhs = ce.e1;
11549 rhsType = ct;
11554 if (!sc.needsCodegen()) // interpreter can handle these
11555 return setResult(res);
11557 const lowerToArrayCtor =
11558 ( (rhsType.ty == Tarray && !rhs.isArrayLiteralExp) ||
11559 (rhsType.ty == Tsarray && rhs.isLvalue) ) &&
11560 t1e.equivalent(t2b.nextOf);
11562 // Construction from a single element?
11563 // If the RHS is an rvalue, then we'll need to make a temporary for it (copied multiple times).
11564 const lowerToArraySetCtor = !lowerToArrayCtor && t1e.equivalent(t2b);
11566 if (lowerToArrayCtor || lowerToArraySetCtor)
11568 auto func = lowerToArrayCtor ? Id._d_arrayctor : Id._d_arraysetctor;
11569 const other = lowerToArrayCtor ? "other array" : "value";
11570 if (!verifyHookExist(exp.loc, *sc, func, "construct array with " ~ other, Id.object))
11571 return setError();
11573 // Lower to object._d_array{,set}ctor(e1, e2)
11574 Expression id = new IdentifierExp(exp.loc, Id.empty);
11575 id = new DotIdExp(exp.loc, id, Id.object);
11576 id = new DotIdExp(exp.loc, id, func);
11578 auto arguments = new Expressions();
11579 arguments.push(new CastExp(ae.loc, ae.e1, t1e.arrayOf).expressionSemantic(sc));
11580 if (lowerToArrayCtor)
11582 arguments.push(new CastExp(ae.loc, rhs, t2b.nextOf.arrayOf).expressionSemantic(sc));
11583 Expression ce = new CallExp(exp.loc, id, arguments);
11584 res = ce.expressionSemantic(sc);
11586 else
11588 Expression e0;
11589 // promote an rvalue RHS element to a temporary, it's passed by ref to _d_arraysetctor
11590 if (!ae.e2.isLvalue)
11592 auto vd = copyToTemp(STC.scope_, "__setctor", ae.e2);
11593 e0 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc);
11594 arguments.push(new VarExp(vd.loc, vd).expressionSemantic(sc));
11596 else
11597 arguments.push(ae.e2);
11599 Expression ce = new CallExp(exp.loc, id, arguments);
11600 res = Expression.combine(e0, ce).expressionSemantic(sc);
11603 if (global.params.v.verbose)
11604 message("lowered %s =>\n %s", exp.toChars(), res.toChars());
11607 else if (auto ae = res.isAssignExp())
11608 res = lowerArrayAssign(ae);
11609 else if (auto ce = res.isCommaExp())
11611 if (auto ae1 = ce.e1.isAssignExp())
11612 ce.e1 = lowerArrayAssign(ae1, true);
11613 if (auto ae2 = ce.e2.isAssignExp())
11614 ce.e2 = lowerArrayAssign(ae2, true);
11617 return setResult(res);
11620 /***************************************
11621 * Lower AssignExp to `_d_array{setassign,assign_l,assign_r}` if needed.
11623 * Params:
11624 * ae = the AssignExp to be lowered
11625 * fromCommaExp = indicates whether `ae` is part of a CommaExp or not,
11626 * so no unnecessary temporay variable is created.
11627 * Returns:
11628 * a CommaExp contiaining call a to `_d_array{setassign,assign_l,assign_r}`
11629 * if needed or `ae` otherwise
11631 private Expression lowerArrayAssign(AssignExp ae, bool fromCommaExp = false)
11633 Type t1b = ae.e1.type.toBasetype();
11634 if (t1b.ty != Tsarray && t1b.ty != Tarray)
11635 return ae;
11637 const isArrayAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) &&
11638 (ae.e2.type.ty == Tsarray || ae.e2.type.ty == Tarray) &&
11639 (ae.e1.type.nextOf() && ae.e2.type.nextOf() && ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf()));
11641 const isArraySetAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) &&
11642 (ae.e1.type.nextOf() && ae.e2.type.implicitConvTo(ae.e1.type.nextOf()));
11644 if (!isArrayAssign && !isArraySetAssign)
11645 return ae;
11647 const ts = t1b.nextOf().baseElemOf().isTypeStruct();
11648 if (!ts || (!ts.sym.postblit && !ts.sym.dtor))
11649 return ae;
11651 Expression res;
11652 Identifier func = isArraySetAssign ? Id._d_arraysetassign :
11653 ae.e2.isLvalue() || ae.e2.isSliceExp() ? Id._d_arrayassign_l : Id._d_arrayassign_r;
11655 // Lower to `.object._d_array{setassign,assign_l,assign_r}(e1, e2)``
11656 Expression id = new IdentifierExp(ae.loc, Id.empty);
11657 id = new DotIdExp(ae.loc, id, Id.object);
11658 id = new DotIdExp(ae.loc, id, func);
11660 auto arguments = new Expressions();
11661 arguments.push(new CastExp(ae.loc, ae.e1, ae.e1.type.nextOf.arrayOf)
11662 .expressionSemantic(sc));
11664 Expression eValue2, value2 = ae.e2;
11665 if (isArrayAssign && value2.isLvalue())
11666 value2 = new CastExp(ae.loc, ae.e2, ae.e2.type.nextOf.arrayOf())
11667 .expressionSemantic(sc);
11668 else if (!fromCommaExp &&
11669 (isArrayAssign || (isArraySetAssign && !value2.isLvalue())))
11671 // Rvalues from CommaExps were introduced in `visit(AssignExp)`
11672 // and are temporary variables themselves. Rvalues from trivial
11673 // SliceExps are simply passed by reference without any copying.
11675 // `__assigntmp` will be destroyed together with the array `ae.e1`.
11676 // When `ae.e2` is a variadic arg array, it is also `scope`, so
11677 // `__assigntmp` may also be scope.
11678 StorageClass stc = STC.nodtor;
11679 if (isArrayAssign)
11680 stc |= STC.rvalue | STC.scope_;
11682 auto vd = copyToTemp(stc, "__assigntmp", ae.e2);
11683 eValue2 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc);
11684 value2 = new VarExp(vd.loc, vd).expressionSemantic(sc);
11686 arguments.push(value2);
11688 Expression ce = new CallExp(ae.loc, id, arguments);
11689 res = Expression.combine(eValue2, ce).expressionSemantic(sc);
11690 if (isArrayAssign)
11691 res = Expression.combine(res, ae.e1).expressionSemantic(sc);
11693 if (global.params.v.verbose)
11694 message("lowered %s =>\n %s", ae.toChars(), res.toChars());
11696 res = new LoweredAssignExp(ae, res);
11697 res.type = ae.type;
11699 return res;
11702 override void visit(PowAssignExp exp)
11704 if (exp.type)
11706 result = exp;
11707 return;
11710 Expression e = exp.op_overload(sc);
11711 if (e)
11713 result = e;
11714 return;
11717 if (exp.e1.checkReadModifyWrite(exp.op, exp.e2))
11718 return setError();
11720 assert(exp.e1.type && exp.e2.type);
11721 if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
11723 if (checkNonAssignmentArrayOp(exp.e1))
11724 return setError();
11726 // T[] ^^= ...
11727 if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
11729 // T[] ^^= T
11730 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
11732 else if (Expression ex = typeCombine(exp, sc))
11734 result = ex;
11735 return;
11738 // Check element types are arithmetic
11739 Type tb1 = exp.e1.type.nextOf().toBasetype();
11740 Type tb2 = exp.e2.type.toBasetype();
11741 if (tb2.ty == Tarray || tb2.ty == Tsarray)
11742 tb2 = tb2.nextOf().toBasetype();
11743 if ((tb1.isintegral() || tb1.isfloating()) && (tb2.isintegral() || tb2.isfloating()))
11745 exp.type = exp.e1.type;
11746 result = arrayOp(exp, sc);
11747 return;
11750 else
11752 exp.e1 = exp.e1.modifiableLvalue(sc);
11755 if ((exp.e1.type.isintegral() || exp.e1.type.isfloating()) && (exp.e2.type.isintegral() || exp.e2.type.isfloating()))
11757 Expression e0 = null;
11758 e = exp.reorderSettingAAElem(sc);
11759 e = Expression.extractLast(e, e0);
11760 assert(e == exp);
11762 if (exp.e1.op == EXP.variable)
11764 // Rewrite: e1 = e1 ^^ e2
11765 e = new PowExp(exp.loc, exp.e1.syntaxCopy(), exp.e2);
11766 e = new AssignExp(exp.loc, exp.e1, e);
11768 else
11770 // Rewrite: ref tmp = e1; tmp = tmp ^^ e2
11771 auto v = copyToTemp(STC.ref_, "__powtmp", exp.e1);
11772 auto de = new DeclarationExp(exp.e1.loc, v);
11773 auto ve = new VarExp(exp.e1.loc, v);
11774 e = new PowExp(exp.loc, ve, exp.e2);
11775 e = new AssignExp(exp.loc, new VarExp(exp.e1.loc, v), e);
11776 e = new CommaExp(exp.loc, de, e);
11778 e = Expression.combine(e0, e);
11779 e = e.expressionSemantic(sc);
11780 result = e;
11781 return;
11783 result = exp.incompatibleTypes();
11786 override void visit(CatAssignExp exp)
11788 if (exp.type)
11790 result = exp;
11791 return;
11794 //printf("CatAssignExp::semantic() %s\n", exp.toChars());
11795 Expression e = exp.op_overload(sc);
11796 if (e)
11798 result = e;
11799 return;
11802 if (SliceExp se = exp.e1.isSliceExp())
11804 if (se.e1.type.toBasetype().ty == Tsarray)
11806 error(exp.loc, "cannot append to static array `%s`", se.e1.type.toChars());
11807 return setError();
11811 exp.e1 = exp.e1.modifiableLvalue(sc);
11812 if (exp.e1.op == EXP.error)
11814 result = exp.e1;
11815 return;
11817 if (exp.e2.op == EXP.error)
11819 result = exp.e2;
11820 return;
11823 if (checkNonAssignmentArrayOp(exp.e2))
11824 return setError();
11826 Type tb1 = exp.e1.type.toBasetype();
11827 Type tb1next = tb1.nextOf();
11828 Type tb2 = exp.e2.type.toBasetype();
11830 /* Possibilities:
11831 * EXP.concatenateAssign: appending T[] to T[]
11832 * EXP.concatenateElemAssign: appending T to T[]
11833 * EXP.concatenateDcharAssign: appending dchar to T[]
11835 if ((tb1.ty == Tarray) &&
11836 (tb2.ty == Tarray || tb2.ty == Tsarray) &&
11837 (exp.e2.implicitConvTo(exp.e1.type) ||
11838 (tb2.nextOf().implicitConvTo(tb1next) &&
11839 (tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial)))))
11841 // EXP.concatenateAssign
11842 assert(exp.op == EXP.concatenateAssign);
11843 if (tb1next.checkPostblit(exp.e1.loc, sc))
11844 return setError();
11846 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
11848 else if ((tb1.ty == Tarray) && exp.e2.implicitConvTo(tb1next))
11850 /* https://issues.dlang.org/show_bug.cgi?id=19782
11852 * If e2 is implicitly convertible to tb1next, the conversion
11853 * might be done through alias this, in which case, e2 needs to
11854 * be modified accordingly (e2 => e2.aliasthis).
11856 if (tb2.ty == Tstruct && (cast(TypeStruct)tb2).implicitConvToThroughAliasThis(tb1next))
11857 goto Laliasthis;
11858 if (tb2.ty == Tclass && (cast(TypeClass)tb2).implicitConvToThroughAliasThis(tb1next))
11859 goto Laliasthis;
11860 // Append element
11861 if (tb2.checkPostblit(exp.e2.loc, sc))
11862 return setError();
11864 if (checkNewEscape(sc, exp.e2, false))
11865 return setError();
11867 exp = new CatElemAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, tb1next));
11868 exp.e2 = doCopyOrMove(sc, exp.e2);
11870 else if (tb1.ty == Tarray &&
11871 (tb1next.ty == Tchar || tb1next.ty == Twchar) &&
11872 exp.e2.type.ty != tb1next.ty &&
11873 exp.e2.implicitConvTo(Type.tdchar))
11875 // Append dchar to char[] or wchar[]
11876 exp = new CatDcharAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, Type.tdchar));
11878 /* Do not allow appending wchar to char[] because if wchar happens
11879 * to be a surrogate pair, nothing good can result.
11882 else
11884 // Try alias this on first operand
11885 static Expression tryAliasThisForLhs(BinAssignExp exp, Scope* sc)
11887 AggregateDeclaration ad1 = isAggregate(exp.e1.type);
11888 if (!ad1 || !ad1.aliasthis)
11889 return null;
11891 /* Rewrite (e1 op e2) as:
11892 * (e1.aliasthis op e2)
11894 if (isRecursiveAliasThis(exp.att1, exp.e1.type))
11895 return null;
11896 //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
11897 Expression e1 = new DotIdExp(exp.loc, exp.e1, ad1.aliasthis.ident);
11898 BinExp be = cast(BinExp)exp.copy();
11899 be.e1 = e1;
11900 return be.trySemantic(sc);
11903 // Try alias this on second operand
11904 static Expression tryAliasThisForRhs(BinAssignExp exp, Scope* sc)
11906 AggregateDeclaration ad2 = isAggregate(exp.e2.type);
11907 if (!ad2 || !ad2.aliasthis)
11908 return null;
11909 /* Rewrite (e1 op e2) as:
11910 * (e1 op e2.aliasthis)
11912 if (isRecursiveAliasThis(exp.att2, exp.e2.type))
11913 return null;
11914 //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
11915 Expression e2 = new DotIdExp(exp.loc, exp.e2, ad2.aliasthis.ident);
11916 BinExp be = cast(BinExp)exp.copy();
11917 be.e2 = e2;
11918 return be.trySemantic(sc);
11921 Laliasthis:
11922 result = tryAliasThisForLhs(exp, sc);
11923 if (result)
11924 return;
11926 result = tryAliasThisForRhs(exp, sc);
11927 if (result)
11928 return;
11930 error(exp.loc, "cannot append type `%s` to type `%s`", tb2.toChars(), tb1.toChars());
11931 return setError();
11934 if (exp.e2.checkValue() || exp.e2.checkSharedAccess(sc))
11935 return setError();
11937 exp.type = exp.e1.type;
11938 auto assignElem = exp.e2;
11939 auto res = exp.reorderSettingAAElem(sc);
11940 if (res != exp) // `AA[k] = v` rewrite was performed
11941 checkNewEscape(sc, assignElem, false);
11942 else if (exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign)
11943 checkAssignEscape(sc, res, false, false);
11945 result = res;
11947 if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) && sc.needsCodegen())
11949 // if aa ordering is triggered, `res` will be a CommaExp
11950 // and `.e2` will be the rewritten original expression.
11952 // `output` will point to the expression that the lowering will overwrite
11953 Expression* output;
11954 if (auto comma = res.isCommaExp())
11956 output = &comma.e2;
11957 // manual cast because it could be either CatAssignExp or CatElemAssignExp
11958 exp = cast(CatAssignExp)comma.e2;
11960 else
11962 output = &result;
11963 exp = cast(CatAssignExp)result;
11966 if (exp.op == EXP.concatenateAssign)
11968 Identifier hook = global.params.tracegc ? Id._d_arrayappendTTrace : Id._d_arrayappendT;
11970 if (!verifyHookExist(exp.loc, *sc, hook, "appending array to arrays", Id.object))
11971 return setError();
11973 // Lower to object._d_arrayappendT{,Trace}({file, line, funcname}, e1, e2)
11974 Expression id = new IdentifierExp(exp.loc, Id.empty);
11975 id = new DotIdExp(exp.loc, id, Id.object);
11976 id = new DotIdExp(exp.loc, id, hook);
11978 auto arguments = new Expressions();
11979 arguments.reserve(5);
11980 if (global.params.tracegc)
11982 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
11983 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
11984 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
11985 arguments.push(new StringExp(exp.loc, funcname.toDString()));
11988 arguments.push(exp.e1);
11989 arguments.push(exp.e2);
11990 Expression ce = new CallExp(exp.loc, id, arguments);
11992 exp.lowering = ce.expressionSemantic(sc);
11993 *output = exp;
11995 else if (exp.op == EXP.concatenateElemAssign)
11997 /* Do not lower concats to the indices array returned by
11998 *`static foreach`, as this array is only used at compile-time.
12000 if (auto ve = exp.e1.isVarExp)
12002 import core.stdc.ctype : isdigit;
12003 // The name of the indices array that static foreach loops uses.
12004 // See dmd.cond.lowerNonArrayAggregate
12005 enum varName = "__res";
12006 const(char)[] id = ve.var.ident.toString;
12007 if (ve.var.storage_class & STC.temp && id.length > varName.length &&
12008 id[0 .. varName.length] == varName && id[varName.length].isdigit)
12009 return;
12012 Identifier hook = global.params.tracegc ? Id._d_arrayappendcTXTrace : Id._d_arrayappendcTX;
12013 if (!verifyHookExist(exp.loc, *sc, hook, "appending element to arrays", Id.object))
12014 return setError();
12016 // Lower to object._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2
12017 Expression id = new IdentifierExp(exp.loc, Id.empty);
12018 id = new DotIdExp(exp.loc, id, Id.object);
12019 id = new DotIdExp(exp.loc, id, hook);
12021 auto arguments = new Expressions();
12022 arguments.reserve(5);
12023 if (global.params.tracegc)
12025 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
12026 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
12027 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
12028 arguments.push(new StringExp(exp.loc, funcname.toDString()));
12031 Expression eValue1;
12032 Expression value1 = extractSideEffect(sc, "__appendtmp", eValue1, exp.e1);
12034 arguments.push(value1);
12035 arguments.push(new IntegerExp(exp.loc, 1, Type.tsize_t));
12037 Expression ce = new CallExp(exp.loc, id, arguments);
12039 Expression eValue2;
12040 Expression value2 = exp.e2;
12041 if (!value2.isVarExp() && !value2.isConst())
12043 /* Before the template hook, this check was performed in e2ir.d
12044 * for expressions like `a ~= a[$-1]`. Here, $ will be modified
12045 * by calling `_d_arrayappendcTX`, so we need to save `a[$-1]` in
12046 * a temporary variable.
12048 value2 = extractSideEffect(sc, "__appendtmp", eValue2, value2, true);
12050 // `__appendtmp*` will be destroyed together with the array `exp.e1`.
12051 auto vd = eValue2.isDeclarationExp().declaration.isVarDeclaration();
12052 vd.storage_class |= STC.nodtor;
12053 // Be more explicit that this "declaration" is local to the expression
12054 vd.storage_class |= STC.exptemp;
12057 auto ale = new ArrayLengthExp(exp.loc, value1);
12058 auto elem = new IndexExp(exp.loc, value1, new MinExp(exp.loc, ale, IntegerExp.literal!1));
12059 auto ae = new ConstructExp(exp.loc, elem, value2);
12061 auto e0 = Expression.combine(ce, ae).expressionSemantic(sc);
12062 e0 = Expression.combine(e0, value1);
12063 e0 = Expression.combine(eValue1, e0);
12064 e0 = Expression.combine(eValue2, e0);
12066 exp.lowering = e0.expressionSemantic(sc);
12067 *output = exp;
12072 override void visit(AddExp exp)
12074 static if (LOGSEMANTIC)
12076 printf("AddExp::semantic('%s')\n", exp.toChars());
12078 if (exp.type)
12080 result = exp;
12081 return;
12084 if (Expression ex = binSemanticProp(exp, sc))
12086 result = ex;
12087 return;
12089 Expression e = exp.op_overload(sc);
12090 if (e)
12092 result = e;
12093 return;
12096 /* ImportC: convert arrays to pointers, functions to pointers to functions
12098 exp.e1 = exp.e1.arrayFuncConv(sc);
12099 exp.e2 = exp.e2.arrayFuncConv(sc);
12101 Type tb1 = exp.e1.type.toBasetype();
12102 Type tb2 = exp.e2.type.toBasetype();
12104 bool err = false;
12105 if (tb1.ty == Tdelegate || tb1.isPtrToFunction())
12107 err |= exp.e1.checkArithmetic(exp.op) || exp.e1.checkSharedAccess(sc);
12109 if (tb2.ty == Tdelegate || tb2.isPtrToFunction())
12111 err |= exp.e2.checkArithmetic(exp.op) || exp.e2.checkSharedAccess(sc);
12113 if (err)
12114 return setError();
12116 if (tb1.ty == Tpointer && exp.e2.type.isintegral() || tb2.ty == Tpointer && exp.e1.type.isintegral())
12118 result = scaleFactor(exp, sc);
12119 return;
12122 if (tb1.ty == Tpointer && tb2.ty == Tpointer)
12124 result = exp.incompatibleTypes();
12125 return;
12128 if (Expression ex = typeCombine(exp, sc))
12130 result = ex;
12131 return;
12134 Type tb = exp.type.toBasetype();
12135 if (tb.ty == Tarray || tb.ty == Tsarray)
12137 if (!isArrayOpValid(exp))
12139 result = arrayOpInvalidError(exp);
12140 return;
12142 result = exp;
12143 return;
12146 tb1 = exp.e1.type.toBasetype();
12147 if (!target.isVectorOpSupported(tb1, exp.op, tb2))
12149 result = exp.incompatibleTypes();
12150 return;
12152 if ((tb1.isreal() && exp.e2.type.isimaginary()) || (tb1.isimaginary() && exp.e2.type.isreal()))
12154 switch (exp.type.toBasetype().ty)
12156 case Tfloat32:
12157 case Timaginary32:
12158 exp.type = Type.tcomplex32;
12159 break;
12161 case Tfloat64:
12162 case Timaginary64:
12163 exp.type = Type.tcomplex64;
12164 break;
12166 case Tfloat80:
12167 case Timaginary80:
12168 exp.type = Type.tcomplex80;
12169 break;
12171 default:
12172 assert(0);
12175 result = exp;
12178 override void visit(MinExp exp)
12180 static if (LOGSEMANTIC)
12182 printf("MinExp::semantic('%s')\n", exp.toChars());
12184 if (exp.type)
12186 result = exp;
12187 return;
12190 if (Expression ex = binSemanticProp(exp, sc))
12192 result = ex;
12193 return;
12195 Expression e = exp.op_overload(sc);
12196 if (e)
12198 result = e;
12199 return;
12202 /* ImportC: convert arrays to pointers, functions to pointers to functions
12204 exp.e1 = exp.e1.arrayFuncConv(sc);
12205 exp.e2 = exp.e2.arrayFuncConv(sc);
12207 Type t1 = exp.e1.type.toBasetype();
12208 Type t2 = exp.e2.type.toBasetype();
12210 bool err = false;
12211 if (t1.ty == Tdelegate || t1.isPtrToFunction())
12213 err |= exp.e1.checkArithmetic(exp.op) || exp.e1.checkSharedAccess(sc);
12215 if (t2.ty == Tdelegate || t2.isPtrToFunction())
12217 err |= exp.e2.checkArithmetic(exp.op) || exp.e2.checkSharedAccess(sc);
12219 if (err)
12220 return setError();
12222 if (t1.ty == Tpointer)
12224 if (t2.ty == Tpointer)
12226 // https://dlang.org/spec/expression.html#add_expressions
12227 // "If both operands are pointers, and the operator is -, the pointers are
12228 // subtracted and the result is divided by the size of the type pointed to
12229 // by the operands. It is an error if the pointers point to different types."
12230 Type p1 = t1.nextOf();
12231 Type p2 = t2.nextOf();
12233 if (!p1.equivalent(p2))
12235 // Deprecation to remain for at least a year, after which this should be
12236 // changed to an error
12237 // See https://github.com/dlang/dmd/pull/7332
12238 deprecation(exp.loc,
12239 "cannot subtract pointers to different types: `%s` and `%s`.",
12240 t1.toChars(), t2.toChars());
12243 // Need to divide the result by the stride
12244 // Replace (ptr - ptr) with (ptr - ptr) / stride
12245 long stride;
12247 // make sure pointer types are compatible
12248 if (Expression ex = typeCombine(exp, sc))
12250 result = ex;
12251 return;
12254 exp.type = Type.tptrdiff_t;
12255 stride = t2.nextOf().size();
12256 if (stride == 0)
12258 e = new IntegerExp(exp.loc, 0, Type.tptrdiff_t);
12260 else if (stride == cast(long)SIZE_INVALID)
12261 e = ErrorExp.get();
12262 else
12264 e = new DivExp(exp.loc, exp, new IntegerExp(Loc.initial, stride, Type.tptrdiff_t));
12265 e.type = Type.tptrdiff_t;
12268 else if (t2.isintegral())
12269 e = scaleFactor(exp, sc);
12270 else
12272 error(exp.loc, "can't subtract `%s` from pointer", t2.toChars());
12273 e = ErrorExp.get();
12275 result = e;
12276 return;
12278 if (t2.ty == Tpointer)
12280 exp.type = exp.e2.type;
12281 error(exp.loc, "can't subtract pointer from `%s`", exp.e1.type.toChars());
12282 return setError();
12285 if (Expression ex = typeCombine(exp, sc))
12287 result = ex;
12288 return;
12291 Type tb = exp.type.toBasetype();
12292 if (tb.ty == Tarray || tb.ty == Tsarray)
12294 if (!isArrayOpValid(exp))
12296 result = arrayOpInvalidError(exp);
12297 return;
12299 result = exp;
12300 return;
12303 t1 = exp.e1.type.toBasetype();
12304 t2 = exp.e2.type.toBasetype();
12305 if (!target.isVectorOpSupported(t1, exp.op, t2))
12307 result = exp.incompatibleTypes();
12308 return;
12310 if ((t1.isreal() && t2.isimaginary()) || (t1.isimaginary() && t2.isreal()))
12312 switch (exp.type.ty)
12314 case Tfloat32:
12315 case Timaginary32:
12316 exp.type = Type.tcomplex32;
12317 break;
12319 case Tfloat64:
12320 case Timaginary64:
12321 exp.type = Type.tcomplex64;
12322 break;
12324 case Tfloat80:
12325 case Timaginary80:
12326 exp.type = Type.tcomplex80;
12327 break;
12329 default:
12330 assert(0);
12333 result = exp;
12334 return;
12338 * If the given expression is a `CatExp`, the function tries to lower it to
12339 * `_d_arraycatnTX`.
12341 * Params:
12342 * ee = the `CatExp` to lower
12343 * Returns:
12344 * `_d_arraycatnTX(e1, e2, ..., en)` if `ee` is `e1 ~ e2 ~ ... en`
12345 * `ee` otherwise
12347 private Expression lowerToArrayCat(CatExp exp)
12349 // String literals are concatenated by the compiler. No lowering is needed.
12350 if ((exp.e1.isStringExp() && (exp.e2.isIntegerExp() || exp.e2.isStringExp())) ||
12351 (exp.e2.isStringExp() && (exp.e1.isIntegerExp() || exp.e1.isStringExp())))
12352 return exp;
12354 bool useTraceGCHook = global.params.tracegc && sc.needsCodegen();
12356 Identifier hook = useTraceGCHook ? Id._d_arraycatnTXTrace : Id._d_arraycatnTX;
12357 if (!verifyHookExist(exp.loc, *sc, hook, "concatenating arrays"))
12359 setError();
12360 return result;
12363 void handleCatArgument(Expressions *arguments, Expression e, Type catType, bool isRightArg)
12365 auto tb = e.type.toBasetype();
12367 if ((isRightArg && e.parens) || (!isRightArg && !tb.equals(catType)))
12369 arguments.push(e);
12370 return;
12373 if (auto ce = e.isCatExp())
12375 Expression lowering = ce.lowering;
12377 /* Skip `file`, `line`, and `funcname` if the hook of the parent
12378 * `CatExp` is `_d_arraycatnTXTrace`.
12380 if (auto callExp = isRuntimeHook(lowering, hook))
12382 if (hook == Id._d_arraycatnTX)
12383 arguments.pushSlice((*callExp.arguments)[]);
12384 else
12385 arguments.pushSlice((*callExp.arguments)[3 .. $]);
12388 else
12389 arguments.push(e);
12392 auto arguments = new Expressions();
12393 if (useTraceGCHook)
12395 auto funcname = (sc.callsc && sc.callsc.func) ?
12396 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
12397 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
12398 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
12399 arguments.push(new StringExp(exp.loc, funcname.toDString()));
12402 handleCatArgument(arguments, exp.e1, exp.type.toBasetype(), false);
12403 handleCatArgument(arguments, exp.e2, exp.type.toBasetype(), true);
12405 Expression id = new IdentifierExp(exp.loc, Id.empty);
12406 id = new DotIdExp(exp.loc, id, Id.object);
12408 auto tiargs = new Objects();
12409 tiargs.push(exp.type);
12410 id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs);
12411 id = new CallExp(exp.loc, id, arguments);
12412 return id.expressionSemantic(sc);
12415 void trySetCatExpLowering(Expression exp)
12417 /* `_d_arraycatnTX` canot be used with `-betterC`, but `CatExp`s may be
12418 * used with `-betterC`, but only during CTFE.
12420 if (!global.params.useGC)
12421 return;
12423 if (auto ce = exp.isCatExp())
12424 ce.lowering = lowerToArrayCat(ce);
12427 override void visit(CatExp exp)
12429 // https://dlang.org/spec/expression.html#cat_expressions
12430 //printf("CatExp.semantic() %s\n", toChars());
12431 if (exp.type)
12433 result = exp;
12434 return;
12437 if (Expression ex = binSemanticProp(exp, sc))
12439 result = ex;
12440 return;
12442 Expression e = exp.op_overload(sc);
12443 if (e)
12445 result = e;
12446 return;
12449 Type tb1 = exp.e1.type.toBasetype();
12450 Type tb2 = exp.e2.type.toBasetype();
12452 auto f1 = checkNonAssignmentArrayOp(exp.e1);
12453 auto f2 = checkNonAssignmentArrayOp(exp.e2);
12454 if (f1 || f2)
12455 return setError();
12457 Type tb1next = tb1.nextOf();
12458 Type tb2next = tb2.nextOf();
12460 // Check for: array ~ array
12461 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)))
12463 /* https://issues.dlang.org/show_bug.cgi?id=9248
12464 * Here to avoid the case of:
12465 * void*[] a = [cast(void*)1];
12466 * void*[] b = [cast(void*)2];
12467 * a ~ b;
12468 * becoming:
12469 * a ~ [cast(void*)b];
12472 /* https://issues.dlang.org/show_bug.cgi?id=14682
12473 * Also to avoid the case of:
12474 * int[][] a;
12475 * a ~ [];
12476 * becoming:
12477 * a ~ cast(int[])[];
12479 goto Lpeer;
12482 // Check for: array ~ element
12483 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && tb2.ty != Tvoid)
12485 if (exp.e1.op == EXP.arrayLiteral)
12487 exp.e2 = doCopyOrMove(sc, exp.e2);
12488 // https://issues.dlang.org/show_bug.cgi?id=14686
12489 // Postblit call appears in AST, and this is
12490 // finally translated to an ArrayLiteralExp in below optimize().
12492 else if (exp.e1.op == EXP.string_)
12494 // No postblit call exists on character (integer) value.
12496 else
12498 if (tb2.checkPostblit(exp.e2.loc, sc))
12499 return setError();
12500 // Postblit call will be done in runtime helper function
12503 if (exp.e1.op == EXP.arrayLiteral && exp.e1.implicitConvTo(tb2.arrayOf()))
12505 exp.e1 = exp.e1.implicitCastTo(sc, tb2.arrayOf());
12506 exp.type = tb2.arrayOf();
12507 goto L2elem;
12509 if (exp.e2.implicitConvTo(tb1next) >= MATCH.convert)
12511 exp.e2 = exp.e2.implicitCastTo(sc, tb1next);
12512 exp.type = tb1next.arrayOf();
12513 L2elem:
12514 if (checkNewEscape(sc, exp.e2, false))
12515 return setError();
12516 result = exp.optimize(WANTvalue);
12517 trySetCatExpLowering(result);
12518 return;
12521 // Check for: element ~ array
12522 if ((tb2.ty == Tsarray || tb2.ty == Tarray) && tb1.ty != Tvoid)
12524 if (exp.e2.op == EXP.arrayLiteral)
12526 exp.e1 = doCopyOrMove(sc, exp.e1);
12528 else if (exp.e2.op == EXP.string_)
12531 else
12533 if (tb1.checkPostblit(exp.e1.loc, sc))
12534 return setError();
12537 if (exp.e2.op == EXP.arrayLiteral && exp.e2.implicitConvTo(tb1.arrayOf()))
12539 exp.e2 = exp.e2.implicitCastTo(sc, tb1.arrayOf());
12540 exp.type = tb1.arrayOf();
12541 goto L1elem;
12543 if (exp.e1.implicitConvTo(tb2next) >= MATCH.convert)
12545 exp.e1 = exp.e1.implicitCastTo(sc, tb2next);
12546 exp.type = tb2next.arrayOf();
12547 L1elem:
12548 if (checkNewEscape(sc, exp.e1, false))
12549 return setError();
12550 result = exp.optimize(WANTvalue);
12551 trySetCatExpLowering(result);
12552 return;
12556 Lpeer:
12557 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && (tb2.ty == Tsarray || tb2.ty == Tarray) && (tb1next.mod || tb2next.mod) && (tb1next.mod != tb2next.mod))
12559 Type t1 = tb1next.mutableOf().constOf().arrayOf();
12560 Type t2 = tb2next.mutableOf().constOf().arrayOf();
12561 if (exp.e1.op == EXP.string_ && !(cast(StringExp)exp.e1).committed)
12562 exp.e1.type = t1;
12563 else
12564 exp.e1 = exp.e1.castTo(sc, t1);
12565 if (exp.e2.op == EXP.string_ && !(cast(StringExp)exp.e2).committed)
12566 exp.e2.type = t2;
12567 else
12568 exp.e2 = exp.e2.castTo(sc, t2);
12571 if (Expression ex = typeCombine(exp, sc))
12573 result = ex;
12574 trySetCatExpLowering(result);
12575 return;
12577 exp.type = exp.type.toHeadMutable();
12579 Type tb = exp.type.toBasetype();
12580 if (tb.ty == Tsarray)
12581 exp.type = tb.nextOf().arrayOf();
12582 if (exp.type.ty == Tarray && tb1next && tb2next && tb1next.mod != tb2next.mod)
12584 exp.type = exp.type.nextOf().toHeadMutable().arrayOf();
12586 if (Type tbn = tb.nextOf())
12588 if (tbn.checkPostblit(exp.loc, sc))
12589 return setError();
12591 Type t1 = exp.e1.type.toBasetype();
12592 Type t2 = exp.e2.type.toBasetype();
12593 if ((t1.ty == Tarray || t1.ty == Tsarray) &&
12594 (t2.ty == Tarray || t2.ty == Tsarray))
12596 // Normalize to ArrayLiteralExp or StringExp as far as possible
12597 e = exp.optimize(WANTvalue);
12599 else
12601 //printf("(%s) ~ (%s)\n", e1.toChars(), e2.toChars());
12602 result = exp.incompatibleTypes();
12603 return;
12606 result = e;
12607 trySetCatExpLowering(result);
12610 override void visit(MulExp exp)
12612 version (none)
12614 printf("MulExp::semantic() %s\n", exp.toChars());
12616 if (exp.type)
12618 result = exp;
12619 return;
12622 if (Expression ex = binSemanticProp(exp, sc))
12624 result = ex;
12625 return;
12627 Expression e = exp.op_overload(sc);
12628 if (e)
12630 result = e;
12631 return;
12634 if (Expression ex = typeCombine(exp, sc))
12636 result = ex;
12637 return;
12640 Type tb = exp.type.toBasetype();
12641 if (tb.ty == Tarray || tb.ty == Tsarray)
12643 if (!isArrayOpValid(exp))
12645 result = arrayOpInvalidError(exp);
12646 return;
12648 result = exp;
12649 return;
12652 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
12653 return setError();
12655 if (exp.type.isfloating())
12657 Type t1 = exp.e1.type;
12658 Type t2 = exp.e2.type;
12660 if (t1.isreal())
12662 exp.type = t2;
12664 else if (t2.isreal())
12666 exp.type = t1;
12668 else if (t1.isimaginary())
12670 if (t2.isimaginary())
12672 switch (t1.toBasetype().ty)
12674 case Timaginary32:
12675 exp.type = Type.tfloat32;
12676 break;
12678 case Timaginary64:
12679 exp.type = Type.tfloat64;
12680 break;
12682 case Timaginary80:
12683 exp.type = Type.tfloat80;
12684 break;
12686 default:
12687 assert(0);
12690 // iy * iv = -yv
12691 exp.e1.type = exp.type;
12692 exp.e2.type = exp.type;
12693 e = new NegExp(exp.loc, exp);
12694 e = e.expressionSemantic(sc);
12695 result = e;
12696 return;
12698 else
12699 exp.type = t2; // t2 is complex
12701 else if (t2.isimaginary())
12703 exp.type = t1; // t1 is complex
12706 else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12708 result = exp.incompatibleTypes();
12709 return;
12711 result = exp;
12714 override void visit(DivExp exp)
12716 if (exp.type)
12718 result = exp;
12719 return;
12722 if (Expression ex = binSemanticProp(exp, sc))
12724 result = ex;
12725 return;
12727 Expression e = exp.op_overload(sc);
12728 if (e)
12730 result = e;
12731 return;
12734 if (Expression ex = typeCombine(exp, sc))
12736 result = ex;
12737 return;
12740 Type tb = exp.type.toBasetype();
12741 if (tb.ty == Tarray || tb.ty == Tsarray)
12743 if (!isArrayOpValid(exp))
12745 result = arrayOpInvalidError(exp);
12746 return;
12748 result = exp;
12749 return;
12752 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
12753 return setError();
12755 if (exp.type.isfloating())
12757 Type t1 = exp.e1.type;
12758 Type t2 = exp.e2.type;
12760 if (t1.isreal())
12762 exp.type = t2;
12763 if (t2.isimaginary())
12765 // x/iv = i(-x/v)
12766 exp.e2.type = t1;
12767 e = new NegExp(exp.loc, exp);
12768 e = e.expressionSemantic(sc);
12769 result = e;
12770 return;
12773 else if (t2.isreal())
12775 exp.type = t1;
12777 else if (t1.isimaginary())
12779 if (t2.isimaginary())
12781 switch (t1.toBasetype().ty)
12783 case Timaginary32:
12784 exp.type = Type.tfloat32;
12785 break;
12787 case Timaginary64:
12788 exp.type = Type.tfloat64;
12789 break;
12791 case Timaginary80:
12792 exp.type = Type.tfloat80;
12793 break;
12795 default:
12796 assert(0);
12799 else
12800 exp.type = t2; // t2 is complex
12802 else if (t2.isimaginary())
12804 exp.type = t1; // t1 is complex
12807 else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12809 result = exp.incompatibleTypes();
12810 return;
12812 result = exp;
12815 override void visit(ModExp exp)
12817 if (exp.type)
12819 result = exp;
12820 return;
12823 if (Expression ex = binSemanticProp(exp, sc))
12825 result = ex;
12826 return;
12828 Expression e = exp.op_overload(sc);
12829 if (e)
12831 result = e;
12832 return;
12835 if (Expression ex = typeCombine(exp, sc))
12837 result = ex;
12838 return;
12841 Type tb = exp.type.toBasetype();
12842 if (tb.ty == Tarray || tb.ty == Tsarray)
12844 if (!isArrayOpValid(exp))
12846 result = arrayOpInvalidError(exp);
12847 return;
12849 result = exp;
12850 return;
12852 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12854 result = exp.incompatibleTypes();
12855 return;
12858 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
12859 return setError();
12861 if (exp.type.isfloating())
12863 exp.type = exp.e1.type;
12864 if (exp.e2.type.iscomplex())
12866 error(exp.loc, "cannot perform modulo complex arithmetic");
12867 return setError();
12870 result = exp;
12873 override void visit(PowExp exp)
12875 if (exp.type)
12877 result = exp;
12878 return;
12881 //printf("PowExp::semantic() %s\n", toChars());
12882 if (Expression ex = binSemanticProp(exp, sc))
12884 result = ex;
12885 return;
12887 Expression e = exp.op_overload(sc);
12888 if (e)
12890 result = e;
12891 return;
12894 if (Expression ex = typeCombine(exp, sc))
12896 result = ex;
12897 return;
12900 Type tb = exp.type.toBasetype();
12901 if (tb.ty == Tarray || tb.ty == Tsarray)
12903 if (!isArrayOpValid(exp))
12905 result = arrayOpInvalidError(exp);
12906 return;
12908 result = exp;
12909 return;
12912 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
12913 return setError();
12915 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12917 result = exp.incompatibleTypes();
12918 return;
12921 // First, attempt to fold the expression.
12922 e = exp.optimize(WANTvalue);
12923 if (e.op != EXP.pow)
12925 e = e.expressionSemantic(sc);
12926 result = e;
12927 return;
12930 Module mmath = Module.loadStdMath();
12931 if (!mmath)
12933 error(e.loc, "`%s` requires `std.math` for `^^` operators", e.toChars());
12934 return setError();
12936 e = new ScopeExp(exp.loc, mmath);
12938 if (exp.e2.op == EXP.float64 && exp.e2.toReal() == CTFloat.half)
12940 // Replace e1 ^^ 0.5 with .std.math.sqrt(e1)
12941 e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._sqrt), exp.e1);
12943 else
12945 // Replace e1 ^^ e2 with .std.math.pow(e1, e2)
12946 e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._pow), exp.e1, exp.e2);
12948 e = e.expressionSemantic(sc);
12949 result = e;
12950 return;
12953 override void visit(ShlExp exp)
12955 //printf("ShlExp::semantic(), type = %p\n", type);
12956 if (exp.type)
12958 result = exp;
12959 return;
12962 if (Expression ex = binSemanticProp(exp, sc))
12964 result = ex;
12965 return;
12967 Expression e = exp.op_overload(sc);
12968 if (e)
12970 result = e;
12971 return;
12974 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
12975 return setError();
12977 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
12979 result = exp.incompatibleTypes();
12980 return;
12982 exp.e1 = integralPromotions(exp.e1, sc);
12983 if (exp.e2.type.toBasetype().ty != Tvector)
12984 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
12986 exp.type = exp.e1.type;
12987 result = exp;
12990 override void visit(ShrExp exp)
12992 if (exp.type)
12994 result = exp;
12995 return;
12998 if (Expression ex = binSemanticProp(exp, sc))
13000 result = ex;
13001 return;
13003 Expression e = exp.op_overload(sc);
13004 if (e)
13006 result = e;
13007 return;
13010 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
13011 return setError();
13013 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
13015 result = exp.incompatibleTypes();
13016 return;
13018 exp.e1 = integralPromotions(exp.e1, sc);
13019 if (exp.e2.type.toBasetype().ty != Tvector)
13020 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
13022 exp.type = exp.e1.type;
13023 result = exp;
13026 override void visit(UshrExp exp)
13028 if (exp.type)
13030 result = exp;
13031 return;
13034 if (Expression ex = binSemanticProp(exp, sc))
13036 result = ex;
13037 return;
13039 Expression e = exp.op_overload(sc);
13040 if (e)
13042 result = e;
13043 return;
13046 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
13047 return setError();
13049 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
13051 result = exp.incompatibleTypes();
13052 return;
13054 exp.e1 = integralPromotions(exp.e1, sc);
13055 if (exp.e2.type.toBasetype().ty != Tvector)
13056 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
13058 exp.type = exp.e1.type;
13059 result = exp;
13062 override void visit(AndExp exp)
13064 if (exp.type)
13066 result = exp;
13067 return;
13070 if (Expression ex = binSemanticProp(exp, sc))
13072 result = ex;
13073 return;
13075 Expression e = exp.op_overload(sc);
13076 if (e)
13078 result = e;
13079 return;
13082 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
13084 exp.type = exp.e1.type;
13085 result = exp;
13086 return;
13089 if (Expression ex = typeCombine(exp, sc))
13091 result = ex;
13092 return;
13095 Type tb = exp.type.toBasetype();
13096 if (tb.ty == Tarray || tb.ty == Tsarray)
13098 if (!isArrayOpValid(exp))
13100 result = arrayOpInvalidError(exp);
13101 return;
13103 result = exp;
13104 return;
13106 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
13108 result = exp.incompatibleTypes();
13109 return;
13111 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
13112 return setError();
13114 result = exp;
13117 override void visit(OrExp exp)
13119 if (exp.type)
13121 result = exp;
13122 return;
13125 if (Expression ex = binSemanticProp(exp, sc))
13127 result = ex;
13128 return;
13130 Expression e = exp.op_overload(sc);
13131 if (e)
13133 result = e;
13134 return;
13137 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
13139 exp.type = exp.e1.type;
13140 result = exp;
13141 return;
13144 if (Expression ex = typeCombine(exp, sc))
13146 result = ex;
13147 return;
13150 Type tb = exp.type.toBasetype();
13151 if (tb.ty == Tarray || tb.ty == Tsarray)
13153 if (!isArrayOpValid(exp))
13155 result = arrayOpInvalidError(exp);
13156 return;
13158 result = exp;
13159 return;
13161 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
13163 result = exp.incompatibleTypes();
13164 return;
13166 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
13167 return setError();
13169 result = exp;
13172 override void visit(XorExp exp)
13174 if (exp.type)
13176 result = exp;
13177 return;
13180 if (Expression ex = binSemanticProp(exp, sc))
13182 result = ex;
13183 return;
13185 Expression e = exp.op_overload(sc);
13186 if (e)
13188 result = e;
13189 return;
13192 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
13194 exp.type = exp.e1.type;
13195 result = exp;
13196 return;
13199 if (Expression ex = typeCombine(exp, sc))
13201 result = ex;
13202 return;
13205 Type tb = exp.type.toBasetype();
13206 if (tb.ty == Tarray || tb.ty == Tsarray)
13208 if (!isArrayOpValid(exp))
13210 result = arrayOpInvalidError(exp);
13211 return;
13213 result = exp;
13214 return;
13216 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
13218 result = exp.incompatibleTypes();
13219 return;
13221 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
13222 return setError();
13224 result = exp;
13227 override void visit(LogicalExp exp)
13229 static if (LOGSEMANTIC)
13231 printf("LogicalExp::semantic() %s\n", exp.toChars());
13234 if (exp.type)
13236 result = exp;
13237 return;
13240 exp.setNoderefOperands();
13242 Expression e1x = exp.e1.expressionSemantic(sc);
13244 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
13245 if (e1x.op == EXP.type)
13246 e1x = resolveAliasThis(sc, e1x);
13248 e1x = resolveProperties(sc, e1x);
13249 e1x = e1x.toBoolean(sc);
13251 if (sc.flags & SCOPE.condition)
13253 /* If in static if, don't evaluate e2 if we don't have to.
13255 e1x = e1x.optimize(WANTvalue);
13256 if (e1x.toBool().hasValue(exp.op == EXP.orOr))
13258 if (sc.flags & SCOPE.Cfile)
13259 result = new IntegerExp(exp.op == EXP.orOr);
13260 else
13261 result = IntegerExp.createBool(exp.op == EXP.orOr);
13262 return;
13266 CtorFlow ctorflow = sc.ctorflow.clone();
13267 Expression e2x = exp.e2.expressionSemantic(sc);
13268 sc.merge(exp.loc, ctorflow);
13269 ctorflow.freeFieldinit();
13271 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
13272 if (e2x.op == EXP.type)
13273 e2x = resolveAliasThis(sc, e2x);
13275 e2x = resolveProperties(sc, e2x);
13277 auto f1 = checkNonAssignmentArrayOp(e1x);
13278 auto f2 = checkNonAssignmentArrayOp(e2x);
13279 if (f1 || f2)
13280 return setError();
13282 // Unless the right operand is 'void', the expression is converted to 'bool'.
13283 if (e2x.type.ty != Tvoid)
13284 e2x = e2x.toBoolean(sc);
13286 if (e2x.op == EXP.type || e2x.op == EXP.scope_)
13288 error(exp.loc, "`%s` is not an expression", exp.e2.toChars());
13289 return setError();
13291 if (e1x.op == EXP.error || e1x.type.ty == Tnoreturn)
13293 result = e1x;
13294 return;
13296 if (e2x.op == EXP.error)
13298 result = e2x;
13299 return;
13302 // The result type is 'bool', unless the right operand has type 'void'.
13303 if (e2x.type.ty == Tvoid)
13304 exp.type = Type.tvoid;
13305 else
13306 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
13308 exp.e1 = e1x;
13309 exp.e2 = e2x;
13310 result = exp;
13314 override void visit(CmpExp exp)
13316 static if (LOGSEMANTIC)
13318 printf("CmpExp::semantic('%s')\n", exp.toChars());
13320 if (exp.type)
13322 result = exp;
13323 return;
13326 exp.setNoderefOperands();
13328 if (Expression ex = binSemanticProp(exp, sc))
13330 result = ex;
13331 return;
13333 Type t1 = exp.e1.type.toBasetype();
13334 Type t2 = exp.e2.type.toBasetype();
13335 if (t1.ty == Tclass && exp.e2.op == EXP.null_ || t2.ty == Tclass && exp.e1.op == EXP.null_)
13337 error(exp.loc, "do not use `null` when comparing class types");
13338 return setError();
13342 EXP cmpop = exp.op;
13343 if (auto e = exp.op_overload(sc, &cmpop))
13345 if (!e.type.isscalar() && e.type.equals(exp.e1.type))
13347 error(exp.loc, "recursive `opCmp` expansion");
13348 return setError();
13350 if (e.op == EXP.call)
13353 if (t1.ty == Tclass && t2.ty == Tclass)
13355 // Lower to object.__cmp(e1, e2)
13356 Expression cl = new IdentifierExp(exp.loc, Id.empty);
13357 cl = new DotIdExp(exp.loc, cl, Id.object);
13358 cl = new DotIdExp(exp.loc, cl, Id.__cmp);
13359 cl = cl.expressionSemantic(sc);
13361 auto arguments = new Expressions();
13362 // Check if op_overload found a better match by calling e2.opCmp(e1)
13363 // If the operands were swapped, then the result must be reversed
13364 // e1.opCmp(e2) == -e2.opCmp(e1)
13365 // cmpop takes care of this
13366 if (exp.op == cmpop)
13368 arguments.push(exp.e1);
13369 arguments.push(exp.e2);
13371 else
13373 // Use better match found by op_overload
13374 arguments.push(exp.e2);
13375 arguments.push(exp.e1);
13378 cl = new CallExp(exp.loc, cl, arguments);
13379 cl = new CmpExp(cmpop, exp.loc, cl, new IntegerExp(0));
13380 result = cl.expressionSemantic(sc);
13381 return;
13384 e = new CmpExp(cmpop, exp.loc, e, IntegerExp.literal!0);
13385 e = e.expressionSemantic(sc);
13387 result = e;
13388 return;
13392 if (Expression ex = typeCombine(exp, sc))
13394 result = ex;
13395 return;
13398 auto f1 = checkNonAssignmentArrayOp(exp.e1);
13399 auto f2 = checkNonAssignmentArrayOp(exp.e2);
13400 if (f1 || f2)
13401 return setError();
13403 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
13405 // Special handling for array comparisons
13406 Expression arrayLowering = null;
13407 t1 = exp.e1.type.toBasetype();
13408 t2 = exp.e2.type.toBasetype();
13409 if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && (t2.ty == Tarray || t2.ty == Tsarray || t2.ty == Tpointer))
13411 Type t1next = t1.nextOf();
13412 Type t2next = t2.nextOf();
13413 if (t1next.implicitConvTo(t2next) < MATCH.constant && t2next.implicitConvTo(t1next) < MATCH.constant && (t1next.ty != Tvoid && t2next.ty != Tvoid))
13415 error(exp.loc, "array comparison type mismatch, `%s` vs `%s`", t1next.toChars(), t2next.toChars());
13416 return setError();
13419 if ((t1.ty == Tarray || t1.ty == Tsarray) &&
13420 (t2.ty == Tarray || t2.ty == Tsarray))
13422 if (!verifyHookExist(exp.loc, *sc, Id.__cmp, "comparing arrays"))
13423 return setError();
13425 // Lower to object.__cmp(e1, e2)
13426 Expression al = new IdentifierExp(exp.loc, Id.empty);
13427 al = new DotIdExp(exp.loc, al, Id.object);
13428 al = new DotIdExp(exp.loc, al, Id.__cmp);
13429 al = al.expressionSemantic(sc);
13431 auto arguments = new Expressions(2);
13432 (*arguments)[0] = exp.e1;
13433 (*arguments)[1] = exp.e2;
13435 al = new CallExp(exp.loc, al, arguments);
13436 al = new CmpExp(exp.op, exp.loc, al, IntegerExp.literal!0);
13438 arrayLowering = al;
13441 else if (t1.ty == Tstruct || t2.ty == Tstruct || (t1.ty == Tclass && t2.ty == Tclass))
13443 if (t2.ty == Tstruct)
13444 error(exp.loc, "need member function `opCmp()` for %s `%s` to compare", t2.toDsymbol(sc).kind(), t2.toChars());
13445 else
13446 error(exp.loc, "need member function `opCmp()` for %s `%s` to compare", t1.toDsymbol(sc).kind(), t1.toChars());
13447 return setError();
13449 else if (t1.iscomplex() || t2.iscomplex())
13451 error(exp.loc, "compare not defined for complex operands");
13452 return setError();
13454 else if (t1.ty == Taarray || t2.ty == Taarray)
13456 error(exp.loc, "`%s` is not defined for associative arrays", EXPtoString(exp.op).ptr);
13457 return setError();
13459 else if (!target.isVectorOpSupported(t1, exp.op, t2))
13461 result = exp.incompatibleTypes();
13462 return;
13464 else
13466 bool r1 = exp.e1.checkValue() || exp.e1.checkSharedAccess(sc);
13467 bool r2 = exp.e2.checkValue() || exp.e2.checkSharedAccess(sc);
13468 if (r1 || r2)
13469 return setError();
13472 //printf("CmpExp: %s, type = %s\n", e.toChars(), e.type.toChars());
13473 if (arrayLowering)
13475 arrayLowering = arrayLowering.expressionSemantic(sc);
13476 result = arrayLowering;
13477 return;
13480 if (auto tv = t1.isTypeVector())
13481 exp.type = tv.toBooleanVector();
13483 result = exp;
13484 return;
13487 override void visit(InExp exp)
13489 if (exp.type)
13491 result = exp;
13492 return;
13495 if (Expression ex = binSemanticProp(exp, sc))
13497 result = ex;
13498 return;
13500 Expression e = exp.op_overload(sc);
13501 if (e)
13503 result = e;
13504 return;
13507 Type t2b = exp.e2.type.toBasetype();
13508 switch (t2b.ty)
13510 case Taarray:
13512 TypeAArray ta = cast(TypeAArray)t2b;
13514 // Special handling for array keys
13515 if (!arrayTypeCompatibleWithoutCasting(exp.e1.type, ta.index))
13517 // Convert key to type of key
13518 exp.e1 = exp.e1.implicitCastTo(sc, ta.index);
13521 semanticTypeInfo(sc, ta.index);
13523 // Return type is pointer to value
13524 exp.type = ta.nextOf().pointerTo();
13525 break;
13528 case Terror:
13529 return setError();
13531 case Tarray, Tsarray:
13532 result = exp.incompatibleTypes();
13533 errorSupplemental(exp.loc, "`in` is only allowed on associative arrays");
13534 const(char)* slice = (t2b.ty == Tsarray) ? "[]" : "";
13535 errorSupplemental(exp.loc, "perhaps use `std.algorithm.find(%s, %s%s)` instead",
13536 exp.e1.toChars(), exp.e2.toChars(), slice);
13537 return;
13539 default:
13540 result = exp.incompatibleTypes();
13541 return;
13543 result = exp;
13546 override void visit(RemoveExp e)
13548 if (Expression ex = binSemantic(e, sc))
13550 result = ex;
13551 return;
13553 result = e;
13556 override void visit(EqualExp exp)
13558 //printf("EqualExp::semantic('%s')\n", exp.toChars());
13559 if (exp.type)
13561 result = exp;
13562 return;
13565 exp.setNoderefOperands();
13567 if (auto e = binSemanticProp(exp, sc))
13569 result = e;
13570 return;
13572 if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
13574 /* https://issues.dlang.org/show_bug.cgi?id=12520
13575 * empty tuples are represented as types so special cases are added
13576 * so that they can be compared for equality with tuples of values.
13578 static auto extractTypeTupAndExpTup(Expression e)
13580 static struct Result { bool ttEmpty; bool te; }
13581 auto tt = e.op == EXP.type ? e.isTypeExp().type.isTypeTuple() : null;
13582 return Result(tt && (!tt.arguments || !tt.arguments.length), e.isTupleExp() !is null);
13584 auto tups1 = extractTypeTupAndExpTup(exp.e1);
13585 auto tups2 = extractTypeTupAndExpTup(exp.e2);
13586 // AliasSeq!() == AliasSeq!(<at least a value>)
13587 if (tups1.ttEmpty && tups2.te)
13589 result = IntegerExp.createBool(exp.op != EXP.equal);
13590 return;
13592 // AliasSeq!(<at least a value>) == AliasSeq!()
13593 else if (tups1.te && tups2.ttEmpty)
13595 result = IntegerExp.createBool(exp.op != EXP.equal);
13596 return;
13598 // AliasSeq!() == AliasSeq!()
13599 else if (tups1.ttEmpty && tups2.ttEmpty)
13601 result = IntegerExp.createBool(exp.op == EXP.equal);
13602 return;
13604 // otherwise, two types are really not comparable
13605 result = exp.incompatibleTypes();
13606 return;
13610 auto t1 = exp.e1.type;
13611 auto t2 = exp.e2.type;
13612 if (t1.ty == Tenum && t2.ty == Tenum && !t1.equivalent(t2))
13613 error(exp.loc, "comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`",
13614 t1.toChars(), t2.toChars());
13617 /* Before checking for operator overloading, check to see if we're
13618 * comparing the addresses of two statics. If so, we can just see
13619 * if they are the same symbol.
13621 if (exp.e1.op == EXP.address && exp.e2.op == EXP.address)
13623 AddrExp ae1 = cast(AddrExp)exp.e1;
13624 AddrExp ae2 = cast(AddrExp)exp.e2;
13625 if (ae1.e1.op == EXP.variable && ae2.e1.op == EXP.variable)
13627 VarExp ve1 = cast(VarExp)ae1.e1;
13628 VarExp ve2 = cast(VarExp)ae2.e1;
13629 if (ve1.var == ve2.var)
13631 // They are the same, result is 'true' for ==, 'false' for !=
13632 result = IntegerExp.createBool(exp.op == EXP.equal);
13633 return;
13638 Type t1 = exp.e1.type.toBasetype();
13639 Type t2 = exp.e2.type.toBasetype();
13641 // Indicates whether the comparison of the 2 specified array types
13642 // requires an object.__equals() lowering.
13643 static bool needsDirectEq(Type t1, Type t2, Scope* sc)
13645 Type t1n = t1.nextOf().toBasetype();
13646 Type t2n = t2.nextOf().toBasetype();
13647 if ((t1n.ty.isSomeChar && t2n.ty.isSomeChar) ||
13648 (t1n.ty == Tvoid || t2n.ty == Tvoid))
13650 return false;
13652 if (t1n.constOf() != t2n.constOf())
13653 return true;
13655 Type t = t1n;
13656 while (t.toBasetype().nextOf())
13657 t = t.nextOf().toBasetype();
13658 if (auto ts = t.isTypeStruct())
13660 // semanticTypeInfo() makes sure hasIdentityEquals has been computed
13661 if (global.params.useTypeInfo && Type.dtypeinfo)
13662 semanticTypeInfo(sc, ts);
13664 return ts.sym.hasIdentityEquals; // has custom opEquals
13667 return false;
13670 if (auto e = exp.op_overload(sc))
13672 result = e;
13673 return;
13677 const isArrayComparison = (t1.ty == Tarray || t1.ty == Tsarray) &&
13678 (t2.ty == Tarray || t2.ty == Tsarray);
13679 const needsArrayLowering = isArrayComparison && needsDirectEq(t1, t2, sc);
13681 if (!needsArrayLowering)
13683 // https://issues.dlang.org/show_bug.cgi?id=23783
13684 if (exp.e1.checkSharedAccess(sc) || exp.e2.checkSharedAccess(sc))
13685 return setError();
13686 if (auto e = typeCombine(exp, sc))
13688 result = e;
13689 return;
13693 auto f1 = checkNonAssignmentArrayOp(exp.e1);
13694 auto f2 = checkNonAssignmentArrayOp(exp.e2);
13695 if (f1 || f2)
13696 return setError();
13698 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
13700 if (!isArrayComparison)
13702 if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
13704 // Cast both to complex
13705 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
13706 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80);
13710 // lower some array comparisons to object.__equals(e1, e2)
13711 if (needsArrayLowering || (t1.ty == Tarray && t2.ty == Tarray))
13713 //printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars());
13715 // https://issues.dlang.org/show_bug.cgi?id=22390
13716 // Equality comparison between array of noreturns simply lowers to length equality comparison
13717 if (t1.nextOf.isTypeNoreturn() && t2.nextOf.isTypeNoreturn())
13719 Expression exp_l1 = new DotIdExp(exp.e1.loc, exp.e1, Id.length);
13720 Expression exp_l2 = new DotIdExp(exp.e2.loc, exp.e2, Id.length);
13721 auto e = new EqualExp(EXP.equal, exp.loc, exp_l1, exp_l2);
13722 result = e.expressionSemantic(sc);
13723 return;
13726 if (!verifyHookExist(exp.loc, *sc, Id.__equals, "equal checks on arrays"))
13727 return setError();
13729 Expression __equals = new IdentifierExp(exp.loc, Id.empty);
13730 Identifier id = Identifier.idPool("__equals");
13731 __equals = new DotIdExp(exp.loc, __equals, Id.object);
13732 __equals = new DotIdExp(exp.loc, __equals, id);
13734 /* https://issues.dlang.org/show_bug.cgi?id=23674
13736 * Optimize before creating the call expression to the
13737 * druntime hook as the optimizer may output errors
13738 * that will get swallowed otherwise.
13740 exp.e1 = exp.e1.optimize(WANTvalue);
13741 exp.e2 = exp.e2.optimize(WANTvalue);
13743 auto arguments = new Expressions(2);
13744 (*arguments)[0] = exp.e1;
13745 (*arguments)[1] = exp.e2;
13747 __equals = new CallExp(exp.loc, __equals, arguments);
13748 if (exp.op == EXP.notEqual)
13750 __equals = new NotExp(exp.loc, __equals);
13752 __equals = __equals.trySemantic(sc); // for better error message
13753 if (!__equals)
13755 error(exp.loc, "incompatible types for array comparison: `%s` and `%s`",
13756 exp.e1.type.toChars(), exp.e2.type.toChars());
13757 __equals = ErrorExp.get();
13760 result = __equals;
13761 return;
13764 if (exp.e1.type.toBasetype().ty == Taarray)
13765 semanticTypeInfo(sc, exp.e1.type.toBasetype());
13768 if (!target.isVectorOpSupported(t1, exp.op, t2))
13770 result = exp.incompatibleTypes();
13771 return;
13774 if (auto tv = t1.isTypeVector())
13775 exp.type = tv.toBooleanVector();
13777 result = exp;
13780 override void visit(IdentityExp exp)
13782 if (exp.type)
13784 result = exp;
13785 return;
13788 exp.setNoderefOperands();
13790 if (auto e = binSemanticProp(exp, sc))
13792 result = e;
13793 return;
13796 if (auto e = typeCombine(exp, sc))
13798 result = e;
13799 return;
13802 auto f1 = checkNonAssignmentArrayOp(exp.e1);
13803 auto f2 = checkNonAssignmentArrayOp(exp.e2);
13804 if (f1 || f2)
13805 return setError();
13807 if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
13809 result = exp.incompatibleTypes();
13810 return;
13813 exp.type = Type.tbool;
13815 if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
13817 // Cast both to complex
13818 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
13819 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80);
13822 auto tb1 = exp.e1.type.toBasetype();
13823 auto tb2 = exp.e2.type.toBasetype();
13824 if (!target.isVectorOpSupported(tb1, exp.op, tb2))
13826 result = exp.incompatibleTypes();
13827 return;
13830 if (exp.e1.op == EXP.call)
13831 exp.e1 = (cast(CallExp)exp.e1).addDtorHook(sc);
13832 if (exp.e2.op == EXP.call)
13833 exp.e2 = (cast(CallExp)exp.e2).addDtorHook(sc);
13835 if (exp.e1.type.toBasetype().ty == Tsarray ||
13836 exp.e2.type.toBasetype().ty == Tsarray)
13837 deprecation(exp.loc, "identity comparison of static arrays "
13838 ~ "implicitly coerces them to slices, "
13839 ~ "which are compared by reference");
13841 result = exp;
13844 override void visit(CondExp exp)
13846 static if (LOGSEMANTIC)
13848 printf("CondExp::semantic('%s')\n", exp.toChars());
13850 if (exp.type)
13852 result = exp;
13853 return;
13856 if (auto die = exp.econd.isDotIdExp())
13857 die.noderef = true;
13859 Expression ec = exp.econd.expressionSemantic(sc);
13860 ec = resolveProperties(sc, ec);
13861 ec = ec.toBoolean(sc);
13863 CtorFlow ctorflow_root = sc.ctorflow.clone();
13864 Expression e1x = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
13865 e1x = resolveProperties(sc, e1x);
13867 CtorFlow ctorflow1 = sc.ctorflow;
13868 sc.ctorflow = ctorflow_root;
13869 Expression e2x = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
13870 e2x = resolveProperties(sc, e2x);
13872 sc.merge(exp.loc, ctorflow1);
13873 ctorflow1.freeFieldinit();
13875 if (ec.op == EXP.error)
13877 result = ec;
13878 return;
13880 if (ec.type == Type.terror)
13881 return setError();
13882 exp.econd = ec;
13884 if (e1x.op == EXP.error)
13886 result = e1x;
13887 return;
13889 if (e1x.type == Type.terror)
13890 return setError();
13891 exp.e1 = e1x;
13893 if (e2x.op == EXP.error)
13895 result = e2x;
13896 return;
13898 if (e2x.type == Type.terror)
13899 return setError();
13900 exp.e2 = e2x;
13902 auto f0 = checkNonAssignmentArrayOp(exp.econd);
13903 auto f1 = checkNonAssignmentArrayOp(exp.e1);
13904 auto f2 = checkNonAssignmentArrayOp(exp.e2);
13905 if (f0 || f1 || f2)
13906 return setError();
13908 Type t1 = exp.e1.type;
13909 Type t2 = exp.e2.type;
13911 // https://issues.dlang.org/show_bug.cgi?id=23767
13912 // `cast(void*) 0` should be treated as `null` so the ternary expression
13913 // gets the pointer type of the other branch
13914 if (sc.flags & SCOPE.Cfile)
13916 static void rewriteCNull(ref Expression e, ref Type t)
13918 if (!t.isTypePointer())
13919 return;
13920 if (auto ie = e.optimize(WANTvalue).isIntegerExp())
13922 if (ie.getInteger() == 0)
13924 e = new NullExp(e.loc, Type.tnull);
13925 t = Type.tnull;
13929 rewriteCNull(exp.e1, t1);
13930 rewriteCNull(exp.e2, t2);
13933 if (t1.ty == Tnoreturn)
13935 exp.type = t2;
13936 exp.e1 = specialNoreturnCast(exp.e1, exp.type);
13938 else if (t2.ty == Tnoreturn)
13940 exp.type = t1;
13941 exp.e2 = specialNoreturnCast(exp.e2, exp.type);
13943 // If either operand is void the result is void, we have to cast both
13944 // the expression to void so that we explicitly discard the expression
13945 // value if any
13946 // https://issues.dlang.org/show_bug.cgi?id=16598
13947 else if (t1.ty == Tvoid || t2.ty == Tvoid)
13949 exp.type = Type.tvoid;
13950 exp.e1 = exp.e1.castTo(sc, exp.type);
13951 exp.e2 = exp.e2.castTo(sc, exp.type);
13953 else if (t1 == t2)
13954 exp.type = t1;
13955 else
13957 if (Expression ex = typeCombine(exp, sc))
13959 result = ex;
13960 return;
13963 switch (exp.e1.type.toBasetype().ty)
13965 case Tcomplex32:
13966 case Tcomplex64:
13967 case Tcomplex80:
13968 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
13969 break;
13970 default:
13971 break;
13973 switch (exp.e2.type.toBasetype().ty)
13975 case Tcomplex32:
13976 case Tcomplex64:
13977 case Tcomplex80:
13978 exp.e1 = exp.e1.castTo(sc, exp.e2.type);
13979 break;
13980 default:
13981 break;
13983 if (exp.type.toBasetype().ty == Tarray)
13985 exp.e1 = exp.e1.castTo(sc, exp.type);
13986 exp.e2 = exp.e2.castTo(sc, exp.type);
13989 exp.type = exp.type.merge2();
13990 version (none)
13992 printf("res: %s\n", exp.type.toChars());
13993 printf("e1 : %s\n", exp.e1.type.toChars());
13994 printf("e2 : %s\n", exp.e2.type.toChars());
13997 /* https://issues.dlang.org/show_bug.cgi?id=14696
13998 * If either e1 or e2 contain temporaries which need dtor,
13999 * make them conditional.
14000 * Rewrite:
14001 * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2)
14002 * to:
14003 * (auto __cond = cond) ? (... __tmp1) : (... __tmp2)
14004 * and replace edtors of __tmp1 and __tmp2 with:
14005 * __tmp1.edtor --> __cond && __tmp1.dtor()
14006 * __tmp2.edtor --> __cond || __tmp2.dtor()
14008 exp.hookDtors(sc);
14010 result = exp;
14013 override void visit(GenericExp exp)
14015 static if (LOGSEMANTIC)
14017 printf("GenericExp::semantic('%s')\n", exp.toChars());
14019 // C11 6.5.1.1 Generic Selection
14021 auto ec = exp.cntlExp.expressionSemantic(sc).arrayFuncConv(sc);
14022 bool errors = ec.isErrorExp() !is null;
14023 auto tc = ec.type;
14025 auto types = (*exp.types)[];
14026 foreach (i, ref t; types)
14028 if (!t)
14029 continue; // `default:` case
14030 t = t.typeSemantic(ec.loc, sc);
14031 if (t.isTypeError())
14033 errors = true;
14034 continue;
14037 /* C11 6.5.1-2 duplicate check
14039 /* C11 distinguishes int, long, and long long. But D doesn't, so depending on the
14040 * C target, a long may have the same type as `int` in the D type system.
14041 * So, skip checks when this may be the case. Later pick the first match
14043 if (
14044 (t.ty == Tint32 || t.ty == Tuns32) && target.c.longsize == 4 ||
14045 (t.ty == Tint64 || t.ty == Tuns64) && target.c.longsize == 8 ||
14046 (t.ty == Tfloat64 || t.ty == Timaginary64 || t.ty == Tcomplex64) && target.c.long_doublesize == 8
14048 continue;
14050 foreach (t2; types[0 .. i])
14052 if (t2 && t2.equals(t))
14054 error(ec.loc, "generic association type `%s` can only appear once", t.toChars());
14055 errors = true;
14056 break;
14061 auto exps = (*exp.exps)[];
14062 foreach (ref e; exps)
14064 e = e.expressionSemantic(sc);
14065 if (e.isErrorExp())
14066 errors = true;
14069 if (errors)
14070 return setError();
14072 enum size_t None = ~0;
14073 size_t imatch = None;
14074 size_t idefault = None;
14075 foreach (const i, t; types)
14077 if (t)
14079 /* if tc is compatible with t, it's a match
14080 * C11 6.2.7 defines a compatible type as being the same type, including qualifiers
14082 if (tc.equals(t))
14084 assert(imatch == None);
14085 imatch = i;
14086 break; // pick first match
14089 else
14090 idefault = i; // multiple defaults are not allowed, and are caught by cparse
14093 if (imatch == None)
14094 imatch = idefault;
14095 if (imatch == None)
14097 error(exp.loc, "no compatible generic association type for controlling expression type `%s`", tc.toChars());
14098 return setError();
14101 result = exps[imatch];
14104 override void visit(FileInitExp e)
14106 //printf("FileInitExp::semantic()\n");
14107 e.type = Type.tstring;
14108 result = e.resolveLoc(e.loc, sc);
14111 override void visit(LineInitExp e)
14113 e.type = Type.tint32;
14114 result = e.resolveLoc(e.loc, sc);
14117 override void visit(ModuleInitExp e)
14119 //printf("ModuleInitExp::semantic()\n");
14120 e.type = Type.tstring;
14121 result = e.resolveLoc(e.loc, sc);
14124 override void visit(FuncInitExp e)
14126 //printf("FuncInitExp::semantic()\n");
14127 e.type = Type.tstring;
14128 result = e.resolveLoc(e.loc, sc);
14131 override void visit(PrettyFuncInitExp e)
14133 //printf("PrettyFuncInitExp::semantic()\n");
14134 e.type = Type.tstring;
14135 result = e.resolveLoc(e.loc, sc);
14139 /**********************************
14140 * Try to run semantic routines.
14141 * If they fail, return NULL.
14143 Expression trySemantic(Expression exp, Scope* sc)
14145 //printf("+trySemantic(%s)\n", exp.toChars());
14146 uint errors = global.startGagging();
14147 Expression e = expressionSemantic(exp, sc);
14148 if (global.endGagging(errors))
14150 e = null;
14152 //printf("-trySemantic(%s)\n", exp.toChars());
14153 return e;
14156 /**************************
14157 * Helper function for easy error propagation.
14158 * If error occurs, returns ErrorExp. Otherwise returns NULL.
14160 Expression unaSemantic(UnaExp e, Scope* sc)
14162 static if (LOGSEMANTIC)
14164 printf("UnaExp::semantic('%s')\n", e.toChars());
14166 Expression e1x = e.e1.expressionSemantic(sc);
14167 if (e1x.op == EXP.error)
14168 return e1x;
14169 e.e1 = e1x;
14170 return null;
14173 /**************************
14174 * Helper function for easy error propagation.
14175 * If error occurs, returns ErrorExp. Otherwise returns NULL.
14177 Expression binSemantic(BinExp e, Scope* sc)
14179 static if (LOGSEMANTIC)
14181 printf("BinExp::semantic('%s')\n", e.toChars());
14183 Expression e1x = e.e1.expressionSemantic(sc);
14184 Expression e2x = e.e2.expressionSemantic(sc);
14186 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
14187 if (e1x.op == EXP.type)
14188 e1x = resolveAliasThis(sc, e1x);
14189 if (e2x.op == EXP.type)
14190 e2x = resolveAliasThis(sc, e2x);
14192 if (e1x.op == EXP.error)
14193 return e1x;
14194 if (e2x.op == EXP.error)
14195 return e2x;
14196 e.e1 = e1x;
14197 e.e2 = e2x;
14198 return null;
14201 Expression binSemanticProp(BinExp e, Scope* sc)
14203 if (Expression ex = binSemantic(e, sc))
14204 return ex;
14205 Expression e1x = resolveProperties(sc, e.e1);
14206 Expression e2x = resolveProperties(sc, e.e2);
14207 if (e1x.op == EXP.error)
14208 return e1x;
14209 if (e2x.op == EXP.error)
14210 return e2x;
14211 e.e1 = e1x;
14212 e.e2 = e2x;
14213 return null;
14216 // entrypoint for semantic ExpressionSemanticVisitor
14217 Expression expressionSemantic(Expression e, Scope* sc)
14219 scope v = new ExpressionSemanticVisitor(sc);
14220 e.accept(v);
14221 return v.result;
14224 private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc)
14226 //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars());
14227 if (Expression ex = unaSemantic(exp, sc))
14228 return ex;
14230 if (!(sc.flags & SCOPE.Cfile) && exp.ident == Id._mangleof)
14232 // symbol.mangleof
14234 // return mangleof as an Expression
14235 static Expression dotMangleof(const ref Loc loc, Scope* sc, Dsymbol ds, bool hasOverloads)
14237 Expression e;
14239 assert(ds);
14240 if (auto f = ds.isFuncDeclaration())
14242 if (f.checkForwardRef(loc))
14243 return ErrorExp.get();
14245 if (f.purityInprocess || f.safetyInprocess || f.nothrowInprocess || f.nogcInprocess)
14247 error(loc, "%s `%s` cannot retrieve its `.mangleof` while inferring attributes", f.kind, f.toPrettyChars);
14248 return ErrorExp.get();
14251 if (!hasOverloads)
14252 e = StringExp.create(loc, mangleExact(f));
14255 if (!e)
14257 OutBuffer buf;
14258 mangleToBuffer(ds, buf);
14259 e = new StringExp(loc, buf.extractSlice());
14262 return e.expressionSemantic(sc);
14265 Dsymbol ds;
14266 switch (exp.e1.op)
14268 case EXP.scope_: return dotMangleof(exp.loc, sc, exp.e1.isScopeExp().sds, false);
14269 case EXP.overloadSet: return dotMangleof(exp.loc, sc, exp.e1.isOverExp().vars, false);
14270 case EXP.variable:
14272 VarExp ve = exp.e1.isVarExp();
14273 return dotMangleof(exp.loc, sc, ve.var, ve.hasOverloads);
14275 case EXP.dotVariable:
14277 DotVarExp dve = exp.e1.isDotVarExp();
14278 return dotMangleof(exp.loc, sc, dve.var, dve.hasOverloads);
14280 case EXP.template_:
14282 TemplateExp te = exp.e1.isTemplateExp();
14283 return dotMangleof(exp.loc, sc, ds = te.fd ? te.fd.isDsymbol() : te.td, false);
14286 default:
14287 break;
14291 if (exp.e1.isVarExp() && exp.e1.type.toBasetype().isTypeSArray() && exp.ident == Id.length)
14293 // bypass checkPurity
14294 return exp.e1.type.dotExp(sc, exp.e1, exp.ident, cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref));
14297 if (!exp.e1.isDotExp())
14299 exp.e1 = resolvePropertiesX(sc, exp.e1);
14302 if (auto te = exp.e1.isTupleExp())
14304 if (exp.ident == Id.offsetof)
14306 /* 'distribute' the .offsetof to each of the tuple elements.
14308 auto exps = new Expressions(te.exps.length);
14309 foreach (i, e; (*te.exps)[])
14311 (*exps)[i] = new DotIdExp(e.loc, e, Id.offsetof);
14313 // Don't evaluate te.e0 in runtime
14314 Expression e = new TupleExp(exp.loc, null, exps);
14315 e = e.expressionSemantic(sc);
14316 return e;
14318 if (exp.ident == Id.length)
14320 // Don't evaluate te.e0 in runtime
14321 return new IntegerExp(exp.loc, te.exps.length, Type.tsize_t);
14325 // https://issues.dlang.org/show_bug.cgi?id=14416
14326 // Template has no built-in properties except for 'stringof'.
14327 if ((exp.e1.isDotTemplateExp() || exp.e1.isTemplateExp()) && exp.ident != Id.stringof)
14329 error(exp.loc, "template `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
14330 return ErrorExp.get();
14332 if (!exp.e1.type)
14334 error(exp.loc, "expression `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
14335 return ErrorExp.get();
14338 return exp;
14341 private bool checkDisabled(Dsymbol s, ref Loc loc, Scope* sc)
14343 if (auto d = s.isDeclaration())
14344 return d.checkDisabled(loc, sc);
14346 return false;
14349 /******************************
14350 * Resolve properties, i.e. `e1.ident`, without seeing UFCS.
14351 * Params:
14352 * exp = expression to resolve
14353 * sc = context
14354 * gag = do not emit error messages, just return `null`
14355 * Returns:
14356 * resolved expression, null if error
14358 Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
14360 //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars());
14362 //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
14364 const cfile = (sc.flags & SCOPE.Cfile) != 0;
14366 /* Special case: rewrite this.id and super.id
14367 * to be classtype.id and baseclasstype.id
14368 * if we have no this pointer.
14370 if ((exp.e1.isThisExp() || exp.e1.isSuperExp()) && !hasThis(sc))
14372 if (AggregateDeclaration ad = sc.getStructClassScope())
14374 if (exp.e1.isThisExp())
14376 exp.e1 = new TypeExp(exp.e1.loc, ad.type);
14378 else
14380 if (auto cd = ad.isClassDeclaration())
14382 if (cd.baseClass)
14383 exp.e1 = new TypeExp(exp.e1.loc, cd.baseClass.type);
14390 Expression e = dotIdSemanticPropX(exp, sc);
14391 if (e != exp)
14392 return e;
14395 Expression eleft;
14396 Expression eright;
14397 if (auto de = exp.e1.isDotExp())
14399 eleft = de.e1;
14400 eright = de.e2;
14402 else
14404 eleft = null;
14405 eright = exp.e1;
14408 Type t1b = exp.e1.type.toBasetype();
14410 if (auto ie = eright.isScopeExp()) // also used for template alias's
14412 SearchOptFlags flags = SearchOpt.localsOnly;
14413 /* Disable access to another module's private imports.
14414 * The check for 'is sds our current module' is because
14415 * the current module should have access to its own imports.
14417 if (ie.sds.isModule() && ie.sds != sc._module)
14418 flags |= SearchOpt.ignorePrivateImports;
14419 if (sc.flags & SCOPE.ignoresymbolvisibility)
14420 flags |= SearchOpt.ignoreVisibility;
14421 Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags);
14422 /* Check for visibility before resolving aliases because public
14423 * aliases to private symbols are public.
14425 if (s && !(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc._module, s))
14427 s = null;
14429 if (s)
14431 auto p = s.isPackage();
14432 if (p && checkAccess(sc, p))
14434 s = null;
14437 if (s)
14439 // if 's' is a tuple variable, the tuple is returned.
14440 s = s.toAlias();
14442 s.checkDeprecated(exp.loc, sc);
14443 s.checkDisabled(exp.loc, sc);
14445 if (auto em = s.isEnumMember())
14447 return em.getVarExp(exp.loc, sc);
14449 if (auto v = s.isVarDeclaration())
14451 //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars());
14452 if (!v.type ||
14453 !v.type.deco && v.inuse)
14455 if (v.inuse)
14456 error(exp.loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
14457 else
14458 error(exp.loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
14459 return ErrorExp.get();
14461 if (v.type.isTypeError())
14462 return ErrorExp.get();
14464 if ((v.storage_class & STC.manifest) && v._init && !exp.wantsym)
14466 /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2().
14467 * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably
14468 * be reverted. `wantsym` is the hack to work around the problem.
14470 if (v.inuse)
14472 error(exp.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
14473 return ErrorExp.get();
14475 auto e = v.expandInitializer(exp.loc);
14476 v.inuse++;
14477 e = e.expressionSemantic(sc);
14478 v.inuse--;
14479 return e;
14482 Expression e;
14483 if (v.needThis())
14485 if (!eleft)
14486 eleft = new ThisExp(exp.loc);
14487 e = new DotVarExp(exp.loc, eleft, v);
14488 e = e.expressionSemantic(sc);
14490 else
14492 e = new VarExp(exp.loc, v);
14493 if (eleft)
14495 e = new CommaExp(exp.loc, eleft, e);
14496 e.type = v.type;
14499 e = e.deref();
14500 return e.expressionSemantic(sc);
14503 if (auto f = s.isFuncDeclaration())
14505 //printf("it's a function\n");
14506 if (!functionSemantic(f))
14507 return ErrorExp.get();
14508 Expression e;
14509 if (f.needThis())
14511 if (!eleft)
14512 eleft = new ThisExp(exp.loc);
14513 e = new DotVarExp(exp.loc, eleft, f, true);
14514 e = e.expressionSemantic(sc);
14516 else
14518 e = new VarExp(exp.loc, f, true);
14519 if (eleft)
14521 e = new CommaExp(exp.loc, eleft, e);
14522 e.type = f.type;
14525 return e;
14527 if (auto td = s.isTemplateDeclaration())
14529 Expression e;
14530 if (eleft)
14531 e = new DotTemplateExp(exp.loc, eleft, td);
14532 else
14533 e = new TemplateExp(exp.loc, td);
14534 e = e.expressionSemantic(sc);
14535 return e;
14537 if (OverDeclaration od = s.isOverDeclaration())
14539 Expression e = new VarExp(exp.loc, od, true);
14540 if (eleft)
14542 e = new CommaExp(exp.loc, eleft, e);
14543 e.type = Type.tvoid; // ambiguous type?
14545 return e.expressionSemantic(sc);
14547 if (auto o = s.isOverloadSet())
14549 //printf("'%s' is an overload set\n", o.toChars());
14550 return new OverExp(exp.loc, o);
14553 if (auto t = s.getType())
14555 return (new TypeExp(exp.loc, t)).expressionSemantic(sc);
14558 if (auto tup = s.isTupleDeclaration())
14560 if (eleft)
14562 Expression e = new DotVarExp(exp.loc, eleft, tup);
14563 e = e.expressionSemantic(sc);
14564 return e;
14566 Expression e = new TupleExp(exp.loc, tup);
14567 e = e.expressionSemantic(sc);
14568 return e;
14571 if (auto sds = s.isScopeDsymbol())
14573 //printf("it's a ScopeDsymbol %s\n", ident.toChars());
14574 Expression e = new ScopeExp(exp.loc, sds);
14575 e = e.expressionSemantic(sc);
14576 if (eleft)
14577 e = new DotExp(exp.loc, eleft, e);
14578 return e;
14581 if (auto imp = s.isImport())
14583 Expression se = new ScopeExp(exp.loc, imp.pkg);
14584 return se.expressionSemantic(sc);
14587 if (auto attr = s.isAttribDeclaration())
14589 if (auto sm = ie.sds.search(exp.loc, exp.ident, flags))
14591 auto es = new DsymbolExp(exp.loc, sm);
14592 return es;
14596 // BUG: handle other cases like in IdentifierExp::semantic()
14597 debug
14599 printf("s = %p '%s', kind = '%s'\n", s, s.toChars(), s.kind());
14601 assert(0);
14603 else if (exp.ident == Id.stringof)
14605 Expression e = new StringExp(exp.loc, ie.toString());
14606 e = e.expressionSemantic(sc);
14607 return e;
14609 if (ie.sds.isPackage() || ie.sds.isImport() || ie.sds.isModule())
14611 gag = false;
14613 if (gag)
14614 return null;
14615 s = ie.sds.search_correct(exp.ident);
14616 if (s && symbolIsVisible(sc, s))
14618 if (s.isPackage())
14619 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());
14620 else
14621 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());
14623 else
14624 error(exp.loc, "undefined identifier `%s` in %s `%s`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars());
14625 return ErrorExp.get();
14627 else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum &&
14629 exp.ident == Id.__sizeof ||
14630 exp.ident == Id.__xalignof ||
14631 !cfile &&
14632 (exp.ident == Id._mangleof ||
14633 exp.ident == Id.offsetof ||
14634 exp.ident == Id._init ||
14635 exp.ident == Id.stringof)
14638 Type t1bn = t1b.nextOf();
14639 if (gag)
14641 if (AggregateDeclaration ad = isAggregate(t1bn))
14643 if (!ad.members) // https://issues.dlang.org/show_bug.cgi?id=11312
14644 return null;
14648 /* Rewrite:
14649 * p.ident
14650 * as:
14651 * (*p).ident
14653 if (gag && t1bn.ty == Tvoid)
14654 return null;
14655 Expression e = new PtrExp(exp.loc, exp.e1);
14656 e = e.expressionSemantic(sc);
14657 const newFlag = cast(DotExpFlag) (gag * DotExpFlag.gag | exp.noderef * DotExpFlag.noDeref);
14658 return e.type.dotExp(sc, e, exp.ident, newFlag);
14660 else if (exp.ident == Id.__xalignof &&
14661 exp.e1.isVarExp() &&
14662 exp.e1.isVarExp().var.isVarDeclaration() &&
14663 !exp.e1.isVarExp().var.isVarDeclaration().alignment.isUnknown())
14665 // For `x.alignof` get the alignment of the variable, not the alignment of its type
14666 const explicitAlignment = exp.e1.isVarExp().var.isVarDeclaration().alignment;
14667 const naturalAlignment = exp.e1.type.alignsize();
14668 const actualAlignment = explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get();
14669 Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
14670 return e;
14672 else if ((exp.ident == Id.max || exp.ident == Id.min) &&
14673 exp.e1.isVarExp() &&
14674 exp.e1.isVarExp().var.isBitFieldDeclaration())
14676 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
14677 auto bf = exp.e1.isVarExp().var.isBitFieldDeclaration();
14678 return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type);
14680 else if ((exp.ident == Id.max || exp.ident == Id.min) &&
14681 exp.e1.isDotVarExp() &&
14682 exp.e1.isDotVarExp().var.isBitFieldDeclaration())
14684 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
14685 auto bf = exp.e1.isDotVarExp().var.isBitFieldDeclaration();
14686 return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type);
14688 else
14690 if (exp.e1.isTypeExp() || exp.e1.isTemplateExp())
14691 gag = false;
14693 const flag = cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref | gag * DotExpFlag.gag);
14695 Expression e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag);
14696 if (e)
14698 e = e.expressionSemantic(sc);
14700 return e;
14705 * Resolve `e1.ident!tiargs` without seeing UFCS.
14706 * Params:
14707 * exp = the `DotTemplateInstanceExp` to resolve
14708 * sc = the semantic scope
14709 * gag = stop "not a property" error and return `null`.
14710 * Returns:
14711 * `null` if error or not found, or the resolved expression.
14713 Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, bool gag)
14715 static if (LOGSEMANTIC)
14717 printf("DotTemplateInstanceExpY::semantic('%s')\n", exp.toChars());
14720 static Expression errorExp()
14722 return ErrorExp.get();
14725 Expression e1 = exp.e1;
14727 if (exp.ti.tempdecl && exp.ti.tempdecl.parent && exp.ti.tempdecl.parent.isTemplateMixin())
14729 // if 'ti.tempdecl' happens to be found in a mixin template don't lose that info
14730 // and do the symbol search in that context (Issue: 19476)
14731 auto tm = cast(TemplateMixin)exp.ti.tempdecl.parent;
14732 e1 = new DotExp(exp.e1.loc, exp.e1, new ScopeExp(tm.loc, tm));
14735 auto die = new DotIdExp(exp.loc, e1, exp.ti.name);
14737 Expression e = die.dotIdSemanticPropX(sc);
14738 if (e == die)
14740 exp.e1 = die.e1; // take back
14741 Type t1b = exp.e1.type.toBasetype();
14742 if (t1b.ty == Tarray || t1b.ty == Tsarray || t1b.ty == Taarray || t1b.ty == Tnull || (t1b.isTypeBasic() && t1b.ty != Tvoid))
14744 /* No built-in type has templatized properties, so do shortcut.
14745 * It is necessary in: 1024.max!"a < b"
14747 if (gag)
14748 return null;
14750 e = die.dotIdSemanticProp(sc, gag);
14751 if (gag)
14753 if (!e ||
14754 isDotOpDispatch(e))
14756 /* opDispatch!tiargs would be a function template that needs IFTI,
14757 * so it's not a template
14759 return null;
14763 assert(e);
14765 if (e.op == EXP.error)
14766 return e;
14767 if (DotVarExp dve = e.isDotVarExp())
14769 if (FuncDeclaration fd = dve.var.isFuncDeclaration())
14771 if (TemplateDeclaration td = fd.findTemplateDeclRoot())
14773 e = new DotTemplateExp(dve.loc, dve.e1, td);
14774 e = e.expressionSemantic(sc);
14777 else if (OverDeclaration od = dve.var.isOverDeclaration())
14779 exp.e1 = dve.e1; // pull semantic() result
14781 if (!exp.findTempDecl(sc))
14782 goto Lerr;
14783 if (exp.ti.needsTypeInference(sc))
14784 return exp;
14785 exp.ti.dsymbolSemantic(sc);
14786 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
14787 return errorExp();
14789 if (Declaration v = exp.ti.toAlias().isDeclaration())
14791 if (v.type && !v.type.deco)
14792 v.type = v.type.typeSemantic(v.loc, sc);
14793 return new DotVarExp(exp.loc, exp.e1, v)
14794 .expressionSemantic(sc);
14796 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
14797 .expressionSemantic(sc);
14800 else if (e.op == EXP.variable)
14802 VarExp ve = cast(VarExp)e;
14803 if (FuncDeclaration fd = ve.var.isFuncDeclaration())
14805 if (TemplateDeclaration td = fd.findTemplateDeclRoot())
14807 e = new TemplateExp(ve.loc, td)
14808 .expressionSemantic(sc);
14811 else if (OverDeclaration od = ve.var.isOverDeclaration())
14813 exp.ti.tempdecl = od;
14814 return new ScopeExp(exp.loc, exp.ti)
14815 .expressionSemantic(sc);
14819 if (DotTemplateExp dte = e.isDotTemplateExp())
14821 exp.e1 = dte.e1; // pull semantic() result
14823 exp.ti.tempdecl = dte.td;
14824 if (!exp.ti.semanticTiargs(sc))
14825 return errorExp();
14826 if (exp.ti.needsTypeInference(sc))
14827 return exp;
14828 exp.ti.dsymbolSemantic(sc);
14829 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
14830 return errorExp();
14832 if (Declaration v = exp.ti.toAlias().isDeclaration())
14834 return new DotVarExp(exp.loc, exp.e1, v)
14835 .expressionSemantic(sc);
14837 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
14838 .expressionSemantic(sc);
14840 else if (e.op == EXP.template_)
14842 exp.ti.tempdecl = (cast(TemplateExp)e).td;
14843 return new ScopeExp(exp.loc, exp.ti)
14844 .expressionSemantic(sc);
14846 else if (DotExp de = e.isDotExp())
14848 if (de.e2.op == EXP.overloadSet)
14850 if (!exp.findTempDecl(sc) || !exp.ti.semanticTiargs(sc))
14852 return errorExp();
14854 if (exp.ti.needsTypeInference(sc))
14855 return exp;
14856 exp.ti.dsymbolSemantic(sc);
14857 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
14858 return errorExp();
14860 if (Declaration v = exp.ti.toAlias().isDeclaration())
14862 if (v.type && !v.type.deco)
14863 v.type = v.type.typeSemantic(v.loc, sc);
14864 return new DotVarExp(exp.loc, exp.e1, v)
14865 .expressionSemantic(sc);
14867 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
14868 .expressionSemantic(sc);
14871 else if (OverExp oe = e.isOverExp())
14873 exp.ti.tempdecl = oe.vars;
14874 return new ScopeExp(exp.loc, exp.ti)
14875 .expressionSemantic(sc);
14878 Lerr:
14879 error(exp.loc, "`%s` isn't a template", e.toChars());
14880 return errorExp();
14883 MATCH matchType(FuncExp funcExp, Type to, Scope* sc, FuncExp* presult, ErrorSink eSink)
14885 auto loc = funcExp.loc;
14886 auto tok = funcExp.tok;
14887 auto td = funcExp.td;
14888 auto fd = funcExp.fd;
14889 auto type = funcExp.type;
14891 MATCH cannotInfer()
14893 eSink.error(loc, "cannot infer parameter types from `%s`", to.toChars());
14894 return MATCH.nomatch;
14897 //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars());
14898 if (presult)
14899 *presult = null;
14901 TypeFunction tof = null;
14902 if (to.ty == Tdelegate)
14904 if (tok == TOK.function_)
14906 eSink.error(loc, "cannot match function literal to delegate type `%s`", to.toChars());
14907 return MATCH.nomatch;
14909 tof = cast(TypeFunction)to.nextOf();
14911 else if (to.ty == Tpointer && (tof = to.nextOf().isTypeFunction()) !is null)
14913 if (tok == TOK.delegate_)
14915 eSink.error(loc, "cannot match delegate literal to function pointer type `%s`", to.toChars());
14916 return MATCH.nomatch;
14920 if (td)
14922 if (!tof)
14924 return cannotInfer();
14927 // Parameter types inference from 'tof'
14928 assert(td._scope);
14929 TypeFunction tf = fd.type.isTypeFunction();
14930 //printf("\ttof = %s\n", tof.toChars());
14931 //printf("\ttf = %s\n", tf.toChars());
14932 const dim = tf.parameterList.length;
14934 if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs)
14935 return cannotInfer();
14937 auto tiargs = new Objects();
14938 tiargs.reserve(td.parameters.length);
14940 foreach (tp; *td.parameters)
14942 size_t u = 0;
14943 foreach (i, p; tf.parameterList)
14945 if (auto ti = p.type.isTypeIdentifier())
14946 if (ti && ti.ident == tp.ident)
14947 break;
14949 ++u;
14951 assert(u < dim);
14952 Parameter pto = tof.parameterList[u];
14953 Type t = pto.type;
14954 if (t.ty == Terror)
14955 return cannotInfer();
14956 tf.parameterList[u].storageClass = tof.parameterList[u].storageClass;
14957 tiargs.push(t);
14960 // Set target of return type inference
14961 if (!tf.next && tof.next)
14962 fd.treq = to;
14964 auto ti = new TemplateInstance(loc, td, tiargs);
14965 Expression ex = (new ScopeExp(loc, ti)).expressionSemantic(td._scope);
14967 // Reset inference target for the later re-semantic
14968 fd.treq = null;
14970 if (ex.op == EXP.error)
14971 return MATCH.nomatch;
14972 if (auto ef = ex.isFuncExp())
14973 return ef.matchType(to, sc, presult, eSink);
14974 else
14975 return cannotInfer();
14978 if (!tof || !tof.next)
14979 return MATCH.nomatch;
14981 assert(type && type != Type.tvoid);
14982 if (fd.type.ty == Terror)
14983 return MATCH.nomatch;
14984 auto tfx = fd.type.isTypeFunction();
14985 bool convertMatch = (type.ty != to.ty);
14987 if (fd.inferRetType && tfx.next.implicitConvTo(tof.next) == MATCH.convert)
14989 /* If return type is inferred and covariant return,
14990 * tweak return statements to required return type.
14992 * interface I {}
14993 * class C : Object, I{}
14995 * I delegate() dg = delegate() { return new class C(); }
14997 convertMatch = true;
14999 auto tfy = new TypeFunction(tfx.parameterList, tof.next,
15000 tfx.linkage, STC.undefined_);
15001 tfy.mod = tfx.mod;
15002 tfy.trust = tfx.trust;
15003 tfy.isnothrow = tfx.isnothrow;
15004 tfy.isnogc = tfx.isnogc;
15005 tfy.purity = tfx.purity;
15006 tfy.isproperty = tfx.isproperty;
15007 tfy.isref = tfx.isref;
15008 tfy.isInOutParam = tfx.isInOutParam;
15009 tfy.isInOutQual = tfx.isInOutQual;
15010 tfy.deco = tfy.merge().deco;
15012 tfx = tfy;
15014 Type tx;
15015 if (tok == TOK.delegate_ ||
15016 tok == TOK.reserved && (type.ty == Tdelegate || type.ty == Tpointer && to.ty == Tdelegate))
15018 // Allow conversion from implicit function pointer to delegate
15019 tx = new TypeDelegate(tfx);
15020 tx.deco = tx.merge().deco;
15022 else
15024 assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer || fd.errors);
15025 tx = tfx.pointerTo();
15027 //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars());
15029 MATCH m = tx.implicitConvTo(to);
15030 if (m > MATCH.nomatch)
15032 // MATCH.exact: exact type match
15033 // MATCH.constant: covairiant type match (eg. attributes difference)
15034 // MATCH.convert: context conversion
15035 m = convertMatch ? MATCH.convert : tx.equals(to) ? MATCH.exact : MATCH.constant;
15037 if (presult)
15039 (*presult) = cast(FuncExp)funcExp.copy();
15040 (*presult).type = to;
15042 // https://issues.dlang.org/show_bug.cgi?id=12508
15043 // Tweak function body for covariant returns.
15044 (*presult).fd.modifyReturns(sc, tof.next);
15047 else if (!cast(ErrorSinkNull)eSink)
15049 auto ts = toAutoQualChars(tx, to);
15050 eSink.error(loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
15051 funcExp.toChars(), ts[0], ts[1]);
15053 return m;
15056 private bool checkSharedAccessBin(BinExp binExp, Scope* sc)
15058 const r1 = binExp.e1.checkSharedAccess(sc);
15059 const r2 = binExp.e2.checkSharedAccess(sc);
15060 return (r1 || r2);
15063 /***************************************
15064 * If expression is shared, check that we can access it.
15065 * Give error message if not.
15067 * Params:
15068 * e = expression to check
15069 * sc = context
15070 * returnRef = Whether this expression is for a `return` statement
15071 * off a `ref` function, in which case a single level
15072 * of dereference is allowed (e.g. `shared(int)*`).
15073 * Returns:
15074 * true on error
15076 bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
15078 if (global.params.noSharedAccess != FeatureState.enabled ||
15079 !sc ||
15080 sc.intypeof ||
15081 sc.flags & SCOPE.ctfe)
15083 return false;
15086 //printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef);
15088 bool check(Expression e, bool allowRef)
15090 bool sharedError(Expression e)
15092 // https://dlang.org/phobos/core_atomic.html
15093 error(e.loc, "direct access to shared `%s` is not allowed, see `core.atomic`", e.toChars());
15094 return true;
15097 // Error by default
15098 bool visit(Expression e)
15100 // https://issues.dlang.org/show_bug.cgi?id=23639
15101 // Should be able to cast(shared)
15102 if (!e.isCastExp() && e.type.isShared())
15103 return sharedError(e);
15104 return false;
15107 bool visitNew(NewExp e)
15109 if (e.thisexp)
15110 check(e.thisexp, false);
15111 return false;
15114 bool visitVar(VarExp e)
15116 // https://issues.dlang.org/show_bug.cgi?id=20908
15117 // direct access to init symbols is ok as they
15118 // cannot be modified.
15119 if (e.var.isSymbolDeclaration())
15120 return false;
15122 // https://issues.dlang.org/show_bug.cgi?id=22626
15123 // Synchronized functions don't need to use core.atomic
15124 // when accessing `this`.
15125 if (sc.func && sc.func.isSynchronized())
15127 if (e.var.isThisDeclaration())
15128 return false;
15129 else
15130 return sharedError(e);
15132 else if (!allowRef && e.var.type.isShared())
15133 return sharedError(e);
15135 return false;
15138 bool visitAddr(AddrExp e)
15140 return check(e.e1, true);
15143 bool visitPtr(PtrExp e)
15145 if (!allowRef && e.type.isShared())
15146 return sharedError(e);
15148 if (e.e1.type.isShared())
15149 return sharedError(e);
15151 return check(e.e1, false);
15154 bool visitDotVar(DotVarExp e)
15156 //printf("dotvarexp = %s\n", e.toChars());
15157 if (e.type.isShared())
15159 if (e.e1.isThisExp())
15161 // https://issues.dlang.org/show_bug.cgi?id=22626
15162 if (sc.func && sc.func.isSynchronized())
15163 return false;
15165 // https://issues.dlang.org/show_bug.cgi?id=23790
15166 if (e.e1.type.isTypeStruct())
15167 return false;
15170 auto fd = e.var.isFuncDeclaration();
15171 const sharedFunc = fd && fd.type.isShared;
15172 if (!allowRef && !sharedFunc)
15173 return sharedError(e);
15175 // Allow using `DotVarExp` within value types
15176 if (e.e1.type.isTypeSArray() || e.e1.type.isTypeStruct())
15177 return check(e.e1, allowRef);
15179 // If we end up with a single `VarExp`, it might be a `ref` param
15180 // `shared ref T` param == `shared(T)*`.
15181 if (auto ve = e.e1.isVarExp())
15183 return check(e.e1, allowRef && (ve.var.storage_class & STC.ref_));
15186 return sharedError(e);
15189 return check(e.e1, false);
15192 bool visitIndex(IndexExp e)
15194 if (!allowRef && e.type.isShared())
15195 return sharedError(e);
15197 if (e.e1.type.isShared())
15198 return sharedError(e);
15200 return check(e.e1, false);
15203 bool visitComma(CommaExp e)
15205 // Cannot be `return ref` since we can't use the return,
15206 // but it's better to show that error than an unrelated `shared` one
15207 return check(e.e2, true);
15210 switch (e.op)
15212 default: return visit(e);
15214 // Those have no indirections / can be ignored
15215 case EXP.call:
15216 case EXP.error:
15217 case EXP.complex80:
15218 case EXP.int64:
15219 case EXP.null_: return false;
15221 case EXP.variable: return visitVar(e.isVarExp());
15222 case EXP.new_: return visitNew(e.isNewExp());
15223 case EXP.address: return visitAddr(e.isAddrExp());
15224 case EXP.star: return visitPtr(e.isPtrExp());
15225 case EXP.dotVariable: return visitDotVar(e.isDotVarExp());
15226 case EXP.index: return visitIndex(e.isIndexExp());
15230 return check(e, returnRef);
15233 /****************************************
15234 * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE_FULL_PATH__ to loc.
15236 Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
15238 // Don't replace the special keywords, while we are inside a default
15239 // argument. They are replaced later when copied to the call site.
15240 if (sc.inDefaultArg)
15241 return exp;
15243 exp.loc = loc;
15245 Expression visit(Expression exp)
15247 if (auto binExp = exp.isBinExp())
15249 binExp.e1 = binExp.e1.resolveLoc(loc, sc);
15250 binExp.e2 = binExp.e2.resolveLoc(loc, sc);
15251 return binExp;
15253 if (auto unaExp = exp.isUnaExp())
15255 unaExp.e1 = unaExp.e1.resolveLoc(loc, sc);
15256 return unaExp;
15258 return exp;
15261 Expression visitCond(CondExp exp)
15263 exp.e1 = exp.e1.resolveLoc(loc, sc);
15264 exp.e2 = exp.e2.resolveLoc(loc, sc);
15265 exp.econd = exp.econd.resolveLoc(loc, sc);
15266 return exp;
15269 Expression visitCat(CatExp exp)
15271 exp.e1 = exp.e1.resolveLoc(loc, sc);
15272 exp.e2 = exp.e2.resolveLoc(loc, sc);
15273 if (exp.lowering)
15274 exp.lowering = exp.lowering.resolveLoc(loc, sc);
15275 return exp;
15278 Expression visitStructLiteral(StructLiteralExp exp)
15280 foreach (ref element; *exp.elements)
15282 if (element)
15283 element = element.resolveLoc(loc, sc);
15286 return exp;
15289 Expression visitNew(NewExp exp)
15291 if (exp.thisexp)
15292 exp.thisexp = exp.thisexp.resolveLoc(loc, sc);
15293 if (exp.argprefix)
15294 exp.argprefix = exp.argprefix.resolveLoc(loc, sc);
15295 if (exp.lowering)
15296 exp.lowering = exp.lowering.resolveLoc(loc, sc);
15298 foreach (ref element; *exp.arguments)
15300 if (element)
15301 element = element.resolveLoc(loc, sc);
15304 return exp;
15307 Expression visitCall(CallExp exp)
15309 foreach (ref element; *exp.arguments)
15311 if (element)
15312 element = element.resolveLoc(loc, sc);
15315 return exp;
15318 Expression visitArray(ArrayExp exp)
15320 exp.e1 = exp.e1.resolveLoc(loc, sc);
15322 foreach (ref element; *exp.arguments)
15324 if (element)
15325 element = element.resolveLoc(loc, sc);
15328 return exp;
15331 Expression visitSlice(SliceExp exp)
15333 exp.e1 = exp.e1.resolveLoc(loc, sc);
15334 exp.lwr = exp.lwr.resolveLoc(loc, sc);
15335 exp.upr = exp.upr.resolveLoc(loc, sc);
15337 return exp;
15340 Expression visitInterval(IntervalExp exp)
15342 exp.lwr = exp.lwr.resolveLoc(loc, sc);
15343 exp.upr = exp.upr.resolveLoc(loc, sc);
15345 return exp;
15348 Expression visitArrayLiteral(ArrayLiteralExp exp)
15350 if (exp.basis)
15351 exp.basis = exp.basis.resolveLoc(loc, sc);
15353 foreach (ref element; *exp.elements)
15355 if (element)
15356 element = element.resolveLoc(loc, sc);
15359 return exp;
15362 Expression visitAssocArrayLiteral(AssocArrayLiteralExp exp)
15364 foreach (ref element; *exp.keys)
15366 if (element)
15367 element = element.resolveLoc(loc, sc);
15370 foreach (ref element; *exp.values)
15372 if (element)
15373 element = element.resolveLoc(loc, sc);
15376 return exp;
15379 Expression visitFileInit(FileInitExp exp)
15381 //printf("FileInitExp::resolve() %s\n", exp.toChars());
15382 const(char)* s;
15383 if (exp.op == EXP.fileFullPath)
15384 s = FileName.toAbsolute(loc.isValid() ? loc.filename : sc._module.srcfile.toChars());
15385 else
15386 s = loc.isValid() ? loc.filename : sc._module.ident.toChars();
15388 Expression e = new StringExp(loc, s.toDString());
15389 return e.expressionSemantic(sc);
15392 Expression visitLineInit(LineInitExp exp)
15394 Expression e = new IntegerExp(loc, loc.linnum, Type.tint32);
15395 return e.expressionSemantic(sc);
15398 Expression visitModuleInit(ModuleInitExp exp)
15400 const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString();
15401 Expression e = new StringExp(loc, s);
15402 return e.expressionSemantic(sc);
15405 Expression visitFuncInit(FuncInitExp exp)
15407 const(char)* s;
15408 if (sc.callsc && sc.callsc.func)
15409 s = sc.callsc.func.Dsymbol.toPrettyChars();
15410 else if (sc.func)
15411 s = sc.func.Dsymbol.toPrettyChars();
15412 else
15413 s = "";
15414 Expression e = new StringExp(loc, s.toDString());
15415 return e.expressionSemantic(sc);
15418 Expression visitPrettyFunc(PrettyFuncInitExp exp)
15420 FuncDeclaration fd = (sc.callsc && sc.callsc.func)
15421 ? sc.callsc.func
15422 : sc.func;
15424 const(char)* s;
15425 if (fd)
15427 const funcStr = fd.Dsymbol.toPrettyChars();
15428 OutBuffer buf;
15429 functionToBufferWithIdent(fd.type.isTypeFunction(), buf, funcStr, fd.isStatic);
15430 s = buf.extractChars();
15432 else
15434 s = "";
15437 Expression e = new StringExp(loc, s.toDString());
15438 e = e.expressionSemantic(sc);
15439 e.type = Type.tstring;
15440 return e;
15443 switch(exp.op)
15445 default: return visit(exp);
15446 case EXP.structLiteral: return visitStructLiteral(exp.isStructLiteralExp());
15447 case EXP.new_: return visitNew(exp.isNewExp());
15448 case EXP.concatenate: return visitCat(exp.isCatExp());
15449 case EXP.call: return visitCall(exp.isCallExp());
15450 case EXP.question: return visitCond(exp.isCondExp());
15451 case EXP.array: return visitArray(exp.isArrayExp());
15452 case EXP.slice: return visitSlice(exp.isSliceExp());
15453 case EXP.interval: return visitInterval(exp.isIntervalExp());
15454 case EXP.arrayLiteral: return visitArrayLiteral(exp.isArrayLiteralExp());
15455 case EXP.assocArrayLiteral: return visitAssocArrayLiteral(exp.isAssocArrayLiteralExp());
15456 case EXP.file:
15457 case EXP.fileFullPath: return visitFileInit(exp.isFileInitExp());
15458 case EXP.line: return visitLineInit(exp.isLineInitExp);
15459 case EXP.moduleString: return visitModuleInit(exp.isModuleInitExp());
15460 case EXP.functionString: return visitFuncInit(exp.isFuncInitExp());
15461 case EXP.prettyFunction: return visitPrettyFunc(exp.isPrettyFuncInitExp());
15465 /************************************************
15466 * Destructors are attached to VarDeclarations.
15467 * Hence, if expression returns a temp that needs a destructor,
15468 * make sure and create a VarDeclaration for that temp.
15470 Expression addDtorHook(Expression e, Scope* sc)
15472 Expression visit(Expression exp)
15474 return exp;
15477 Expression visitStructLiteral(StructLiteralExp exp)
15479 auto sd = exp.sd;
15480 /* If struct requires a destructor, rewrite as:
15481 * (S tmp = S()),tmp
15482 * so that the destructor can be hung on tmp.
15484 if (sd.dtor && sc.func)
15486 /* Make an identifier for the temporary of the form:
15487 * __sl%s%d, where %s is the struct name
15489 char[10] buf = void;
15490 const prefix = "__sl";
15491 const ident = sd.ident.toString;
15492 const fullLen = prefix.length + ident.length;
15493 const len = fullLen < buf.length ? fullLen : buf.length;
15494 buf[0 .. prefix.length] = prefix;
15495 buf[prefix.length .. len] = ident[0 .. len - prefix.length];
15497 auto tmp = copyToTemp(0, buf[0 .. len], exp);
15498 Expression ae = new DeclarationExp(exp.loc, tmp);
15499 Expression e = new CommaExp(exp.loc, ae, new VarExp(exp.loc, tmp));
15500 e = e.expressionSemantic(sc);
15501 return e;
15504 return exp;
15507 Expression visitCall(CallExp exp)
15509 auto e1 = exp.e1;
15510 auto type = exp.type;
15511 /* Only need to add dtor hook if it's a type that needs destruction.
15512 * Use same logic as VarDeclaration::callScopeDtor()
15515 if (auto tf = e1.type.isTypeFunction())
15517 if (tf.isref)
15518 return exp;
15521 Type tv = type.baseElemOf();
15522 if (auto ts = tv.isTypeStruct())
15524 StructDeclaration sd = ts.sym;
15525 if (sd.dtor)
15527 /* Type needs destruction, so declare a tmp
15528 * which the back end will recognize and call dtor on
15530 auto tmp = copyToTemp(0, Id.__tmpfordtor.toString(), exp);
15531 auto de = new DeclarationExp(exp.loc, tmp);
15532 auto ve = new VarExp(exp.loc, tmp);
15533 Expression e = new CommaExp(exp.loc, de, ve);
15534 e = e.expressionSemantic(sc);
15535 return e;
15539 return exp;
15542 Expression visitCast(CastExp exp)
15544 if (exp.to.toBasetype().ty == Tvoid) // look past the cast(void)
15545 exp.e1 = exp.e1.addDtorHook(sc);
15546 return exp;
15549 Expression visitComma(CommaExp exp)
15551 exp.e2 = exp.e2.addDtorHook(sc);
15552 return exp;
15555 switch(e.op)
15557 default: return visit(e);
15559 case EXP.structLiteral: return visitStructLiteral(e.isStructLiteralExp());
15560 case EXP.call: return visitCall(e.isCallExp());
15561 case EXP.cast_: return visitCast(e.isCastExp());
15562 case EXP.comma: return visitComma(e.isCommaExp());
15566 /*******************************
15567 * Try to convert an expression to be an lvalue.
15569 * Give error if we're not an lvalue.
15570 * Params:
15571 * _this = expression to convert
15572 * sc = scope
15573 * action = for error messages, what the lvalue is needed for (e.g. take address of for `&x`, modify for `x++`)
15574 * Returns: converted expression, or `ErrorExp` on error
15576 Expression toLvalue(Expression _this, Scope* sc, const(char)* action)
15578 return toLvalueImpl(_this, sc, action, _this);
15581 // e = original un-lowered expression for error messages, in case of recursive calls
15582 private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action, Expression e)
15584 if (!action)
15585 action = "create lvalue of";
15587 assert(e);
15588 Expression visit(Expression _this)
15590 // BinaryAssignExp does not have an EXP associated
15591 // so it's treated on the default path.
15592 // Lvalue-ness will be handled in glue :layer.
15593 if (_this.isBinAssignExp())
15594 return _this;
15595 if (!_this.loc.isValid())
15596 _this.loc = e.loc;
15598 if (e.op == EXP.type)
15599 error(_this.loc, "cannot %s type `%s`", action, e.type.toChars());
15600 else if (e.op == EXP.template_)
15601 error(_this.loc, "cannot %s template `%s`, perhaps instantiate it first", action, e.toChars());
15602 else
15603 error(_this.loc, "cannot %s expression `%s` because it is not an lvalue", action, e.toChars());
15605 return ErrorExp.get();
15608 Expression visitInteger(IntegerExp _this)
15610 if (!_this.loc.isValid())
15611 _this.loc = e.loc;
15612 error(e.loc, "cannot %s constant `%s`", action, e.toChars());
15613 return ErrorExp.get();
15616 Expression visitThis(ThisExp _this)
15618 if (_this.type.toBasetype().ty == Tclass)
15620 // Class `this` is an rvalue; struct `this` is an lvalue.
15621 return visit(_this);
15624 return _this;
15627 Expression visitString(StringExp _this)
15629 //printf("StringExp::toLvalue(%s) type = %s\n", _this.toChars(), _this.type ? _this.type.toChars() : NULL);
15630 return (_this.type && _this.type.toBasetype().ty == Tsarray) ? _this : visit(_this);
15633 Expression visitStructLiteral(StructLiteralExp _this)
15635 if (sc.flags & SCOPE.Cfile)
15636 return _this; // C struct literals are lvalues
15637 else
15638 return visit(_this);
15641 Expression visitTemplate(TemplateExp _this)
15643 if (!_this.fd)
15644 return visit(_this);
15646 assert(sc);
15647 return symbolToExp(_this.fd, _this.loc, sc, true);
15651 Expression visitVar(VarExp _this)
15653 auto var = _this.var;
15654 if (var.storage_class & STC.manifest)
15656 error(_this.loc, "cannot %s manifest constant `%s`", action, var.toChars());
15657 return ErrorExp.get();
15659 if (var.storage_class & STC.lazy_ && !_this.delegateWasExtracted)
15661 error(_this.loc, "cannot %s lazy variable `%s`", action, var.toChars());
15662 return ErrorExp.get();
15664 if (var.ident == Id.ctfe)
15666 error(_this.loc, "cannot %s compiler-generated variable `__ctfe`", action);
15667 return ErrorExp.get();
15669 if (var.ident == Id.dollar) // https://issues.dlang.org/show_bug.cgi?id=13574
15671 error(_this.loc, "cannot %s operator `$`", action);
15672 return ErrorExp.get();
15674 return _this;
15677 Expression visitDotVar(DotVarExp _this)
15679 auto e1 = _this.e1;
15680 auto var = _this.var;
15681 //printf("DotVarExp::toLvalue(%s)\n", toChars());
15682 if (sc && sc.flags & SCOPE.Cfile)
15684 /* C11 6.5.2.3-3: A postfix expression followed by the '.' or '->' operator
15685 * is an lvalue if the first expression is an lvalue.
15687 if (!e1.isLvalue())
15688 return visit(_this);
15690 if (!_this.isLvalue())
15691 return visit(_this);
15692 if (e1.op == EXP.this_ && sc.ctorflow.fieldinit.length && !(sc.ctorflow.callSuper & CSX.any_ctor))
15694 if (VarDeclaration vd = var.isVarDeclaration())
15696 auto ad = vd.isMember2();
15697 if (ad && ad.fields.length == sc.ctorflow.fieldinit.length)
15699 foreach (i, f; ad.fields)
15701 if (f == vd)
15703 if (!(sc.ctorflow.fieldinit[i].csx & CSX.this_ctor))
15705 /* If the address of vd is taken, assume it is thereby initialized
15706 * https://issues.dlang.org/show_bug.cgi?id=15869
15708 modifyFieldVar(_this.loc, sc, vd, e1);
15710 break;
15716 return _this;
15719 Expression visitCall(CallExp _this)
15721 if (_this.isLvalue())
15722 return _this;
15723 return visit(_this);
15726 Expression visitCast(CastExp _this)
15728 if (sc && sc.flags & SCOPE.Cfile)
15730 /* C11 6.5.4-5: A cast does not yield an lvalue.
15732 return visit(_this);
15734 if (_this.isLvalue())
15735 return _this;
15736 return visit(_this);
15739 Expression visitVectorArray(VectorArrayExp _this)
15741 _this.e1 = _this.e1.toLvalueImpl(sc, action, e);
15742 return _this;
15745 Expression visitSlice(SliceExp _this)
15747 //printf("SliceExp::toLvalue(%s) _this.type = %s\n", _this.toChars(), _this.type ? _this.type.toChars() : NULL);
15748 return (_this.type && _this.type.toBasetype().ty == Tsarray) ? _this : visit(_this);
15751 Expression visitArray(ArrayExp _this)
15753 if (_this.type && _this.type.toBasetype().ty == Tvoid)
15754 error(_this.loc, "`void`s have no value");
15755 return _this;
15758 Expression visitComma(CommaExp _this)
15760 _this.e2 = _this.e2.toLvalue(sc, action);
15761 return _this;
15764 Expression visitDelegatePointer(DelegatePtrExp _this)
15766 _this.e1 = _this.e1.toLvalueImpl(sc, action, e);
15767 return _this;
15770 Expression visitDelegateFuncptr(DelegateFuncptrExp _this)
15772 _this.e1 = _this.e1.toLvalueImpl(sc, action, e);
15773 return _this;
15776 Expression visitIndex(IndexExp _this)
15778 if (_this.isLvalue())
15779 return _this;
15780 return visit(_this);
15783 Expression visitAssign(AssignExp _this)
15785 if (_this.e1.op == EXP.slice || _this.e1.op == EXP.arrayLength)
15787 return visit(_this);
15790 /* In front-end level, AssignExp should make an lvalue of e1.
15791 * Taking the address of e1 will be handled in low level layer,
15792 * so this function does nothing.
15794 return _this;
15797 Expression visitCond(CondExp _this)
15799 // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
15800 CondExp e = cast(CondExp)(_this.copy());
15801 e.e1 = _this.e1.toLvalue(sc, action).addressOf();
15802 e.e2 = _this.e2.toLvalue(sc, action).addressOf();
15803 e.type = _this.type.pointerTo();
15804 return new PtrExp(_this.loc, e, _this.type);
15808 switch(_this.op)
15810 default: return visit(_this);
15812 case EXP.int64: return visitInteger(_this.isIntegerExp());
15813 case EXP.error: return _this;
15814 case EXP.identifier: return _this;
15815 case EXP.dSymbol: return _this;
15816 case EXP.this_: return visitThis(_this.isThisExp());
15817 case EXP.super_: return visitThis(_this.isSuperExp());
15818 case EXP.string_: return visitString(_this.isStringExp());
15819 case EXP.structLiteral: return visitStructLiteral(_this.isStructLiteralExp());
15820 case EXP.template_: return visitTemplate(_this.isTemplateExp());
15821 case EXP.variable: return visitVar(_this.isVarExp());
15822 case EXP.overloadSet: return _this;
15823 case EXP.dotVariable: return visitDotVar(_this.isDotVarExp());
15824 case EXP.call: return visitCall(_this.isCallExp());
15825 case EXP.star: return _this;
15826 case EXP.cast_: return visitCast(_this.isCastExp());
15827 case EXP.vectorArray: return visitVectorArray(_this.isVectorArrayExp());
15828 case EXP.slice: return visitSlice(_this.isSliceExp());
15829 case EXP.array: return visitArray(_this.isArrayExp());
15830 case EXP.comma: return visitComma(_this.isCommaExp());
15831 case EXP.delegatePointer: return visitDelegatePointer(_this.isDelegatePtrExp());
15832 case EXP.delegateFunctionPointer: return visitDelegateFuncptr(_this.isDelegateFuncptrExp());
15833 case EXP.index: return visitIndex(_this.isIndexExp());
15834 case EXP.construct: return visitAssign(_this.isConstructExp());
15835 case EXP.loweredAssignExp: return visitAssign(_this.isLoweredAssignExp());
15836 case EXP.blit: return visitAssign(_this.isBlitExp());
15837 case EXP.assign: return visitAssign(_this.isAssignExp());
15838 case EXP.question: return visitCond(_this.isCondExp());
15842 /***************************************
15843 * Parameters:
15844 * sc: scope
15845 * flag: 1: do not issue error message for invalid modification
15846 2: the exp is a DotVarExp and a subfield of the leftmost
15847 variable is modified
15848 * Returns:
15849 * Whether the type is modifiable
15851 Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag = ModifyFlags.none)
15853 switch(exp.op)
15855 case EXP.variable:
15856 auto varExp = cast(VarExp)exp;
15858 //printf("VarExp::checkModifiable %s", varExp.toChars());
15859 assert(varExp.type);
15860 return varExp.var.checkModify(varExp.loc, sc, null, flag);
15862 case EXP.dotVariable:
15863 auto dotVarExp = cast(DotVarExp)exp;
15865 //printf("DotVarExp::checkModifiable %s %s\n", dotVarExp.toChars(), dotVarExp.type.toChars());
15866 if (dotVarExp.e1.op == EXP.this_)
15867 return dotVarExp.var.checkModify(dotVarExp.loc, sc, dotVarExp.e1, flag);
15869 /* https://issues.dlang.org/show_bug.cgi?id=12764
15870 * If inside a constructor and an expression of type `this.field.var`
15871 * is encountered, where `field` is a struct declaration with
15872 * default construction disabled, we must make sure that
15873 * assigning to `var` does not imply that `field` was initialized
15875 if (sc.func && sc.func.isCtorDeclaration())
15877 // if inside a constructor scope and e1 of this DotVarExp
15878 // is another DotVarExp, then check if the leftmost expression is a `this` identifier
15879 if (auto dve = dotVarExp.e1.isDotVarExp())
15881 // Iterate the chain of DotVarExp to find `this`
15882 // Keep track whether access to fields was limited to union members
15883 // s.t. one can initialize an entire struct inside nested unions
15884 // (but not its members)
15885 bool onlyUnion = true;
15886 while (true)
15888 auto v = dve.var.isVarDeclaration();
15889 assert(v);
15891 // Accessing union member?
15892 auto t = v.type.isTypeStruct();
15893 if (!t || !t.sym.isUnionDeclaration())
15894 onlyUnion = false;
15896 // Another DotVarExp left?
15897 if (!dve.e1 || dve.e1.op != EXP.dotVariable)
15898 break;
15900 dve = cast(DotVarExp) dve.e1;
15903 if (dve.e1.op == EXP.this_)
15905 scope v = dve.var.isVarDeclaration();
15906 /* if v is a struct member field with no initializer, no default construction
15907 * and v wasn't intialized before
15909 if (v && v.isField() && !v._init && !v.ctorinit)
15911 if (auto ts = v.type.isTypeStruct())
15913 if (ts.sym.noDefaultCtor)
15915 /* checkModify will consider that this is an initialization
15916 * of v while it is actually an assignment of a field of v
15918 scope modifyLevel = v.checkModify(dotVarExp.loc, sc, dve.e1, !onlyUnion ? (flag | ModifyFlags.fieldAssign) : flag);
15919 if (modifyLevel == Modifiable.initialization)
15921 // https://issues.dlang.org/show_bug.cgi?id=22118
15922 // v is a union type field that was assigned
15923 // a variable, therefore it counts as initialization
15924 if (v.ctorinit)
15925 return Modifiable.initialization;
15927 return Modifiable.yes;
15929 return modifyLevel;
15937 //printf("\te1 = %s\n", e1.toChars());
15938 return dotVarExp.e1.checkModifiable(sc, flag);
15940 case EXP.star:
15941 auto ptrExp = cast(PtrExp)exp;
15942 if (auto se = ptrExp.e1.isSymOffExp())
15944 return se.var.checkModify(ptrExp.loc, sc, null, flag);
15946 else if (auto ae = ptrExp.e1.isAddrExp())
15948 return ae.e1.checkModifiable(sc, flag);
15950 return Modifiable.yes;
15952 case EXP.slice:
15953 auto sliceExp = cast(SliceExp)exp;
15955 //printf("SliceExp::checkModifiable %s\n", sliceExp.toChars());
15956 auto e1 = sliceExp.e1;
15957 if (e1.type.ty == Tsarray || (e1.op == EXP.index && e1.type.ty != Tarray) || e1.op == EXP.slice)
15959 return e1.checkModifiable(sc, flag);
15961 return Modifiable.yes;
15963 case EXP.comma:
15964 return (cast(CommaExp)exp).e2.checkModifiable(sc, flag);
15966 case EXP.index:
15967 auto indexExp = cast(IndexExp)exp;
15968 auto e1 = indexExp.e1;
15969 if (e1.type.ty == Tsarray ||
15970 e1.type.ty == Taarray ||
15971 (e1.op == EXP.index && e1.type.ty != Tarray) ||
15972 e1.op == EXP.slice)
15974 return e1.checkModifiable(sc, flag);
15976 return Modifiable.yes;
15978 case EXP.question:
15979 auto condExp = cast(CondExp)exp;
15980 if (condExp.e1.checkModifiable(sc, flag) != Modifiable.no
15981 && condExp.e2.checkModifiable(sc, flag) != Modifiable.no)
15982 return Modifiable.yes;
15983 return Modifiable.no;
15985 default:
15986 return exp.type ? Modifiable.yes : Modifiable.no; // default modifiable
15991 * Similar to `toLvalue`, but also enforce it is mutable or raise an error.
15992 * Params:
15993 * _this = Expression to convert
15994 * sc = scope
15995 * Returns: `_this` converted to an lvalue, or an `ErrorExp`
15997 Expression modifiableLvalue(Expression _this, Scope* sc)
15999 return modifiableLvalueImpl(_this, sc, _this);
16002 // e = original / un-lowered expression to print in error messages
16003 private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression e)
16005 assert(e);
16006 Expression visit(Expression exp)
16008 //printf("Expression::modifiableLvalue() %s, type = %s\n", exp.toChars(), exp.type.toChars());
16009 // See if this expression is a modifiable lvalue (i.e. not const)
16010 if (exp.isBinAssignExp())
16011 return exp.toLvalue(sc, "modify");
16013 auto type = exp.type;
16014 if (checkModifiable(exp, sc) == Modifiable.yes)
16016 assert(type);
16017 if (!type.isMutable())
16019 if (auto dve = exp.isDotVarExp())
16021 if (isNeedThisScope(sc, dve.var))
16022 for (Dsymbol s = sc.func; s; s = s.toParentLocal())
16024 FuncDeclaration ff = s.isFuncDeclaration();
16025 if (!ff)
16026 break;
16027 if (!ff.type.isMutable)
16029 error(exp.loc, "cannot modify `%s` in `%s` function", exp.toChars(), MODtoChars(type.mod));
16030 return ErrorExp.get();
16034 error(exp.loc, "cannot modify `%s` expression `%s`", MODtoChars(type.mod), exp.toChars());
16035 return ErrorExp.get();
16037 else if (!type.isAssignable())
16039 error(exp.loc, "cannot modify struct instance `%s` of type `%s` because it contains `const` or `immutable` members",
16040 exp.toChars(), type.toChars());
16041 return ErrorExp.get();
16044 return exp.toLvalueImpl(sc, "modify", e);
16047 Expression visitString(StringExp exp)
16049 error(exp.loc, "cannot modify string literal `%s`", exp.toChars());
16050 return ErrorExp.get();
16053 Expression visitVar(VarExp exp)
16055 //printf("VarExp::modifiableLvalue('%s')\n", exp.var.toChars());
16056 if (exp.var.storage_class & STC.manifest)
16058 error(exp.loc, "cannot modify manifest constant `%s`", exp.toChars());
16059 return ErrorExp.get();
16061 // See if this expression is a modifiable lvalue (i.e. not const)
16062 return visit(exp);
16065 Expression visitPtr(PtrExp exp)
16067 //printf("PtrExp::modifiableLvalue() %s, type %s\n", exp.toChars(), exp.type.toChars());
16068 Declaration var;
16069 auto e1 = exp.e1;
16070 if (auto se = e1.isSymOffExp())
16071 var = se.var;
16072 else if (auto ve = e1.isVarExp())
16073 var = ve.var;
16074 if (var && var.type.isFunction_Delegate_PtrToFunction())
16076 if (var.type.isTypeFunction())
16077 error(exp.loc, "function `%s` is not an lvalue and cannot be modified", var.toChars());
16078 else
16079 error(exp.loc, "function pointed to by `%s` is not an lvalue and cannot be modified", var.toChars());
16080 return ErrorExp.get();
16082 return visit(exp);
16085 Expression visitSlice(SliceExp exp)
16087 error(exp.loc, "slice expression `%s` is not a modifiable lvalue", exp.toChars());
16088 return exp;
16091 Expression visitComma(CommaExp exp)
16093 exp.e2 = exp.e2.modifiableLvalueImpl(sc, e);
16094 return exp;
16097 Expression visitDelegatePtr(DelegatePtrExp exp)
16099 if (sc.setUnsafe(false, exp.loc, "cannot modify delegate pointer in `@safe` code `%s`", exp))
16101 return ErrorExp.get();
16103 return visit(exp);
16106 Expression visitDelegateFuncptr(DelegateFuncptrExp exp)
16108 if (sc.setUnsafe(false, exp.loc, "cannot modify delegate function pointer in `@safe` code `%s`", exp))
16110 return ErrorExp.get();
16112 return visit(exp);
16115 Expression visitIndex(IndexExp exp)
16117 //printf("IndexExp::modifiableLvalue(%s)\n", exp.toChars());
16118 Expression ex = exp.markSettingAAElem();
16119 if (ex.op == EXP.error)
16120 return ex;
16122 return visit(exp);
16125 Expression visitCond(CondExp exp)
16127 if (!exp.e1.isLvalue() && !exp.e2.isLvalue())
16129 error(exp.loc, "conditional expression `%s` is not a modifiable lvalue", exp.toChars());
16130 return ErrorExp.get();
16132 exp.e1 = exp.e1.modifiableLvalue(sc);
16133 exp.e2 = exp.e2.modifiableLvalue(sc);
16134 return exp.toLvalue(sc, "modify");
16137 switch(_this.op)
16139 default: return visit(_this);
16140 case EXP.string_: return visitString(_this.isStringExp());
16141 case EXP.variable: return visitVar(_this.isVarExp());
16142 case EXP.star: return visitPtr(_this.isPtrExp());
16143 case EXP.slice: return visitSlice(_this.isSliceExp());
16144 case EXP.comma: return visitComma(_this.isCommaExp());
16145 case EXP.delegatePointer: return visitDelegatePtr(_this.isDelegatePtrExp());
16146 case EXP.delegateFunctionPointer: return visitDelegateFuncptr(_this.isDelegateFuncptrExp());
16147 case EXP.index: return visitIndex(_this.isIndexExp());
16148 case EXP.question: return visitCond(_this.isCondExp());
16153 /****************************************************
16154 * Determine if `exp`, which gets its address taken, can do so safely.
16155 * Params:
16156 * sc = context
16157 * exp = expression having its address taken
16158 * v = the variable getting its address taken
16159 * Returns:
16160 * `true` if ok, `false` for error
16162 bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
16164 //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars());
16165 if (v is null)
16166 return true;
16168 if (!v.canTakeAddressOf())
16170 error(exp.loc, "cannot take address of `%s`", exp.toChars());
16171 return false;
16173 if (sc.func && !sc.intypeof && !v.isDataseg())
16175 if (sc.useDIP1000 != FeatureState.enabled &&
16176 !(v.storage_class & STC.temp) &&
16177 sc.setUnsafe(false, exp.loc, "cannot take address of local `%s` in `@safe` function `%s`", v, sc.func))
16179 return false;
16182 return true;
16185 /**************************************
16186 * This check ensures that the object in `exp` can have its address taken, or
16187 * issue a diagnostic error.
16188 * Params:
16189 * e = expression to check
16190 * sc = context
16191 * Returns:
16192 * true if the expression is addressable
16194 bool checkAddressable(Expression e, Scope* sc)
16196 Expression ex = e;
16197 while (true)
16199 switch (ex.op)
16201 case EXP.dotVariable:
16202 // https://issues.dlang.org/show_bug.cgi?id=22749
16203 // Error about taking address of any bit-field, regardless of
16204 // whether SCOPE.Cfile is set.
16205 if (auto bf = ex.isDotVarExp().var.isBitFieldDeclaration())
16207 error(e.loc, "cannot take address of bit-field `%s`", bf.toChars());
16208 return false;
16210 goto case EXP.cast_;
16212 case EXP.index:
16213 ex = ex.isBinExp().e1;
16214 continue;
16216 case EXP.address:
16217 case EXP.array:
16218 case EXP.cast_:
16219 ex = ex.isUnaExp().e1;
16220 continue;
16222 case EXP.variable:
16223 if (sc.flags & SCOPE.Cfile)
16225 // C11 6.5.3.2: A variable that has its address taken cannot be
16226 // stored in a register.
16227 // C11 6.3.2.1: An array that has its address computed with `[]`
16228 // or cast to an lvalue pointer cannot be stored in a register.
16229 if (ex.isVarExp().var.storage_class & STC.register)
16231 if (e.isIndexExp())
16232 error(e.loc, "cannot index through register variable `%s`", ex.toChars());
16233 else
16234 error(e.loc, "cannot take address of register variable `%s`", ex.toChars());
16235 return false;
16238 break;
16240 default:
16241 break;
16243 break;
16245 return true;
16249 /*******************************
16250 * Checks the attributes of a function.
16251 * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`)
16252 * and usage of `deprecated` and `@disabled`-ed symbols are checked.
16254 * Params:
16255 * exp = expression to check attributes for
16256 * sc = scope of the function
16257 * f = function to be checked
16258 * Returns: `true` if error occur.
16260 private bool checkFunctionAttributes(Expression exp, Scope* sc, FuncDeclaration f)
16262 bool error = f.checkDisabled(exp.loc, sc);
16263 error |= f.checkDeprecated(exp.loc, sc);
16264 error |= f.checkPurity(exp.loc, sc);
16265 error |= f.checkSafety(exp.loc, sc);
16266 error |= f.checkNogc(exp.loc, sc);
16267 return error;
16270 /*******************************
16271 * Helper function for `getRightThis()`.
16272 * Gets `this` of the next outer aggregate.
16273 * Params:
16274 * loc = location to use for error messages
16275 * sc = context
16276 * s = the parent symbol of the existing `this`
16277 * ad = struct or class we need the correct `this` for
16278 * e1 = existing `this`
16279 * t = type of the existing `this`
16280 * var = the specific member of ad we're accessing
16281 * flag = if true, return `null` instead of throwing an error
16282 * Returns:
16283 * Expression representing the `this` for the var
16285 Expression getThisSkipNestedFuncs(const ref Loc loc, Scope* sc, Dsymbol s, AggregateDeclaration ad, Expression e1, Type t, Dsymbol var, bool flag = false)
16287 int n = 0;
16288 while (s && s.isFuncDeclaration())
16290 FuncDeclaration f = s.isFuncDeclaration();
16291 if (f.vthis)
16293 n++;
16294 e1 = new VarExp(loc, f.vthis);
16295 if (f.hasDualContext())
16297 // (*__this)[i]
16298 if (n > 1)
16299 e1 = e1.expressionSemantic(sc);
16300 e1 = new PtrExp(loc, e1);
16301 uint i = f.followInstantiationContext(ad);
16302 e1 = new IndexExp(loc, e1, new IntegerExp(i));
16303 s = f.toParentP(ad);
16304 continue;
16307 else
16309 if (flag)
16310 return null;
16311 error(e1.loc, "need `this` of type `%s` to access member `%s` from static function `%s`", ad.toChars(), var.toChars(), f.toChars());
16312 e1 = ErrorExp.get();
16313 return e1;
16315 s = s.toParent2();
16317 if (n > 1 || e1.op == EXP.index)
16318 e1 = e1.expressionSemantic(sc);
16319 if (s && e1.type.equivalent(Type.tvoidptr))
16321 if (auto sad = s.isAggregateDeclaration())
16323 Type ta = sad.handleType();
16324 if (ta.ty == Tstruct)
16325 ta = ta.pointerTo();
16326 e1.type = ta;
16329 e1.type = e1.type.addMod(t.mod);
16330 return e1;
16333 /*******************************
16334 * Make a dual-context container for use as a `this` argument.
16335 * Params:
16336 * loc = location to use for error messages
16337 * sc = current scope
16338 * fd = target function that will take the `this` argument
16339 * Returns:
16340 * Temporary closure variable.
16341 * Note:
16342 * The function `fd` is added to the nested references of the
16343 * newly created variable such that a closure is made for the variable when
16344 * the address of `fd` is taken.
16346 VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration fd)
16348 Type tthis2 = Type.tvoidptr.sarrayOf(2);
16349 VarDeclaration vthis2 = new VarDeclaration(loc, tthis2, Identifier.generateId("__this"), null);
16350 vthis2.storage_class |= STC.temp;
16351 vthis2.dsymbolSemantic(sc);
16352 vthis2.parent = sc.parent;
16353 // make it a closure var
16354 assert(sc.func);
16355 sc.func.closureVars.push(vthis2);
16356 // add `fd` to the nested refs
16357 vthis2.nestedrefs.push(fd);
16358 return vthis2;
16361 /*******************************
16362 * Make sure that the runtime hook `id` exists.
16363 * Params:
16364 * loc = location to use for error messages
16365 * sc = current scope
16366 * id = the hook identifier
16367 * description = what the hook does
16368 * module_ = what module the hook is located in
16369 * Returns:
16370 * a `bool` indicating if the hook is present.
16372 bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string description, Identifier module_ = Id.object)
16374 Dsymbol pscopesym;
16375 auto rootSymbol = sc.search(loc, Id.empty, pscopesym);
16376 if (auto moduleSymbol = rootSymbol.search(loc, module_))
16377 if (moduleSymbol.search(loc, id))
16378 return true;
16379 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);
16380 return false;
16383 /***************************************
16384 * Fit elements[] to the corresponding types of the `sd`'s fields.
16386 * Params:
16387 * sd = the struct declaration
16388 * loc = location to use for error messages
16389 * sc = context
16390 * elements = explicit arguments used to construct object
16391 * stype = the constructed object type.
16392 * Returns:
16393 * false if any errors occur,
16394 * otherwise true and elements[] are rewritten for the output.
16396 private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions* elements, Type stype)
16398 if (!elements)
16399 return true;
16401 const nfields = sd.nonHiddenFields();
16402 size_t offset = 0;
16403 for (size_t i = 0; i < elements.length; i++)
16405 Expression e = (*elements)[i];
16406 if (!e)
16407 continue;
16409 e = resolveProperties(sc, e);
16410 if (i >= nfields)
16412 if (i < sd.fields.length && e.op == EXP.null_)
16414 // CTFE sometimes creates null as hidden pointer; we'll allow this.
16415 continue;
16417 .error(loc, "more initializers than fields (%llu) of `%s`", cast(ulong)nfields, sd.toChars());
16418 return false;
16420 VarDeclaration v = sd.fields[i];
16421 if (v.offset < offset)
16423 .error(loc, "overlapping initialization for `%s`", v.toChars());
16424 if (!sd.isUnionDeclaration())
16426 enum errorMsg = "`struct` initializers that contain anonymous unions" ~
16427 " must initialize only the first member of a `union`. All subsequent" ~
16428 " non-overlapping fields are default initialized";
16429 .errorSupplemental(loc, errorMsg);
16431 return false;
16433 const vsize = v.type.size();
16434 if (vsize == SIZE_INVALID)
16435 return false;
16436 offset = cast(uint)(v.offset + vsize);
16438 Type t = v.type;
16439 if (stype)
16440 t = t.addMod(stype.mod);
16441 Type origType = t;
16442 Type tb = t.toBasetype();
16444 const hasPointers = tb.hasPointers();
16445 if (hasPointers)
16447 if ((!stype.alignment.isDefault() && stype.alignment.get() < target.ptrsize ||
16448 (v.offset & (target.ptrsize - 1))) &&
16449 (sc.setUnsafe(false, loc,
16450 "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, v)))
16452 return false;
16456 /* Look for case of initializing a static array with a too-short
16457 * string literal, such as:
16458 * char[5] foo = "abc";
16459 * Allow this by doing an explicit cast, which will lengthen the string
16460 * literal.
16462 if (e.op == EXP.string_ && tb.ty == Tsarray)
16464 StringExp se = cast(StringExp)e;
16465 Type typeb = se.type.toBasetype();
16466 TY tynto = tb.nextOf().ty;
16467 if (!se.committed &&
16468 (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar &&
16469 se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger())
16471 e = se.castTo(sc, t);
16472 goto L1;
16476 while (!e.implicitConvTo(t) && tb.ty == Tsarray)
16478 /* Static array initialization, as in:
16479 * T[3][5] = e;
16481 t = tb.nextOf();
16482 tb = t.toBasetype();
16484 if (!e.implicitConvTo(t))
16485 t = origType; // restore type for better diagnostic
16487 e = e.implicitCastTo(sc, t);
16489 if (e.op == EXP.error)
16490 return false;
16492 (*elements)[i] = doCopyOrMove(sc, e);
16494 return true;
16499 * Returns `em` as a VariableExp
16500 * Params:
16501 * em = the EnumMember to wrap
16502 * loc = location of use of em
16503 * sc = scope of use of em
16504 * Returns:
16505 * VarExp referenceing `em` or ErrorExp if `em` if disabled/deprecated
16507 Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc)
16509 dsymbolSemantic(em, sc);
16510 if (em.errors)
16511 return ErrorExp.get();
16512 em.checkDisabled(loc, sc);
16514 if (em.depdecl && !em.depdecl._scope)
16516 em.depdecl._scope = sc;
16517 em.depdecl._scope.setNoFree();
16519 em.checkDeprecated(loc, sc);
16521 if (em.errors)
16522 return ErrorExp.get();
16523 Expression e = new VarExp(loc, em);
16524 e = e.expressionSemantic(sc);
16525 if (!(sc.flags & SCOPE.Cfile) && em.isCsymbol())
16527 /* C11 types them as int. But if in D file,
16528 * type qualified names as the enum
16530 e.type = em.parent.isEnumDeclaration().type;
16531 assert(e.type);
16533 return e;
16537 /*****************************
16538 * Try to treat `exp` as a boolean,
16539 * Params:
16540 * exp = the expression
16541 * sc = scope to evalute `exp` in
16542 * Returns:
16543 * Modified expression on success, ErrorExp on error
16545 Expression toBoolean(Expression exp, Scope* sc)
16547 switch(exp.op)
16549 case EXP.delete_:
16550 error(exp.loc, "`delete` does not give a boolean result");
16551 return ErrorExp.get();
16553 case EXP.comma:
16554 auto ce = exp.isCommaExp();
16555 auto ex2 = ce.e2.toBoolean(sc);
16556 if (ex2.op == EXP.error)
16557 return ex2;
16558 ce.e2 = ex2;
16559 ce.type = ce.e2.type;
16560 return ce;
16562 case EXP.assign:
16563 case EXP.construct:
16564 case EXP.blit:
16565 case EXP.loweredAssignExp:
16566 if (sc.flags & SCOPE.Cfile)
16567 return exp;
16568 // Things like:
16569 // if (a = b) ...
16570 // are usually mistakes.
16571 error(exp.loc, "assignment cannot be used as a condition, perhaps `==` was meant?");
16572 return ErrorExp.get();
16574 //LogicalExp
16575 case EXP.andAnd:
16576 case EXP.orOr:
16577 auto le = exp.isLogicalExp();
16578 auto ex2 = le.e2.toBoolean(sc);
16579 if (ex2.op == EXP.error)
16580 return ex2;
16581 le.e2 = ex2;
16582 return le;
16584 case EXP.question:
16585 auto ce = exp.isCondExp();
16586 auto ex1 = ce.e1.toBoolean(sc);
16587 auto ex2 = ce.e2.toBoolean(sc);
16588 if (ex1.op == EXP.error)
16589 return ex1;
16590 if (ex2.op == EXP.error)
16591 return ex2;
16592 ce.e1 = ex1;
16593 ce.e2 = ex2;
16594 return ce;
16597 default:
16598 // Default is 'yes' - do nothing
16599 Expression e = arrayFuncConv(exp, sc);
16600 Type t = e.type;
16601 Type tb = t.toBasetype();
16602 Type att = null;
16604 while (1)
16606 // Structs can be converted to bool using opCast(bool)()
16607 if (auto ts = tb.isTypeStruct())
16609 AggregateDeclaration ad = ts.sym;
16610 /* Don't really need to check for opCast first, but by doing so we
16611 * get better error messages if it isn't there.
16613 if (Dsymbol fd = search_function(ad, Id._cast))
16615 e = new CastExp(exp.loc, e, Type.tbool);
16616 e = e.expressionSemantic(sc);
16617 return e;
16620 // Forward to aliasthis.
16621 if (ad.aliasthis && !isRecursiveAliasThis(att, tb))
16623 e = resolveAliasThis(sc, e);
16624 t = e.type;
16625 tb = e.type.toBasetype();
16626 continue;
16629 break;
16632 if (!t.isBoolean())
16634 if (tb != Type.terror)
16635 error(exp.loc, "expression `%s` of type `%s` does not have a boolean value",
16636 exp.toChars(), t.toChars());
16637 return ErrorExp.get();
16639 return e;
16643 /********************************************
16644 * Semantically analyze and then evaluate a static condition at compile time.
16645 * This is special because short circuit operators &&, || and ?: at the top
16646 * level are not semantically analyzed if the result of the expression is not
16647 * necessary.
16648 * Params:
16649 * sc = instantiating scope
16650 * original = original expression, for error messages
16651 * e = resulting expression
16652 * errors = set to `true` if errors occurred
16653 * negatives = array to store negative clauses
16654 * Returns:
16655 * true if evaluates to true
16657 bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool errors, Expressions* negatives = null)
16659 if (negatives)
16660 negatives.setDim(0);
16662 bool impl(Expression e)
16664 if (e.isNotExp())
16666 NotExp ne = cast(NotExp)e;
16667 return !impl(ne.e1);
16670 if (e.op == EXP.andAnd || e.op == EXP.orOr)
16672 LogicalExp aae = cast(LogicalExp)e;
16673 bool result = impl(aae.e1);
16674 if (errors)
16675 return false;
16676 if (e.op == EXP.andAnd)
16678 if (!result)
16679 return false;
16681 else
16683 if (result)
16684 return true;
16686 result = impl(aae.e2);
16687 return !errors && result;
16690 if (e.op == EXP.question)
16692 CondExp ce = cast(CondExp)e;
16693 bool result = impl(ce.econd);
16694 if (errors)
16695 return false;
16696 Expression leg = result ? ce.e1 : ce.e2;
16697 result = impl(leg);
16698 return !errors && result;
16701 Expression before = e;
16702 const uint nerrors = global.errors;
16704 sc = sc.startCTFE();
16705 sc.flags |= SCOPE.condition;
16707 e = e.expressionSemantic(sc);
16708 e = resolveProperties(sc, e);
16709 e = e.toBoolean(sc);
16711 sc = sc.endCTFE();
16712 e = e.optimize(WANTvalue);
16714 if (nerrors != global.errors ||
16715 e.isErrorExp() ||
16716 e.type.toBasetype() == Type.terror)
16718 errors = true;
16719 return false;
16722 e = e.ctfeInterpret();
16724 const opt = e.toBool();
16725 if (opt.isEmpty())
16727 if (!e.type.isTypeError())
16728 error(e.loc, "expression `%s` is not constant", e.toChars());
16729 errors = true;
16730 return false;
16733 if (negatives && !opt.get())
16734 negatives.push(before);
16735 return opt.get();
16737 return impl(e);